text:
#==============================================================================#
# DirectoryService.jl
#
# This file is generated from:
# https://github.com/aws/aws-sdk-js/blob/master/apis/ds-2015-04-16.normal.json
#==============================================================================#

__precompile__()

module DirectoryService

using AWSCore

"""
    using AWSSDK.DirectoryService.add_ip_routes
    add_ip_routes([::AWSConfig], arguments::Dict)
    add_ip_routes([::AWSConfig]; DirectoryId=, IpRoutes=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "AddIpRoutes", arguments::Dict)
    ds([::AWSConfig], "AddIpRoutes", DirectoryId=, IpRoutes=, <keyword arguments>)

# AddIpRoutes Operation

If the DNS server for your on-premises domain uses a publicly addressable IP address, you must add a CIDR address block to correctly route traffic to and from your Microsoft AD on Amazon Web Services. *AddIpRoutes* adds this address block. You can also use *AddIpRoutes* to facilitate routing traffic that uses public IP ranges from your Microsoft AD on AWS to a peer VPC.

Before you call *AddIpRoutes*, ensure that all of the required permissions have been explicitly granted through a policy. For details about what permissions are required to run the *AddIpRoutes* operation, see [AWS Directory Service API Permissions: Actions, Resources, and Conditions Reference](http://docs.aws.amazon.com/directoryservice/latest/admin-guide/UsingWithDS_IAM_ResourcePermissions.html).

# Arguments

## `DirectoryId = ::String` -- *Required*
Identifier (ID) of the directory to which to add the address block.

## `IpRoutes = [[ ... ], ...]` -- *Required*
IP address blocks, using CIDR format, of the traffic to route. This is often the IP address block of the DNS server used for your on-premises domain.
```
 IpRoutes = [[
        "CidrIp" =>  ::String,
        "Description" =>  ::String
    ], ...]
```

## `UpdateSecurityGroupForDirectoryControllers = ::Bool`
If set to true, updates the inbound and outbound rules of the security group that has the description: "AWS created security group for *directory ID* directory controllers." Following are the new rules:

Inbound:

*   Type: Custom UDP Rule, Protocol: UDP, Range: 88, Source: 0.0.0.0/0

*   Type: Custom UDP Rule, Protocol: UDP, Range: 123, Source: 0.0.0.0/0

*   Type: Custom UDP Rule, Protocol: UDP, Range: 138, Source: 0.0.0.0/0

*   Type: Custom UDP Rule, Protocol: UDP, Range: 389, Source: 0.0.0.0/0

*   Type: Custom UDP Rule, Protocol: UDP, Range: 464, Source: 0.0.0.0/0

*   Type: Custom UDP Rule, Protocol: UDP, Range: 445, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 88, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 135, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 445, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 464, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 636, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 1024-65535, Source: 0.0.0.0/0

*   Type: Custom TCP Rule, Protocol: TCP, Range: 3268-33269, Source: 0.0.0.0/0

*   Type: DNS (UDP), Protocol: UDP, Range: 53, Source: 0.0.0.0/0

*   Type: DNS (TCP), Protocol: TCP, Range: 53, Source: 0.0.0.0/0

*   Type: LDAP, Protocol: TCP, Range: 389, Source: 0.0.0.0/0

*   Type: All ICMP, Protocol: All, Range: N/A, Source: 0.0.0.0/0

Outbound:

*   Type: All traffic, Protocol: All, Range: All, Destination: 0.0.0.0/0

These security rules impact an internal network interface that is not exposed publicly.

# Returns

`AddIpRoutesResult`

# Exceptions

`EntityDoesNotExistException`, `EntityAlreadyExistsException`, `InvalidParameterException`, `DirectoryUnavailableException`, `IpRouteLimitExceededException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/AddIpRoutes)
"""
@inline add_ip_routes(aws::AWSConfig=default_aws_config(); args...) = add_ip_routes(aws, args)

@inline add_ip_routes(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "AddIpRoutes", args)

@inline add_ip_routes(args) = add_ip_routes(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.add_tags_to_resource
    add_tags_to_resource([::AWSConfig], arguments::Dict)
    add_tags_to_resource([::AWSConfig]; ResourceId=, Tags=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "AddTagsToResource", arguments::Dict)
    ds([::AWSConfig], "AddTagsToResource", ResourceId=, Tags=)

# AddTagsToResource Operation

Adds or overwrites one or more tags for the specified directory. Each directory can have a maximum of 50 tags. Each tag consists of a key and optional value. Tag keys must be unique to each resource.

# Arguments

## `ResourceId = ::String` -- *Required*
Identifier (ID) for the directory to which to add the tag.

## `Tags = [[ ... ], ...]` -- *Required*
The tags to be assigned to the directory.
```
 Tags = [[
        "Key" => <required> ::String,
        "Value" => <required> ::String
    ], ...]
```

# Returns

`AddTagsToResourceResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `TagLimitExceededException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/AddTagsToResource)
"""
@inline add_tags_to_resource(aws::AWSConfig=default_aws_config(); args...) = add_tags_to_resource(aws, args)

@inline add_tags_to_resource(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "AddTagsToResource", args)

@inline add_tags_to_resource(args) = add_tags_to_resource(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.cancel_schema_extension
    cancel_schema_extension([::AWSConfig], arguments::Dict)
    cancel_schema_extension([::AWSConfig]; DirectoryId=, SchemaExtensionId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CancelSchemaExtension", arguments::Dict)
    ds([::AWSConfig], "CancelSchemaExtension", DirectoryId=, SchemaExtensionId=)

# CancelSchemaExtension Operation

Cancels an in-progress schema extension to a Microsoft AD directory. Once a schema extension has started replicating to all domain controllers, the task can no longer be canceled. A schema extension can be canceled during any of the following states; `Initializing`, `CreatingSnapshot`, and `UpdatingSchema`.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory whose schema extension will be canceled.

## `SchemaExtensionId = ::String` -- *Required*
The identifier of the schema extension that will be canceled.

# Returns

`CancelSchemaExtensionResult`

# Exceptions

`EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CancelSchemaExtension)
"""
@inline cancel_schema_extension(aws::AWSConfig=default_aws_config(); args...) = cancel_schema_extension(aws, args)

