text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: sfn
using AWS.Compat
using AWS.UUIDs

"""
    create_activity(name)
    create_activity(name, params::Dict{String,<:Any})

Creates an activity. An activity is a task that you write in any programming language and
host on any machine that has access to AWS Step Functions. Activities must poll Step
Functions using the GetActivityTask API action and respond using SendTask* API actions.
This function lets Step Functions know the existence of your activity and returns an
identifier for use in a state machine and when polling from the activity.  This operation
is eventually consistent. The results are best effort and may not reflect very recent
updates and changes.    CreateActivity is an idempotent API. Subsequent requests won’t
create a duplicate resource if it was already created. CreateActivity's idempotency check
is based on the activity name. If a following request has different tags values, Step
Functions will ignore these differences and treat it as an idempotent request of the
previous. In this case, tags will not be updated, even if they are different.

# Arguments
- `name`: The name of the activity to create. This name must be unique for your AWS account
  and region for 90 days. For more information, see  Limits Related to State Machine
  Executions in the AWS Step Functions Developer Guide. A name must not contain:   white
  space   brackets < > { } [ ]    wildcard characters ? *    special characters \" # %
  ^ | ~ `  & , ; : /    control characters (U+0000-001F, U+007F-009F)   To enable logging
  with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"tags"`: The list of tags to add to a resource. An array of key-value pairs. For more
  information, see Using Cost Allocation Tags in the AWS Billing and Cost Management User
  Guide, and Controlling Access Using IAM Tags. Tags may only contain Unicode letters,
  digits, white space, or these symbols: _ . : / = + - @.
"""
create_activity(name; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("CreateActivity", Dict{String, Any}("name"=>name); aws_config=aws_config)
create_activity(name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("CreateActivity", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("name"=>name), params)); aws_config=aws_config)

"""
    create_state_machine(definition, name, role_arn)
    create_state_machine(definition, name, role_arn, params::Dict{String,<:Any})

Creates a state machine. A state machine consists of a collection of states that can do
work (Task states), determine to which states to transition next (Choice states), stop an
execution with an error (Fail states), and so on. State machines are specified using a
JSON-based, structured language. For more information, see Amazon States Language in the
AWS Step Functions User Guide.  This operation is eventually consistent. The results are
best effort and may not reflect very recent updates and changes.    CreateStateMachine is
an idempotent API. Subsequent requests won’t create a duplicate resource if it was
already created. CreateStateMachine's idempotency check is based on the state machine name,
definition, type, LoggingConfiguration and TracingConfiguration. If a following request has
a different roleArn or tags, Step Functions will ignore these differences and treat it as
an idempotent request of the previous. In this case, roleArn and tags will not be updated,
even if they are different.

# Arguments
- `definition`: The Amazon States Language definition of the state machine. See Amazon
  States Language.
- `name`: The name of the state machine.  A name must not contain:   white space   brackets
  < > { } [ ]    wildcard characters ? *    special characters \" # %  ^ | ~ `  & ,
  ; : /    control characters (U+0000-001F, U+007F-009F)   To enable logging with CloudWatch
  Logs, the name should only contain 0-9, A-Z, a-z, - and _.
- `role_arn`: The Amazon Resource Name (ARN) of the IAM role to use for this state machine.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"loggingConfiguration"`: Defines what execution history events are logged and where they
  are logged.  By default, the level is set to OFF. For more information see Log Levels in
  the AWS Step Functions User Guide.
- `"tags"`: Tags to be added when creating a state machine. An array of key-value pairs.
  For more information, see Using Cost Allocation Tags in the AWS Billing and Cost Management
  User Guide, and Controlling Access Using IAM Tags. Tags may only contain Unicode letters,
  digits, white space, or these symbols: _ . : / = + - @.
- `"tracingConfiguration"`: Selects whether AWS X-Ray tracing is enabled.
- `"type"`: Determines whether a Standard or Express state machine is created. The default
  is STANDARD. You cannot update the type of a state machine once it has been created.
"""
create_state_machine(definition, name, roleArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("CreateStateMachine", Dict{String, Any}("definition"=>definition, "name"=>name, "roleArn"=>roleArn); aws_config=aws_config)
create_state_machine(definition, name, roleArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("CreateStateMachine", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("definition"=>definition, "name"=>name, "roleArn"=>roleArn), params)); aws_config=aws_config)

"""
    delete_activity(activity_arn)
    delete_activity(activity_arn, params::Dict{String,<:Any})

Deletes an activity.

# Arguments
- `activity_arn`: The Amazon Resource Name (ARN) of the activity to delete.

"""
delete_activity(activityArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DeleteActivity", Dict{String, Any}("activityArn"=>activityArn); aws_config=aws_config)
delete_activity(activityArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DeleteActivity", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("activityArn"=>activityArn), params)); aws_config=aws_config)

"""
    delete_state_machine(state_machine_arn)
    delete_state_machine(state_machine_arn, params::Dict{String,<:Any})

Deletes a state machine. This is an asynchronous operation: It sets the state machine's
status to DELETING and begins the deletion process.   For EXPRESSstate machines, the
deletion will happen eventually (usually less than a minute). Running executions may emit
logs after DeleteStateMachine API is called.

# Arguments
- `state_machine_arn`: The Amazon Resource Name (ARN) of the state machine to delete.

"""
delete_state_machine(stateMachineArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DeleteStateMachine", Dict{String, Any}("stateMachineArn"=>stateMachineArn); aws_config=aws_config)
delete_state_machine(stateMachineArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DeleteStateMachine", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stateMachineArn"=>stateMachineArn), params)); aws_config=aws_config)

"""
    describe_activity(activity_arn)
    describe_activity(activity_arn, params::Dict{String,<:Any})

Describes an activity.  This operation is eventually consistent. The results are best
effort and may not reflect very recent updates and changes.

# Arguments
- `activity_arn`: The Amazon Resource Name (ARN) of the activity to describe.

"""
describe_activity(activityArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeActivity", Dict{String, Any}("activityArn"=>activityArn); aws_config=aws_config)
describe_activity(activityArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeActivity", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("activityArn"=>activityArn), params)); aws_config=aws_config)

"""
    describe_execution(execution_arn)
    describe_execution(execution_arn, params::Dict{String,<:Any})

Describes an execution.  This operation is eventually consistent. The results are best
effort and may not reflect very recent updates and changes.  This API action is not
supported by EXPRESS state machines.

# Arguments
- `execution_arn`: The Amazon Resource Name (ARN) of the execution to describe.

"""
describe_execution(executionArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeExecution", Dict{String, Any}("executionArn"=>executionArn); aws_config=aws_config)
describe_execution(executionArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeExecution", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("executionArn"=>executionArn), params)); aws_config=aws_config)

"""
    describe_state_machine(state_machine_arn)
    describe_state_machine(state_machine_arn, params::Dict{String,<:Any})

Describes a state machine.  This operation is eventually consistent. The results are best
effort and may not reflect very recent updates and changes.

# Arguments
- `state_machine_arn`: The Amazon Resource Name (ARN) of the state machine to describe.

"""
describe_state_machine(stateMachineArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeStateMachine", Dict{String, Any}("stateMachineArn"=>stateMachineArn); aws_config=aws_config)
describe_state_machine(stateMachineArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeStateMachine", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stateMachineArn"=>stateMachineArn), params)); aws_config=aws_config)

"""
    describe_state_machine_for_execution(execution_arn)
    describe_state_machine_for_execution(execution_arn, params::Dict{String,<:Any})

Describes the state machine associated with a specific execution.  This operation is
eventually consistent. The results are best effort and may not reflect very recent updates
and changes.  This API action is not supported by EXPRESS state machines.

# Arguments
- `execution_arn`: The Amazon Resource Name (ARN) of the execution you want state machine
  information for.

"""
describe_state_machine_for_execution(executionArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeStateMachineForExecution", Dict{String, Any}("executionArn"=>executionArn); aws_config=aws_config)
describe_state_machine_for_execution(executionArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("DescribeStateMachineForExecution", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("executionArn"=>executionArn), params)); aws_config=aws_config)

"""
    get_activity_task(activity_arn)
    get_activity_task(activity_arn, params::Dict{String,<:Any})

Used by workers to retrieve a task (with the specified activity ARN) which has been
scheduled for execution by a running state machine. This initiates a long poll, where the
service holds the HTTP connection open and responds as soon as a task becomes available
(i.e. an execution of a task of this type is needed.) The maximum time the service holds on
to the request before responding is 60 seconds. If no task is available within 60 seconds,
the poll returns a taskToken with a null string.  Workers should set their client side
socket timeout to at least 65 seconds (5 seconds higher than the maximum time the service
may hold the poll request). Polling with GetActivityTask can cause latency in some
implementations. See Avoid Latency When Polling for Activity Tasks in the Step Functions
Developer Guide.

# Arguments
- `activity_arn`: The Amazon Resource Name (ARN) of the activity to retrieve tasks from
  (assigned when you create the task using CreateActivity.)

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"workerName"`: You can provide an arbitrary name in order to identify the worker that
  the task is assigned to. This name is used when it is logged in the execution history.
"""
get_activity_task(activityArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("GetActivityTask", Dict{String, Any}("activityArn"=>activityArn); aws_config=aws_config)
get_activity_task(activityArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("GetActivityTask", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("activityArn"=>activityArn), params)); aws_config=aws_config)

"""
    get_execution_history(execution_arn)
    get_execution_history(execution_arn, params::Dict{String,<:Any})

Returns the history of the specified execution as a list of events. By default, the results
are returned in ascending order of the timeStamp of the events. Use the reverseOrder
parameter to get the latest events first. If nextToken is returned, there are more results
available. The value of nextToken is a unique pagination token for each page. Make the call
again using the returned token to retrieve the next page. Keep all other arguments
unchanged. Each pagination token expires after 24 hours. Using an expired pagination token
will return an HTTP 400 InvalidToken error. This API action is not supported by EXPRESS
state machines.

# Arguments
- `execution_arn`: The Amazon Resource Name (ARN) of the execution.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"includeExecutionData"`: You can select whether execution data (input or output of a
  history event) is returned. The default is true.
- `"maxResults"`: The maximum number of results that are returned per call. You can use
  nextToken to obtain further pages of results. The default is 100 and the maximum allowed
  page size is 1000. A value of 0 uses the default. This is only an upper limit. The actual
  number of results returned per call might be fewer than the specified maximum.
- `"nextToken"`: If nextToken is returned, there are more results available. The value of
  nextToken is a unique pagination token for each page. Make the call again using the
  returned token to retrieve the next page. Keep all other arguments unchanged. Each
  pagination token expires after 24 hours. Using an expired pagination token will return an
  HTTP 400 InvalidToken error.
- `"reverseOrder"`: Lists events in descending order of their timeStamp.
"""
get_execution_history(executionArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("GetExecutionHistory", Dict{String, Any}("executionArn"=>executionArn); aws_config=aws_config)
get_execution_history(executionArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("GetExecutionHistory", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("executionArn"=>executionArn), params)); aws_config=aws_config)

"""
    list_activities()
    list_activities(params::Dict{String,<:Any})

Lists the existing activities. If nextToken is returned, there are more results available.
The value of nextToken is a unique pagination token for each page. Make the call again
using the returned token to retrieve the next page. Keep all other arguments unchanged.
Each pagination token expires after 24 hours. Using an expired pagination token will return
an HTTP 400 InvalidToken error.  This operation is eventually consistent. The results are
best effort and may not reflect very recent updates and changes.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results that are returned per call. You can use
  nextToken to obtain further pages of results. The default is 100 and the maximum allowed
  page size is 1000. A value of 0 uses the default. This is only an upper limit. The actual
  number of results returned per call might be fewer than the specified maximum.
- `"nextToken"`: If nextToken is returned, there are more results available. The value of
  nextToken is a unique pagination token for each page. Make the call again using the
  returned token to retrieve the next page. Keep all other arguments unchanged. Each
  pagination token expires after 24 hours. Using an expired pagination token will return an
  HTTP 400 InvalidToken error.
"""
list_activities(; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListActivities"; aws_config=aws_config)
list_activities(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListActivities", params; aws_config=aws_config)

"""
    list_executions(state_machine_arn)
    list_executions(state_machine_arn, params::Dict{String,<:Any})

Lists the executions of a state machine that meet the filtering criteria. Results are
sorted by time, with the most recent execution first. If nextToken is returned, there are
more results available. The value of nextToken is a unique pagination token for each page.
Make the call again using the returned token to retrieve the next page. Keep all other
arguments unchanged. Each pagination token expires after 24 hours. Using an expired
pagination token will return an HTTP 400 InvalidToken error.  This operation is eventually
consistent. The results are best effort and may not reflect very recent updates and
changes.  This API action is not supported by EXPRESS state machines.

# Arguments
- `state_machine_arn`: The Amazon Resource Name (ARN) of the state machine whose executions
  is listed.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results that are returned per call. You can use
  nextToken to obtain further pages of results. The default is 100 and the maximum allowed
  page size is 1000. A value of 0 uses the default. This is only an upper limit. The actual
  number of results returned per call might be fewer than the specified maximum.
- `"nextToken"`: If nextToken is returned, there are more results available. The value of
  nextToken is a unique pagination token for each page. Make the call again using the
  returned token to retrieve the next page. Keep all other arguments unchanged. Each
  pagination token expires after 24 hours. Using an expired pagination token will return an
  HTTP 400 InvalidToken error.
- `"statusFilter"`: If specified, only list the executions whose current execution status
  matches the given filter.
"""
list_executions(stateMachineArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListExecutions", Dict{String, Any}("stateMachineArn"=>stateMachineArn); aws_config=aws_config)
list_executions(stateMachineArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListExecutions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stateMachineArn"=>stateMachineArn), params)); aws_config=aws_config)

"""
    list_state_machines()
    list_state_machines(params::Dict{String,<:Any})

Lists the existing state machines. If nextToken is returned, there are more results
available. The value of nextToken is a unique pagination token for each page. Make the call
again using the returned token to retrieve the next page. Keep all other arguments
unchanged. Each pagination token expires after 24 hours. Using an expired pagination token
will return an HTTP 400 InvalidToken error.  This operation is eventually consistent. The
results are best effort and may not reflect very recent updates and changes.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results that are returned per call. You can use
  nextToken to obtain further pages of results. The default is 100 and the maximum allowed
  page size is 1000. A value of 0 uses the default. This is only an upper limit. The actual
  number of results returned per call might be fewer than the specified maximum.
- `"nextToken"`: If nextToken is returned, there are more results available. The value of
  nextToken is a unique pagination token for each page. Make the call again using the
  returned token to retrieve the next page. Keep all other arguments unchanged. Each
  pagination token expires after 24 hours. Using an expired pagination token will return an
  HTTP 400 InvalidToken error.
"""
list_state_machines(; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListStateMachines"; aws_config=aws_config)
list_state_machines(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListStateMachines", params; aws_config=aws_config)

"""
    list_tags_for_resource(resource_arn)
    list_tags_for_resource(resource_arn, params::Dict{String,<:Any})

List tags for a given resource. Tags may only contain Unicode letters, digits, white space,
or these symbols: _ . : / = + - @.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) for the Step Functions state machine or
  activity.

"""
list_tags_for_resource(resourceArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListTagsForResource", Dict{String, Any}("resourceArn"=>resourceArn); aws_config=aws_config)
list_tags_for_resource(resourceArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("ListTagsForResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceArn"=>resourceArn), params)); aws_config=aws_config)

"""
    send_task_failure(task_token)
    send_task_failure(task_token, params::Dict{String,<:Any})

Used by activity workers and task states using the callback pattern to report that the task
identified by the taskToken failed.

# Arguments
- `task_token`: The token that represents this task. Task tokens are generated by Step
  Functions when tasks are assigned to a worker, or in the context object when a workflow
  enters a task state. See GetActivityTaskOutputtaskToken.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"cause"`: A more detailed explanation of the cause of the failure.
- `"error"`: The error code of the failure.
"""
send_task_failure(taskToken; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("SendTaskFailure", Dict{String, Any}("taskToken"=>taskToken); aws_config=aws_config)
send_task_failure(taskToken, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("SendTaskFailure", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("taskToken"=>taskToken), params)); aws_config=aws_config)

"""
    send_task_heartbeat(task_token)
    send_task_heartbeat(task_token, params::Dict{String,<:Any})

Used by activity workers and task states using the callback pattern to report to Step
Functions that the task represented by the specified taskToken is still making progress.
This action resets the Heartbeat clock. The Heartbeat threshold is specified in the state
machine's Amazon States Language definition (HeartbeatSeconds). This action does not in
itself create an event in the execution history. However, if the task times out, the
execution history contains an ActivityTimedOut entry for activities, or a TaskTimedOut
entry for for tasks using the job run or callback pattern.  The Timeout of a task, defined
in the state machine's Amazon States Language definition, is its maximum allowed duration,
regardless of the number of SendTaskHeartbeat requests received. Use HeartbeatSeconds to
configure the timeout interval for heartbeats.

# Arguments
- `task_token`: The token that represents this task. Task tokens are generated by Step
  Functions when tasks are assigned to a worker, or in the context object when a workflow
  enters a task state. See GetActivityTaskOutputtaskToken.

"""
send_task_heartbeat(taskToken; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("SendTaskHeartbeat", Dict{String, Any}("taskToken"=>taskToken); aws_config=aws_config)
send_task_heartbeat(taskToken, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("SendTaskHeartbeat", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("taskToken"=>taskToken), params)); aws_config=aws_config)

"""
    send_task_success(output, task_token)
    send_task_success(output, task_token, params::Dict{String,<:Any})

Used by activity workers and task states using the callback pattern to report that the task
identified by the taskToken completed successfully.

# Arguments
- `output`: The JSON output of the task. Length constraints apply to the payload size, and
  are expressed as bytes in UTF-8 encoding.
- `task_token`: The token that represents this task. Task tokens are generated by Step
  Functions when tasks are assigned to a worker, or in the context object when a workflow
  enters a task state. See GetActivityTaskOutputtaskToken.

"""
send_task_success(output, taskToken; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("SendTaskSuccess", Dict{String, Any}("output"=>output, "taskToken"=>taskToken); aws_config=aws_config)
send_task_success(output, taskToken, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("SendTaskSuccess", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("output"=>output, "taskToken"=>taskToken), params)); aws_config=aws_config)

"""
    start_execution(state_machine_arn)
    start_execution(state_machine_arn, params::Dict{String,<:Any})

Starts a state machine execution.   StartExecution is idempotent. If StartExecution is
called with the same name and input as a running execution, the call will succeed and
return the same response as the original request. If the execution is closed or if the
input is different, it will return a 400 ExecutionAlreadyExists error. Names can be reused
after 90 days.

# Arguments
- `state_machine_arn`: The Amazon Resource Name (ARN) of the state machine to execute.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"input"`: The string that contains the JSON input data for the execution, for example:
  \"input\": \"{\"first_name\" : \"test\"}\"   If you don't include any JSON input data, you
  still must include the two braces, for example: \"input\": \"{}\"   Length constraints
  apply to the payload size, and are expressed as bytes in UTF-8 encoding.
- `"name"`: The name of the execution. This name must be unique for your AWS account,
  region, and state machine for 90 days. For more information, see  Limits Related to State
  Machine Executions in the AWS Step Functions Developer Guide. A name must not contain:
  white space   brackets < > { } [ ]    wildcard characters ? *    special characters
  \" # %  ^ | ~ `  & , ; : /    control characters (U+0000-001F, U+007F-009F)   To enable
  logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.
- `"traceHeader"`: Passes the AWS X-Ray trace header. The trace header can also be passed
  in the request payload.
"""
start_execution(stateMachineArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("StartExecution", Dict{String, Any}("stateMachineArn"=>stateMachineArn); aws_config=aws_config)
start_execution(stateMachineArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("StartExecution", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stateMachineArn"=>stateMachineArn), params)); aws_config=aws_config)

"""
    start_sync_execution(state_machine_arn)
    start_sync_execution(state_machine_arn, params::Dict{String,<:Any})

Starts a Synchronous Express state machine execution.

# Arguments
- `state_machine_arn`: The Amazon Resource Name (ARN) of the state machine to execute.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"input"`: The string that contains the JSON input data for the execution, for example:
  \"input\": \"{\"first_name\" : \"test\"}\"   If you don't include any JSON input data, you
  still must include the two braces, for example: \"input\": \"{}\"   Length constraints
  apply to the payload size, and are expressed as bytes in UTF-8 encoding.
- `"name"`: The name of the execution.
- `"traceHeader"`: Passes the AWS X-Ray trace header. The trace header can also be passed
  in the request payload.
"""
start_sync_execution(stateMachineArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("StartSyncExecution", Dict{String, Any}("stateMachineArn"=>stateMachineArn); aws_config=aws_config)
start_sync_execution(stateMachineArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("StartSyncExecution", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stateMachineArn"=>stateMachineArn), params)); aws_config=aws_config)

"""
    stop_execution(execution_arn)
    stop_execution(execution_arn, params::Dict{String,<:Any})

Stops an execution. This API action is not supported by EXPRESS state machines.

# Arguments
- `execution_arn`: The Amazon Resource Name (ARN) of the execution to stop.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"cause"`: A more detailed explanation of the cause of the failure.
- `"error"`: The error code of the failure.
"""
stop_execution(executionArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("StopExecution", Dict{String, Any}("executionArn"=>executionArn); aws_config=aws_config)
stop_execution(executionArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("StopExecution", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("executionArn"=>executionArn), params)); aws_config=aws_config)

"""
    tag_resource(resource_arn, tags)
    tag_resource(resource_arn, tags, params::Dict{String,<:Any})

Add a tag to a Step Functions resource. An array of key-value pairs. For more information,
see Using Cost Allocation Tags in the AWS Billing and Cost Management User Guide, and
Controlling Access Using IAM Tags. Tags may only contain Unicode letters, digits, white
space, or these symbols: _ . : / = + - @.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) for the Step Functions state machine or
  activity.
- `tags`: The list of tags to add to a resource. Tags may only contain Unicode letters,
  digits, white space, or these symbols: _ . : / = + - @.

"""
tag_resource(resourceArn, tags; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("TagResource", Dict{String, Any}("resourceArn"=>resourceArn, "tags"=>tags); aws_config=aws_config)
tag_resource(resourceArn, tags, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("TagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceArn"=>resourceArn, "tags"=>tags), params)); aws_config=aws_config)

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Remove a tag from a Step Functions resource

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) for the Step Functions state machine or
  activity.
- `tag_keys`: The list of tags to remove from the resource.

"""
untag_resource(resourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("UntagResource", Dict{String, Any}("resourceArn"=>resourceArn, "tagKeys"=>tagKeys); aws_config=aws_config)
untag_resource(resourceArn, tagKeys, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("UntagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceArn"=>resourceArn, "tagKeys"=>tagKeys), params)); aws_config=aws_config)

"""
    update_state_machine(state_machine_arn)
    update_state_machine(state_machine_arn, params::Dict{String,<:Any})

Updates an existing state machine by modifying its definition, roleArn, or
loggingConfiguration. Running executions will continue to use the previous definition and
roleArn. You must include at least one of definition or roleArn or you will receive a
MissingRequiredParameter error.  All StartExecution calls within a few seconds will use the
updated definition and roleArn. Executions started immediately after calling
UpdateStateMachine may use the previous state machine definition and roleArn.

# Arguments
- `state_machine_arn`: The Amazon Resource Name (ARN) of the state machine.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"definition"`: The Amazon States Language definition of the state machine. See Amazon
  States Language.
- `"loggingConfiguration"`: The LoggingConfiguration data type is used to set CloudWatch
  Logs options.
- `"roleArn"`: The Amazon Resource Name (ARN) of the IAM role of the state machine.
- `"tracingConfiguration"`: Selects whether AWS X-Ray tracing is enabled.
"""
update_state_machine(stateMachineArn; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("UpdateStateMachine", Dict{String, Any}("stateMachineArn"=>stateMachineArn); aws_config=aws_config)
update_state_machine(stateMachineArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = sfn("UpdateStateMachine", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stateMachineArn"=>stateMachineArn), params)); aws_config=aws_config)


text:
using Libdl
const shared_lib = "./ocaml.so"

function start_ocaml()
    lib = Libdl.dlopen(shared_lib)
    ccall(("ocaml_jl_start", shared_lib), Cvoid, ())
end

start_ocaml()

fn = Main.mycaml_fn
Main.mycaml_fn(x=1, y=2)
println(fn((1, "foo", [1.2, "bar"])))
for i in 1:3
    println(fn(i, "foo", [1.2, "bar"]))
end

fn2 = Main.myother_fn
println(fn2(4))
println(fn2(2; y="test"))

fn2 = Main.yetanother_fn
println(fn2(4))
println(typeof(fn2(4)))
println(fn2(4)[2])

println(Main.with_julia_callback_fn(42, x -> 2*x))

ext: jl


text:
module TestBlobs

using Blobs
using Test

struct Foo
    x::Int64
    y::Float32 # tests conversion and alignment
end

# Blob

blob = Blob{Int64}(Libc.malloc(16), 0, 8)
@test_nowarn blob[]
@test_throws BoundsError (blob+1)[]
if Base.JLOptions().check_bounds == 0
    # @inbounds only kicks in if compiled
    f1(blob) = @inbounds (blob+1)[]
    f1(blob)
end

foo = Blobs.malloc_and_init(Foo)
foo.x[] = 1
@test foo.x[] == 1
foo.y[] = 2.5
@test foo.y[] == 2.5
@test foo[] == Foo(1,2.5)
# test interior pointers
@test foo == foo
@test pointer(foo.y) == pointer(foo) + sizeof(Int64)

foo2_ref = Ref(Foo(42, 3.14))
foo2 = Blob(foo2_ref)
@test foo2[] == Foo(42, 3.14)

foo3_arr = [Foo(1, -1), Foo(2, -2)]
foo31 = Blob(pointer(foo3_arr), 0, 2sizeof(Foo))
foo32 = Blob(pointer(foo3_arr), sizeof(Foo), 2sizeof(Foo))
foo33 = Blob(pointer(foo3_arr, 2))
@test foo31[] == Foo(1, -1)
@test foo32[] == Foo(2, -2)
@test foo33[] == Foo(2, -2)

foo4 = Blobs.calloc(Foo)
@test foo4[] == Foo(0, 0)

# nested Blob

bfoo = Blobs.malloc_and_init(Blob{Foo})
foo = bfoo[]
foo.x[] = 1
@test foo.x[] == 1

# BlobVector

@test Blobs.self_size(BlobVector{Int64}) == 16

data = Blob{Int64}(Libc.malloc(sizeof(Int64) * 4), 0, sizeof(Int64) * 3)
bv = BlobVector{Int64}(data, 4)
@test_nowarn bv[3]
@test_throws BoundsError bv[4]
if Base.JLOptions().check_bounds == 0
    f2(bv) = @inbounds bv[4]
    f2(bv)
end

bbv = Blobs.malloc_and_init(BlobVector{Foo}, 3)
bv = bbv[]
bv[2] = Foo(2, 2.2)
@test bv[2] == Foo(2, 2.2)
@test bbv[2][] == Foo(2, 2.2)
@test length(bv) == 3
bv[1] = Foo(1, 1.1)
bv[3] = Foo(3, 3.3)
# test iteration
@test collect(bv) == [Foo(1,1.1), Foo(2,2.2), Foo(3,3.3)]
# test interior pointers
@test pointer(bbv[2]) - pointer(bv.data) == Blobs.self_size(Foo)

bbv2 = Blobs.malloc_and_init(BlobVector{Foo}, 3)
bv2 = bbv2[]

copy!(bv2, 1, bv, 1, 3)
@test bv == bv2

copy!(bv2, 2, bv, 1, 2)
@test bv[1:2] == bv2[2:3]

@test_throws BoundsError copy!(bv2, 0, bv, 1, 3)
@test_throws BoundsError copy!(bv2, 1, bv, 1, 4)
@test_throws BoundsError copy!(bv2, 1, bv, 0, 3)
@test_throws BoundsError copy!(bv2, 0, bv, 0, 4)

# Copy to self
bv3 = Blobs.malloc_and_init(BlobVector{Int}, 5)[]
for i in 1:5
    bv3[i] = i
end

copy!(bv3, 4, bv3, 1, 2)
@test bv3 == [1,2,3,1,2]
copy!(bv3, 2, bv3, 1, 4)
@test bv3 == [1,1,2,3,1]
copy!(bv3, 1, bv3, 2, 4)
@test bv3 == [1,2,3,1,1]

@test_throws BoundsError copy!(bv3, 2, bv3, 1, 5)

# BlobBitVector

@test Blobs.self_size(BlobBitVector) == 16
@test Blobs.child_size(BlobBitVector, 1) == 8*1
@test Blobs.child_size(BlobBitVector, 64*3) == 8*3
@test Blobs.child_size(BlobBitVector, 64*3 + 1) == 8*4

data = Blob{UInt64}(Libc.malloc(sizeof(UInt64)*4), 0, sizeof(UInt64)*3)
bv = BlobBitVector(data, 64*4)
@test_nowarn bv[64*3]
@test_throws BoundsError bv[64*3 + 1]
if Base.JLOptions().check_bounds == 0
    f3(bv) = @inbounds bv[64*3 + 1]
    f3(bv)
end

bbv = Blobs.malloc_and_init(BlobBitVector, 3)
bv = bbv[]
bv[2] = true
@test bv[2] == true
@test bbv[2][] == true
@test length(bv) == 3
bv[1] = false
bv[3] = false
# test search methods
@test findnext(bv, 1) == 2
@test findnext(bv, 2) == 2
@test findnext(bv, 3) == nothing
@test findnext(bv, 4) == nothing
@test Base.findnextnot(bv, 1) == 1
@test Base.findnextnot(bv, 2) == 3
@test Base.findnextnot(bv, 3) == 3
bv[3] = true
@test Base.findnextnot(bv, 3) == nothing
bv[3] = false
@test Base.findprevnot(bv, 0) == nothing
@test Base.findprevnot(bv, 1) == 1
@test Base.findprevnot(bv, 2) == 1
@test Base.findprevnot(bv, 3) == 3
bv[1] = true
@test Base.findprevnot(bv, 1) == nothing
bv[1] = false

# test iteration
@test collect(bv) == [false, true, false]
fill!(bv, false)
@test collect(bv) == [false, false, false]
# test interior pointers
bv2 = bbv[2]
@test bv2[] == false
bv2[] = true
@test bv2[] == true
@test bv[2] == true

# BlobString

@test Blobs.self_size(BlobString) == 16

data = Blob{UInt8}(Libc.malloc(8), 0, 8)
@test_nowarn BlobString(data, 8)[8]
# pretty much any access to a unicode string touches beginning and end
@test_throws BoundsError BlobString(data, 16)[8]
# @inbounds doesn't work for strings - too much work to propagate

# test strings and unicode
s = "普通话/普通話"
bbs = Blobs.malloc_and_init(BlobString, s)
bs = bbs[]
@test unsafe_string(pointer(bs), sizeof(bs)) == s
@test bs == s
@test repr(bs) == repr(s)
@test collect(bs) == collect(s)
@test findfirst(bs, "通") == findfirst(s, "通")
@test findlast(bs, "通") == findlast(s, "通")

# test right-to-left
s = "سلام"
bbs = Blobs.malloc_and_init(BlobString, s)
bs = bbs[]
@test unsafe_string(pointer(bs), sizeof(bs)) == s
@test bs == s
@test repr(bs) == repr(s)
@test collect(bs) == collect(s)
@test findfirst(bs, "ا") == findfirst(s, "ا")
@test findlast(bs, "ا") == findlast(s, "ا")

# test string conversions

@test isbitstype(typeof(bs))
@test String(bs) isa String
@test String(bs) == s

println(s)
println("Testing: $s")

# test string slices

s = "aye bee sea"
bbs = Blobs.malloc_and_init(BlobString, s)
bs = bbs[]
@test bs[5:7] isa BlobString
@test bs[5:7] == "bee"

# sketch of paged pmas

struct PackedMemoryArray{K,V}
     keys::BlobVector{K}
     values::BlobVector{V}
     mask::BlobBitVector
     count::Int
     #...other stuff
end

function Blobs.child_size(::Type{PackedMemoryArray{K,V}}, length::Int64) where {K,V}
    T = PackedMemoryArray{K,V}
    +(Blobs.child_size(fieldtype(T, :keys), length),
      Blobs.child_size(fieldtype(T, :values), length),
      Blobs.child_size(fieldtype(T, :mask), length))
  end

function Blobs.init(pma::Blob{PackedMemoryArray{K,V}}, free::Blob{Nothing}, length::Int64) where {K,V}
    free = Blobs.init(pma.keys, free, length)
    free = Blobs.init(pma.values, free, length)
    free = Blobs.init(pma.mask, free, length)
    fill!(pma.mask[], false)
    pma.count[] = 0
    free
end

pma = Blobs.malloc_and_init(PackedMemoryArray{Int64, Float32}, 3)
@test pma.count[] == 0
@test pma.keys.length[] == 3
# tests fill!
@test !any(pma.mask[])
# tests pointer <-> offset conversion
@test unsafe_load(convert(Ptr{Int64}, pointer(pma)), 1) == Blobs.self_size(PackedMemoryArray{Int64, Float32})
# tests nested interior pointers
pma2 = pma.mask[2]
@test pma2[] == false
pma2[] = true
@test pma2[] == true
@test pma.mask[2][] == true

# test api works ok with varying sizes

struct Quux
    x::BlobVector{Int}
    y::Float64
end

struct Bar
    a::Int
    b::BlobBitVector
    c::Bool
    d::BlobVector{Float64}
    e::Blob{Quux}
end

@test Blobs.self_size(Bar) == 8 + 16 + 1 + 16 + 8 # Blob{Quux} is smaller in the blob

function Blobs.child_size(::Type{Quux}, x_len::Int64, y::Float64)
    T = Quux
    +(Blobs.child_size(fieldtype(T, :x), x_len))
end

function Blobs.child_size(::Type{Bar}, b_len::Int64, c::Bool, d_len::Int64, x_len::Int64, y::Float64)
    T = Bar
    +(Blobs.child_size(fieldtype(T, :b), b_len),
      Blobs.child_size(fieldtype(T, :d), d_len),
      Blobs.child_size(fieldtype(T, :e), x_len, y))
end

function Blobs.init(quux::Blob{Quux}, free::Blob{Nothing}, x_len::Int64, y::Float64)
    free = Blobs.init(quux.x, free, x_len)
    quux.y[] = y
    free
end

function Blobs.init(bar::Blob{Bar}, free::Blob{Nothing}, b_len::Int64, c::Bool, d_len::Int64, x_len::Int64, y::Float64)
    free = Blobs.init(bar.b, free, b_len)
    free = Blobs.init(bar.d, free, d_len)
    free = Blobs.init(bar.e, free, x_len, y)
    bar.c[] = c
    free
end

bar = Blobs.malloc_and_init(Bar, 10, false, 20, 15, 1.5)
quux = bar.e[]

@test length(bar.b[]) == 10
@test bar.c[] == false
@test length(bar.d[]) == 20
@test length(quux.x[]) == 15
@test quux.y[] == 1.5

# Tuples
bt = Blobs.malloc_and_init(Tuple{Int64,Int64})
bt[] = (2,3)
@test bt[] == (2,3)
@test bt[][1] == 2

# Structs inside tuples
struct Toto{N}
    data::NTuple{N, UInt8} # Immutable statically sized tuple
    len::Int64 # in bytes
end

bt = Blobs.malloc_and_init(Tuple{Toto{1}})
bt[] = (Toto{1}((0x0,), 8),)
@test bt[][1].len == 8

# Non-isbitstype types are not supported
@test_throws ErrorException Blobs.malloc_and_init(String)

include("compat-tests.jl")

end


text:
##
@traitfn function mean_f(model::TGP) where {T,TGP<:AbstractGP{T};IsMultiOutput{TGP}}
    μ_q = mean_f.(model.f)
    μ_f = []
    for i in 1:(model.nTask)
        x = ntuple(_ -> zeros(T, model.inference.nMinibatch), model.nf_per_task[i])
        for j in 1:model.nf_per_task[i]
            x[j] .= sum(model.A[i][j] .* μ_q)
        end
        push!(μ_f, x)
    end
    return μ_f
end

##
@traitfn function var_f(model::TGP) where {T,TGP<:AbstractGP{T};IsMultiOutput{TGP}}
    Σ_q = var_f.(model.f)
    Σ_f = []
    for i in 1:(model.nTask)
        x = ntuple(_ -> zeros(T, model.inference.nMinibatch), model.nf_per_task[i])
        for j in 1:model.nf_per_task[i]
            x[j] .= sum(model.A[i][j] .^ 2 .* Σ_q)
        end
        push!(Σ_f, x)
    end
    return Σ_f
end

## return the linear sum of the expectation gradient given μ ##
@traitfn function ∇E_μ(m::TGP) where {T,TGP<:AbstractGP{T};IsMultiOutput{TGP}}
    ∇ = [zeros(T, nMinibatch(m.inference)) for i in 1:nLatent(m)]
    ∇Eμs = ∇E_μ.(likelihood(m), Ref(opt_type(m.inference)), yview(m))
    ∇EΣs = ∇E_Σ.(likelihood(m), Ref(opt_type(m.inference)), yview(m))
    μ_f = mean_f.(m.f)
    for t in 1:(m.nTask)
        for j in 1:m.nf_per_task[t]
            for q in 1:nLatent(m)
                ∇[q] .+=
                    m.A[t][j][q] * (
                        ∇Eμs[t][j] -
                        2 * ∇EΣs[t][j] .*
                        sum(m.A[t][j][qq] * μ_f[qq] for qq in 1:nLatent(m) if qq != q)
                    )
            end
        end
    end
    return ∇
end

## return the linear sum of the expectation gradient given diag(Σ) ##
@traitfn function ∇E_Σ(m::TGP) where {T,TGP<:AbstractGP{T};IsMultiOutput{TGP}}
    ∇ = [zeros(T, nMinibatch(m.inference)) for i in 1:(m.nLatent)]
    ∇Es = ∇E_Σ.(m.likelihood, Ref(opt_type(m.inference)), yview(m))
    for t in 1:(m.nTask)
        for j in 1:m.nf_per_task[t]
            for q in 1:nLatent(m)
                ∇[q] .+= m.A[t][j][q]^2 * ∇Es[t][j]
            end
        end
    end
    return ∇
end

##
@traitfn function update_A!(m::TGP) where {T,TGP<:AbstractGP{T};IsMultiOutput{TGP}}
    if !isnothing(m.A_opt)
        μ_f = mean_f.(m.f) # κμ || μ
        Σ_f = var_f.(m.f) #Diag(K̃ + κΣκ) || Diag(Σ)
        ∇Eμ = ∇E_μ.(m.likelihood, Ref(opt_type(m.inference)), yview(m))
        ∇EΣ = ∇E_Σ.(m.likelihood, Ref(opt_type(m.inference)), yview(m))
        # new_A = zero(model.A)
        for t in 1:(m.nTask)
            for j in 1:m.nf_per_task[t]
                ∇A = zero(m.A[t][j])
                for q in 1:nLatent(m)
                    x1 =
                        dot(∇Eμ[t][j], μ_f[q]) -
                        2 * dot(
                            ∇EΣ[t][j],
                            μ_f[q] .*
                            sum(m.A[t][j][qq] * μ_f[qq] for qq in 1:nLatent(m) if qq != q),
                        )
                    x2 = dot(∇EΣ[t][j], abs2.(μ_f[q]) + Σ_f[q])
                    # new_A[t,j,q] = x1/(2*x2)
                    ∇A[q] = x1 - 2 * m.A[t][j][q] * x2
                end
                m.A[t][j] .+= Flux.Optimise.apply!(m.A_opt, m.A[t][j], ∇A)
                m.A[t][j] /= sqrt(sum(abs2, m.A[t][j])) # Projection on the unit circle
            end
        end
    end
end


text:
using Gadfly

set_default_plot_size(6inch, 3inch)

n = 10
plot(x=rand(n), y=rand(n), color=e.^rand(n),
     Scale.color_log(minvalue=1))


text:
using Test
using SymmetricTensors
using Random
using Combinatorics

import SymmetricTensors: ind2range, pyramidindices, issymetric, sizetest,
getblock, getblockunsafe, randsymarray, fixpointperms, randblock, setindexunsafe!

@testset "Helpers" begin
  A = reshape(collect(1.:8.), 2, 2, 2)
  @testset "unfold" begin
    @test unfold(A, 1) == [[1.0 3.0 5.0 7.0]; [2.0 4.0 6.0 8.0]]
    @test unfold(A, 2) == [[1.0 2.0 5.0 6.0]; [3.0 4.0 7.0 8.0]]
    @test unfold(A, 3) == [[1.0 2.0 3.0 4.0]; [5.0 6.0 7.0 8.0]]
  end
  @testset "issymmetric" begin
    A = reshape(collect(1.:8.), 2, 2, 2)
    @test_throws AssertionError issymetric(A)
    @test issymetric([[1.0 2.0]; [2.0 1.0]]) == nothing
  end
  @testset "indexing" begin
    @test pyramidindices(2, 3) == [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
    @test ind2range(2, 3, 5) == 4:5
  end
  @testset "random generate of symmetric array" begin
    Random.seed!(40)
    t = randsymarray(4, 2)
    @test (t-transpose(t)) == zeros(4,4)
  end
  @testset "sizetest" begin
    @test_throws DimensionMismatch sizetest(2,3)
  end
end

# generates symmetric tensors
Random.seed!(42)
t = randsymarray(7, 3)
t1 = randsymarray(7, 3)

@testset "Converting" begin
  b = SymmetricTensor(t, 3)
  @testset "Geting blocks of Symmetric Tensors" begin
    @test getblockunsafe(b, (1, 1, 1)) == t[1:3, 1:3, 1:3]
    @test getblock(b, (2, 1, 2)) == t[4:6, 1:3, 4:6]
    @test getblock(b, (2, 1, 1)) == t[4:6, 1:3, 1:3]
  end
  @testset "Geting indices" begin
    @test b[1, 1, 1] == t[1, 1, 1]
    @test b[3, 4, 7] == t[3, 4, 7]
    @test b[3, 3, 4] == t[3, 3, 4]
    @test b[7, 7, 7] == t[7, 7, 7]
    @test b[7, 7, 3] == t[7, 7, 3]
    @test b[6, 4, 2] == t[6, 4, 2]
  end
  @testset "converting from array to SymmetricTensor" begin
    a = reshape(collect(1.:16.), 4, 4)
    @test getblockunsafe(SymmetricTensor(a*a'), (1,1)) ==  [276.0  304.0; 304.0  336.0]
    @test b.frame[1, 1, 1] ≈ t[1:3, 1:3, 1:3]
    @test b.frame[1, 2, 2] ≈ t[1:3, 4:6, 4:6]
    @test b.frame[2, 2, 2] ≈ t[4:6, 4:6, 4:6]
    @test b.frame[2, 1, 1] == nothing
  end
  @testset "Constructor tests" begin
    b1 = SymmetricTensor(t[1:6, 1:6, 1:6], 2)
    @test !(b.sqr)
    @test b1.sqr
    @test b.bls == 3
    @test b.bln == 3
    @test b.dats == 7
  end
end

@testset "Random symmetric tensor generation" begin
  @test fixpointperms((1,2,3,3)) == [[1,2,3,4],[1,2,4,3]]
  @test fixpointperms((1,2,3,4)) == [[1,2,3,4]]
  Random.seed!(42)
  aa = Array(rand(SymmetricTensor{Float64, 4}, 3))
  tt = cat([0.533183 0.454029; 0.454029 0.0176868], [0.454029 0.0176868; 0.0176868 0.172933], dims = 3)
  #@test aa ≈ tt atol=1.0e-5
  issymetric(aa)
  @test aa == permutedims(aa, (2,1,3,4)) == permutedims(aa, (2,3,1,4)) == permutedims(aa, (4,3,1,2))
  @test aa[:,:,1,1] == transpose(aa[:,:,1,1])
  Random.seed!(42)
  @test randblock(Float64, (2,2), (1,1)) ≈ [0.533183  0.454029; 0.454029  0.0176868] atol=1.0e-5
  @test randblock(Float64, (2,2), (1,2)) ≈ [0.172933  0.973566; 0.958926  0.30387] atol=1.0e-5
end

@testset "Seting value" begin
    @testset "Unsafe" begin
      Random.seed!(42)
      x = rand(SymmetricTensor{Float64, 4}, 7)
      y = rand(SymmetricTensor{Float64, 3}, 7)
      setindexunsafe!(x, 10000., 1,1,2,2)
      setindexunsafe!(x, 100., 4,4,4,4)
      setindexunsafe!(x, 200., 3,5,6,7)
      @test prod(map(i -> x[(1,1,2,2)[i]...], collect(permutations(1:4))) .== 10000.)
      @test prod(map(i -> x[(3,5,6,7)[i]...], collect(permutations(1:4))) .== 200.)
      @test x[4,4,4,4] == 100.
      issymetric(Array(x))
      setindexunsafe!(y, 10000., 1,2,3)
      setindexunsafe!(y, 100., 7,7,7)
      @test prod(map(i -> y[(1,2,3)[i]...], collect(permutations(1:3))) .== 10000.)
      @test y[7,7,7] == 100.
      issymetric(Array(y))
    end
    @testset "safe" begin
      x = rand(SymmetricTensor{Float64, 4}, 7)
      x[7,4,3,1] = 20.
      @test prod(map(i -> x[(1,3,4,7)[i]...], collect(permutations(1:4))) .== 20.)
      issymetric(Array(x))
    end
end

@testset "Basic operations" begin
  b = SymmetricTensor(t)
  b1 = SymmetricTensor(t1)
  @testset "Get super-diagonal" begin
    @test diag(b) ≈ [t[fill(i, ndims(t))...,] for i = 1:size(t, 1)]
    @test diag(b1) ≈ [t1[fill(i, ndims(t1))...,] for i = 1:size(t1, 1)]
  end
  @testset "Elementwise operations" begin
    @test Array(b + b1) ≈ t + t1
    @test Array(b - b1) ≈ t - t1
  end
  @testset "Matrix--scalar operations" begin
    @test Array(b * 2.1) ≈ t * 2.1
    @test Array(b / 2.1) ≈ t / 2.1
    @test Array(b / 2) ≈ t / 2
    @test Array(b + 2.1) ≈ t .+ 2.1
    @test Array(b - 2.1) ≈ t .- 2.1
    @test Array(b + 2) ≈ t .+ 2
    @test Array(2 + b) ≈ t .+ 2
  end
end

@testset "Exceptions" begin
  @testset "Dimensions in operations" begin
    b = SymmetricTensor(t)
    b1 = SymmetricTensor(t, 4)
    b4 = SymmetricTensor(t[1:4, 1:4, 1:4])
    b5 = SymmetricTensor(t[1:3, 1:3, 1:3])
    b2 = SymmetricTensor(t[:,:,1])
    @test_throws DimensionMismatch b + b1
    @test_throws DimensionMismatch b4 + b5
    @test_throws MethodError b + b2
    @test_throws UndefVarError b + b3
  end
  @testset "Constructor exceptions" begin
    @test_throws MethodError SymmetricTensor([1.0 2.0], [3.0 4.0])
    @test_throws DimensionMismatch SymmetricTensor(t[:, :, 1:2])
    b = SymmetricTensor(t).frame
    b1 = copy(b)
    b2 = copy(b)
    b[1,1,1] = reshape(collect(1:8), (2,2,2))
    @test_throws AssertionError SymmetricTensor(b)
    b1[1,2,3] = reshape(collect(1:4), (2,2,1))
    @test_throws AssertionError SymmetricTensor(b1)
    b2[3,2,1] = reshape(collect(1:8), (2,2,2))
    @test_throws AssertionError SymmetricTensor(b2)
    # wrong block size
    @test_throws DimensionMismatch SymmetricTensor(t, 25)
    @test_throws DimensionMismatch SymmetricTensor(t, 0)
  end
end


text:
"""
    function perc_pos_to_num_tests_scale(model)
Fit a linear realationship between the % PCR positive (7 day running average) and the number of PCR tests performed on each day (7-day running average),
over the last 60 days of available data. Returns a `NamedTuple` with the regression coefficients and the std over error.
"""
function perc_pos_to_num_tests_scale(model)
    prop_pos = model.PCR_cases[:,1]./model.PCR_cases[:,2]
    prop_pos_mv_av = [mean(prop_pos[(t-3):t+3]) for t = 4:(length(prop_pos)-3)]
    number_pos_mv_av = [mean(model.PCR_cases[:,1][(t-3):t+3]) for t = 4:(length(model.PCR_cases[:,1])-3)]
    number_tests_mv_av = [mean(model.PCR_cases[:,2][(t-3):t+3]) for t = 4:(length(model.PCR_cases[:,2])-3)]

    idxs = (.~isnan.(prop_pos_mv_av)).&(prop_pos_mv_av .> 0).&(1:length(prop_pos_mv_av) .>= length(prop_pos_mv_av) - 21).&(number_tests_mv_av .> 0)
    xs = prop_pos_mv_av[idxs];ys = number_tests_mv_av[idxs];
    β = [ones(length(xs)) xs] \ ys
    pred_ys = [ones(length(xs)) xs]*β
    std_ys = std(ys .- pred_ys)
    return (β = β, σ = std_ys )
end

"""
    function get_unscaled_predictions(ι₁,ι₂,p_ID,rel_test_rate;fitlength=430)
Useful method for collating a matrix of of unnormalised (i.e. IFR not applied) estimates of the daily death rate from the model incidence estimates.
"""
function get_unscaled_predictions(ι₁,ι₂,p_ID,rel_test_rate;fitlength=430)
    unscaled_deaths1 = similar(ι₁)[1:fitlength,:]
    unscaled_deaths2 = similar(ι₂)[1:fitlength,:]
    for j = 1:size(unscaled_deaths1,2)
        unscaled_deaths1[:,j] .= KenyaCoVSD.simple_conv(ι₁[:,j],p_ID)[1:fitlength].*rel_test_rate[1:fitlength]
        unscaled_deaths2[:,j] .= KenyaCoVSD.simple_conv(ι₂[:,j],p_ID)[1:fitlength].*rel_test_rate[1:fitlength]
    end
    return unscaled_deaths1,unscaled_deaths2
end

"""
    function get_predictions(model::KenyaCoVSD.CoVAreaModel,projection_date::Date;seroreversionrate=0.0,σ = 0.16,ω = 1/180,ct_min2 = 0.445,fitlength = 400)
Main method for gathering predictions from a fitted `CoVAreaModel`.
"""

function get_predictions(model::KenyaCoVaccines.CoVAreaModel,projection_date::Date,p_ID;seroreversionrate=0.0,σ = 0.16,ω = 1/180,fitlength = 400)
    @unpack PCR_cases,sero_cases,baseline_sero_array,PCR_array,sero_sensitivity,sero_specificity,N,M_BB,prob,α,γ,relative_testing_rate = model
    MCMCdraws = get(model.MCMC_results.chain,[:β₀,:β_home,:β_school,:β_other,:β_work,:ϵ,:χ,:p_test,:E₁,:E₂,:E₃,:E₄,:E₅,:E₆,:inc_R_αvar,:time_scale_αvar,:mid_point_αvar,:inc_R_δvar,:time_scale_δvar,:mid_point_δvar,:init_scale])

    incidence₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    firstincidence₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    firstincidence₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    serocoverted₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    serocoverted₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    susceptible₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    susceptible₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    Rt₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    Rt₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    PCR_pred = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    prop_PCR_pred = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    forecast_testing_rate = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    pred_deaths = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))

    #Calculate prop_pos to test ratio
    test_fit = perc_pos_to_num_tests_scale(model)
    println("incidence fitting")
    for k = 1:length(first(MCMCdraws))
        N₁ = MCMCdraws.P_eff[k]*N
        N₂ = N - N₁
        p = [MCMCdraws.R₀[k],model.α,model.γ,MCMCdraws.ϵ[k],σ,N₁,N₂,ω,MCMCdraws.schooleffect[k],MCMCdraws.ct_min1[k],ct_min2]
        u0 = [N₁,MCMCdraws.E₀[k],0.,0.,0.,0.,N₂,MCMCdraws.E₀[k],0.,0.,0.,0.,0.0,0.0 ]

        function new_variant_effect!(integrator)
            integrator.p[1] *= MCMCdraws.extra_transmissibility[k]
            integrator.u[2] += MCMCdraws.influx_exposed_new_variant[k] #Lower SES
            integrator.u[8] += MCMCdraws.influx_exposed_new_variant[k] #Higher SES
        end

        janendpoint = (Date(2021,1,30) - Date(2020,2,20)).value
        variant_cb = PresetTimeCallback([janendpoint],new_variant_effect!,save_positions=(false,false))
        #Sero-waning
        sero_array = vcat(baseline_sero_array[1:30],[(1-seroreversionrate)^k for k in 1:600])
        #solve model
        sol = solve(prob, BS3();tspan = (0,(projection_date - Date(2020,2,20)).value),callback = variant_cb,u0=u0, p=p, saveat = 1)
        ι₁ = diff(sol[:C₁])
        ι₂ = diff(sol[:C₂])
        ι_sero₁ = diff(sol[:C_sero₁])
        ι_sero₂ = diff(sol[:C_sero₂])

        PCR₁ = KenyaCoVSD.simple_conv(ι₁,PCR_array)
        PCR₂ = KenyaCoVSD.simple_conv(ι₂,PCR_array)
        incidence₁[:,k] = ι₁
        incidence₂[:,k] = ι₂
        firstincidence₁[:,k] = ι_sero₁
        firstincidence₂[:,k] = ι_sero₂
        susceptible₁[:,k] = sol[:S₁][2:end]
        susceptible₂[:,k] = sol[:S₂][2:end]
        serocoverted₁[:,k] .= sero_sensitivity.*KenyaCoVSD.simple_conv(ι_sero₁,sero_array)
        serocoverted₂[:,k] .= sero_sensitivity.*KenyaCoVSD.simple_conv(ι_sero₂,sero_array)

        #Calculate effective R
        Reff = [MCMCdraws.R₀[k]*(t < 24 || t ≥ 319) + MCMCdraws.R₀[k]*MCMCdraws.schooleffect[k]*(t≥ 24 && t< 319) for t = 1:length(ι₁)]
        new_variant_multiplier = [1.0*(t < janendpoint) + MCMCdraws.extra_transmissibility[k]*(t >= janendpoint) for t = 1:length(ι₁)]
        ct1 = [KenyaCoVSD.ct_kenya(t,MCMCdraws.ct_min1[k]) for t = 1:length(ι₁)]
        ct2 = [KenyaCoVSD.ct_kenya(t,ct_min2) for t = 1:length(ι₁)]
        Rt₁[:,k] .= new_variant_multiplier.*Reff.*(((ct1.*sol[:S₁][2:end]./N₁).*MCMCdraws.ϵ[k].*ct1) .+ ((ct2.*sol[:S₂][2:end]./N₂).*(1 .- MCMCdraws.ϵ[k]).*ct1))
        Rt₂[:,k] .= new_variant_multiplier.*Reff.*(((ct1.*sol[:S₁][2:end]./N₁).*(1 .- MCMCdraws.ϵ[k]).*ct2) .+ ((ct2.*sol[:S₂][2:end]./N₂).*MCMCdraws.ϵ[k].*ct2))

        #PCR test predictions
        new_variant_multiplier_detection_multiplier = [1.0*(t < janendpoint) + MCMCdraws.p_test_boost[k]*(t >= janendpoint) for t = 1:length(ι₁)]
        PCR_pred[:,k] = new_variant_multiplier_detection_multiplier.*relative_testing_rate[1:length(ι₁)].*(MCMCdraws.p_test₁[k].*PCR₁ .+ MCMCdraws.p_test₂[k].*PCR₂)

        prop_PCR_prenv = MCMCdraws.p_choose1[k].*(MCMCdraws.χ₁[k].*PCR₁[1:janendpoint]./((MCMCdraws.χ₁[k]-1).*PCR₁[1:janendpoint] .+ sum(N₁)))
        prop_PCR_prenv .+=  (1 .- MCMCdraws.p_choose1[k]).*(MCMCdraws.χ₂[k].*PCR₂[1:janendpoint]./((MCMCdraws.χ₂[k]-1).*PCR₂[1:janendpoint] .+ sum(N₂)))
        prop_PCR_postnv = MCMCdraws.p_choose1[k].*(MCMCdraws.χ_boost[k]*MCMCdraws.χ₁[k].*PCR₁[(janendpoint+1):end]./((MCMCdraws.χ_boost[k]*MCMCdraws.χ₁[k]-1).*PCR₁[(janendpoint+1):end] .+ sum(N₁)))
        prop_PCR_postnv .+=  (1 .- MCMCdraws.p_choose1[k]).*(MCMCdraws.χ_boost[k]*MCMCdraws.χ₂[k].*PCR₂[(janendpoint+1):end]./((MCMCdraws.χ_boost[k]*MCMCdraws.χ₂[k]-1).*PCR₂[(janendpoint+1):end].+ sum(N₂)))
        prop_PCR_pred[:,k] .= vcat(prop_PCR_prenv,prop_PCR_postnv)

        #PCR forecast accounting for test rates in last 60 days of period
        forecast_testing_rate[:,k] .= [ones(length(prop_PCR_pred[:,k])) prop_PCR_pred[:,k]]*test_fit.β

    end

    return (incidence₁ = incidence₁,incidence₂ = incidence₂,
            firstincidence₁ = firstincidence₁,firstincidence₂ = firstincidence₂,
            serocoverted₁ = serocoverted₁,serocoverted₂ = serocoverted₂,
            susceptible₁ = susceptible₁,susceptible₂ = susceptible₂,
            Rt₁ = Rt₁,Rt₂ = Rt₂,
            PCR_pred = PCR_pred,prop_PCR_pred = prop_PCR_pred,
            forecast_testing_rate = forecast_testing_rate,
            pred_deaths = pred_deaths,
            test_fit=test_fit)
end

function get_predictions_delta(model::KenyaCoVSD.CoVAreaModel,projection_date::Date,p_ID;seroreversionrate=0.0,σ = 0.16,ω = 1/180,ct_min2 = 0.445,fitlength = 400,p_test_scale=5e-4,scale_δ_transmissibility = 1.0)
    @unpack PCR_cases,sero_cases,baseline_sero_array,PCR_array,sero_sensitivity,sero_specificity,N,M_BB,prob,α,γ,relative_testing_rate = model
    MCMCdraws = get(model.MCMC_results.chain,[:ct_min1,:R₀,:ϵ,:χ₁,:χ₂,:p_test₁,:p_test₂,:P_eff,:schooleffect,:Rα,:time_scale_αvar,:mid_point_αvar,:Rδ,:time_scale_δvar,:mid_point_δvar,:E₀])

    incidence₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    incidence₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    firstincidence₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    firstincidence₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    serocoverted₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    serocoverted₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    susceptible₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    susceptible₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    Rt₁ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    Rt₂ = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    PCR_pred = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    prop_PCR_pred = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    forecast_testing_rate = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))
    pred_deaths = zeros((projection_date - Date(2020,2,20)).value,length(first(MCMCdraws)))

    #Calculate prop_pos to test ratio
    test_fit = perc_pos_to_num_tests_scale(model)
    println("incidence fitting - delta variant")
    for k = 1:length(first(MCMCdraws))
        N₁ = MCMCdraws.P_eff[k]*N

        N₂ = N - N₁
        p = [MCMCdraws.R₀[k],model.α,model.γ,MCMCdraws.ϵ[k],σ,N₁,N₂,ω,MCMCdraws.schooleffect[k],MCMCdraws.ct_min1[k],ct_min2,MCMCdraws.Rα[k],MCMCdraws.time_scale_αvar[k],347.0 + MCMCdraws.mid_point_αvar[k]*30.0,MCMCdraws.Rδ[k]*scale_δ_transmissibility,MCMCdraws.time_scale_δvar[k],406.0 + MCMCdraws.mid_point_δvar[k]*30.0]
        u0 = [N₁,MCMCdraws.E₀[k],0.,0.,0.,0.,N₂,MCMCdraws.E₀[k],0.,0.,0.,0.,0.0,0.0 ]

        juneendpoint = (Date(2021,7,1) - Date(2020,2,20)).value
        #Sero-waning
        sero_array = vcat(baseline_sero_array[1:30],[(1-seroreversionrate)^k for k in 1:600])
        #solve model
        sol = solve(prob, Vern9();tspan = (0,(projection_date - Date(2020,2,20)).value),
                                    u0=u0,
                                    p=p,
                                    saveat = 1,
                                    isoutofdomain=(u,p,t) -> any(x -> x < 0, u),
                                    force_dtmin = true)
        ι₁ = diff(sol[:C₁])
        ι₂ = diff(sol[:C₂])
        ι_sero₁ = diff(sol[:C_sero₁])
        ι_sero₂ = diff(sol[:C_sero₂])

        PCR₁ = KenyaCoVSD.simple_conv(ι₁,PCR_array)
        PCR₂ = KenyaCoVSD.simple_conv(ι₂,PCR_array)
        incidence₁[:,k] = ι₁
        incidence₂[:,k] = ι₂
        firstincidence₁[:,k] = ι_sero₁
        firstincidence₂[:,k] = ι_sero₂
        susceptible₁[:,k] = sol[:S₁][2:end]
        susceptible₂[:,k] = sol[:S₂][2:end]
        serocoverted₁[:,k] .= sero_sensitivity.*KenyaCoVSD.simple_conv(ι_sero₁,sero_array)
        serocoverted₂[:,k] .= sero_sensitivity.*KenyaCoVSD.simple_conv(ι_sero₂,sero_array)

        #Calculate effective R
        Reff = [(MCMCdraws.R₀[k]*(t < 24 || t ≥ 319) + MCMCdraws.R₀[k]*MCMCdraws.schooleffect[k]*(t≥ 24 && t< 319))*(1 + KenyaCoVSD.gen_logistic(t;L = MCMCdraws.Rα[k],κ = 1/MCMCdraws.time_scale_αvar[k], x₀ = 347.0 + MCMCdraws.mid_point_αvar[k]*30.0))*(1 + KenyaCoVSD.gen_logistic(t;L = MCMCdraws.Rδ[k],κ = 1/MCMCdraws.time_scale_δvar[k], x₀ = 406.0 + MCMCdraws.mid_point_δvar[k]*30.0))
                    for t = 1:length(ι₁)]

        ct1 = [KenyaCoVSD.ct_kenya(t,MCMCdraws.ct_min1[k]) for t = 1:length(ι₁)]
        ct2 = [KenyaCoVSD.ct_kenya(t,ct_min2) for t = 1:length(ι₁)]
        Rt₁[:,k] .= Reff.*(((ct1.*sol[:S₁][2:end]./N₁).*MCMCdraws.ϵ[k].*ct1) .+ ((ct2.*sol[:S₂][2:end]./N₂).*(1 .- MCMCdraws.ϵ[k]).*ct1))
        Rt₂[:,k] .= Reff.*(((ct1.*sol[:S₁][2:end]./N₁).*(1 .- MCMCdraws.ϵ[k]).*ct2) .+ ((ct2.*sol[:S₂][2:end]./N₂).*MCMCdraws.ϵ[k].*ct2))

        #PCR test predictions
        PCR_pred[:,k] = p_test_scale*relative_testing_rate[1:length(ι₁)].*(MCMCdraws.p_test₁[k].*PCR₁ .+ MCMCdraws.p_test₂[k].*PCR₂)

        p_PCR_pred_num = p_test_scale.*(MCMCdraws.p_test₁[k].*PCR₁ .+ MCMCdraws.p_test₂[k].*PCR₂)
        p_PCR_pred_denom = p_PCR_pred_num .+ p_test_scale.*((MCMCdraws.p_test₁[k]/MCMCdraws.χ₁[k]).*(N₁ .- PCR₁) .+ (MCMCdraws.p_test₂[k]/MCMCdraws.χ₂[k]).*(N₂ .- PCR₂))
        prop_PCR_pred[:,k] .= p_PCR_pred_num./p_PCR_pred_denom

        #PCR forecast accounting for test rates in last 60 days of period
        forecast_testing_rate[:,k] .= [ones(length(prop_PCR_pred[:,k])) prop_PCR_pred[:,k]]*test_fit.β

    end

    return (incidence₁ = incidence₁,incidence₂ = incidence₂,
            firstincidence₁ = firstincidence₁,firstincidence₂ = firstincidence₂,
            serocoverted₁ = serocoverted₁,serocoverted₂ = serocoverted₂,
            susceptible₁ = susceptible₁,susceptible₂ = susceptible₂,
            Rt₁ = Rt₁,Rt₂ = Rt₂,
            PCR_pred = PCR_pred,prop_PCR_pred = prop_PCR_pred,
            forecast_testing_rate = forecast_testing_rate,
            pred_deaths = pred_deaths,
            test_fit=test_fit)
end

function condense_prediction(prediction,num_tests,deaths,p_ID,relative_testing_rate)
    mean_incidence₁ = mean(prediction.firstincidence₁,dims = 2)[:]
    std_incidence₁ = std(prediction.firstincidence₁,dims = 2)[:]
    mean_incidence₂ = mean(prediction.firstincidence₂,dims = 2)[:]
    std_incidence₂ = std(prediction.firstincidence₂,dims = 2)[:]

    mean_total_incidence₁ = mean(prediction.incidence₁,dims = 2)[:]
    std_total_incidence₁ = std(prediction.incidence₁,dims = 2)[:]
    mean_total_incidence₂ = mean(prediction.incidence₂,dims = 2)[:]
    std_total_incidence₂ = std(prediction.incidence₂,dims = 2)[:]

    mean_serocoverted₁ = mean(prediction.serocoverted₁,dims = 2)[:]
    std_serocoverted₁ = std(prediction.serocoverted₁,dims = 2)[:]
    mean_serocoverted₂ = mean(prediction.serocoverted₂,dims = 2)[:]
    std_serocoverted₂ = std(prediction.serocoverted₂,dims = 2)[:]
    mean_susceptible₁ = mean(prediction.susceptible₁,dims = 2)[:]
    std_susceptible₁ = std(prediction.susceptible₁,dims = 2)[:]
    mean_susceptible₂ = mean(prediction.susceptible₂,dims = 2)[:]
    std_susceptible₂ = std(prediction.susceptible₂,dims = 2)[:]
    mean_Rt₁ = mean(prediction.Rt₁,dims = 2)[:]
    std_Rt₁ = std(prediction.Rt₁,dims = 2)[:]
    mean_Rt₂ = mean(prediction.Rt₂,dims = 2)[:]
    std_Rt₂ = std(prediction.Rt₂,dims = 2)[:]
    mean_PCR_pred_no_test_rate = mean(prediction.PCR_pred,dims = 2)[:]
    std_PCR_pred_no_test_rate = std(prediction.PCR_pred,dims = 2)[:]
    mean_prop_PCR_pred = mean(prediction.prop_PCR_pred,dims = 2)[:]
    std_prop_PCR_pred = std(prediction.prop_PCR_pred,dims = 2)[:]

    # mean_PCR_forecast = mean(prediction.prop_PCR_pred.*prediction.forecast_testing_rate,dims = 2)[:]
    # std_PCR_forecast = std(prediction.prop_PCR_pred.*prediction.forecast_testing_rate,dims = 2)[:]

    n = length(num_tests)
    idxs_neg_tests = num_tests .>= 0

    PCR_pred_mat = similar(prediction.prop_PCR_pred)

    for j = 1:size(PCR_pred_mat,2)
        past = prediction.PCR_pred[1:n,j].*(.~idxs_neg_tests) .+ prediction.prop_PCR_pred[1:n,j].*num_tests.*(idxs_neg_tests)
        PCR_pred_mat[:,j] .= vcat(past[1:(n-8)],
                                    prediction.prop_PCR_pred[(n-7):end,j].*prediction.forecast_testing_rate[(n-7):end,j])
    end

    mean_PCR_forecast = mean(PCR_pred_mat,dims = 2)
    std_PCR_forecast = std(PCR_pred_mat,dims = 2)

    #Fit deaths

    unscaled_deaths1,unscaled_deaths2 = get_unscaled_predictions(prediction.incidence₁,
                                        prediction.incidence₂,
                                        p_ID,
                                        relative_testing_rate;
                                        fitlength=size(prediction.incidence₁,1))

    mean_unscaled_deaths1 = mean(unscaled_deaths1,dims = 2)[:]
    mean_unscaled_deaths2 = mean(unscaled_deaths2,dims = 2)[:]
    println("fitting deaths")
    function neg_ll(μ)
        LL = 0.
        for (t,D) in enumerate(deaths)
            LL += logpdf(Poisson(exp(μ[1])*max(mean_unscaled_deaths1[t],1e-5) + exp(μ[2])*max(mean_unscaled_deaths2[t],1e-5)),D)
        end
        return -LL
    end

    res = optimize(neg_ll,log.([0.0001,0.0001]),LBFGS())
    μ_fit = exp.(res.minimizer)

    pred_deaths = μ_fit[1].*unscaled_deaths1 .+ μ_fit[2].*unscaled_deaths2
    mean_deaths = mean(pred_deaths,dims = 2)[:]
    std_deaths = std(pred_deaths,dims = 2)[:]

    return (mean_incidence₁ = mean_incidence₁,
            std_incidence₁ = std_incidence₁,
            mean_incidence₂ = mean_incidence₂,
            std_incidence₂ = std_incidence₂,
            mean_total_incidence₁ = mean_total_incidence₁,
            std_total_incidence₁ = std_total_incidence₁,
            mean_total_incidence₂ = mean_total_incidence₂,
            std_total_incidence₂ = std_total_incidence₂,
            mean_serocoverted₁ = mean_serocoverted₁,
            std_serocoverted₁ = std_serocoverted₁,
            mean_serocoverted₂=mean_serocoverted₂,
            std_serocoverted₂=std_serocoverted₂,
            mean_susceptible₁=mean_susceptible₁,
            std_susceptible₁=std_susceptible₁,
            mean_susceptible₂=mean_susceptible₂,
            std_susceptible₂=std_susceptible₂,
            mean_Rt₁=mean_Rt₁,
            std_Rt₁=std_Rt₁,
            mean_Rt₂=mean_Rt₂,
            std_Rt₂=std_Rt₂,
            mean_PCR_pred_no_test_rate=mean_PCR_pred_no_test_rate,
            std_PCR_pred_no_test_rate = std_PCR_pred_no_test_rate,
            mean_prop_PCR_pred=mean_prop_PCR_pred,
            std_prop_PCR_pred=std_prop_PCR_pred,
            mean_PCR_forecast=mean_PCR_forecast,
            std_PCR_forecast=std_PCR_forecast,
            mean_deaths = mean_deaths,
            std_deaths=std_deaths,
            test_fit = prediction.test_fit,
            μ_fit = μ_fit)

end

function weekly_mv_av(x)
     return [mean(x[(t-3):(t+3)]) for t = 4:(length(x)-3)]
end

function get_Rt(model::KenyaCoVSD.CoVAreaModel,projection_date::Date;seroreversionrate=1/365,σ = 0.16,ω = 1/180,ct_min2 = 0.445)
    @unpack PCR_cases,sero_cases,baseline_sero_array,PCR_array,sero_sensitivity,sero_specificity,N,M_BB,prob,α,γ,relative_testing_rate = model
    MCMCdraws = get(model.MCMC_results.chain,[:ct_min1,:R₀,:ϵ,:χ₁,:χ₂,:p_test₁,:p_test₂,:p_choose1,:P_eff,:schooleffect,:extra_transmissibility,:influx_exposed_new_variant,:p_test_boost,:χ_boost,:E₀])

    Rt₁ = zeros((projection_date - Date(2020,2,20)).value+1,length(first(MCMCdraws)))
    Rt₂ = zeros((projection_date - Date(2020,2,20)).value+1,length(first(MCMCdraws)))

    #Calculate prop_pos to test ratio

    for k = 1:length(first(MCMCdraws))
        N₁ = MCMCdraws.P_eff[k]*N
        N₂ = N - N₁
        p = [MCMCdraws.R₀[k],model.α,model.γ,MCMCdraws.ϵ[k],σ,N₁,N₂,ω,MCMCdraws.schooleffect[k],MCMCdraws.ct_min1[k],ct_min2]
        u0 = [N₁,MCMCdraws.E₀[k],0.,0.,0.,0.,N₂,MCMCdraws.E₀[k],0.,0.,0.,0.,0.0,0.0 ]

        function new_variant_effect!(integrator)
            integrator.p[1] *= MCMCdraws.extra_transmissibility[k]
            integrator.u[2] += MCMCdraws.influx_exposed_new_variant[k] #Lower SES
            integrator.u[8] += MCMCdraws.influx_exposed_new_variant[k] #Higher SES
        end

        janendpoint = (Date(2021,1,30) - Date(2020,2,20)).value
        variant_cb = PresetTimeCallback([janendpoint],new_variant_effect!)
        #solve model
        sol = solve(prob, BS3();tspan = (0,(projection_date - Date(2020,2,20)).value),callback = variant_cb,u0=u0, p=p, saveat = 1)
        #Calculate effective R
        Reff = [MCMCdraws.R₀[k]*(t < 24 || t ≥ 319) + MCMCdraws.R₀[k]*MCMCdraws.schooleffect[k]*(t≥ 24 && t< 319) for t = 1:length(sol[:S₁][2:end])]
        new_variant_multiplier = [1.0*(t < janendpoint) + MCMCdraws.extra_transmissibility[k]*(t >= janendpoint) for t = 1:length(sol[:S₁][2:end])]
        ct1 = [KenyaCoVSD.ct_kenya(t,MCMCdraws.ct_min1[k]) for t = 1:length(sol[:S₁][2:end])]
        ct2 = [KenyaCoVSD.ct_kenya(t,ct_min2) for t = 1:length(sol[:S₁][2:end])]
        Rt₁[:,k] .= new_variant_multiplier.*Reff.*(((ct1.*sol[:S₁][2:end]./N₁).*MCMCdraws.ϵ[k].*ct1) .+ ((ct2.*sol[:S₂][2:end]./N₂).*(1 .- MCMCdraws.ϵ[k]).*ct1))
        Rt₂[:,k] .= new_variant_multiplier.*Reff.*(((ct1.*sol[:S₁][2:end]./N₁).*(1 .- MCMCdraws.ϵ[k]).*ct2) .+ ((ct2.*sol[:S₂][2:end]./N₂).*MCMCdraws.ϵ[k].*ct2))

    end

    return (Rt₁_fit = get_credible_intervals(Rt₁),Rt₂_fit =get_credible_intervals(Rt₂))
end

function get_credible_intervals(X)
    pred = mean(X,dims = 2)
    lb =  pred .- [quantile(X[t,:],0.025) for t = 1:size(X,1)]
    ub = [quantile(X[t,:],0.975) for t = 1:size(X,1)] .- pred
    return (pred=pred,lb=lb,ub=ub)
end

function dailytestrate_to_probofdetections(p_test,PCR_array)
        1 - prod(1 .- p_test.*PCR_array)
end


text:
#!/usr/bin/julia

using Distributions, DataFrames, CSV, StatsBase, Plots

results = CSV.read("output_corei7.csv", delim="; ", DataFrame)
# Rename labels to lowercase, as @formula seems to not like uppercase strings.
for name in names(results)
	h = name => lowercase(name)
	rename!(results, replace.(names(results), h))
end

filter!(:parallel => x -> x == 1, results)
max_insns = maximum(results.expected_insns)
max_functions = maximum(results.functions)

pltobj = histogram(results.expected_insns,
                   xaxis="Number of Instructions", yaxis="Frequency",
				   label="Frequency", bins=50)
savefig("histogram.svg")

max_stars_repo_name: giulianobelinassi/LTO-Timing-Analysis

max_issues_repo_name: giulianobelinassi/LTO-Timing-Analysis

max_forks_repo_name: giulianobelinassi/LTO-Timing-Analysis


text:
# This is a collection of C functions provided by the
# plotting library MathGL

# Constants and Types
#-------------------------------------------------------------------------#

const lib     = Libdl.find_library(["libmgl", "libmgl2"])
# For debugging purposes
#=const lib     = Libdl.find_library(["/home/thomas/downloads/mathgl-2.3.5.1/src/libmgl2.so"])=#
const libqt   = Libdl.find_library(["libmgl-qt"])
const libfltk = Libdl.find_library(["libmgl-fltk"])
const libglut = Libdl.find_library(["libmgl-glut"])

typealias HMGL Ptr{Void}
typealias HCDT Ptr{Void}
typealias HMDT Ptr{Void}
typealias HADT Ptr{Void}
typealias HMPR Ptr{Void}
typealias HMEX Ptr{Void}
typealias HMAX Ptr{Void}

typealias DrawCallback Ptr{Void}
typealias LoadCallback Ptr{Void}

typealias Float Float64
typealias Dual  Complex{Float}

include("constants.jl")

# Functions
#-------------------------------------------------------------------------#

# The "raw" access to the C interface provided by the mgl libs is handled
# by the getf macro, defined in getfunction.jl
include("getfunction.jl")
# The functions are called as they are in the C api, though this notation
# does not meet the usual julia styling conventions (the C interface is not
# intended to be exposed to users who do not explicitly want everything to
# be like in the C api).

include("functions.jl")

# For the functions requireing qt/glut/fltk no test were/are conducted
include("qtfunctions.jl")
include("glutfunctions.jl")
include("fltkfunctions.jl")


text:
function build_conflict_groups(g::FlatlandGraph)
    grid = get_grid(g)
    h, w = size(grid)
    conflict_groups = Vector{Int}[]
    # Add cell groups
    for i in 1:h, j in 1:w
        grid[i, j] > 0 || continue
        group = vertices_on_cell(g, i, j)
        push!(conflict_groups, group)
    end
    # Add cell border groups
    for v in vertices(g)
        (_, _, _, kind) = get_label(g, v)
        kind == REAL || continue
        v_mirror = mirror_vertex(g, v)
        [v_mirror, v] in conflict_groups && continue
        group = [v, v_mirror]
        push!(conflict_groups, group)
    end
    return conflict_groups
end

function flatland_mapf(pyenv::Py)
    agents = [Agent(pyagent) for pyagent in pyenv.agents]
    g = flatland_graph(pyenv, agents)
    sources = [get_vertex(g, initial_label(agent)) for agent in agents]
    destinations = [get_vertex(g, target_label(agent)) for agent in agents]
    starting_times = [agent.earliest_departure for agent in agents]
    conflict_groups = build_conflict_groups(g)
    mapf = MAPF(;
        graph=g,
        sources=sources,
        destinations=destinations,
        starting_times=starting_times,
        conflict_groups=conflict_groups,
    )
    return mapf
end


text:
function loadcase(case::Symbol, ε_max::Number, ts, voigt_struct::Symbol = :sym)

    if voigt_struct == :unsym
        voigt_size = 9
        off_diags = 6
    elseif voigt_struct == :sym
        voigt_size = 6
        off_diags = 3
    else
        throw(ArgumentError("Invalid voigt structure, :sym or :unsym valid"))
    end

    εpt = ε_max / maximum(ts)

    if case == :uniaxial_strain
        ε_control = ones(Bool, voigt_size)
        εs = [εpt; zeros(voigt_size-1)] * ts'

    elseif case == :uniaxial_stress
        ε_control = [true; false; false; ones(Bool, off_diags)]
        εs = [εpt; zeros(voigt_size-1)] * ts'

    elseif case == :biaxial_strain_plstrain
        ε_control = ones(Bool, voigt_size)
        εs = [εpt; εpt; zeros(voigt_size-2)] * ts'

    elseif case == :biaxial_strain_plstress
        ε_control = [true; true; false; ones(Bool, off_diags)]
        εs = [εpt; εpt; zeros(voigt_size-2)] * ts'

    elseif case == :simpleshear
        ε_control = ones(Bool, voigt_size)
        if voigt_struct == :unsym
            εs = [0.0, 0.0, 0.0, εpt, 0.0, 0.0, 0.0, 0.0, εpt] * ts'
        else
            εs = [0.0, 0.0, 0.0, εpt, 0.0, 0.0] * ts'
        end
    else
        throw(ArgumentError("invalid case"))
    end

    size(εs, 1) == voigt_size || throw(ErrorException("invalid creation of strains, bug!"))
    length(ε_control) == voigt_size || throw(ErrorException("invalid creation of strains, bug!"))

    σs = zeros(voigt_size) * ts'
    return εs, σs, ε_control
end


text:
# Copyright (c) 2021 Idiap Research Institute, http://www.idiap.ch/
#  Niccolò Antonello <nantonel@idiap.ch>

struct ComposeIterator{D<:Integer,
                       F1<:WFST,
                       F2<:WFST,
                       F3,
                       CF
                      }
  A::F1
  B::F2
  C::F3      # this can be anything you need to build (e.g. a WFST)
  filter::CF # composition filter
  updateC!::Function      # modify C in place
  updateCfinal!::Function # modify C in place (after all arcs)
  function ComposeIterator(A::F1,
                           B::F2,
                           C::F3,
                           filter::CF,
                           updateC!,
                           updateCfinal!
                          ) where {D,W,I,O,O2,
                                   A1 <: Arc{W,D},
                                   F1 <: WFST{W,A1,D,I,O},
                                   F2 <: WFST{W,A1,D,O,O2},
                                   F3,
                                   CF
                                  }
    new{D,F1,F2,F3,CF}(A,B,C,filter,updateC!,updateCfinal!)
  end
end

function init(it::ComposeIterator{D}) where {D}
  Q = Dict{Tuple{D,D,D},D}()
  S = Queue{Tuple{D,D,D}}()
  i1 = get_initial(it.A, single=true)
  i2 = get_initial(it.B, single=true)
  src = 1 #new state for C
  i3 = it.filter.i3
  push!(Q, (i1,i2,i3) => src)
  enqueue!(S,(i1,i2,i3))
  return Q, S, src
end

function Base.iterate(it::ComposeIterator, it_st=init(it))
  Q, S, i = it_st
  if isempty(S)
    return nothing
  else
    q = dequeue!(S)
    q1, q2, q3 = q[1],q[2],q[3]
    arcs1 = it.A[q1]
    arcs2 = it.B[q2]
    w3 = it.filter.rho[q3]
    src = Q[q]

    for e1 in arcs1, e2 in arcs2
      e1, e2, q3_new = phi(it.filter, e1, e2, q3)
      if q3_new != 0
        n = get_nextstate(e1), get_nextstate(e2), q3_new
        if !(n in keys(Q))
          i += 1
          enqueue!(S,n)
          push!(Q, n => i)
        end
        dest = Q[n]
        it.updateC!(it,i,q1,q2,q3,w3,e1,e2,src,dest)
      end
    end
    it.updateCfinal!(it,i,q1,q2,q3,w3,src)
    return i, (Q, S, i)
  end
end


text:
Base.promote_rule{C3<:Color3,Cgray<:AbstractGray}(::Type{C3}, ::Type{Cgray}) = base_colorant_type(C3){promote_type(eltype(C3), eltype(Cgray))}
Base.promote_rule{C3<:Color3,Cagray<:AbstractAGray}(::Type{C3}, ::Type{Cagray}) = alphacolor(base_colorant_type(C3)){promote_type(eltype(C3), eltype(Cagray))}
Base.promote_rule{C3<:Color3,Cgraya<:AbstractGrayA}(::Type{C3}, ::Type{Cgraya}) = coloralpha(base_colorant_type(C3)){promote_type(eltype(C3), eltype(Cgraya))}

Base.promote_rule{C4<:Transparent4,Cgray<:AbstractGray}(::Type{C4}, ::Type{Cgray}) = base_colorant_type(C4){promote_type(eltype(C4), eltype(Cgray))}
Base.promote_rule{C4<:Transparent4,Cgray<:TransparentGray}(::Type{C4}, ::Type{Cgray}) = base_colorant_type(C4){promote_type(eltype(C4), eltype(Cgray))}


text:
#--------------------------------------------------------------------------------------------------
# FunEnv tests
#--------------------------------------------------------------------------------------------------
using Test
using Hensel

#--------------------------------------------------------------------------------------------------

@test Hensel.FunEnv((x) -> x+1, (0, 1), 2, 5, (1, 2))(0.25) == 1.25
@test Hensel.to01(1.25, (1, 2)) == 0.25

@test Hensel.hVector(0.25, 2, 5) == [0,1,0,0,0]
@test Hensel.iValue(Hensel.hVector(0.25, 2, 5), 2) == 2
@test Hensel.rValue(2, 2, 5) == 0.265625
@test Hensel.rValue(2, 2, 5, (1, 2)) == 1.265625
@test Hensel.FunEnv((x) -> x+1, (0, 1), 2, 5, (1, 2))(2) == 2
@test Hensel.FunEnv((x) -> x+1, (0, 1), 2, 5, (1, 2))(2, return_type="hensel") == [0,1,0,0,0]
@test Hensel.FunEnv((x) -> x+1, (0, 1), 2, 5, (1, 2))(2, return_type="real") == 1.265625
@test Hensel.FunEnv((x) -> x+1, (0, 1), 2, 5, (1, 2)).(0:9) == 0:9
@test ((y) -> Hensel.FunEnv((x) -> x+1, (0, 1), 2, 5, (1, 2))(y, return_type="real")).(0:9) == [
    1.015625,
    1.515625,
    1.265625,
    1.765625,
    1.140625,
    1.640625,
    1.390625,
    1.890625,
    1.078125,
    1.578125,
]

@test Hensel.hVector(0.25, 3, 5) == [0,2,0,2,0]
@test Hensel.iValue(Hensel.hVector(0.25, 3, 5), 3) == 60
@test Hensel.FunEnv((x) -> x+1, (0, 1), 3, 5, (1, 2))(60) == 60
@test Hensel.FunEnv((x) -> x+1, (0, 1), 3, 5, (1, 2))(60, return_type="hensel") == [0,2,0,2,0]
@test Hensel.FunEnv((x) -> x+1, (0, 1), 3, 5, (1, 2))(60, return_type="real") == 1.2489711934156378
@test Hensel.FunEnv((x) -> x+1, (0, 1), 3, 5, (1, 2)).(0:9) == 0:9
@test ((y) -> Hensel.FunEnv((x) -> x+1, (0, 1), 3, 5, (1, 2))(y, return_type="real")).(0:9) == [
    1.0020576131687242,
    1.3353909465020577,
    1.668724279835391,
    1.1131687242798354,
    1.4465020576131686,
    1.7798353909465021,
    1.2242798353909465,
    1.5576131687242798,
    1.8909465020576133,
    1.0390946502057614
]

@test Hensel.hVector(0.25, 7, 5) == [1,5,1,5,1]
@test Hensel.iValue(Hensel.hVector(0.25, 7, 5), 7) == 4201
@test Hensel.FunEnv((x) -> x+1, (0, 1), 7, 5, (1, 2))(4201) == 4201
@test Hensel.FunEnv((x) -> x+1, (0, 1), 7, 5, (1, 2))(4201, return_type="hensel") == [1,5,1,5,1]
@test Hensel.FunEnv((x) -> x+1, (0, 1), 7, 5, (1, 2))(4201, return_type="real") == 1.2499851252454335
@test Hensel.FunEnv((x) -> x+1, (0, 1), 7, 5, (1, 2)).(0:9) == 0:9
@test ((y) -> Hensel.FunEnv((x) -> x+1, (0, 1), 7, 5, (1, 2))(y, return_type="real")).(0:9) == [
    1.000029749509133,
    1.142886892366276,
    1.2857440352234188,
    1.4286011780805616,
    1.5714583209377047,
    1.7143154637948474,
    1.8571726066519902,
    1.0204379127744392,
    1.163295055631582,
    1.306152198488725
]

# -----------------------------------------------------------------
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 5, (2, 5))(0.25) == 2.75
@test Hensel.to01(2.75, (2, 5)) == 0.25

@test Hensel.hVector(0.25, 2, 5) == [0,1,0,0,0]
@test Hensel.iValue(Hensel.hVector(0.25, 2, 5), 2) == 2
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 5, (2, 5))(2) == 2
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 5, (2, 5))(2, return_type="hensel") == [0,1,0,0,0]
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 5, (2, 5))(2, return_type="real") == 2.796875
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 5, (2, 5)).(0:9) == 0:9

@test Hensel.hVector(0.25, 3, 5) == [0,2,0,2,0]
@test Hensel.hVector(1//4, 3, 5) == [0,2,0,2,0]
@test Hensel.iValue(Hensel.hVector(0.25, 3, 5), 3) == 60
@test Hensel.iValue(Hensel.hVector(1//4, 3, 5), 3) == 60
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 3, 5, (2, 5))(60) == 60
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 3, 5, (2, 5))(60, return_type="hensel") == [0,2,0,2,0]
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 3, 5, (2, 5))(60, return_type="real") == 2.746913580246914
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 3, 5, (2, 5)).(0:9) == 0:9

@test Hensel.hVector(0.25, 7, 5) == [1,5,1,5,1]
@test Hensel.iValue(Hensel.hVector(0.25, 7, 5), 7) == 4201
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 7, 5, (2, 5))(4201) == 4201
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 7, 5, (2, 5))(4201, return_type="hensel") == [1,5,1,5,1]
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 7, 5, (2, 5))(4201, return_type="real") == 2.7499553757363002
@test Hensel.FunEnv((x) -> 3*x+2, (0, 1), 7, 5, (2, 5)).(0:9) == 0:9

@test Hensel.FunEnv((x) -> 0.6*x*(1.0-x), (0.0, 1.0), 2, 8, (0.0, 1.0)).(0:10) == [
    0,
    100,
     56,
     56,
    136,
    196,
     36,
      8,
    144,
    164,
    132
]
@test Hensel.FunEnv((x) -> 0.6*x*(1-x), (0.0, 1.0), 2, 8, (0.0, 1.0))(0.5) == 0.15
@test Hensel.rValue(Hensel.hVector(100, 2, 8), 2) == 0.150390625

#--------------------------------------------------------------------------------------------------

@test ((y) -> Hensel.δ(Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 8, (2, 5)), y))(0.0) == -2^(-9)*3
@test ((y) -> Hensel.δ(Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 8, (2, 5)), y))(0.3) == 0.003515624999999911
@test ((y) -> Hensel.δ(y, Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 8, (2, 5))))(0.3) == 0
@test findmax(((y) -> abs(Hensel.δ(Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 8, (2, 5)), y))).(collect(0:0.1:1))) == (2^(-9)*3, 1)
@test findmax(((y) -> abs(Hensel.δ(y, Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 8, (2, 5))))).(collect(0:0.1:1))) == (0, 1)

#--------------------------------------------------------------------------------------------------

@test Hensel.mexpansion(Hensel.FunEnv((x) -> 3*x+2, (0, 1), 2, 8, (2, 5)), 8) == [0,1,0,0,0,0,0,0]

max_stars_repo_name: ayarodionov/Hensel

max_issues_repo_name: ayarodionov/Hensel

max_forks_repo_name: ayarodionov/Hensel


text:
# NEED:
# A Julia JIT Compiler
# USAGE:
# type "python pi.py [iterations]" into terminal/prompt

# needed variables to approximate pi
iterations = 10000
total = 0.0
in_circle = 0.0
radius = 1.0

# get user input, otherwise use default value
if length(ARGS) > 0
    iterations = parse(ARGS[1])
else
    println("No iteration limit specified --> used default: ", iterations)
end

# initialize random 2 dimensional array and square each value for later calculation quadratic
points = (rand!(zeros(iterations,2)) .* radius) .^ 2

# is point in circle/ out of circle
for i = 1:iterations
    total += 1
    distance = sqrt(points[i,1] + points[i,2])
    if distance < radius
        in_circle += 1
    end
end

# pi approximation
pi = 4 * (in_circle / total)

# user output
println("Iterations: ", iterations)
println("PI-Approximation: ", pi)

max_stars_repo_name: CitrusPunk/approximatePi

max_issues_repo_name: CitrusPunk/approximatePi

max_forks_repo_name: CitrusPunk/approximatePi


text:
###########################################################
##
## MAPS
##
## maps between residue rings of polynomials and in general
##
###########################################################

function domain(M::Map(HeckeMap))
  return M.header.domain
end

function codomain(M::Map(HeckeMap))
  return M.header.codomain
end

function image_function(f::Map(HeckeMap))
  if isdefined(f.header, :image)
    return f.header.image
  else
    return x -> image(f, x)
  end
end

function preimage_function(f::Map(HeckeMap))
  if isdefined(f.header, :preimage)
    return f.header.preimage
  else
    return x -> preimage(f, x)
  end
end

export Map

mutable struct MapCache{D, C, De, Ce}
  lim::Int

  im::Dict{De, Ce}
  imStat::Dict{De, Int}

  pr::Dict{Ce, De}
  prStat::Dict{Ce, Int}

  old_im
  old_pr

  function MapCache(dom::D, cod::C, ::Type{De}, ::Type{Ce}, lim::Int=100) where {D, C, De, Ce}
    r = new{D, C, De, Ce}()
    r.lim = lim
    r.im = Dict{De, Ce}()
    r.imStat = Dict{De, Int}()
    r.pr = Dict{Ce, De}()
    r.prStat = Dict{Ce, Int}()
    return r
  end
end

@attributes mutable struct MapHeader{D, C}
  domain::D
  codomain::C
  image
  preimage
  cache::MapCache

  function MapHeader{D, C}() where {D, C}
    z = new{D, C}()
    return z
  end

  function MapHeader{D, C}(domain::D, codomain::C) where {D, C}
    z = new{D, C}()
    z.domain = domain
    z.codomain = codomain
    return z
  end

  function MapHeader{D, C}(domain::D, codomain::C, image) where {D, C}
    z = new{D, C}()
    z.domain = domain
    z.codomain = codomain
    z.image = image
    return z
  end

  function MapHeader{D, C}(domain::D, codomain::C, image, preimage) where {D, C}
    z = new{D, C}()
    z.domain = domain
    z.codomain = codomain
    z.image = image
    z.preimage = preimage
    return z
  end
end

function MapHeader(domain::D, codomain::C) where {D, C}
  return MapHeader{D, C}(domain, codomain)
end

function MapHeader(domain::D, codomain::C, image) where {D, C}
  return MapHeader{D, C}(domain, codomain, image)
end

function MapHeader(domain::D, codomain::C, image, preimage) where {D, C}
  return MapHeader{D, C}(domain, codomain, image, preimage)
end

function preimage(f::AbstractAlgebra.Generic.CompositeMap, a)
  return preimage(f.map1, preimage(f.map2, a))
end

preimage_function(f) = a -> preimage(f, a)
image_function(f) = a -> image(f, a)

#function _compose(f, g)
#  return AbstractAlgebra.Generic.compose(g, f)
#end

#function compose(f::Map(HeckeMap){R, C}, g::Map(HeckeMap){D, R}) where {D, C, R}
#  return CompositeMap{D, C, R}(f, g)
#end

mutable struct InverseMap{D, C} <: Map{D, C, HeckeMap, InverseMap}
  header::MapHeader{D, C}
  origin::Map{C, D}

  function InverseMap{D, C}(f::Map{C, D}) where {D, C}
    z = new{D, C}()
    z.header = MapHeader(codomain(f), domain(f), preimage_function(f), image_function(f))
    z.origin = f
    return z
  end
end

function InverseMap(f::Map{C, D}) where {D, C}
  return InverseMap{D, C}(f)
end

###########################################################
# To turn a Function (method) into a map.
###########################################################

"""
    MapFromFunc(f, [g], D, C)

Creates the map `D -> C, x -> f(x)` given the callable
object `f`. If `g` is provided, it is assumed to satisfy
`f(g(x)) = x` and will be used as the preimage function.

# Example

```jldoctest
julia> F = GF(2);

julia> f = MapFromFunc(x -> F(numerator(x)) * inv(F(denominator(x))), QQ, F)
Map from
Rational Field to Galois field with characteristic 2 defined by a julia-function

julia> f(QQ(1//3))
1

julia> f = MapFromFunc(x -> F(numerator(x)) * inv(F(denominator(x))), y -> QQ(lift(y)),  QQ, F)
Map from
Rational Field to Galois field with characteristic 2 defined by a julia-function with inverse

julia> preimage(f, F(1))
1
```
"""
mutable struct MapFromFunc{R, T} <: Map{R, T, HeckeMap, MapFromFunc}
  header::Hecke.MapHeader{R, T}
  f
  g

  function MapFromFunc{R, T}(f, D::R, C::T) where {R, T}
    n = new{R, T}()
    n.header = Hecke.MapHeader(D, C, f)
    n.f = f
    return n
  end

  function MapFromFunc{R, T}(f, g, D::R, C::T) where {R, T}
    n = new{R, T}()
    n.header = Hecke.MapHeader(D, C, f, g)
    n.f = f
    n.g = g
    return n
  end
end

function image(f::MapFromFunc, x)
  @req parent(x) === domain(f) "Element not in the domain"
  y = f.f(x)
  @req parent(y) === codomain(f) "Image not in the codomain"
  return y
end

function preimage(f::MapFromFunc, y)
  @req parent(y) === codomain(f) "Element not in the codomain"
  x = f.g(y)
  @req parent(x) === domain(f) "Preimage not in the domain"
  return x
end

function Base.show(io::IO, M::MapFromFunc)
  @show_name(io, M)

  io = IOContext(io, :compact => true)
#  println(io, "Map from the $(M.f) julia-function")
  println(io, "Map from")
  show(io, domain(M))
  print(io, " to ")
  show(io, codomain(M))
  print(io, " defined by a julia-function")
  if isdefined(M, :g)
#    println(io, "with inverse by $(M.g)")
    print(io, " with inverse")
  end
end

function MapFromFunc(f, D, C)
  return MapFromFunc{typeof(D), typeof(C)}(f, D, C)
end

function MapFromFunc(f, g, D, C)
  return MapFromFunc{typeof(D), typeof(C)}(f, g, D, C)
end

function Base.inv(M::MapFromFunc)
  if isdefined(M, :g)
     return MapFromFunc(M.g, M.f, codomain(M), domain(M))
  else
     return MapFromFunc(x->preimage(M, x), codomain(M), domain(M))
  end
end

export MapFromFunc


text:
module ForwardDiff

using DiffRules, DiffResults
using DiffResults: DiffResult, MutableDiffResult, ImmutableDiffResult
using StaticArrays
using Random
using LinearAlgebra

import Printf
import NaNMath
import SpecialFunctions
import CommonSubexpressions

include("prelude.jl")
include("partials.jl")
include("dual.jl")
include("config.jl")
include("apiutils.jl")
include("derivative.jl")
include("gradient.jl")
include("jacobian.jl")
include("hessian.jl")

export DiffResults

end # module


text:
"Abstract linear operator."
abstract type AbstractLinearTransform{T} end

"Operator dimensions are either integer or tuples of integers."
DimType = Union{Int,Tuple{Vararg{Int}}}

"General linear operator"
struct LinearTransform{T} <: AbstractLinearTransform{T}
    dimsRange::DimType
    dimsDomain::DimType
    prod::Function
    tprod::Function
end

"Constructor with default Float64 element type"
LinearTransform(dimsRange::DimType, dimsDomain::DimType, prod::Function, tprod::Function) = LinearTransform{Float64}(dimsRange, dimsDomain, prod, tprod)

eltype(::AbstractLinearTransform{T}) where {T} = T
isreal(op::AbstractLinearTransform) = eltype(op) <: Real