@inline cancel_schema_extension(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CancelSchemaExtension", args)

@inline cancel_schema_extension(args) = cancel_schema_extension(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.connect_directory
    connect_directory([::AWSConfig], arguments::Dict)
    connect_directory([::AWSConfig]; Name=, Password=, Size=, ConnectSettings=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "ConnectDirectory", arguments::Dict)
    ds([::AWSConfig], "ConnectDirectory", Name=, Password=, Size=, ConnectSettings=, <keyword arguments>)

# ConnectDirectory Operation

Creates an AD Connector to connect to an on-premises directory.

Before you call *ConnectDirectory*, ensure that all of the required permissions have been explicitly granted through a policy. For details about what permissions are required to run the *ConnectDirectory* operation, see [AWS Directory Service API Permissions: Actions, Resources, and Conditions Reference](http://docs.aws.amazon.com/directoryservice/latest/admin-guide/UsingWithDS_IAM_ResourcePermissions.html).

# Arguments

## `Name = ::String` -- *Required*
The fully-qualified name of the on-premises directory, such as `corp.example.com`.

## `ShortName = ::String`
The NetBIOS name of the on-premises directory, such as `CORP`.

## `Password = ::String` -- *Required*
The password for the on-premises user account.

## `Description = ::String`
A textual description for the directory.

## `Size = "Small" or "Large"` -- *Required*
The size of the directory.

## `ConnectSettings = [ ... ]` -- *Required*
A [DirectoryConnectSettings](@ref) object that contains additional information for the operation.
```
 ConnectSettings = [
        "VpcId" => <required> ::String,
        "SubnetIds" => <required> [::String, ...],
        "CustomerDnsIps" => <required> [::String, ...],
        "CustomerUserName" => <required> ::String
    ]
```

# Returns

`ConnectDirectoryResult`

# Exceptions

`DirectoryLimitExceededException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/ConnectDirectory)
"""
@inline connect_directory(aws::AWSConfig=default_aws_config(); args...) = connect_directory(aws, args)

@inline connect_directory(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "ConnectDirectory", args)

@inline connect_directory(args) = connect_directory(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_alias
    create_alias([::AWSConfig], arguments::Dict)
    create_alias([::AWSConfig]; DirectoryId=, Alias=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateAlias", arguments::Dict)
    ds([::AWSConfig], "CreateAlias", DirectoryId=, Alias=)

# CreateAlias Operation

Creates an alias for a directory and assigns the alias to the directory. The alias is used to construct the access URL for the directory, such as `http://<alias>.awsapps.com`.

**Important**
> After an alias has been created, it cannot be deleted or reused, so this operation should only be used when absolutely necessary.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which to create the alias.

## `Alias = ::String` -- *Required*
The requested alias.

The alias must be unique amongst all aliases in AWS. This operation throws an `EntityAlreadyExistsException` error if the alias already exists.

# Returns

`CreateAliasResult`

# Exceptions

`EntityAlreadyExistsException`, `EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateAlias)
"""
@inline create_alias(aws::AWSConfig=default_aws_config(); args...) = create_alias(aws, args)

@inline create_alias(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateAlias", args)

@inline create_alias(args) = create_alias(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_computer
    create_computer([::AWSConfig], arguments::Dict)
    create_computer([::AWSConfig]; DirectoryId=, ComputerName=, Password=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateComputer", arguments::Dict)
    ds([::AWSConfig], "CreateComputer", DirectoryId=, ComputerName=, Password=, <keyword arguments>)

# CreateComputer Operation

Creates a computer account in the specified directory, and joins the computer to the directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory in which to create the computer account.

## `ComputerName = ::String` -- *Required*
The name of the computer account.

## `Password = ::String` -- *Required*
A one-time password that is used to join the computer to the directory. You should generate a random, strong password to use for this parameter.

## `OrganizationalUnitDistinguishedName = ::String`
The fully-qualified distinguished name of the organizational unit to place the computer account in.

## `ComputerAttributes = [[ ... ], ...]`
An array of [Attribute](@ref) objects that contain any LDAP attributes to apply to the computer account.
```
 ComputerAttributes = [[
        "Name" =>  ::String,
        "Value" =>  ::String
    ], ...]
```

# Returns

`CreateComputerResult`

# Exceptions

`AuthenticationFailedException`, `DirectoryUnavailableException`, `EntityAlreadyExistsException`, `EntityDoesNotExistException`, `InvalidParameterException`, `UnsupportedOperationException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateComputer)
"""
@inline create_computer(aws::AWSConfig=default_aws_config(); args...) = create_computer(aws, args)

@inline create_computer(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateComputer", args)

@inline create_computer(args) = create_computer(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_conditional_forwarder
    create_conditional_forwarder([::AWSConfig], arguments::Dict)
    create_conditional_forwarder([::AWSConfig]; DirectoryId=, RemoteDomainName=, DnsIpAddrs=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateConditionalForwarder", arguments::Dict)
    ds([::AWSConfig], "CreateConditionalForwarder", DirectoryId=, RemoteDomainName=, DnsIpAddrs=)

# CreateConditionalForwarder Operation

Creates a conditional forwarder associated with your AWS directory. Conditional forwarders are required in order to set up a trust relationship with another domain. The conditional forwarder points to the trusted domain.

# Arguments

## `DirectoryId = ::String` -- *Required*
The directory ID of the AWS directory for which you are creating the conditional forwarder.

## `RemoteDomainName = ::String` -- *Required*
The fully qualified domain name (FQDN) of the remote domain with which you will set up a trust relationship.

## `DnsIpAddrs = [::String, ...]` -- *Required*
The IP addresses of the remote DNS server associated with RemoteDomainName.

# Returns

`CreateConditionalForwarderResult`

# Exceptions

`EntityAlreadyExistsException`, `EntityDoesNotExistException`, `DirectoryUnavailableException`, `InvalidParameterException`, `UnsupportedOperationException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateConditionalForwarder)
"""
@inline create_conditional_forwarder(aws::AWSConfig=default_aws_config(); args...) = create_conditional_forwarder(aws, args)

@inline create_conditional_forwarder(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateConditionalForwarder", args)

@inline create_conditional_forwarder(args) = create_conditional_forwarder(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_directory
    create_directory([::AWSConfig], arguments::Dict)
    create_directory([::AWSConfig]; Name=, Password=, Size=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateDirectory", arguments::Dict)
    ds([::AWSConfig], "CreateDirectory", Name=, Password=, Size=, <keyword arguments>)

# CreateDirectory Operation

Creates a Simple AD directory.

Before you call *CreateDirectory*, ensure that all of the required permissions have been explicitly granted through a policy. For details about what permissions are required to run the *CreateDirectory* operation, see [AWS Directory Service API Permissions: Actions, Resources, and Conditions Reference](http://docs.aws.amazon.com/directoryservice/latest/admin-guide/UsingWithDS_IAM_ResourcePermissions.html).

# Arguments

## `Name = ::String` -- *Required*
The fully qualified name for the directory, such as `corp.example.com`.

## `ShortName = ::String`
The short name of the directory, such as `CORP`.

## `Password = ::String` -- *Required*
The password for the directory administrator. The directory creation process creates a directory administrator account with the username `Administrator` and this password.

## `Description = ::String`
A textual description for the directory.

## `Size = "Small" or "Large"` -- *Required*
The size of the directory.

## `VpcSettings = [ ... ]`
A [DirectoryVpcSettings](@ref) object that contains additional information for the operation.
```
 VpcSettings = [
        "VpcId" => <required> ::String,
        "SubnetIds" => <required> [::String, ...]
    ]
```

# Returns

`CreateDirectoryResult`

# Exceptions

`DirectoryLimitExceededException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateDirectory)
"""
@inline create_directory(aws::AWSConfig=default_aws_config(); args...) = create_directory(aws, args)

@inline create_directory(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateDirectory", args)

@inline create_directory(args) = create_directory(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_microsoft_ad
    create_microsoft_ad([::AWSConfig], arguments::Dict)
    create_microsoft_ad([::AWSConfig]; Name=, Password=, VpcSettings=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateMicrosoftAD", arguments::Dict)
    ds([::AWSConfig], "CreateMicrosoftAD", Name=, Password=, VpcSettings=, <keyword arguments>)

# CreateMicrosoftAD Operation

Creates a Microsoft AD in the AWS cloud.

Before you call *CreateMicrosoftAD*, ensure that all of the required permissions have been explicitly granted through a policy. For details about what permissions are required to run the *CreateMicrosoftAD* operation, see [AWS Directory Service API Permissions: Actions, Resources, and Conditions Reference](http://docs.aws.amazon.com/directoryservice/latest/admin-guide/UsingWithDS_IAM_ResourcePermissions.html).

# Arguments

## `Name = ::String` -- *Required*
The fully qualified domain name for the directory, such as `corp.example.com`. This name will resolve inside your VPC only. It does not need to be publicly resolvable.

## `ShortName = ::String`
The NetBIOS name for your domain. A short identifier for your domain, such as `CORP`. If you don't specify a NetBIOS name, it will default to the first part of your directory DNS. For example, `CORP` for the directory DNS `corp.example.com`.

## `Password = ::String` -- *Required*
The password for the default administrative user named `Admin`.

## `Description = ::String`
A textual description for the directory. This label will appear on the AWS console `Directory Details` page after the directory is created.

## `VpcSettings = [ ... ]` -- *Required*
Contains VPC information for the [CreateDirectory](@ref) or [CreateMicrosoftAD](@ref) operation.
```
 VpcSettings = [
        "VpcId" => <required> ::String,
        "SubnetIds" => <required> [::String, ...]
    ]
```

## `Edition = "Enterprise" or "Standard"`
AWS Microsoft AD is available in two editions: Standard and Enterprise. Enterprise is the default.

# Returns

`CreateMicrosoftADResult`

# Exceptions

`DirectoryLimitExceededException`, `InvalidParameterException`, `ClientException`, `ServiceException` or `UnsupportedOperationException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateMicrosoftAD)
"""
@inline create_microsoft_ad(aws::AWSConfig=default_aws_config(); args...) = create_microsoft_ad(aws, args)

@inline create_microsoft_ad(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateMicrosoftAD", args)

@inline create_microsoft_ad(args) = create_microsoft_ad(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_snapshot
    create_snapshot([::AWSConfig], arguments::Dict)
    create_snapshot([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateSnapshot", arguments::Dict)
    ds([::AWSConfig], "CreateSnapshot", DirectoryId=, <keyword arguments>)

# CreateSnapshot Operation

Creates a snapshot of a Simple AD or Microsoft AD directory in the AWS cloud.

**Note**
> You cannot take snapshots of AD Connector directories.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory of which to take a snapshot.

## `Name = ::String`
The descriptive name to apply to the snapshot.

# Returns

`CreateSnapshotResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `SnapshotLimitExceededException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateSnapshot)
"""
@inline create_snapshot(aws::AWSConfig=default_aws_config(); args...) = create_snapshot(aws, args)

@inline create_snapshot(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateSnapshot", args)

@inline create_snapshot(args) = create_snapshot(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.create_trust
    create_trust([::AWSConfig], arguments::Dict)
    create_trust([::AWSConfig]; DirectoryId=, RemoteDomainName=, TrustPassword=, TrustDirection=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "CreateTrust", arguments::Dict)
    ds([::AWSConfig], "CreateTrust", DirectoryId=, RemoteDomainName=, TrustPassword=, TrustDirection=, <keyword arguments>)

# CreateTrust Operation

AWS Directory Service for Microsoft Active Directory allows you to configure trust relationships. For example, you can establish a trust between your Microsoft AD in the AWS cloud, and your existing on-premises Microsoft Active Directory. This would allow you to provide users and groups access to resources in either domain, with a single set of credentials.

This action initiates the creation of the AWS side of a trust relationship between a Microsoft AD in the AWS cloud and an external domain.

# Arguments

## `DirectoryId = ::String` -- *Required*
The Directory ID of the Microsoft AD in the AWS cloud for which to establish the trust relationship.

## `RemoteDomainName = ::String` -- *Required*
The Fully Qualified Domain Name (FQDN) of the external domain for which to create the trust relationship.

## `TrustPassword = ::String` -- *Required*
The trust password. The must be the same password that was used when creating the trust relationship on the external domain.

## `TrustDirection = "One-Way: Outgoing", "One-Way: Incoming" or "Two-Way"` -- *Required*
The direction of the trust relationship.

## `TrustType = "Forest"`
The trust relationship type.

## `ConditionalForwarderIpAddrs = [::String, ...]`
The IP addresses of the remote DNS server associated with RemoteDomainName.

# Returns

`CreateTrustResult`

# Exceptions

`EntityAlreadyExistsException`, `EntityDoesNotExistException`, `InvalidParameterException`, `ClientException`, `ServiceException` or `UnsupportedOperationException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/CreateTrust)
"""
@inline create_trust(aws::AWSConfig=default_aws_config(); args...) = create_trust(aws, args)

@inline create_trust(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "CreateTrust", args)

@inline create_trust(args) = create_trust(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.delete_conditional_forwarder
    delete_conditional_forwarder([::AWSConfig], arguments::Dict)
    delete_conditional_forwarder([::AWSConfig]; DirectoryId=, RemoteDomainName=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DeleteConditionalForwarder", arguments::Dict)
    ds([::AWSConfig], "DeleteConditionalForwarder", DirectoryId=, RemoteDomainName=)

# DeleteConditionalForwarder Operation

Deletes a conditional forwarder that has been set up for your AWS directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The directory ID for which you are deleting the conditional forwarder.

## `RemoteDomainName = ::String` -- *Required*
The fully qualified domain name (FQDN) of the remote domain with which you are deleting the conditional forwarder.

# Returns

`DeleteConditionalForwarderResult`

# Exceptions

`EntityDoesNotExistException`, `DirectoryUnavailableException`, `InvalidParameterException`, `UnsupportedOperationException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DeleteConditionalForwarder)
"""
@inline delete_conditional_forwarder(aws::AWSConfig=default_aws_config(); args...) = delete_conditional_forwarder(aws, args)

@inline delete_conditional_forwarder(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DeleteConditionalForwarder", args)

@inline delete_conditional_forwarder(args) = delete_conditional_forwarder(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.delete_directory
    delete_directory([::AWSConfig], arguments::Dict)
    delete_directory([::AWSConfig]; DirectoryId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DeleteDirectory", arguments::Dict)
    ds([::AWSConfig], "DeleteDirectory", DirectoryId=)

# DeleteDirectory Operation

Deletes an AWS Directory Service directory.

Before you call *DeleteDirectory*, ensure that all of the required permissions have been explicitly granted through a policy. For details about what permissions are required to run the *DeleteDirectory* operation, see [AWS Directory Service API Permissions: Actions, Resources, and Conditions Reference](http://docs.aws.amazon.com/directoryservice/latest/admin-guide/UsingWithDS_IAM_ResourcePermissions.html).

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory to delete.

# Returns

`DeleteDirectoryResult`

# Exceptions

`EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DeleteDirectory)
"""
@inline delete_directory(aws::AWSConfig=default_aws_config(); args...) = delete_directory(aws, args)

@inline delete_directory(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DeleteDirectory", args)

@inline delete_directory(args) = delete_directory(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.delete_snapshot
    delete_snapshot([::AWSConfig], arguments::Dict)
    delete_snapshot([::AWSConfig]; SnapshotId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DeleteSnapshot", arguments::Dict)
    ds([::AWSConfig], "DeleteSnapshot", SnapshotId=)

# DeleteSnapshot Operation

Deletes a directory snapshot.

# Arguments

## `SnapshotId = ::String` -- *Required*
The identifier of the directory snapshot to be deleted.

# Returns

`DeleteSnapshotResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DeleteSnapshot)
"""
@inline delete_snapshot(aws::AWSConfig=default_aws_config(); args...) = delete_snapshot(aws, args)

@inline delete_snapshot(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DeleteSnapshot", args)

@inline delete_snapshot(args) = delete_snapshot(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.delete_trust
    delete_trust([::AWSConfig], arguments::Dict)
    delete_trust([::AWSConfig]; TrustId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DeleteTrust", arguments::Dict)
    ds([::AWSConfig], "DeleteTrust", TrustId=, <keyword arguments>)

# DeleteTrust Operation

Deletes an existing trust relationship between your Microsoft AD in the AWS cloud and an external domain.

# Arguments

## `TrustId = ::String` -- *Required*
The Trust ID of the trust relationship to be deleted.

## `DeleteAssociatedConditionalForwarder = ::Bool`
Delete a conditional forwarder as part of a DeleteTrustRequest.

# Returns

`DeleteTrustResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException`, `ServiceException` or `UnsupportedOperationException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DeleteTrust)
"""
@inline delete_trust(aws::AWSConfig=default_aws_config(); args...) = delete_trust(aws, args)

@inline delete_trust(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DeleteTrust", args)

@inline delete_trust(args) = delete_trust(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.deregister_event_topic
    deregister_event_topic([::AWSConfig], arguments::Dict)
    deregister_event_topic([::AWSConfig]; DirectoryId=, TopicName=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DeregisterEventTopic", arguments::Dict)
    ds([::AWSConfig], "DeregisterEventTopic", DirectoryId=, TopicName=)

# DeregisterEventTopic Operation

Removes the specified directory as a publisher to the specified SNS topic.

# Arguments

## `DirectoryId = ::String` -- *Required*
The Directory ID to remove as a publisher. This directory will no longer send messages to the specified SNS topic.

## `TopicName = ::String` -- *Required*
The name of the SNS topic from which to remove the directory as a publisher.

# Returns

`DeregisterEventTopicResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DeregisterEventTopic)
"""
@inline deregister_event_topic(aws::AWSConfig=default_aws_config(); args...) = deregister_event_topic(aws, args)

@inline deregister_event_topic(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DeregisterEventTopic", args)

@inline deregister_event_topic(args) = deregister_event_topic(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.describe_conditional_forwarders
    describe_conditional_forwarders([::AWSConfig], arguments::Dict)
    describe_conditional_forwarders([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DescribeConditionalForwarders", arguments::Dict)
    ds([::AWSConfig], "DescribeConditionalForwarders", DirectoryId=, <keyword arguments>)

# DescribeConditionalForwarders Operation

Obtains information about the conditional forwarders for this account.

If no input parameters are provided for RemoteDomainNames, this request describes all conditional forwarders for the specified directory ID.

# Arguments

## `DirectoryId = ::String` -- *Required*
The directory ID for which to get the list of associated conditional forwarders.

## `RemoteDomainNames = [::String, ...]`
The fully qualified domain names (FQDN) of the remote domains for which to get the list of associated conditional forwarders. If this member is null, all conditional forwarders are returned.

# Returns

`DescribeConditionalForwardersResult`

# Exceptions

`EntityDoesNotExistException`, `DirectoryUnavailableException`, `InvalidParameterException`, `UnsupportedOperationException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DescribeConditionalForwarders)
"""
@inline describe_conditional_forwarders(aws::AWSConfig=default_aws_config(); args...) = describe_conditional_forwarders(aws, args)

@inline describe_conditional_forwarders(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DescribeConditionalForwarders", args)

@inline describe_conditional_forwarders(args) = describe_conditional_forwarders(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.describe_directories
    describe_directories([::AWSConfig], arguments::Dict)
    describe_directories([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DescribeDirectories", arguments::Dict)
    ds([::AWSConfig], "DescribeDirectories", <keyword arguments>)

# DescribeDirectories Operation

Obtains information about the directories that belong to this account.

You can retrieve information about specific directories by passing the directory identifiers in the *DirectoryIds* parameter. Otherwise, all directories that belong to the current account are returned.

This operation supports pagination with the use of the *NextToken* request and response parameters. If more results are available, the *DescribeDirectoriesResult.NextToken* member contains a token that you pass in the next call to [DescribeDirectories](@ref) to retrieve the next set of items.

You can also specify a maximum number of return results with the *Limit* parameter.

# Arguments

## `DirectoryIds = [::String, ...]`
A list of identifiers of the directories for which to obtain the information. If this member is null, all directories that belong to the current account are returned.

An empty list results in an `InvalidParameterException` being thrown.

## `NextToken = ::String`
The *DescribeDirectoriesResult.NextToken* value from a previous call to [DescribeDirectories](@ref). Pass null if this is the first call.

## `Limit = ::Int`
The maximum number of items to return. If this value is zero, the maximum number of items is specified by the limitations of the operation.

# Returns

`DescribeDirectoriesResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `InvalidNextTokenException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DescribeDirectories)
"""
@inline describe_directories(aws::AWSConfig=default_aws_config(); args...) = describe_directories(aws, args)

@inline describe_directories(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DescribeDirectories", args)

@inline describe_directories(args) = describe_directories(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.describe_domain_controllers
    describe_domain_controllers([::AWSConfig], arguments::Dict)
    describe_domain_controllers([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DescribeDomainControllers", arguments::Dict)
    ds([::AWSConfig], "DescribeDomainControllers", DirectoryId=, <keyword arguments>)

# DescribeDomainControllers Operation

Provides information about any domain controllers in your directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
Identifier of the directory for which to retrieve the domain controller information.

## `DomainControllerIds = [::String, ...]`
A list of identifiers for the domain controllers whose information will be provided.

## `NextToken = ::String`
The *DescribeDomainControllers.NextToken* value from a previous call to [DescribeDomainControllers](@ref). Pass null if this is the first call.

## `Limit = ::Int`
The maximum number of items to return.

# Returns

`DescribeDomainControllersResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidNextTokenException`, `InvalidParameterException`, `ClientException`, `ServiceException` or `UnsupportedOperationException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DescribeDomainControllers)
"""
@inline describe_domain_controllers(aws::AWSConfig=default_aws_config(); args...) = describe_domain_controllers(aws, args)

@inline describe_domain_controllers(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DescribeDomainControllers", args)

@inline describe_domain_controllers(args) = describe_domain_controllers(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.describe_event_topics
    describe_event_topics([::AWSConfig], arguments::Dict)
    describe_event_topics([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DescribeEventTopics", arguments::Dict)
    ds([::AWSConfig], "DescribeEventTopics", <keyword arguments>)

# DescribeEventTopics Operation

Obtains information about which SNS topics receive status messages from the specified directory.

If no input parameters are provided, such as DirectoryId or TopicName, this request describes all of the associations in the account.

# Arguments

## `DirectoryId = ::String`
The Directory ID for which to get the list of associated SNS topics. If this member is null, associations for all Directory IDs are returned.

## `TopicNames = [::String, ...]`
A list of SNS topic names for which to obtain the information. If this member is null, all associations for the specified Directory ID are returned.

An empty list results in an `InvalidParameterException` being thrown.

# Returns

`DescribeEventTopicsResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DescribeEventTopics)
"""
@inline describe_event_topics(aws::AWSConfig=default_aws_config(); args...) = describe_event_topics(aws, args)

@inline describe_event_topics(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DescribeEventTopics", args)

@inline describe_event_topics(args) = describe_event_topics(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.describe_snapshots
    describe_snapshots([::AWSConfig], arguments::Dict)
    describe_snapshots([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DescribeSnapshots", arguments::Dict)
    ds([::AWSConfig], "DescribeSnapshots", <keyword arguments>)

# DescribeSnapshots Operation

Obtains information about the directory snapshots that belong to this account.

This operation supports pagination with the use of the *NextToken* request and response parameters. If more results are available, the *DescribeSnapshots.NextToken* member contains a token that you pass in the next call to [DescribeSnapshots](@ref) to retrieve the next set of items.

You can also specify a maximum number of return results with the *Limit* parameter.

# Arguments

## `DirectoryId = ::String`
The identifier of the directory for which to retrieve snapshot information.

## `SnapshotIds = [::String, ...]`
A list of identifiers of the snapshots to obtain the information for. If this member is null or empty, all snapshots are returned using the *Limit* and *NextToken* members.

## `NextToken = ::String`
The *DescribeSnapshotsResult.NextToken* value from a previous call to [DescribeSnapshots](@ref). Pass null if this is the first call.

## `Limit = ::Int`
The maximum number of objects to return.

# Returns

`DescribeSnapshotsResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `InvalidNextTokenException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DescribeSnapshots)
"""
@inline describe_snapshots(aws::AWSConfig=default_aws_config(); args...) = describe_snapshots(aws, args)

@inline describe_snapshots(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DescribeSnapshots", args)

@inline describe_snapshots(args) = describe_snapshots(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.describe_trusts
    describe_trusts([::AWSConfig], arguments::Dict)
    describe_trusts([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DescribeTrusts", arguments::Dict)
    ds([::AWSConfig], "DescribeTrusts", <keyword arguments>)

# DescribeTrusts Operation

Obtains information about the trust relationships for this account.

If no input parameters are provided, such as DirectoryId or TrustIds, this request describes all the trust relationships belonging to the account.

# Arguments

## `DirectoryId = ::String`
The Directory ID of the AWS directory that is a part of the requested trust relationship.

## `TrustIds = [::String, ...]`
A list of identifiers of the trust relationships for which to obtain the information. If this member is null, all trust relationships that belong to the current account are returned.

An empty list results in an `InvalidParameterException` being thrown.

## `NextToken = ::String`
The *DescribeTrustsResult.NextToken* value from a previous call to [DescribeTrusts](@ref). Pass null if this is the first call.

## `Limit = ::Int`
The maximum number of objects to return.

# Returns

`DescribeTrustsResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidNextTokenException`, `InvalidParameterException`, `ClientException`, `ServiceException` or `UnsupportedOperationException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DescribeTrusts)
"""
@inline describe_trusts(aws::AWSConfig=default_aws_config(); args...) = describe_trusts(aws, args)

@inline describe_trusts(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DescribeTrusts", args)

@inline describe_trusts(args) = describe_trusts(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.disable_radius
    disable_radius([::AWSConfig], arguments::Dict)
    disable_radius([::AWSConfig]; DirectoryId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DisableRadius", arguments::Dict)
    ds([::AWSConfig], "DisableRadius", DirectoryId=)

# DisableRadius Operation

Disables multi-factor authentication (MFA) with the Remote Authentication Dial In User Service (RADIUS) server for an AD Connector directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which to disable MFA.

# Returns

`DisableRadiusResult`

# Exceptions

`EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DisableRadius)
"""
@inline disable_radius(aws::AWSConfig=default_aws_config(); args...) = disable_radius(aws, args)

@inline disable_radius(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DisableRadius", args)

@inline disable_radius(args) = disable_radius(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.disable_sso
    disable_sso([::AWSConfig], arguments::Dict)
    disable_sso([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "DisableSso", arguments::Dict)
    ds([::AWSConfig], "DisableSso", DirectoryId=, <keyword arguments>)

# DisableSso Operation

Disables single-sign on for a directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which to disable single-sign on.

## `UserName = ::String`
The username of an alternate account to use to disable single-sign on. This is only used for AD Connector directories. This account must have privileges to remove a service principal name.

If the AD Connector service account does not have privileges to remove a service principal name, you can specify an alternate account with the *UserName* and *Password* parameters. These credentials are only used to disable single sign-on and are not stored by the service. The AD Connector service account is not changed.

## `Password = ::String`
The password of an alternate account to use to disable single-sign on. This is only used for AD Connector directories. For more information, see the *UserName* parameter.

# Returns

`DisableSsoResult`

# Exceptions

`EntityDoesNotExistException`, `InsufficientPermissionsException`, `AuthenticationFailedException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/DisableSso)
"""
@inline disable_sso(aws::AWSConfig=default_aws_config(); args...) = disable_sso(aws, args)

@inline disable_sso(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "DisableSso", args)

@inline disable_sso(args) = disable_sso(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.enable_radius
    enable_radius([::AWSConfig], arguments::Dict)
    enable_radius([::AWSConfig]; DirectoryId=, RadiusSettings=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "EnableRadius", arguments::Dict)
    ds([::AWSConfig], "EnableRadius", DirectoryId=, RadiusSettings=)

# EnableRadius Operation

Enables multi-factor authentication (MFA) with the Remote Authentication Dial In User Service (RADIUS) server for an AD Connector directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which to enable MFA.

## `RadiusSettings = [ ... ]` -- *Required*
A [RadiusSettings](@ref) object that contains information about the RADIUS server.
```
 RadiusSettings = [
        "RadiusServers" =>  [::String, ...],
        "RadiusPort" =>  ::Int,
        "RadiusTimeout" =>  ::Int,
        "RadiusRetries" =>  ::Int,
        "SharedSecret" =>  ::String,
        "AuthenticationProtocol" =>  "PAP", "CHAP", "MS-CHAPv1" or "MS-CHAPv2",
        "DisplayLabel" =>  ::String,
        "UseSameUsername" =>  ::Bool
    ]
```

# Returns

`EnableRadiusResult`

# Exceptions

`InvalidParameterException`, `EntityAlreadyExistsException`, `EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/EnableRadius)
"""
@inline enable_radius(aws::AWSConfig=default_aws_config(); args...) = enable_radius(aws, args)

@inline enable_radius(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "EnableRadius", args)

@inline enable_radius(args) = enable_radius(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.enable_sso
    enable_sso([::AWSConfig], arguments::Dict)
    enable_sso([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "EnableSso", arguments::Dict)
    ds([::AWSConfig], "EnableSso", DirectoryId=, <keyword arguments>)

# EnableSso Operation

Enables single sign-on for a directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which to enable single-sign on.

## `UserName = ::String`
The username of an alternate account to use to enable single-sign on. This is only used for AD Connector directories. This account must have privileges to add a service principal name.

If the AD Connector service account does not have privileges to add a service principal name, you can specify an alternate account with the *UserName* and *Password* parameters. These credentials are only used to enable single sign-on and are not stored by the service. The AD Connector service account is not changed.

## `Password = ::String`
The password of an alternate account to use to enable single-sign on. This is only used for AD Connector directories. For more information, see the *UserName* parameter.

# Returns

`EnableSsoResult`

# Exceptions

`EntityDoesNotExistException`, `InsufficientPermissionsException`, `AuthenticationFailedException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/EnableSso)
"""
@inline enable_sso(aws::AWSConfig=default_aws_config(); args...) = enable_sso(aws, args)

@inline enable_sso(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "EnableSso", args)

@inline enable_sso(args) = enable_sso(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.get_directory_limits
    get_directory_limits([::AWSConfig], arguments::Dict)
    get_directory_limits([::AWSConfig]; )

    using AWSCore.Services.ds
    ds([::AWSConfig], "GetDirectoryLimits", arguments::Dict)
    ds([::AWSConfig], "GetDirectoryLimits", )

# GetDirectoryLimits Operation

Obtains directory limit information for the current region.

# Arguments

# Returns

`GetDirectoryLimitsResult`

# Exceptions

`EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/GetDirectoryLimits)
"""
@inline get_directory_limits(aws::AWSConfig=default_aws_config(); args...) = get_directory_limits(aws, args)

@inline get_directory_limits(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "GetDirectoryLimits", args)

@inline get_directory_limits(args) = get_directory_limits(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.get_snapshot_limits
    get_snapshot_limits([::AWSConfig], arguments::Dict)
    get_snapshot_limits([::AWSConfig]; DirectoryId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "GetSnapshotLimits", arguments::Dict)
    ds([::AWSConfig], "GetSnapshotLimits", DirectoryId=)

# GetSnapshotLimits Operation

Obtains the manual snapshot limits for a directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
Contains the identifier of the directory to obtain the limits for.

# Returns

`GetSnapshotLimitsResult`

# Exceptions

`EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/GetSnapshotLimits)
"""
@inline get_snapshot_limits(aws::AWSConfig=default_aws_config(); args...) = get_snapshot_limits(aws, args)

@inline get_snapshot_limits(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "GetSnapshotLimits", args)

@inline get_snapshot_limits(args) = get_snapshot_limits(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.list_ip_routes
    list_ip_routes([::AWSConfig], arguments::Dict)
    list_ip_routes([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "ListIpRoutes", arguments::Dict)
    ds([::AWSConfig], "ListIpRoutes", DirectoryId=, <keyword arguments>)

# ListIpRoutes Operation

Lists the address blocks that you have added to a directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
Identifier (ID) of the directory for which you want to retrieve the IP addresses.

## `NextToken = ::String`
The *ListIpRoutes.NextToken* value from a previous call to [ListIpRoutes](@ref). Pass null if this is the first call.

## `Limit = ::Int`
Maximum number of items to return. If this value is zero, the maximum number of items is specified by the limitations of the operation.

# Returns

`ListIpRoutesResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidNextTokenException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/ListIpRoutes)
"""
@inline list_ip_routes(aws::AWSConfig=default_aws_config(); args...) = list_ip_routes(aws, args)

@inline list_ip_routes(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "ListIpRoutes", args)

@inline list_ip_routes(args) = list_ip_routes(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.list_schema_extensions
    list_schema_extensions([::AWSConfig], arguments::Dict)
    list_schema_extensions([::AWSConfig]; DirectoryId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "ListSchemaExtensions", arguments::Dict)
    ds([::AWSConfig], "ListSchemaExtensions", DirectoryId=, <keyword arguments>)

# ListSchemaExtensions Operation

Lists all schema extensions applied to a Microsoft AD Directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory from which to retrieve the schema extension information.

## `NextToken = ::String`
The `ListSchemaExtensions.NextToken` value from a previous call to `ListSchemaExtensions`. Pass null if this is the first call.

## `Limit = ::Int`
The maximum number of items to return.

# Returns

`ListSchemaExtensionsResult`

# Exceptions

`InvalidNextTokenException`, `EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/ListSchemaExtensions)
"""
@inline list_schema_extensions(aws::AWSConfig=default_aws_config(); args...) = list_schema_extensions(aws, args)

@inline list_schema_extensions(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "ListSchemaExtensions", args)

@inline list_schema_extensions(args) = list_schema_extensions(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.list_tags_for_resource
    list_tags_for_resource([::AWSConfig], arguments::Dict)
    list_tags_for_resource([::AWSConfig]; ResourceId=, <keyword arguments>)

    using AWSCore.Services.ds
    ds([::AWSConfig], "ListTagsForResource", arguments::Dict)
    ds([::AWSConfig], "ListTagsForResource", ResourceId=, <keyword arguments>)

# ListTagsForResource Operation

Lists all tags on a directory.

# Arguments

## `ResourceId = ::String` -- *Required*
Identifier (ID) of the directory for which you want to retrieve tags.

## `NextToken = ::String`
Reserved for future use.

## `Limit = ::Int`
Reserved for future use.

# Returns

`ListTagsForResourceResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidNextTokenException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/ListTagsForResource)
"""
@inline list_tags_for_resource(aws::AWSConfig=default_aws_config(); args...) = list_tags_for_resource(aws, args)

@inline list_tags_for_resource(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "ListTagsForResource", args)

@inline list_tags_for_resource(args) = list_tags_for_resource(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.register_event_topic
    register_event_topic([::AWSConfig], arguments::Dict)
    register_event_topic([::AWSConfig]; DirectoryId=, TopicName=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "RegisterEventTopic", arguments::Dict)
    ds([::AWSConfig], "RegisterEventTopic", DirectoryId=, TopicName=)

# RegisterEventTopic Operation

Associates a directory with an SNS topic. This establishes the directory as a publisher to the specified SNS topic. You can then receive email or text (SMS) messages when the status of your directory changes. You get notified if your directory goes from an Active status to an Impaired or Inoperable status. You also receive a notification when the directory returns to an Active status.

# Arguments

## `DirectoryId = ::String` -- *Required*
The Directory ID that will publish status messages to the SNS topic.

## `TopicName = ::String` -- *Required*
The SNS topic name to which the directory will publish status messages. This SNS topic must be in the same region as the specified Directory ID.

# Returns

`RegisterEventTopicResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/RegisterEventTopic)
"""
@inline register_event_topic(aws::AWSConfig=default_aws_config(); args...) = register_event_topic(aws, args)

@inline register_event_topic(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "RegisterEventTopic", args)

@inline register_event_topic(args) = register_event_topic(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.remove_ip_routes
    remove_ip_routes([::AWSConfig], arguments::Dict)
    remove_ip_routes([::AWSConfig]; DirectoryId=, CidrIps=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "RemoveIpRoutes", arguments::Dict)
    ds([::AWSConfig], "RemoveIpRoutes", DirectoryId=, CidrIps=)

# RemoveIpRoutes Operation

Removes IP address blocks from a directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
Identifier (ID) of the directory from which you want to remove the IP addresses.

## `CidrIps = [::String, ...]` -- *Required*
IP address blocks that you want to remove.

# Returns

`RemoveIpRoutesResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `DirectoryUnavailableException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/RemoveIpRoutes)
"""
@inline remove_ip_routes(aws::AWSConfig=default_aws_config(); args...) = remove_ip_routes(aws, args)

@inline remove_ip_routes(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "RemoveIpRoutes", args)

@inline remove_ip_routes(args) = remove_ip_routes(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.remove_tags_from_resource
    remove_tags_from_resource([::AWSConfig], arguments::Dict)
    remove_tags_from_resource([::AWSConfig]; ResourceId=, TagKeys=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "RemoveTagsFromResource", arguments::Dict)
    ds([::AWSConfig], "RemoveTagsFromResource", ResourceId=, TagKeys=)

# RemoveTagsFromResource Operation

Removes tags from a directory.

# Arguments

## `ResourceId = ::String` -- *Required*
Identifier (ID) of the directory from which to remove the tag.

## `TagKeys = [::String, ...]` -- *Required*
The tag key (name) of the tag to be removed.

# Returns

`RemoveTagsFromResourceResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/RemoveTagsFromResource)
"""
@inline remove_tags_from_resource(aws::AWSConfig=default_aws_config(); args...) = remove_tags_from_resource(aws, args)

@inline remove_tags_from_resource(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "RemoveTagsFromResource", args)

@inline remove_tags_from_resource(args) = remove_tags_from_resource(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.reset_user_password
    reset_user_password([::AWSConfig], arguments::Dict)
    reset_user_password([::AWSConfig]; DirectoryId=, UserName=, NewPassword=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "ResetUserPassword", arguments::Dict)
    ds([::AWSConfig], "ResetUserPassword", DirectoryId=, UserName=, NewPassword=)

# ResetUserPassword Operation

Resets the password for any user in your AWS Managed Microsoft AD or Simple AD directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
Identifier of the AWS Managed Microsoft AD or Simple AD directory in which the user resides.

## `UserName = ::String` -- *Required*
The username of the user whose password will be reset.

## `NewPassword = ::String` -- *Required*
The new password that will be reset.

# Returns

`ResetUserPasswordResult`

# Exceptions

`DirectoryUnavailableException`, `UserDoesNotExistException`, `InvalidPasswordException`, `UnsupportedOperationException`, `EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/ResetUserPassword)
"""
@inline reset_user_password(aws::AWSConfig=default_aws_config(); args...) = reset_user_password(aws, args)

@inline reset_user_password(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "ResetUserPassword", args)

@inline reset_user_password(args) = reset_user_password(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.restore_from_snapshot
    restore_from_snapshot([::AWSConfig], arguments::Dict)
    restore_from_snapshot([::AWSConfig]; SnapshotId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "RestoreFromSnapshot", arguments::Dict)
    ds([::AWSConfig], "RestoreFromSnapshot", SnapshotId=)

# RestoreFromSnapshot Operation

Restores a directory using an existing directory snapshot.

When you restore a directory from a snapshot, any changes made to the directory after the snapshot date are overwritten.

This action returns as soon as the restore operation is initiated. You can monitor the progress of the restore operation by calling the [DescribeDirectories](@ref) operation with the directory identifier. When the **DirectoryDescription.Stage** value changes to `Active`, the restore operation is complete.

# Arguments

## `SnapshotId = ::String` -- *Required*
The identifier of the snapshot to restore from.

# Returns

`RestoreFromSnapshotResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/RestoreFromSnapshot)
"""
@inline restore_from_snapshot(aws::AWSConfig=default_aws_config(); args...) = restore_from_snapshot(aws, args)

@inline restore_from_snapshot(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "RestoreFromSnapshot", args)

@inline restore_from_snapshot(args) = restore_from_snapshot(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.start_schema_extension
    start_schema_extension([::AWSConfig], arguments::Dict)
    start_schema_extension([::AWSConfig]; DirectoryId=, CreateSnapshotBeforeSchemaExtension=, LdifContent=, Description=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "StartSchemaExtension", arguments::Dict)
    ds([::AWSConfig], "StartSchemaExtension", DirectoryId=, CreateSnapshotBeforeSchemaExtension=, LdifContent=, Description=)

# StartSchemaExtension Operation

Applies a schema extension to a Microsoft AD directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which the schema extension will be applied to.

## `CreateSnapshotBeforeSchemaExtension = ::Bool` -- *Required*
If true, creates a snapshot of the directory before applying the schema extension.

## `LdifContent = ::String` -- *Required*
The LDIF file represented as a string. To construct the LdifContent string, precede each line as it would be formatted in an ldif file with \\n. See the example request below for more details. The file size can be no larger than 1MB.

## `Description = ::String` -- *Required*
A description of the schema extension.

# Returns

`StartSchemaExtensionResult`

# Exceptions

`DirectoryUnavailableException`, `EntityDoesNotExistException`, `InvalidParameterException`, `SnapshotLimitExceededException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/StartSchemaExtension)
"""
@inline start_schema_extension(aws::AWSConfig=default_aws_config(); args...) = start_schema_extension(aws, args)

@inline start_schema_extension(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "StartSchemaExtension", args)

@inline start_schema_extension(args) = start_schema_extension(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.update_conditional_forwarder
    update_conditional_forwarder([::AWSConfig], arguments::Dict)
    update_conditional_forwarder([::AWSConfig]; DirectoryId=, RemoteDomainName=, DnsIpAddrs=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "UpdateConditionalForwarder", arguments::Dict)
    ds([::AWSConfig], "UpdateConditionalForwarder", DirectoryId=, RemoteDomainName=, DnsIpAddrs=)

# UpdateConditionalForwarder Operation

Updates a conditional forwarder that has been set up for your AWS directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The directory ID of the AWS directory for which to update the conditional forwarder.

## `RemoteDomainName = ::String` -- *Required*
The fully qualified domain name (FQDN) of the remote domain with which you will set up a trust relationship.

## `DnsIpAddrs = [::String, ...]` -- *Required*
The updated IP addresses of the remote DNS server associated with the conditional forwarder.

# Returns

`UpdateConditionalForwarderResult`

# Exceptions

`EntityDoesNotExistException`, `DirectoryUnavailableException`, `InvalidParameterException`, `UnsupportedOperationException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/UpdateConditionalForwarder)
"""
@inline update_conditional_forwarder(aws::AWSConfig=default_aws_config(); args...) = update_conditional_forwarder(aws, args)

@inline update_conditional_forwarder(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "UpdateConditionalForwarder", args)

@inline update_conditional_forwarder(args) = update_conditional_forwarder(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.update_number_of_domain_controllers
    update_number_of_domain_controllers([::AWSConfig], arguments::Dict)
    update_number_of_domain_controllers([::AWSConfig]; DirectoryId=, DesiredNumber=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "UpdateNumberOfDomainControllers", arguments::Dict)
    ds([::AWSConfig], "UpdateNumberOfDomainControllers", DirectoryId=, DesiredNumber=)

# UpdateNumberOfDomainControllers Operation

Adds or removes domain controllers to or from the directory. Based on the difference between current value and new value (provided through this API call), domain controllers will be added or removed. It may take up to 45 minutes for any new domain controllers to become fully active once the requested number of domain controllers is updated. During this time, you cannot make another update request.

# Arguments

## `DirectoryId = ::String` -- *Required*
Identifier of the directory to which the domain controllers will be added or removed.

## `DesiredNumber = ::Int` -- *Required*
The number of domain controllers desired in the directory.

# Returns

`UpdateNumberOfDomainControllersResult`

# Exceptions

`EntityDoesNotExistException`, `DirectoryUnavailableException`, `DomainControllerLimitExceededException`, `InvalidParameterException`, `UnsupportedOperationException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/UpdateNumberOfDomainControllers)
"""
@inline update_number_of_domain_controllers(aws::AWSConfig=default_aws_config(); args...) = update_number_of_domain_controllers(aws, args)

@inline update_number_of_domain_controllers(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "UpdateNumberOfDomainControllers", args)

@inline update_number_of_domain_controllers(args) = update_number_of_domain_controllers(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.update_radius
    update_radius([::AWSConfig], arguments::Dict)
    update_radius([::AWSConfig]; DirectoryId=, RadiusSettings=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "UpdateRadius", arguments::Dict)
    ds([::AWSConfig], "UpdateRadius", DirectoryId=, RadiusSettings=)

# UpdateRadius Operation

Updates the Remote Authentication Dial In User Service (RADIUS) server information for an AD Connector directory.

# Arguments

## `DirectoryId = ::String` -- *Required*
The identifier of the directory for which to update the RADIUS server information.

## `RadiusSettings = [ ... ]` -- *Required*
A [RadiusSettings](@ref) object that contains information about the RADIUS server.
```
 RadiusSettings = [
        "RadiusServers" =>  [::String, ...],
        "RadiusPort" =>  ::Int,
        "RadiusTimeout" =>  ::Int,
        "RadiusRetries" =>  ::Int,
        "SharedSecret" =>  ::String,
        "AuthenticationProtocol" =>  "PAP", "CHAP", "MS-CHAPv1" or "MS-CHAPv2",
        "DisplayLabel" =>  ::String,
        "UseSameUsername" =>  ::Bool
    ]
```

# Returns

`UpdateRadiusResult`

# Exceptions

`InvalidParameterException`, `EntityDoesNotExistException`, `ClientException` or `ServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/UpdateRadius)
"""
@inline update_radius(aws::AWSConfig=default_aws_config(); args...) = update_radius(aws, args)

@inline update_radius(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "UpdateRadius", args)

@inline update_radius(args) = update_radius(default_aws_config(), args)

"""
    using AWSSDK.DirectoryService.verify_trust
    verify_trust([::AWSConfig], arguments::Dict)
    verify_trust([::AWSConfig]; TrustId=)

    using AWSCore.Services.ds
    ds([::AWSConfig], "VerifyTrust", arguments::Dict)
    ds([::AWSConfig], "VerifyTrust", TrustId=)

# VerifyTrust Operation

AWS Directory Service for Microsoft Active Directory allows you to configure and verify trust relationships.

This action verifies a trust relationship between your Microsoft AD in the AWS cloud and an external domain.

# Arguments

## `TrustId = ::String` -- *Required*
The unique Trust ID of the trust relationship to verify.

# Returns

`VerifyTrustResult`

# Exceptions

`EntityDoesNotExistException`, `InvalidParameterException`, `ClientException`, `ServiceException` or `UnsupportedOperationException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/ds-2015-04-16/VerifyTrust)
"""
@inline verify_trust(aws::AWSConfig=default_aws_config(); args...) = verify_trust(aws, args)

@inline verify_trust(aws::AWSConfig, args) = AWSCore.Services.ds(aws, "VerifyTrust", args)

@inline verify_trust(args) = verify_trust(default_aws_config(), args)

end # module DirectoryService

#==============================================================================#
# End of file
#==============================================================================#


text:
# ----------------------------------------------------------------------------------- #
# Copyright (c) 2021 Varnerlab
# Robert Frederick Smith School of Chemical and Biomolecular Engineering
# Cornell University, Ithaca NY 14850
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ----------------------------------------------------------------------------------- #

# include -
include("Include.jl")

function solve_dynamic_problem(time_start::Float64, time_stop::Float64, time_step::Float64,
    parameter_dictionary::Dict{String,Any}, varargs...)

    # Get required stuff from the problem struct -
    time_span = (time_start,time_stop)
    initial_condition_array = parameter_dictionary["initial_condition_array"];

    # build problem object -
    problem_object = ODEProblem(Balances, initial_condition_array, time_span, parameter_dictionary)

    # solve -
    solution = solve(problem_object, AutoTsit5(Rosenbrock23(autodiff=false)), reltol=1e-8,abstol=1e-8)

    # pull solution apart -
    T = solution.t

    # initialize the state array -
    number_of_times_steps = length(T)
    number_of_states = length(initial_condition_array)
    X = zeros(number_of_times_steps,number_of_states)
    for step_index=1:number_of_times_steps

        # grab the solution
        soln_array = solution.u[step_index]
        for state_index = 1:number_of_states
            X[step_index, state_index] = soln_array[state_index]
        end
    end

    # return -
    return (T,X)
end

function solve_static_problem(parameter_dictionary::Dict{String,Any}, varargs...)

    # Get the initial conditions -
    initial_condition_array = problem["initial_condition_array"];

    # calculate the steady-state soln -
    steady_state_prob = SteadyStateProblem(Balances, initial_condition_array, parameter_dictionary)
    steady_state_soln  = solve(steady_state_prob, DynamicSS(AutoTsit5(Rosenbrock23(autodiff=false)); abstol=1e-8, reltol=1e-6, tspan=Inf))

    # return -
    return abs.(steady_state_soln.u)
end

ext: jl


text:
"""
    RodriguesParam{T}

Rodrigues parameters are a three-dimensional parameterization of rotations.
They have a singularity at 180° but do not inherit the sign ambiguities of quaternions
or MRPs
"""
struct RodriguesParam{T} <: Rotation{3,T}
    x::T
    y::T
    z::T
    @inline function RodriguesParam{T}(x, y, z) where T
        new{T}(x, y, z)
    end
end

# ~~~~~~~~~~~~~~~ Constructors ~~~~~~~~~~~~~~~ #
RodriguesParam(x::X, y::Y, z::Z) where {X,Y,Z} = RodriguesParam{promote_type(X,Y,Z)}(x, y, z)
(::Type{RP})(g::StaticVector) where RP<:RodriguesParam = RP(g[1], g[2], g[3])

# ~~~~~~~~~~~~~~~ Conversions ~~~~~~~~~~~~~~~ #
params(g::RodriguesParam) = SVector{3}(g.x, g.y, g.z)

# ~~~~~~~~~~~~~~~ Initializers ~~~~~~~~~~~~~~~ #
@inline Base.one(::Type{RP}) where RP <: RodriguesParam = RP(0.0, 0.0, 0.0)

# ~~~~~~~~~~~~~~~ Quaternion <=> RP ~~~~~~~~~~~~~~~~~~ #
@inline function (::Type{Q})(g::RodriguesParam) where Q<:QuatRotation
    M = 1/sqrt(1 + g.x*g.x + g.y*g.y + g.z*g.z)
    return Q(M, M*g.x, M*g.y, M*g.z, false)
end

@inline function (::Type{G})(q::QuatRotation) where G<:RodriguesParam
    w = real(q.q)
    x, y, z = imag_part(q.q)

    return G(x/w, y/w, z/w)
end

# ~~~~~~~~~~~~~~~ StaticArrays Interface ~~~~~~~~~~~~~~~ #
@inline (::Type{RP})(t::NTuple{9}) where RP<:RodriguesParam = convert(RP, QuatRotation(t))
@inline Base.getindex(rp::RodriguesParam, i::Int) = convert(QuatRotation, rp)[i]
@inline Base.Tuple(rp::RodriguesParam) = Tuple(convert(QuatRotation, rp))

# ~~~~~~~~~~~~~~~ Math Operations ~~~~~~~~~~~~~~~ #
Base.inv(p::RodriguesParam) = RodriguesParam(-p.x, -p.y, -p.z)

# ~~~~~~~~~~~~~~~ Composition ~~~~~~~~~~~~~~~ #
function Base.:*(g2::RodriguesParam, g1::RodriguesParam)
    g2 = params(g2)
    g1 = params(g1)
    RodriguesParam((g2+g1 + g2 × g1)/(1-g2'g1))
end

function Base.:\(g1::RodriguesParam, g2::RodriguesParam)
    g2 = params(g2)
    g1 = params(g1)
    RodriguesParam((g2-g1 + g2 × g1)/(1+g1'g2))
end

function Base.:/(g1::RodriguesParam, g2::RodriguesParam)
    g2 = params(g2)
    g1 = params(g1)
    RodriguesParam((g1-g2 + g2 × g1)/(1+g1'g2))
end

# ~~~~~~~~~~~~~~~ Rotation ~~~~~~~~~~~~~~~ #
Base.:*(g::RodriguesParam, r::StaticVector) = QuatRotation(g)*r
Base.:\(g::RodriguesParam, r::StaticVector) = inv(QuatRotation(g))*r

# ~~~~~~~~~~~~~~~ Kinematics ~~~~~~~~~~~~~~~ #
function kinematics(g::RodriguesParam, ω)
    check_length(ω, 3)
    g = params(g)
    0.5*(I + skew(g) + g*g')*ω
end

function ∇rotate(g0::RodriguesParam, r)
    check_length(r, 3)
    g = params(g0)
    ghat = skew(g)
    n1 = 1/(1 + g'g)
    gxr = cross(g,r) + r
    d1 = ghat*gxr * -2*n1^2 * g'
    d2 = -(ghat*skew(r) + skew(gxr))*n1
    return 2d1 + 2d2
end

function ∇composition1(g2::RodriguesParam, g1::RodriguesParam)
    g2 = params(g2)
    g1 = params(g1)

    N = g2 + g1 + g2 × g1
    D = 1/(1 - g2'g1)
    (I + skew(g2) + D*N*g2')*D
end

function ∇²composition1(g2::RodriguesParam, g1::RodriguesParam, b::AbstractVector)
    check_length(b, 3)
    g2 = params(g2)
    g1 = params(g1)

    N = g2 + g1 + g2 × g1  # 3×1
    D = 1/(1 - g2'g1)  # scalar
    dN = I + skew(g2)
    dD = D^2*g2'
    return g2*b'*(N*(2*D*dD) + D^2*dN) + (I - skew(g2))*b*dD
end

function ∇composition2(g2::RodriguesParam, g1::RodriguesParam)
    g2 = params(g2)
    g1 = params(g1)

    N = g2 + g1 + g2 × g1
    D = 1/(1 - g2'g1)
    (I - skew(g1) + D*N*g1')*D
end

function ∇differential(g::RodriguesParam)
    g = params(g)
    (I + skew(g) + g*g')
end

function ∇²differential(g::RodriguesParam, b::AbstractVector)
    check_length(b, 3)
    g = params(g)
    return g*b'*(2g*g' + I + skew(g)) + (I - skew(g))*b*g'
end


text:
cd(@__DIR__)
using Pkg
Pkg.activate(".")
Pkg.instantiate()

module TestModule
export plusOne, multiply # functions, structs, and other objects that will be directly available once `using ModuleName` is typed

plusOne(x) = x + 1
multiply(x,y) = x * y

end

using .TestModule

plusOne(1.0)
plusOne(1)

multiply(2,3)

include("includedfoo.jl") # which strings will be printed ?

x # error not defined
foo.x
using foo # error: looking up for a package and of course can't find it
using .foo
x
foo.z()
foo.c()

max_stars_repo_name: sylvaticus/IntroSPMLJuliaCourse

max_issues_repo_name: sylvaticus/IntroSPMLJuliaCourse

max_forks_repo_name: sylvaticus/IntroSPMLJuliaCourse


text:
# SPDX-License-Identifier: MIT

"""
    AbstractWishart{D} <: Distribution

Abstract type for Wishart distribution implementations.
"""
abstract type AbstractWishart{D} <: Distribution end

function DefaultWishartParameter(W, v)
    T = eltype(W)
    M = pdmat_inverse(W)
    η₁ = -T(.5)*diag(M)
    η₂ = -vec_tril(M)
    η₃ = T(.5)*v
    DefaultParameter(vcat(η₁, η₂, η₃))
end

"""
    mutable struct Wishart{D} <: AbstractWishart{D}
        param::P where P <: AbstractParameter
    end

Wishart distribution.

# Constructors

    Wishart{D}()
    Wishart(W[, v])

where `T` is the encoding type of the parameters and `W` is a
positive definite DxD matrix.

# Examples
```jldoctest
julia> Wishart([1 0.5; 0.5 1], 2)
Wishart{2}:
  W = [0.9999999999999997 0.5; 0.5 1.0]
  v = 2.0
```
"""
mutable struct Wishart{D} <: AbstractWishart{D}
    param::P where P <: AbstractParameter
end

function Wishart(W::AbstractMatrix, v)
    param = DefaultWishartParameter(W, v)
    P = typeof(param)
    D = size(W,1)
    Wishart{D}(param)
end

#######################################################################
# Distribution interface

function basemeasure(w::AbstractWishart, X::AbstractMatrix)
    D = size(X, 1)
    -.5*(D-1)*pdmat_logdet(X) - .25*D*(D-1)log(pi)
end

function gradlognorm(w::AbstractWishart)
    W, v = stdparam(w, naturalform(w.param))
    D = size(W, 1)
    T = eltype(W)
    ∂η₁ = v * W
    ∂η₂ = sum([digamma((T(v+1-i)/2)) for i in 1:D]) + T(D*log(2)) + pdmat_logdet(W)
    vcat(diag(∂η₁), vec_tril(∂η₁), ∂η₂)
end

function lognorm(w::AbstractWishart{D},
                 η::AbstractVector{T} = naturalform(w.param)) where {T,D}
    diagM = η[1:D]
    trilM = η[D+1:end-1]
    M = -T(2)*matrix(diagM, T(.5)*trilM)
    v = T(2)*sum(η[end:end]) # sum of 1-element array to run to bypass
                             # scalar operation issue

    retval = T(0.5)*(-v * pdmat_logdet(M) + v*D*T(log(2)))
    retval += sum([loggamma(T(0.5) * (v+1- i)) for i in 1:D])
end

stats(w::AbstractWishart, X::AbstractMatrix) = vcat(diag(X), vec_tril(X), pdmat_logdet(X))

function sample(w::AbstractWishart{D}, size = 1) where D
    retval = similar(naturalform(w.param), D, D, size)
    w_ = Dists.Wishart(w.v, PDMat(Array(w.W)))
    retval[:,:,:] = cat(rand(w_, size)..., dims = 3)
    retval
end

function splitgrad(w::AbstractWishart{D}, μ) where {T,D}
    diag_∂₁ = μ[1:D]
    tril_∂₁ = μ[D+1:end-1]
    diag_∂₁, tril_∂₁, sum(μ[end:end])
end

function stdparam(w::AbstractWishart{D},
                  η::AbstractVector{T} = naturalform(w.param)) where {T,D}
    diagM = η[1:D]
    trilM = η[D+1:end-1]
    M = matrix(diagM, T(.5)*trilM)
    W = pdmat_inverse(-T(2)*M)
    v = T(2)*sum(η[end:end])
    (W = W, v = v)
end

max_stars_repo_name: lucasondel/ExpFamilyDistributions-jl

max_issues_repo_name: BUTSpeechFIT/ExpFamilyDistributions

max_forks_repo_name: lucasondel/ExpFamilyDistributions


text:
push!(LOAD_PATH, joinpath(@__DIR__, "../", "core"))

using Base.Threads
using GenericBlas
using LinearAlgebra

@inline function transform(policy::Any, range::Int64, transformer::Any)

@threads for i in 1:range
           transformer(i)
         end
end #transform

@inline function transform_reduce(policy::Any, range::Int64, init::Any, reducer::Any, transformer::Any)
         local res::Float32 = init
@threads for i in 1:range
           local val = transformer(i)
           res       = reducer(res, val)
         end
         println("Res :: ", res)
         return res
end #transform_reduce

data_type   = Float32
scalar_type = Float32

len = 8192

x = Vector{data_type}(undef, len)
y = Vector{data_type}(undef, len)
z = Vector{data_type}(undef, len)

x .= rand(data_type, len)
y .= rand(data_type, len)
z .= rand(data_type, len)

xnr2 = BLAS.nrm2(len, x, 1)
println("Norm check : ", xnr2)

a = scalar_type(1.1)

axpyXmaz_ = GenericBlas.axpyXmaz{scalar_type, data_type}(a,x,y,z)

policy = missing

@time transform(policy, len, axpyXmaz_)

xnr2 = BLAS.nrm2(len, x, 1)
println("Norm check : ", xnr2)

a1 = scalar_type(1.1)
a2 = scalar_type(1.1)

plus  = GenericBlas.plus

#overload Base.:+
#Base.:+(x1::Float32, x2::Float32) = 2.0*x1 - x2
#define alias
plus2 = Base.:+

println(" \n", plus2(a1,a2), "  ", a1)

norm2_x = GenericBlas.norm2{data_type}(x)

@time res = transform_reduce(policy, len, 0.0, plus, norm2_x)

println("Norm 2 : ", res)

max_stars_repo_name: alexstrel/solver-tuner

max_issues_repo_name: alexstrel/solver-tuner

max_forks_repo_name: alexstrel/solver-tuner


text:
# Simulate space state model
# x0 (and x0_2) will be overwritten during execution
function simulate_space_state!{T}(y::Vector{T}, f::Function, g::Function, x0::T,
        time_span::Tuple{Int, Int}, args::Tuple=(); x0_2::T=deepcopy(x0))

    # Define buffers (In order to guarantee it always end up
    # with x = x0 in the final iteration)
    if mod(time_span[2]-time_span[1]+1, 2) == 0
        x = x0
        x_next = x0_2
    else
        x = x0_2
        x_next = x0
    end
    aux = x0_2
    # Iterate using recursive equation
    i = 1
    for k = time_span[1]:time_span[2]
        # Evaluate function
        f(x_next, x, k, args...)
        g(y[i], x, k, args...)
        # Swap buffers
        aux = x
        x = x_next
        x_next = aux
        # Next iteration
        i+=1
    end
    return x
end


text:
### A Pluto.jl notebook ###
# v0.14.1

using Markdown
using InteractiveUtils

# ╔═╡ e03dd22c-884c-11eb-2432-3dc04b0cf286
begin
  using Pkg; Pkg.activate("MLJ_env", shared=true)
  using Test
  using Plots
  using PlutoUI
  using Random
  using Distributions

  push!(LOAD_PATH, "./src")
  using YaLinearAlgebra
end

# ╔═╡ 380c26d0-881d-11eb-0461-f339488ea81e
md"""
## Gradient Descent

ref. from book **"Data Science from Scratch"**, Chap 8

$(html"
© Pascal, April 2021
")
"""

# ╔═╡ 83e01f80-884a-11eb-1ef7-e9cb5ab3ed20
PlutoUI.TableOfContents(indent=true, depth=4, aside=true)

# ╔═╡ 853ab02c-884a-11eb-01bf-1712dc177ffb
html"""

"""

# ╔═╡ 4c951444-8869-11eb-0b88-55a9fb9e51e6
html"""

"""

# ╔═╡ 8c87c3b8-884a-11eb-10c8-73e2dab560ea
md"""
### Context
"""

# ╔═╡ 8c6ba818-884a-11eb-23e0-2f1c297d88f5
md"""
The gradient (vector of partial derivatives) gives the direction in which the function most quickly increase.

In ML we are looking at a best model (relative to some criteria) to fit the data. In this context "best" is obtained by minimizing a quantity (ex. minimize MSE between prediction and ground truth in a supervised setting) or maximizing a quantity (ex. likelihood of the data). This means that the problem is cast as an optimization problem. One technique to solve those optimization problems, which scale rather weel is **Gradient Descent** (or **Gradient Ascent**).

In a nutshell, Gradient Descent consists in picking a random starting point, computing the gradient (derivatives) of a given function w.r.t its parameters and take a small step in the opposite direction of the gradient (minimization setup, alternatively in the direction, for gradient ascent and a maximization setup) and repeat the process with this updated point until some convergence criteria.
"""

# ╔═╡ d2d18b22-884c-11eb-1f93-037453c5395b
begin
  f(x, y) = x^2 + y^2
  x = -10:10
  y = x
  plot(x, y, f, linetype=:surface)

  xₛ = 0:0.5:10
  yₛ = 0:-.45:-9
  zₛ = f.(xₛ, yₛ)
  scatter!(xₛ, yₛ, zₛ, marker=:v, markersize=4, color=:steelblue, legend=false)
end

# ╔═╡ 221734fe-8869-11eb-331a-b5810d0b784c
html"""

"""

# ╔═╡ d297fa06-884c-11eb-294e-85992f901be1
md"""
### Estimating the gradient

If f is a function of one variable, its derivative at point x measures how f(x) changes as we make a very small change of x. The derivative is the limit of the difference of the quotients
"""

# ╔═╡ 1859c082-8853-11eb-18f6-2bc7a180b4a2
begin
  const AF =  AbstractFloat
  const VT = Vector{T} where T <: AbstractFloat
end

# ╔═╡ d27feefa-884c-11eb-3b84-1f529d7f6410
begin
  function diff_quotient(f::Function, x::AF, Δ::AF)::AF
    (f(x + Δ) - f(x)) / Δ
  end

  diff_quotient(f::Function, v::Vector{AF}, Δ::AF) = diff_quotient.(f, v, Δ)
end

# ╔═╡ 5618fb40-8853-11eb-3d2f-032437d22a09
md"""
The derivative is the slope of the tangent line at (x, f (x)) , while the difference quotient is the slope of the almost-tangent line that runs through (x + Δ, f (x + Δ)) . As Δ gets tends to 0,, the almost-tangent line gets closer and closer to the tangent line.
"""

# ╔═╡ 55fab426-8853-11eb-01f8-cbde45c7de9c
# TODO figure

# ╔═╡ 55e3efea-8853-11eb-0821-c5c580bc8fc5
md"""
For many function it is easy to compute the exact derivatives. For example for the square function we have:
"""

# ╔═╡ 55c56cc8-8853-11eb-04f4-3be84a352808
begin
  square(x::AF) = x * x
  square(v::Vector{AF}) = square.(v)

  deriv_square(x::AF) = 2. * x
  deriv_square(v::VT) = deriv_square.(v)
  end

# ╔═╡ d25d8eac-884c-11eb-2063-27413f8aba04
md"""
What if we cannot? Weel we can estimate the derivative by evaluating the difference quotient for very small Δ. For example:
"""

# ╔═╡ 480f7b18-8854-11eb-2898-8d876317ebe2
begin
  xᵣ = -10.:10.
  Δ = 1e-3

  yᵣ = square.(collect(xᵣ));
  dyᵣ = deriv_square.(xᵣ);
  dŷᵣ = diff_quotient.(square, xᵣ, Δ);
end

# ╔═╡ 47ee8cb4-8854-11eb-252b-852fd56aa40f
begin
  plot(xᵣ, yᵣ, label="Square", marker=:o, color=:green)
  scatter!(xᵣ, dyᵣ, label="Actual", marker=:o, color=:salmon)
  scatter!(xᵣ, dŷᵣ, label="Estimate", marker=:x, color=:darkslateblue,
    markersize=5, title="Actual derivatives vs Estimates")
end

# ╔═╡ 47d2c2cc-8854-11eb-35f9-952876481d02
md"""
When a function has sevral variables, it has multiple *partila derivatives* each indicating how f change when a small change is made in one of the input variable (while keeping the rest constant).
"""

# ╔═╡ f5980b54-8856-11eb-3e30-89c3f188ca8d
begin
  function ∂_diff_quotient(f::Function, v::VT, i::Integer, Δ::AF)::AF
    """
    Returns the i-th partial difference quotient of f at v
    """
    w = copy(v)
    w[i] += Δ
    (f.(w...) - f.(v...)) / Δ
  end

  ∂_diff_quotient(f::Function, v::Vector{AF}, Δ::AF)::AF =
    ∂_diff_quotient.(f, Tuple(v), 1:length(v), Δ)
end

# ╔═╡ f57b16b6-8856-11eb-3409-47f7b438f491
md"""
With this definition we can then estimate the gradient.
"""

# ╔═╡ f55dd09c-8856-11eb-1823-290fcb200662
function estimate_∇(f::Function, v::VT, Δ::AF)::VT
  [∂_diff_quotient(f, v, i, Δ) for i in 1:length(v)]
end

# ╔═╡ 33df0458-885c-11eb-2635-371a9590d833
begin
  fn(u::AF, v::AF) = u^2 + v

  ∂fnᵤ(u::AF, _v::AF) = 2. * u  # ∂fn w.r.t u
  ∂fnᵥ(_u::AF, v::AF) = 1       # ∂fn w.r.t v
end

# ╔═╡ e76a5b58-885c-11eb-0067-010ba1d4c9b5
begin
  Base.:≈(x::AF, y::AF; ϵ=1e-4) = abs(x - y) ≤ ϵ

  Base.:≈(u::Vector{T}, v::Vector{T}; ϵ=1e-4) where T <: AF = abs.(u - v) .≤ ϵ
end

# ╔═╡ e783d618-8858-11eb-0c0b-b57e54bd3757
begin
  Δ₁ = 1e-6
  vm = Float64[1., 2.]
  ix = 1
  @test ∂fnᵤ(vm...) ≈ ∂_diff_quotient(fn, vm, ix, Δ₁)
end

# ╔═╡ e767c1bc-8858-11eb-1b29-596a25a4fea4
html"""

"""

# ╔═╡ e747b052-8858-11eb-3c50-5355fef542c9
md"""
### Using the Gradient
"""

# ╔═╡ cc17413a-885d-11eb-1629-47fc5220529e
md"""
It is easy to see that the function `f` defines above is smallest when its input is a vector of zeros. But imagine let's say we do not know. In this case we can use  the gradients to find the minimum (this function is bivariate convexe) among all three-dimensional vectors.

We will start by picking a random starting point and then take tiny steps in the opposite direction of the gradient until we reach a point where the gradient is very small (which is guarantee to happen)
"""

# ╔═╡ cbfa193c-885d-11eb-3a48-97b26377b4fb
function ∇_step(v::VT, ∇::VT, η::AF)::VT
  @assert length(v) == length(∇)
  v + η * ∇
end

# ╔═╡ cbe180fe-885d-11eb-1307-7f3ac4897441
∇_sum_of_square(v::VT) = deriv_square(v)

# ╔═╡ d21bb0fe-884c-11eb-224f-216a811365a8
function gradient_descent(fn;range=1000, rng=MersenneTwister(42), η=1e-2)
  v = rand(rng, 3)
  for epoch ∈ 1:range
    ∇ = fn(v)
    v = ∇_step(v, ∇, -η) ## take a step in negative direction of the gradient
    epoch % 100 == 0 && println("$(epoch) => v: $(v)")
  end
  v
end

# ╔═╡ de2e6604-8863-11eb-3a27-8f8e8b55e5d8
with_terminal() do
  gradient_descent(∇_sum_of_square)
end

# ╔═╡ 3082d12e-8864-11eb-06bc-cdf9202cd20a
begin
  @test all(Base.:≈(gradient_descent(∇_sum_of_square), zeros(Float64, 3); ϵ=1.e-7))
  @test all(gradient_descent(∇_sum_of_square) ≈ zeros(Float64, 3))
end9.93698

-1.0823

# ╔═╡ 306b8d52-8864-11eb-1cbd-1341afcd52ff
html"""

"""

# ╔═╡ 304ff894-8864-11eb-1449-b71da9112247
md"""
### Choosing the right step

It is clear why we choose to move in the opposite direction of the gradient while minimizing an (objective) function. Determining the right step however is something like an art and its value depends on the context.
  - Too large a step size and we are likely to overshoot and not converge to the optimum.
  - Too small a step and it will take ages to converge...

Not easy. There are mutliple options like fixed step size, gradual shrinking of the step size over time and other fancier options... To select the right step (or rnage of steps) one can try different options on a validation set...
"""

# ╔═╡ 8c4d28fc-884a-11eb-0de2-b58988dc7422
html"""

"""

# ╔═╡ 8a07d906-8869-11eb-0bae-2582b352c05c
md"""
### Using Gradient Descent (GD) to fit models

In this collection of notebooks, we will be using gradient descent to fit parameterized models to data.

The usual case involves some dataset which we try to fit with a model (our hypothesis) that is characterized by some differentiable parameters. Also to measure the quality of our progress we will have a loss function.

Taking the data as being fixed, the loss function tells us how good (or bad) our model parameters are. We can use gradient descent to optimize this loss.

Let us try on a toy example.
"""

# ╔═╡ 89ebdac6-8869-11eb-25ac-2dac6a4b20aa
begin
  rng = MersenneTwister(42)
  data = [[x, 10x + 5. + 40. * randn(rng, 1)[1]] for x ∈ -50.:50.]
  # linear pattern with some (Normally distributed) noise
end

# ╔═╡ 89d1728a-8869-11eb-0001-875c2a452cf8
scatter(map(x -> x[1], data), map(y -> y[2], data), legend=false)

# ╔═╡ c0cc67c8-888b-11eb-272c-05a727c634ea
typeof(data)

# ╔═╡ 4bf3d986-886d-11eb-3ea8-7926f5babce0
function linear_∇(x::AF, y::AF, θ::VT)::VT
  slope, intercept = θ
  ŷ = slope * x + intercept   # prediction model
  Δerr = (ŷ - y)
  # squared_Δerr = Δerr^2
  [2. * Δerr * x, 2. * Δerr]
end

# ╔═╡ d8f972a0-8881-11eb-2be8-db89fb95a9f1
md"""
We are going to:
  1. Start with random initialisation of the parameters (θ)
  1. Compute the mean of the gradient
  1. Adjust θ
  1. Repeat
"""

# ╔═╡ 1b26337a-8882-11eb-2439-e106cdb884f5
function ∇_descent(inputs::Vector{Vector{T}};
    η=1e-5, nepochs=5_000) where T <: AF
  u = Uniform(-1., 1.)
  θ = [rand(u) for _ ∈ 1:2]

  for epoch ∈ 1:nepochs
    ∇ = μ([linear_∇(x, y, θ) for (x, y) ∈ inputs])
    θ = ∇_step(θ, ∇, -η)
    epoch % 100 == 0 && println("$(epoch) => θ: $(θ)")
  end

  (slope, intercept) = θ
end

# ╔═╡ 1b09cc9e-8882-11eb-0efc-630028d87217
begin
  slope, intercept = ∇_descent(data; nepochs=1_000)
  @test 9.90 ≤ slope ≤ 10.1
  @test abs(intercept) ≤ 1.0
end

# ╔═╡ 28b44b3c-88f8-11eb-23dd-bbfe325d70d3
md"""
Let's plot our result:
"""

# ╔═╡ 1c89f188-88f6-11eb-026c-e59bb08ac7ac
begin
  x_ = [-50.0, 50.0]
  y_ = slope .* x_ .+ intercept
  #
  scatter(map(x -> x[1], data), map(y -> y[2], data), legend=false)
  plot!(x_, y_, lw=3, color=:darkred)
end

# ╔═╡ 1ad358e4-8882-11eb-0559-bd43867dacfd
html"""

"""

# ╔═╡ d8d3bb0a-8881-11eb-35b2-8f486d6cc094
md"""
### Mini-batch and Stochastic Gradient Descent

In the preceding approach we evaluated the gradient on the whole dataset. This was fine because our dataset was small. In practice datasets can be big/large and this technique  becomes computationally expensive. This is why other techniques were devised, namely stochastic gradient descent and mini-batch gradient descent (a good trade-off between full gradient descent and stochastic gradient descent).

In mini-batch gradient descent, we compute the gradient and take a  gradient step based on a mini-batch sampled from the dataset:
"""

# ╔═╡ cd7c444a-8893-11eb-2409-f161ebc287b5
begin
	"""
	Generates batch-size sized min-batches from given dataset
	"""

	struct MiniBatch{T <: Any}
		ds::Vector{Vector{T}}
		bsize::Integer  # batch-size

		function MiniBatch{T}(ds::Vector{Vector{T}}, bs::Integer) where T <: Any
			@assert 0 < bs ≤ length(ds)
			new(ds, bs)
    	end
  	end

  	Base.collect(iter::MiniBatch) = iter.ds

	function Base.iterate(iter::MiniBatch,
			state=(view(iter.ds, 1:iter.bsize), iter.bsize + 1))
		batch, ix = state
		##
		isnothing(batch) && return nothing
		ix ≥ length(iter.ds) && return (batch, (nothing, ix))
		## otherwise
		jx = ix
		ix += iter.bsize
		ix = ix ≥ length(iter.ds) ? length(iter.ds) : ix
		(batch, (view(iter.ds, jx:ix - 1), ix))
	end

	Base.length(iter::MiniBatch) = length(iter.ds)
	Base.eltype(iter::MiniBatch) = eltype(iter.ds)
end

# ╔═╡ 714137c2-8900-11eb-3b4b-57abc5409bd2
let _ix = 0, bsz = 15
	for batch ∈ MiniBatch{Float64}(data, bsz)
		@assert length(batch) == bsz || 0 ≤ length(batch) ≤ bsz
		_ix += 1
	end
	@test _ix == 7
end

# ╔═╡ 7125e906-8900-11eb-3cd5-69755931c32d
let _ix = 0, bsz = 12
	for batch ∈ MiniBatch{Float64}(data, bsz)
		@assert length(batch) == bsz || 0 ≤ length(batch) ≤ bsz
		_ix += 1
	end
	@test _ix == 9
end

# ╔═╡ 401f3d8e-8904-11eb-1065-1de6c9bf32be
md"""
let's rewrite our gradient(∇) descent with min-batch:
"""

# ╔═╡ 70eef976-8900-11eb-3a03-af04f8dea9cc
function minibatch_∇_descent(inputs::Vector{Vector{T}};
    η=1e-5, nepochs=5_000, bsize=10) where T <: AF
  u = Uniform(-1., 1.)
  θ = [rand(u) for _ ∈ 1:2]

  for epoch ∈ 1:nepochs
		for batch ∈ MiniBatch{eltype(inputs[1][1])}(inputs, bsize)
			∇ = μ([linear_∇(x, y, θ) for (x, y) ∈ inputs])
    		θ = ∇_step(θ, ∇, -η)
		end
    epoch % 100 == 0 && println("$(epoch) => θ: $(θ)")
  end

  (slope, intercept) = θ
end

# ╔═╡ 70d67f74-8900-11eb-0174-f5c05571848e
begin
  slope₂, intercept₂ = minibatch_∇_descent(data; nepochs=100) ## only 100 epochs
  @test 9.90 ≤ slope₂ ≤ 10.1
  @test abs(intercept₂) ≤ 1.0
end

# ╔═╡ 8d33a0f4-8906-11eb-3690-ddd49fc6cee1
begin
  # x_₂ = [-50.0, 50.0]
  y_₂ = slope .* x_ .+ intercept
  #
  scatter(map(x -> x[1], data), map(y -> y[2], data), legend=false)
  plot!(x_, y_₂, lw=3, color=:darkred)
end

# ╔═╡ 0a1acf66-8907-11eb-3eac-59a3e18d9c43
md"""
In this instance our mini-batch gradient descent worked pretty well, finding the optimal parameters in just 100 iteration (and actually less)...

Basing gradient step on a small min-batch or just on one sampel (in the case of stochastic gradient descent) allows to take more steps, but the gradient can fluctuate a lot...
"""

# ╔═╡ Cell order:
# ╟─380c26d0-881d-11eb-0461-f339488ea81e
# ╠═e03dd22c-884c-11eb-2432-3dc04b0cf286
# ╟─83e01f80-884a-11eb-1ef7-e9cb5ab3ed20
# ╟─853ab02c-884a-11eb-01bf-1712dc177ffb
# ╟─4c951444-8869-11eb-0b88-55a9fb9e51e6
# ╟─8c87c3b8-884a-11eb-10c8-73e2dab560ea
# ╟─8c6ba818-884a-11eb-23e0-2f1c297d88f5
# ╠═d2d18b22-884c-11eb-1f93-037453c5395b
# ╟─221734fe-8869-11eb-331a-b5810d0b784c
# ╟─d297fa06-884c-11eb-294e-85992f901be1
# ╠═1859c082-8853-11eb-18f6-2bc7a180b4a2
# ╠═d27feefa-884c-11eb-3b84-1f529d7f6410
# ╟─5618fb40-8853-11eb-3d2f-032437d22a09
# ╠═55fab426-8853-11eb-01f8-cbde45c7de9c
# ╟─55e3efea-8853-11eb-0821-c5c580bc8fc5
# ╠═55c56cc8-8853-11eb-04f4-3be84a352808
# ╟─d25d8eac-884c-11eb-2063-27413f8aba04
# ╠═480f7b18-8854-11eb-2898-8d876317ebe2
# ╠═47ee8cb4-8854-11eb-252b-852fd56aa40f
# ╟─47d2c2cc-8854-11eb-35f9-952876481d02
# ╠═f5980b54-8856-11eb-3e30-89c3f188ca8d
# ╟─f57b16b6-8856-11eb-3409-47f7b438f491
# ╠═f55dd09c-8856-11eb-1823-290fcb200662
# ╠═33df0458-885c-11eb-2635-371a9590d833
# ╠═e76a5b58-885c-11eb-0067-010ba1d4c9b5
# ╠═e783d618-8858-11eb-0c0b-b57e54bd3757
# ╟─e767c1bc-8858-11eb-1b29-596a25a4fea4
# ╟─e747b052-8858-11eb-3c50-5355fef542c9
# ╟─cc17413a-885d-11eb-1629-47fc5220529e
# ╠═cbfa193c-885d-11eb-3a48-97b26377b4fb
# ╠═cbe180fe-885d-11eb-1307-7f3ac4897441
# ╠═d21bb0fe-884c-11eb-224f-216a811365a8
# ╠═de2e6604-8863-11eb-3a27-8f8e8b55e5d8
# ╠═3082d12e-8864-11eb-06bc-cdf9202cd20a
# ╟─306b8d52-8864-11eb-1cbd-1341afcd52ff
# ╟─304ff894-8864-11eb-1449-b71da9112247
# ╟─8c4d28fc-884a-11eb-0de2-b58988dc7422
# ╟─8a07d906-8869-11eb-0bae-2582b352c05c
# ╠═89ebdac6-8869-11eb-25ac-2dac6a4b20aa
# ╠═89d1728a-8869-11eb-0001-875c2a452cf8
# ╠═c0cc67c8-888b-11eb-272c-05a727c634ea
# ╠═4bf3d986-886d-11eb-3ea8-7926f5babce0
# ╟─d8f972a0-8881-11eb-2be8-db89fb95a9f1
# ╠═1b26337a-8882-11eb-2439-e106cdb884f5
# ╠═1b09cc9e-8882-11eb-0efc-630028d87217
# ╟─28b44b3c-88f8-11eb-23dd-bbfe325d70d3
# ╠═1c89f188-88f6-11eb-026c-e59bb08ac7ac
# ╟─1ad358e4-8882-11eb-0559-bd43867dacfd
# ╟─d8d3bb0a-8881-11eb-35b2-8f486d6cc094
# ╠═cd7c444a-8893-11eb-2409-f161ebc287b5
# ╠═714137c2-8900-11eb-3b4b-57abc5409bd2
# ╠═7125e906-8900-11eb-3cd5-69755931c32d
# ╟─401f3d8e-8904-11eb-1065-1de6c9bf32be
# ╠═70eef976-8900-11eb-3a03-af04f8dea9cc
# ╠═70d67f74-8900-11eb-0174-f5c05571848e
# ╠═8d33a0f4-8906-11eb-3690-ddd49fc6cee1
# ╟─0a1acf66-8907-11eb-3eac-59a3e18d9c43

max_stars_repo_path: Data Science From Scratch/08_Gradient_Descent.jl

max_stars_repo_name: pascal-p/julia-notebooks

max_issues_repo_name: pascal-p/julia-notebooks

max_forks_repo_name: pascal-p/julia-notebooks