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

"""
    BatchPutMessage()

Sends messages to a channel.

# Required Parameters
- `channelName`: The name of the channel where the messages are sent.
- `messages`: The list of messages to be sent. Each message has the format: { \"messageId\": \"string\", \"payload\": \"string\"}. The field names of message payloads (data) that you send to AWS IoT Analytics:   Must contain only alphanumeric characters and undescores (_). No other special characters are allowed.   Must begin with an alphabetic character or single underscore (_).   Cannot contain hyphens (-).   In regular expression terms: \"^[A-Za-z_]([A-Za-z0-9]*|[A-Za-z0-9][A-Za-z0-9_]*)\".    Cannot be more than 255 characters.   Are case insensitive. (Fields named foo and FOO in the same payload are considered duplicates.)   For example, {\"temp_01\": 29} or {\"_temp_01\": 29} are valid, but {\"temp-01\": 29}, {\"01_temp\": 29} or {\"__temp_01\": 29} are invalid in message payloads.

"""
batch_put_message(channelName, messages; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/messages/batch", Dict{String, Any}("channelName"=>channelName, "messages"=>messages); aws_config=aws_config)
batch_put_message(channelName, messages, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/messages/batch", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("channelName"=>channelName, "messages"=>messages), args)); aws_config=aws_config)

"""
    CancelPipelineReprocessing()

Cancels the reprocessing of data through the pipeline.

# Required Parameters
- `pipelineName`: The name of pipeline for which data reprocessing is canceled.
- `reprocessingId`: The ID of the reprocessing task (returned by StartPipelineReprocessing).

"""
cancel_pipeline_reprocessing(pipelineName, reprocessingId; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/pipelines/$(pipelineName)/reprocessing/$(reprocessingId)"; aws_config=aws_config)
cancel_pipeline_reprocessing(pipelineName, reprocessingId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/pipelines/$(pipelineName)/reprocessing/$(reprocessingId)", args; aws_config=aws_config)

"""
    CreateChannel()

Creates a channel. A channel collects data from an MQTT topic and archives the raw, unprocessed messages before publishing the data to a pipeline.

# Required Parameters
- `channelName`: The name of the channel.

# Optional Parameters
- `channelStorage`: Where channel data is stored. You can choose one of serviceManagedS3 or customerManagedS3 storage. If not specified, the default is serviceManagedS3. You cannot change this storage option after the channel is created.
- `retentionPeriod`: How long, in days, message data is kept for the channel. When customerManagedS3 storage is selected, this parameter is ignored.
- `tags`: Metadata which can be used to manage the channel.
"""
create_channel(channelName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/channels", Dict{String, Any}("channelName"=>channelName); aws_config=aws_config)
create_channel(channelName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/channels", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("channelName"=>channelName), args)); aws_config=aws_config)

"""
    CreateDataset()

Creates a dataset. A dataset stores data retrieved from a data store by applying a queryAction (a SQL query) or a containerAction (executing a containerized application). This operation creates the skeleton of a dataset. The dataset can be populated manually by calling CreateDatasetContent or automatically according to a trigger you specify.

# Required Parameters
- `actions`: A list of actions that create the data set contents.
- `datasetName`: The name of the data set.

# Optional Parameters
- `contentDeliveryRules`: When dataset contents are created, they are delivered to destinations specified here.
- `lateDataRules`: A list of data rules that send notifications to Amazon CloudWatch, when data arrives late. To specify lateDataRules, the dataset must use a DeltaTimer filter.
- `retentionPeriod`: Optional. How long, in days, versions of dataset contents are kept for the dataset. If not specified or set to null, versions of dataset contents are retained for at most 90 days. The number of versions of dataset contents retained is determined by the versioningConfiguration parameter. For more information, see Keeping Multiple Versions of AWS IoT Analytics Data Sets in the AWS IoT Analytics User Guide.
- `tags`: Metadata which can be used to manage the data set.
- `triggers`: A list of triggers. A trigger causes data set contents to be populated at a specified time interval or when another data set's contents are created. The list of triggers can be empty or contain up to five DataSetTrigger objects.
- `versioningConfiguration`: Optional. How many versions of dataset contents are kept. If not specified or set to null, only the latest version plus the latest succeeded version (if they are different) are kept for the time period specified by the retentionPeriod parameter. For more information, see Keeping Multiple Versions of AWS IoT Analytics Data Sets in the AWS IoT Analytics User Guide.
"""
create_dataset(actions, datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/datasets", Dict{String, Any}("actions"=>actions, "datasetName"=>datasetName); aws_config=aws_config)
create_dataset(actions, datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/datasets", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("actions"=>actions, "datasetName"=>datasetName), args)); aws_config=aws_config)

"""
    CreateDatasetContent()

Creates the content of a data set by applying a queryAction (a SQL query) or a containerAction (executing a containerized application).

# Required Parameters
- `datasetName`: The name of the dataset.

# Optional Parameters
- `versionId`: The version ID of the dataset content. To specify versionId for a dataset content, the dataset must use a DeltaTimer filter.
"""
create_dataset_content(datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/datasets/$(datasetName)/content"; aws_config=aws_config)
create_dataset_content(datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/datasets/$(datasetName)/content", args; aws_config=aws_config)

"""
    CreateDatastore()

Creates a data store, which is a repository for messages.

# Required Parameters
- `datastoreName`: The name of the data store.

# Optional Parameters
- `datastoreStorage`: Where data store data is stored. You can choose one of serviceManagedS3 or customerManagedS3 storage. If not specified, the default is serviceManagedS3. You cannot change this storage option after the data store is created.
- `retentionPeriod`: How long, in days, message data is kept for the data store. When customerManagedS3 storage is selected, this parameter is ignored.
- `tags`: Metadata which can be used to manage the data store.
"""
create_datastore(datastoreName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/datastores", Dict{String, Any}("datastoreName"=>datastoreName); aws_config=aws_config)
create_datastore(datastoreName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/datastores", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("datastoreName"=>datastoreName), args)); aws_config=aws_config)

"""
    CreatePipeline()

Creates a pipeline. A pipeline consumes messages from a channel and allows you to process the messages before storing them in a data store. You must specify both a channel and a datastore activity and, optionally, as many as 23 additional activities in the pipelineActivities array.

# Required Parameters
- `pipelineActivities`: A list of PipelineActivity objects. Activities perform transformations on your messages, such as removing, renaming or adding message attributes; filtering messages based on attribute values; invoking your Lambda functions on messages for advanced processing; or performing mathematical transformations to normalize device data. The list can be 2-25 PipelineActivity objects and must contain both a channel and a datastore activity. Each entry in the list must contain only one activity. For example:  pipelineActivities = [ { \"channel\": { ... } }, { \"lambda\": { ... } }, ... ]
- `pipelineName`: The name of the pipeline.

# Optional Parameters
- `tags`: Metadata which can be used to manage the pipeline.
"""
create_pipeline(pipelineActivities, pipelineName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/pipelines", Dict{String, Any}("pipelineActivities"=>pipelineActivities, "pipelineName"=>pipelineName); aws_config=aws_config)
create_pipeline(pipelineActivities, pipelineName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/pipelines", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("pipelineActivities"=>pipelineActivities, "pipelineName"=>pipelineName), args)); aws_config=aws_config)

"""
    DeleteChannel()

Deletes the specified channel.

# Required Parameters
- `channelName`: The name of the channel to delete.

"""
delete_channel(channelName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/channels/$(channelName)"; aws_config=aws_config)
delete_channel(channelName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/channels/$(channelName)", args; aws_config=aws_config)

"""
    DeleteDataset()

Deletes the specified dataset. You do not have to delete the content of the dataset before you perform this operation.

# Required Parameters
- `datasetName`: The name of the data set to delete.

"""
delete_dataset(datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/datasets/$(datasetName)"; aws_config=aws_config)
delete_dataset(datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/datasets/$(datasetName)", args; aws_config=aws_config)

"""
    DeleteDatasetContent()

Deletes the content of the specified dataset.

# Required Parameters
- `datasetName`: The name of the dataset whose content is deleted.

# Optional Parameters
- `versionId`: The version of the dataset whose content is deleted. You can also use the strings \"LATEST\" or \"LATEST_SUCCEEDED\" to delete the latest or latest successfully completed data set. If not specified, \"LATEST_SUCCEEDED\" is the default.
"""
delete_dataset_content(datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/datasets/$(datasetName)/content"; aws_config=aws_config)
delete_dataset_content(datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/datasets/$(datasetName)/content", args; aws_config=aws_config)

"""
    DeleteDatastore()

Deletes the specified data store.

# Required Parameters
- `datastoreName`: The name of the data store to delete.

"""
delete_datastore(datastoreName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/datastores/$(datastoreName)"; aws_config=aws_config)
delete_datastore(datastoreName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/datastores/$(datastoreName)", args; aws_config=aws_config)

"""
    DeletePipeline()

Deletes the specified pipeline.

# Required Parameters
- `pipelineName`: The name of the pipeline to delete.

"""
delete_pipeline(pipelineName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/pipelines/$(pipelineName)"; aws_config=aws_config)
delete_pipeline(pipelineName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/pipelines/$(pipelineName)", args; aws_config=aws_config)

"""
    DescribeChannel()

Retrieves information about a channel.

# Required Parameters
- `channelName`: The name of the channel whose information is retrieved.

# Optional Parameters
- `includeStatistics`: If true, additional statistical information about the channel is included in the response. This feature cannot be used with a channel whose S3 storage is customer-managed.
"""
describe_channel(channelName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/channels/$(channelName)"; aws_config=aws_config)
describe_channel(channelName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/channels/$(channelName)", args; aws_config=aws_config)

"""
    DescribeDataset()

Retrieves information about a dataset.

# Required Parameters
- `datasetName`: The name of the data set whose information is retrieved.

"""
describe_dataset(datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets/$(datasetName)"; aws_config=aws_config)
describe_dataset(datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets/$(datasetName)", args; aws_config=aws_config)

"""
    DescribeDatastore()

Retrieves information about a data store.

# Required Parameters
- `datastoreName`: The name of the data store

# Optional Parameters
- `includeStatistics`: If true, additional statistical information about the data store is included in the response. This feature cannot be used with a data store whose S3 storage is customer-managed.
"""
describe_datastore(datastoreName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datastores/$(datastoreName)"; aws_config=aws_config)
describe_datastore(datastoreName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datastores/$(datastoreName)", args; aws_config=aws_config)

"""
    DescribeLoggingOptions()

Retrieves the current settings of the AWS IoT Analytics logging options.

"""
describe_logging_options(; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/logging"; aws_config=aws_config)
describe_logging_options(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/logging", args; aws_config=aws_config)

"""
    DescribePipeline()

Retrieves information about a pipeline.

# Required Parameters
- `pipelineName`: The name of the pipeline whose information is retrieved.

"""
describe_pipeline(pipelineName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/pipelines/$(pipelineName)"; aws_config=aws_config)
describe_pipeline(pipelineName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/pipelines/$(pipelineName)", args; aws_config=aws_config)

"""
    GetDatasetContent()

Retrieves the contents of a data set as presigned URIs.

# Required Parameters
- `datasetName`: The name of the data set whose contents are retrieved.

# Optional Parameters
- `versionId`: The version of the data set whose contents are retrieved. You can also use the strings \"LATEST\" or \"LATEST_SUCCEEDED\" to retrieve the contents of the latest or latest successfully completed data set. If not specified, \"LATEST_SUCCEEDED\" is the default.
"""
get_dataset_content(datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets/$(datasetName)/content"; aws_config=aws_config)
get_dataset_content(datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets/$(datasetName)/content", args; aws_config=aws_config)

"""
    ListChannels()

Retrieves a list of channels.

# Optional Parameters
- `maxResults`: The maximum number of results to return in this request. The default value is 100.
- `nextToken`: The token for the next set of results.
"""
list_channels(; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/channels"; aws_config=aws_config)
list_channels(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/channels", args; aws_config=aws_config)

"""
    ListDatasetContents()

Lists information about data set contents that have been created.

# Required Parameters
- `datasetName`: The name of the data set whose contents information you want to list.

# Optional Parameters
- `maxResults`: The maximum number of results to return in this request.
- `nextToken`: The token for the next set of results.
- `scheduledBefore`: A filter to limit results to those data set contents whose creation is scheduled before the given time. See the field triggers.schedule in the CreateDataset request. (timestamp)
- `scheduledOnOrAfter`: A filter to limit results to those data set contents whose creation is scheduled on or after the given time. See the field triggers.schedule in the CreateDataset request. (timestamp)
"""
list_dataset_contents(datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets/$(datasetName)/contents"; aws_config=aws_config)
list_dataset_contents(datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets/$(datasetName)/contents", args; aws_config=aws_config)

"""
    ListDatasets()

Retrieves information about data sets.

# Optional Parameters
- `maxResults`: The maximum number of results to return in this request. The default value is 100.
- `nextToken`: The token for the next set of results.
"""
list_datasets(; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets"; aws_config=aws_config)
list_datasets(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datasets", args; aws_config=aws_config)

"""
    ListDatastores()

Retrieves a list of data stores.

# Optional Parameters
- `maxResults`: The maximum number of results to return in this request. The default value is 100.
- `nextToken`: The token for the next set of results.
"""
list_datastores(; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datastores"; aws_config=aws_config)
list_datastores(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/datastores", args; aws_config=aws_config)

"""
    ListPipelines()

Retrieves a list of pipelines.

# Optional Parameters
- `maxResults`: The maximum number of results to return in this request. The default value is 100.
- `nextToken`: The token for the next set of results.
"""
list_pipelines(; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/pipelines"; aws_config=aws_config)
list_pipelines(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/pipelines", args; aws_config=aws_config)

"""
    ListTagsForResource()

Lists the tags (metadata) that you have assigned to the resource.

# Required Parameters
- `resourceArn`: The ARN of the resource whose tags you want to list.

"""
list_tags_for_resource(resourceArn; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/tags", Dict{String, Any}("resourceArn"=>resourceArn); aws_config=aws_config)
list_tags_for_resource(resourceArn, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/tags", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceArn"=>resourceArn), args)); aws_config=aws_config)

"""
    PutLoggingOptions()

Sets or updates the AWS IoT Analytics logging options. If you update the value of any loggingOptions field, it takes up to one minute for the change to take effect. Also, if you change the policy attached to the role you specified in the roleArn field (for example, to correct an invalid policy), it takes up to five minutes for that change to take effect.

# Required Parameters
- `loggingOptions`: The new values of the AWS IoT Analytics logging options.

"""
put_logging_options(loggingOptions; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/logging", Dict{String, Any}("loggingOptions"=>loggingOptions); aws_config=aws_config)
put_logging_options(loggingOptions, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/logging", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("loggingOptions"=>loggingOptions), args)); aws_config=aws_config)

"""
    RunPipelineActivity()

Simulates the results of running a pipeline activity on a message payload.

# Required Parameters
- `payloads`: The sample message payloads on which the pipeline activity is run.
- `pipelineActivity`: The pipeline activity that is run. This must not be a channel activity or a datastore activity because these activities are used in a pipeline only to load the original message and to store the (possibly) transformed message. If a lambda activity is specified, only short-running Lambda functions (those with a timeout of less than 30 seconds or less) can be used.

"""
run_pipeline_activity(payloads, pipelineActivity; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/pipelineactivities/run", Dict{String, Any}("payloads"=>payloads, "pipelineActivity"=>pipelineActivity); aws_config=aws_config)
run_pipeline_activity(payloads, pipelineActivity, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/pipelineactivities/run", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("payloads"=>payloads, "pipelineActivity"=>pipelineActivity), args)); aws_config=aws_config)

"""
    SampleChannelData()

Retrieves a sample of messages from the specified channel ingested during the specified timeframe. Up to 10 messages can be retrieved.

# Required Parameters
- `channelName`: The name of the channel whose message samples are retrieved.

# Optional Parameters
- `endTime`: The end of the time window from which sample messages are retrieved.
- `maxMessages`: The number of sample messages to be retrieved. The limit is 10. The default is also 10.
- `startTime`: The start of the time window from which sample messages are retrieved.
"""
sample_channel_data(channelName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/channels/$(channelName)/sample"; aws_config=aws_config)
sample_channel_data(channelName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("GET", "/channels/$(channelName)/sample", args; aws_config=aws_config)

"""
    StartPipelineReprocessing()

Starts the reprocessing of raw message data through the pipeline.

# Required Parameters
- `pipelineName`: The name of the pipeline on which to start reprocessing.

# Optional Parameters
- `endTime`: The end time (exclusive) of raw message data that is reprocessed.
- `startTime`: The start time (inclusive) of raw message data that is reprocessed.
"""
start_pipeline_reprocessing(pipelineName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/pipelines/$(pipelineName)/reprocessing"; aws_config=aws_config)
start_pipeline_reprocessing(pipelineName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/pipelines/$(pipelineName)/reprocessing", args; aws_config=aws_config)

"""
    TagResource()

Adds to or modifies the tags of the given resource. Tags are metadata that can be used to manage a resource.

# Required Parameters
- `resourceArn`: The ARN of the resource whose tags you want to modify.
- `tags`: The new or modified tags for the resource.

"""
tag_resource(resourceArn, tags; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/tags", Dict{String, Any}("resourceArn"=>resourceArn, "tags"=>tags); aws_config=aws_config)
tag_resource(resourceArn, tags, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("POST", "/tags", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceArn"=>resourceArn, "tags"=>tags), args)); aws_config=aws_config)

"""
    UntagResource()

Removes the given tags (metadata) from the resource.

# Required Parameters
- `resourceArn`: The ARN of the resource whose tags you want to remove.
- `tagKeys`: The keys of those tags which you want to remove.

"""
untag_resource(resourceArn, tagKeys; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/tags", Dict{String, Any}("resourceArn"=>resourceArn, "tagKeys"=>tagKeys); aws_config=aws_config)
untag_resource(resourceArn, tagKeys, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("DELETE", "/tags", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceArn"=>resourceArn, "tagKeys"=>tagKeys), args)); aws_config=aws_config)

"""
    UpdateChannel()

Updates the settings of a channel.

# Required Parameters
- `channelName`: The name of the channel to be updated.

# Optional Parameters
- `channelStorage`: Where channel data is stored. You can choose one of serviceManagedS3 or customerManagedS3 storage. If not specified, the default is serviceManagedS3. You cannot change this storage option after the channel is created.
- `retentionPeriod`: How long, in days, message data is kept for the channel. The retention period cannot be updated if the channel's S3 storage is customer-managed.
"""
update_channel(channelName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/channels/$(channelName)"; aws_config=aws_config)
update_channel(channelName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/channels/$(channelName)", args; aws_config=aws_config)

"""
    UpdateDataset()

Updates the settings of a data set.

# Required Parameters
- `actions`: A list of DatasetAction objects.
- `datasetName`: The name of the data set to update.

# Optional Parameters
- `contentDeliveryRules`: When dataset contents are created, they are delivered to destinations specified here.
- `lateDataRules`: A list of data rules that send notifications to Amazon CloudWatch, when data arrives late. To specify lateDataRules, the dataset must use a DeltaTimer filter.
- `retentionPeriod`: How long, in days, dataset contents are kept for the dataset.
- `triggers`: A list of DatasetTrigger objects. The list can be empty or can contain up to five DatasetTrigger objects.
- `versioningConfiguration`: Optional. How many versions of dataset contents are kept. If not specified or set to null, only the latest version plus the latest succeeded version (if they are different) are kept for the time period specified by the retentionPeriod parameter. For more information, see Keeping Multiple Versions of AWS IoT Analytics Data Sets in the AWS IoT Analytics User Guide.
"""
update_dataset(actions, datasetName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/datasets/$(datasetName)", Dict{String, Any}("actions"=>actions); aws_config=aws_config)
update_dataset(actions, datasetName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/datasets/$(datasetName)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("actions"=>actions), args)); aws_config=aws_config)

"""
    UpdateDatastore()

Updates the settings of a data store.

# Required Parameters
- `datastoreName`: The name of the data store to be updated.

# Optional Parameters
- `datastoreStorage`: Where data store data is stored. You can choose one of serviceManagedS3 or customerManagedS3 storage. If not specified, the default isserviceManagedS3. You cannot change this storage option after the data store is created.
- `retentionPeriod`: How long, in days, message data is kept for the data store. The retention period cannot be updated if the data store's S3 storage is customer-managed.
"""
update_datastore(datastoreName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/datastores/$(datastoreName)"; aws_config=aws_config)
update_datastore(datastoreName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/datastores/$(datastoreName)", args; aws_config=aws_config)

"""
    UpdatePipeline()

Updates the settings of a pipeline. You must specify both a channel and a datastore activity and, optionally, as many as 23 additional activities in the pipelineActivities array.

# Required Parameters
- `pipelineActivities`: A list of PipelineActivity objects. Activities perform transformations on your messages, such as removing, renaming or adding message attributes; filtering messages based on attribute values; invoking your Lambda functions on messages for advanced processing; or performing mathematical transformations to normalize device data. The list can be 2-25 PipelineActivity objects and must contain both a channel and a datastore activity. Each entry in the list must contain only one activity. For example:  pipelineActivities = [ { \"channel\": { ... } }, { \"lambda\": { ... } }, ... ]
- `pipelineName`: The name of the pipeline to update.

"""
update_pipeline(pipelineActivities, pipelineName; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/pipelines/$(pipelineName)", Dict{String, Any}("pipelineActivities"=>pipelineActivities); aws_config=aws_config)
update_pipeline(pipelineActivities, pipelineName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = iotanalytics("PUT", "/pipelines/$(pipelineName)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("pipelineActivities"=>pipelineActivities), args)); aws_config=aws_config)


text:
using LinearAlgebra
using SparseArrays
using Arpack

"""Laplacian of an adjacency matrix `A`"""
laplacian(A::AbstractSparseMatrix) = spdiagm(0=>vec(sum(A, dims=2))) - A

"""Normalized laplacian of an adjacency matrix `A`"""
function normalized_laplacian(A::AbstractSparseMatrix)
    D = spdiagm(0=>1.0./sqrt.(vec(sum(A, dims=2))))
    return sparse(I, size(D)) - D*A*D
end

"""Spectral clustering results
"""
struct SpectralResult <: ClusteringResult
    res::KmeansResult
    λ::AbstractVector{<:Real}
end
assignments(clust::SpectralResult) = assignments(clust.res)
nclusters(clust::SpectralResult) = nclusters(clust.res)
counts(clust::SpectralResult) = counts(clust.res)

"""Spectral clustering using of square similarity (adjacency) matrix

Accepts sparse matrix `M` and `k` number of expected clusters as parϵ = Infameters.
Parameter `method` specifies clustering algorithm:

- `:njw` for "On Spectral Clustering: Analysis and an algorithm" by Nj, Jordan, Weiss (2002) (default)
- `:sm` for "Normalized Cuts and Image Segmentation" by Shi and Malik (2000)
"""
function spectralclust(A::AbstractSparseMatrix, k::Int; method=:njw, init=:kmpp)
    @assert size(A,1) == size(A,2) "Matrix should be square"
    @assert size(A,1) > k "Number of clusters cannot be more then observations"
    @assert k > 1 "Number of clusters should be more then one"

    if method == :sm
        L = laplacian(A)
        D = Diagonal(L)
        λ, ϕ = eigs(L, D, which=:SR, nev=min(2*k, size(A,1)-1))
        idxs = findall(real(λ).> eps())
        ϕ = ϕ[:,idxs]
        λ = λ[idxs]
    elseif method == :njw
        L = normalized_laplacian(A)
        kk = min(k+1, size(A,1)-1)
        λ, ϕ = eigs(L, which=:SR, nev=kk)
        k = min(length(λ), kk-1)
        ϕ = ϕ[:,1:k]
        λ = λ[1:k]
    else
        throw(ArgumentError("Invalid method `$method`"))
    end

    # normalize
    ϕ = real(ϕ)
    ϕ ./= mapslices(norm,ϕ,dims=2)

    KM = kmeans(ϕ', k, init=init)
    return SpectralResult(KM, real(λ))
end
spectralclust(cplx::AbstractComplex, k::Int; kwargs...) =
    spectralclust(ComputationalHomology.adjacency_matrix(cplx), k; kwargs...)

function plmc(::Type{Spectral},
              flt::Filtration,
              mcr::ModelClusteringResult;
              k = round(Int, sqrt(size(complex(flt),0))), kwargs...)
    cplx = complex(flt)
    scr = spectralclust(cplx, k; kwargs...)
    meta = [Int[] for i in 1:nclusters(scr)]
    # group clustres in a metacluster
    for (i, a) in enumerate(assignments(scr))
        push!(meta[a], i)
    end
    return PLMClusteringResult(mcr, meta, cplx, Inf)
end

ext: jl

max_stars_repo_name: wildart/PLMC

max_issues_repo_name: wildart/PLMC

max_forks_repo_name: wildart/PLMC


text:
# # POVM simulation
# This notebook shows how we can check how much depolarizing noise a qubit positive operator-valued measure (POVM) can take before it becomes simulable by projective measurements. The general method is described in [arXiv:1609.06139](https://arxiv.org/abs/1609.06139). The question of simulability by projective measurements boils down to an SDP problem. Eq. (8) from the paper defines the noisy POVM that we obtain subjecting a POVM $\mathbf{M}$ to a depolarizing channel $\Phi_t$:
#
# $$
# \left[\Phi_t\left(\mathbf{M}\right)\right]_i := t M_i + (1-t)\frac{\mathrm{tr}(M_i)}{d} \mathbb{1}.
# $$
#
# If this visibility $t\in[0,1]$ is one, the POVM $\mathbf{M}$ is simulable.
#
# We will use Convex.jl to solve the SDP problem.

using Convex, SCS, LinearAlgebra

# For the qubit case, a four outcome qubit POVM $\mathbf{M} \in\mathcal{P}(2,4)$ is simulable if and only if
#
# $M_{1}=N_{12}^{+}+N_{13}^{+}+N_{14}^{+},$
#
# $M_{2}=N_{12}^{-}+N_{23}^{+}+N_{24}^{+},$
#
# $M_{3}=N_{13}^{-}+N_{23}^{-}+N_{34}^{+},$
#
# $M_{4}=N_{14}^{-}+N_{24}^{-}+N_{34}^{-},$
#
# where Hermitian operators $N_{ij}^{\pm}$ satisfy $N_{ij}^{\pm}\geq0$ and $N_{ij}^{+}+N_{ij}^{-}=p_{ij}\mathbb{1}$, where $i<j$ , $i,j=1,2,3,4$ and $p_{ij}\geq0$ as well as $\sum_{i<j}p_{ij}=1$, that is, the $p_{ij}$ values form a probability vector. This forms an SDP feasibility problem, which we can rephrase as an optimization problem by adding depolarizing noise to the left-hand side of the above equations and maximizing the visibility $t$:
#
# $\max_{t\in[0,1]} t$
#
# such that
#
# $t\,M_{1}+(1-t)\,\mathrm{tr}(M_{1})\frac{\mathbb{1}}{2}=N_{12}^{+}+N_{13}^{+}+N_{14}^{+},$
#
# $t\,M_{2}+(1-t)\,\mathrm{tr}(M_{2})\frac{\mathbb{1}}{2}=N_{12}^{-}+N_{23}^{+}+N_{24}^{+},$
#
# $t\,M_{3}+(1-t)\,\mathrm{tr}(M_{3})\frac{\mathbb{1}}{2}=N_{13}^{-}+N_{23}^{-}+N_{34}^{+},$
#
# $t\,M_{4}+(1-t)\,\mathrm{tr}(M_{4})\frac{\mathbb{1}}{2}=N_{14}^{-}+N_{24}^{-}+N_{34}^{-}$.
#
# We organize these constraints in a function that takes a four-output qubit POVM as its argument:

function get_visibility(K)
    noise = real([tr(K[i]) * I(2) / 2 for i in 1:size(K, 1)])
    P = [[ComplexVariable(2, 2) for i in 1:2] for j in 1:6]
    q = Variable(6, Positive())
    t = Variable(1, Positive())
    constraints = [P[i][j] in :SDP for i in 1:6 for j in 1:2]
    constraints += sum(q) == 1
    constraints += t <= 1
    constraints += [P[i][1] + P[i][2] == q[i] * I(2) for i in 1:6]
    constraints += t * K[1] + (1 - t) * noise[1] == P[1][1] + P[2][1] + P[3][1]
    constraints += t * K[2] + (1 - t) * noise[2] == P[1][2] + P[4][1] + P[5][1]
    constraints += t * K[3] + (1 - t) * noise[3] == P[2][2] + P[4][2] + P[6][1]
    constraints += t * K[4] + (1 - t) * noise[4] == P[3][2] + P[5][2] + P[6][2]
    p = maximize(t, constraints)
    solve!(p, SCS.Optimizer; silent_solver = true)
    return p.optval
end

# We check this function using the tetrahedron measurement (see Appendix B in [arXiv:quant-ph/0702021](https://arxiv.org/abs/quant-ph/0702021)). This measurement is non-simulable, so we expect a value below one.

function dp(v)
    return I(2) + v[1] * [0 1; 1 0] + v[2] * [0 -im; im 0] + v[3] * [1 0; 0 -1]
end
b = [
    1 1 1
    -1 -1 1
    -1 1 -1
    1 -1 -1
] / sqrt(3)
M = [dp(b[i, :]) for i in 1:size(b, 1)] / 4;
get_visibility(M)

# This value matches the one [we obtained](https://github.com/peterwittek/ipython-notebooks/blob/master/Simulating_POVMs.ipynb) using [PICOS](http://picos.zib.de/).


text:
#=
OutDegree : Calculate the out-degree of matrix A
=#

function OutDegree(A)
    dout = sum(A,2)
    dout_i,dout_j,dout_v = findnz(dout)
    ndout = sum(sparse(dout_i,dout_v,1),1)
    return ndout
end

########################################################
# D4M: Dynamic Distributed Dimensional Data Model
# Architect: Dr. Jeremy Kepner (kepner@ll.mit.edu)
# Software Engineer: Alexander Chen (alexc89@mit.edu)
########################################################


text:
##########################################################################################################
#
#  Conductors for normal extensions of normal fields
#
##########################################################################################################

function tame_conductors_degree_2(O::NfOrd, bound::fmpz; unramified_outside::Vector{fmpz} = fmpz[])
  K = nf(O)
  d = degree(O)
  b1 = Int(root(bound,d))
  ram_primes = ramified_primes(O)
  sort!(ram_primes)
  filter!(x -> x!=2, ram_primes)
  list = squarefree_up_to(b1, coprime_to = vcat(ram_primes,2), prime_base = unramified_outside)

  extra_list = Tuple{Int, fmpz}[(1,fmpz(1))]
  for q in ram_primes
    tr = prime_decomposition_type(O, Int(q))
    e = tr[1][2]
    nq = fmpz(q)^(divexact(d,e))
    if nq > bound
      break
    end
    l=length(extra_list)
    for i = 1:l
      n = extra_list[i][2]*nq
      if n > bound
        continue
      end
      push!(extra_list, (extra_list[i][1]*q, n))
    end
  end

  final_list=Tuple{Int,fmpz}[]
  l = length(list)
  for (el,norm) in extra_list
    for i=1:l
      if fmpz(list[i])^d*norm>bound
        continue
      end
      push!(final_list, (list[i]*el, fmpz(list[i])^d*norm))
    end
  end
  return final_list

end

function squarefree_for_conductors(O::NfOrd, n::Int, deg::Int; coprime_to::Vector{fmpz}=fmpz[], prime_base::Vector{fmpz} = fmpz[])

  sqf = trues(n)
  primes = trues(n)

  #remove primes that can be wildly ramified or
  #that are ramified in the base field
  for x in coprime_to
    if x > n
      continue
    end
    el = Int(x)
    t = el
    while t <= n
      @inbounds sqf[t]=false
      @inbounds primes[t]=false
      t += el
    end
  end

  #sieving procedure

  if !(2 in coprime_to)
    dt = prime_decomposition_type(O,2)
    if isone(gcd(2^dt[1][1]-1, deg))
      j = 2
      while j <= n
        @inbounds sqf[j] = false
        @inbounds primes[j] = false
        j += 2
      end
    else
      i=2
      s=4
      while s <= n
        @inbounds primes[s] = false
        s+=2
      end
      s=4
      while s <= n
        @inbounds sqf[s] = false
        s+=4
      end
    end
  end
  i = 3
  b = isqrt(n)
  while i <= b
    if primes[i]
      if gcd(i-1, deg) != 1 && (!isempty(prime_base) && (i in prime_base))
        j = i
        while j <= n
          @inbounds primes[j] = false
          j += i
        end
        j = i^2
        t = j
        while j <= n
          @inbounds sqf[j] = false
          j += t
        end
      else
        dt = prime_decomposition_type(O, i)
        if gcd(deg, i^dt[1][1]-1) == 1 || (!isempty(prime_base) && !(i in prime_base))
          j = i
          while j <= n
           @inbounds primes[j] = false
           @inbounds sqf[j] = false
           j+=i
          end
        else
          j=i
          while j <= n
            @inbounds primes[j]=false
            j+=i
          end
          j=i^2
          t=j
          while j<= n
            @inbounds sqf[j]=false
            j+=t
          end
        end
      end
    end
    i+=2
  end
  while i<=n
    if primes[i] && gcd(i-1, deg) == 1
      dt=prime_decomposition_type(O,i)
      if gcd(deg, i^dt[1][1]-1) == 1 || (!isempty(prime_base) && !(i in prime_base))
        @inbounds sqf[i]=false
        j=i
        while j <= n
         @inbounds sqf[j]=false
         j+=i
        end
      end
    end
    i+=2
  end

  if degree(O)==1
    i=2
    while i<=length(sqf)
      @inbounds sqf[i]=false
      i+=4
    end
  end
  return Int[i for i=1:length(sqf) if sqf[i]]
end

function conductors_tame(O::NfOrd, n::Int, bound::fmpz; unramified_outside::Vector{fmpz} = fmpz[])

  if n == 2
    return tame_conductors_degree_2(O, bound, unramified_outside = unramified_outside)
  end
  #
  #  First, conductors coprime to the ramified primes and to the
  #  degree of the extension we are searching for.
  #
  d = degree(O)
  K = nf(O)
  wild_ram = collect(keys(factor(fmpz(n)).fac))
  ram_primes = ramified_primes(O)
  filter!(x -> !divisible(fmpz(n),x), ram_primes)
  sort!(ram_primes)
  coprime_to = vcat(ram_primes, wild_ram)
  m = minimum(wild_ram)
  k = divexact(n, m)
  e = Int((m-1)*k)
  b1 = Int(root(bound, degree(O)*e))
  list = squarefree_for_conductors(O, b1, n, coprime_to = coprime_to, prime_base = unramified_outside)

  extra_list = Tuple{Int, fmpz}[(1, fmpz(1))]
  for q in ram_primes
    if !isempty(unramified_outside) && !(q in unramified_outside)
      continue
    end
    tr = prime_decomposition_type(O, Int(q))
    f = tr[1][1]
    nq = q^f
    if is_coprime(nq - 1, fmpz(n))
      continue
    end
    nq = nq^(length(tr)*e)
    if nq > bound
      continue
    end
    l = length(extra_list)
    for i=1:l
      no = extra_list[i][2]*nq
      if no > bound
        continue
      end
      push!(extra_list, (extra_list[i][1]*q, no))
    end
  end

  final_list = Tuple{Int, fmpz}[]
  l = length(list)
  e = Int((m-1)*k)
  for (el,norm) in extra_list
    for i=1:l
      if (list[i]^(e*d)) * norm > bound
        continue
      end
      push!(final_list, (list[i]*el, (fmpz(list[i])^(e*d))*norm))
    end
  end

  return final_list
end

function conductors(O::NfOrd, a::Vector{Int}, bound::fmpz, tame::Bool=false; unramified_outside::Vector{fmpz} = fmpz[])

  #Careful: I am assuming that a is in snf!
  K = nf(O)
  d = degree(O)
  n = prod(a)
  expo = a[end]
  wild_ram = collect(keys(factor(n).fac))

  #
  # First, conductors for tamely ramified extensions
  #
  bound_tame = root(bound, divexact(n, expo))
  list = conductors_tame(O, expo, bound_tame, unramified_outside = unramified_outside)

  if tame
    reverse!(list)
    return Tuple{Int, Dict{NfOrdIdl, Int}}[(x[1], Dict{NfOrdIdl, Int}()) for x in list]
  end
  #
  # now, we have to multiply the obtained conductors by proper powers of wildly ramified ideals.
  #
  wild_list = Tuple{Int, Dict{NfOrdIdl, Int}, fmpz}[(1, Dict{NfOrdIdl, Int}(), fmpz(1))]
  for q in wild_ram
    if !isempty(unramified_outside) && !(q in unramified_outside)
      continue
    end
    lp = prime_decomposition(O, Int(q))
    fq = divexact(d, lp[1][2]*length(lp))
    l = length(wild_list)
    sq = q^(divexact(d,lp[1][2])) #norm of the squarefree part of the integer q
    #=
      we have to use the conductor discriminant formula to understand the maximal possible exponent of q.
      Let ap be the exponent of p in the relative discriminant, let m be the conductor and h_(m,C) the cardinality of the
      quotient of ray class group by its subgroup C.
      Then
          ap= v_p(m)h_(m,C)- sum_{i=1:v_p(m)} h_(m/p^i, C)
      Since m is the conductor, h_(m/p^i, C)<= h_(m,C)/q.
      Consequently, we get
        v_p(m)<= (q*ap)/(h_(m,C)*(q-1))
    =#
    v = valuation(expo, q)
    # First, we compute the bound coming from the bound on the discriminant
    boundsubext = root(bound, Int(divexact(n, q^v))) #The bound on the norm of the discriminant on the subextension
                                                     # of order q^v
    #Bound coming from the bound on the discriminant
    obound = fmpz(flog(boundsubext, sq))

    #Bound coming from the analysis on the different in a local extension
    nbound = q^v + lp[1][2] * v * q^v - 1

    bound_max_ap = min(nbound, obound)  #bound on ap
    bound_max_exp = div(bound_max_ap, (q-1)*q^(v-1)) #bound on the exponent in the conductor

    #Ramification groups bound
    max_nontrivial_ramification_group = div(lp[1][2]*(q^v), q-1)
    if v > 1
      ram_groups_bound = max_nontrivial_ramification_group - sum(q^i for i = 1:v-1) + v
    else
      ram_groups_bound = max_nontrivial_ramification_group + 1
    end
    bound_max_exp = min(ram_groups_bound, bound_max_exp)

    #The prime may be also tamely ramified!
    nisc = gcd(q^(fq)-1, fmpz(expo))
    if nisc != 1
      fnisc=minimum(keys(factor(nisc).fac))
      nq=sq^((fnisc-1)*(divexact(n, fnisc)))
      for s=1:l
        nn=nq*wild_list[s][3]
        if nn>bound
          continue
        end
        push!(wild_list, (q*wild_list[s][1], wild_list[s][2], nn))
      end
    end
    for i=2:bound_max_exp
      d1=Dict{NfOrdIdl, Int}()
      for j=1:length(lp)
        d1[lp[j][1]]=i
      end
      exp1 = i*(q-1)*divexact(n,q)
      nq= sq^(exp1)
      for s=1:l
        nn=nq*wild_list[s][3]
        if nn>bound
          continue
        end
        d2 = merge(max, d1, wild_list[s][2])
        if nisc!=1
          push!(wild_list, (q*wild_list[s][1], d2, nn))
        else
          push!(wild_list, (wild_list[s][1], d2, nn))
        end
      end
    end
  end

  #the final list
  final_list=Tuple{Int, Dict{NfOrdIdl, Int}}[]
  for (el, nm) in list
    for (q,d,nm2) in wild_list
      if nm*nm2 > bound
        continue
      end
      push!(final_list, (el*q,d))
    end
  end
  reverse!(final_list)
  return final_list

end

###############################################################################
#
#  Conductors over QQ
#
###############################################################################

function squarefree_for_conductorsQQ(O::NfOrd, n::Int, a::Vector{Int}; coprime_to::Vector{fmpz}=fmpz[], unramified_outside::Vector{fmpz} = fmpz[])

  G = map(Int, snf(abelian_group(a))[1].snf)
  sqf= trues(n)
  primes= trues(n)
  deg = G[end]
  #remove primes that can be wildly ramified
  for x in coprime_to
    if x > n
      continue
    end
    el = Int(x)
    t=el
    while t <= n
      @inbounds sqf[t] = false
      @inbounds primes[t] = false
      t += el
    end
  end

  single = Vector{Int}()
  push!(single, 1)
  multiple = Vector{Int}()

  #sieving procedure
  #First, I can remove all the multiples of 2
  if !(2 in coprime_to)
    i=2
    while i<=length(sqf)
      @inbounds sqf[i] = false
      i+=2
    end
  end

  i=3
  b = isqrt(n)
  while i <= b
    if primes[i]
      if gcd(deg, i-1) == 1 || (!isempty(unramified_outside) && !(i in unramified_outside))
        @inbounds primes[i]=false
        @inbounds sqf[i]=false
        j=i
        while j<= n
         @inbounds primes[j]=false
         @inbounds sqf[j]=false
         j+=i
        end
      else
        j=i
        while j<= n
          @inbounds primes[j]=false
          j+=i
        end
        j=i^2
        t=2*j
        while j<= n
          @inbounds sqf[j]=false
          j+=t
        end
      end
    end
    i+=2
  end
  while i<=n
    if primes[i]
      if gcd(deg,i-1) == 1 || (!isempty(unramified_outside) && !(i in unramified_outside))
        @inbounds primes[i] = false
        @inbounds sqf[i]=false
        j = i
        while j <= n
         @inbounds sqf[j]=false
         j += i
        end
      end
    end
    i += 2
  end

  if length(G) > 1
    i = 3
    while i < n
      if primes[i]
        push!(single, i)
      elseif sqf[i]
        push!(multiple, i)
      end
      i += 2
    end
  elseif !is_prime(deg)
    i = 3
    while i < n
      if primes[i]
        if rem(i-1, deg) == 0
          push!(multiple, i)
        else
          push!(single, i)
        end
      elseif sqf[i]
        push!(multiple, i)
      end
      i += 2
    end
  else
    multiple = Int[i for i = 2:length(sqf) if sqf[i]]
  end

  return single, multiple

end

function conductors_tameQQ(O::NfOrd, a::Vector{Int}, bound::fmpz; unramified_outside::Vector{fmpz} = fmpz[])

  #
  #  First, conductors coprime to the ramified primes and to the
  #  degree of the extension we are searching for.
  #
  n = prod(a)
  wild_ram = collect(keys(factor(fmpz(n)).fac))
  m = minimum(wild_ram)
  k = divexact(n, m)
  b1 = Int(root(fmpz(bound),Int((m-1)*k)))

  return squarefree_for_conductorsQQ(O, b1, a, coprime_to = wild_ram, unramified_outside = unramified_outside)

end

function conductorsQQ(O::NfOrd, a::Vector{Int}, bound::fmpz, tame::Bool=false; unramified_outside::Vector{fmpz} = fmpz[])

  K = nf(O)
  d = degree(O)
  n = prod(a)
  expo = a[end]
  wild_ram = collect(keys(factor(fmpz(n)).fac))

  #
  # First, conductors for tamely ramified extensions
  #

  single, multiple = conductors_tameQQ(O, a, bound, unramified_outside = unramified_outside)

  if tame
    return multiple
  end
  #
  # now, we have to multiply the obtained conductors by proper powers of wildly ramified ideals.
  #
  wild_list=Tuple{Int, Int, fmpz}[(1, 1, 1)]
  for q in wild_ram
    if !isempty(unramified_outside) && !(q in unramified_outside)
      continue
    end
    l = length(wild_list)
    #=
      we have to use the conductor discriminant formula to understand the maximal possible exponent of q.
      Let ap be the exponent of p in the relative discriminant, let m be the conductor and h_(m,C) the cardinality of the
      quotient of ray class group by its subgroup C.
      Then
          ap= v_p(m)h_(m,C)- sum_{i=1:v_p(m)} h_(m/p^i, C)
      Since m is the conductor, h_(m/p^i, C)<= h_(m,C)/q.
      Consequently, we get
        v_p(m)<= (q*ap)/(h_(m,C)*(q-1))
      To find ap, it is enough to compute a logarithm.
    =#
    v = valuation(expo, q)

    #I don't need to give a bound for a_p on the big extension but only on the maximum extension of q-power order
    #This is the only thing that matters for the exponent of the conductor
    nisc = gcd(q-1,n)
    nbound = q^v + v * q^v - 1
    boundsubext = root(bound, Int(divexact(n, q^v)))
    obound = flog(boundsubext, q)
    nnbound = valuation_bound_discriminant(n, q)
    bound_max_ap = min(nbound, obound, nnbound)  #bound on ap
    bound_max_exp = div(bound_max_ap, (q^(v-1))*(q-1)) #bound on the exponent in the conductor
    if q == 2
      bound_max_exp = min(bound_max_exp, valuation(expo, q)+2)
    else
      bound_max_exp = min(bound_max_exp, valuation(expo, q)+1)
    end
    if nisc != 1
      fnisc=minimum(keys(factor(nisc).fac))
      nq=fmpz(q)^((fnisc-1)*(divexact(n, fnisc)))
      for s=1:l
        nn=nq*wild_list[s][3]
        if nn>bound
          continue
        end
        push!(wild_list, (q*wild_list[s][1], wild_list[s][2], nn))
      end
    end
    t=(q-1)*divexact(n,q)
    for i=2:bound_max_exp
      nq= q^(i*t)
      for s=1:l
        nn=nq*wild_list[s][3]
        if nn>bound
          continue
        end
        push!(wild_list, (wild_list[s][1], wild_list[s][2]*q^i, nn))
      end
    end
  end

  #the final list
  final_list = Int[]
  exps = Int((minimum(wild_ram)-1)*divexact(n, minimum(wild_ram)))
  for el in multiple
    for (q,d,nm2) in wild_list
      if (fmpz(el)^exps)*nm2 > bound
        continue
      end
      push!(final_list, (el*q*d))
    end
  end

  for el in single
    for j = 2:length(wild_list)
      q,d,nm2 = wild_list[j]
      if (fmpz(el)^exps)*nm2 > bound
        continue
      end
      push!(final_list, (el*q*d))
    end
  end
  return final_list

end

################################################################################
#
#  Conductors generic
#
################################################################################

function conductors_generic(K::AnticNumberField, gtype::Vector{Int}, absolute_bound::fmpz; only_tame::Bool = false)
  #I am assuming that gtype is in "SNF"
  conds_tame = conductors_generic_tame(K, gtype, absolute_bound)
  if only_tame
    return Dict{NfOrdIdl, Int}[(x[1], Dict{NfOrdIdl, Int}()) for x in conds_tame]
  end
  OK = maximal_order(K)
  wild = collect(keys(factor(gtype[end]).fac))
  n = prod(gtype)
  bound = div(absolute_bound, abs(discriminant(OK))^n)
  wild_primes = Vector{Tuple{NfOrdIdl, UnitRange{Int}}}()
  for p in wild
    lp = prime_decomposition(OK, p)
    for (P, v) in lp
      starting_power = 2
      ending_power = 2
      nP = norm(P)
      if nP > bound
        continue
      end
      gn = gcd(nP-1, gtype[end])
      if !isone(gn)
        starting_power = 1
      end
      vp = valuation(gtype[end], p)
      # First, we compute the bound coming from the bound on the discriminant
      boundsubext = root(bound, Int(divexact(n, p^vp))) #The bound on the norm of the discriminant on the subextension
                                                        # of order q^v
      #Bound coming from the bound on the discriminant
      obound = flog(boundsubext, nP)

      #Bound coming from the analysis on the different in a local extension
      nbound = p^vp + v * vp * p^vp - 1

      bound_max_ap = min(nbound, obound)  #bound on ap
      ending_power = Int(div(bound_max_ap, (p-1)*p^(vp-1)))
      if ending_power >= starting_power
        push!(wild_primes, (P, starting_power:ending_power))
      end
    end
  end
  #create now a sublist with just the wild ramified primes.
  conds_wild = Vector{Tuple{Dict{NfOrdIdl, Int}, fmpz}}()
  push!(conds_wild, (Dict{NfOrdIdl, Int}(), fmpz(1)))
  # For each p in wild_primes, p[2] describes the possible exponent
  # range. Of course, not every prime needs to appear, so we add
  # 0 to the list of possible exponents.
  it = cartesian_product_iterator(Array{Int}[push!(collect(x[2]), 0) for x in wild_primes], inplace = true)
  for I in it
    if all(x->x<2, I)
      # Exclude exponents (0, 0, ..., 0)
      # Note that all exponents are >= 2 by if they are nonzero
      continue
    end
    D = Dict{NfOrdIdl, Int}()
    nD = fmpz(1)
    for j = 1:length(I)
      if iszero(I[j])
        continue
      end
      P = wild_primes[j][1]
      nP = norm(P)
      p = minimum(P)
      vp = minimum([valuation(gtype[i], p) for i = 1:length(gtype)])
      nD *= nP^((p^vp-p^(vp-1))*I[j])
      if nD > bound
        break
      end
      D[P] = I[j]
    end
    if nD > bound
      continue
    end
    push!(conds_wild, (D, nD))
  end

  #Now, the final merge.
  conds = Vector{Dict{NfOrdIdl, Int}}()
  for i = 1:length(conds_wild)
    for j = 1:length(conds_tame)
      if conds_wild[i][2]*conds_tame[j][2] <= bound
        push!(conds, merge(conds_wild[i][1], conds_tame[j][1]))
      end
    end
  end
  return conds
end

function conductors_generic_tame(K::AnticNumberField, gtype::Vector{Int}, absolute_bound::fmpz)

  OK = maximal_order(K)
  n = prod(gtype)
  wild = collect(keys(factor(n).fac))
  pmin = Int(minimum(wild))
  bound = div(absolute_bound, abs(discriminant(OK))^n)
  lp = prime_ideals_up_to(OK, Int(root(bound, pmin-1)))
  filter!(x -> !(minimum(x, copy = false) in wild), lp)
  lf = Vector{Tuple{NfOrdIdl, fmpz}}()
  for P in lp
    nP = norm(P)
    gn = gcd(nP-1, gtype[end])
    if isone(gn)
      continue
    end
    fgn = factor(gn)
    k = minimum(keys(fgn.fac))
    kp, cpk = ppio(gtype[end], Int(k))
    dP = nP^(div(n, gtype[end])*(k-1)*cpk)
    if dP > bound
      continue
    end
    push!(lf, (P, dP))
  end
  #Now, I have to merge them.
  conds = Vector{Tuple{Dict{NfOrdIdl, Int}, fmpz}}()
  push!(conds, (Dict{NfOrdIdl, Int}(), fmpz(1)))
  if isempty(lf)
    return conds
  end
  for i = 1:length(lf)
    P = lf[i][1]
    dP = lf[i][2]
    indj = length(conds)
    new_conds = Vector{Tuple{Dict{NfOrdIdl, Int}, fmpz}}()
    for j = 1:indj
      Dd = dP*conds[j][2]
      if Dd > bound
        break
      end
      D = copy(conds[j][1])
      D[P] = 1
      push!(new_conds, (D, Dd))
    end
    for j = 1:length(new_conds)
      insert!(conds, searchsortedfirst(conds, new_conds[j], by = x -> x[2]), new_conds[j])
    end
  end
  return conds
end


text:
module OnlineStatsBase

using Statistics, Dates, LinearAlgebra
using OrderedCollections: OrderedDict

import StatsBase: StatsBase, nobs, fit!
import AbstractTrees: AbstractTrees

export
    OnlineStat, Weight,
    # functions
    nobs, value, fit!, eachrow, eachcol,
    # Weights
    EqualWeight, ExponentialWeight, LearningRate, LearningRate2, HarmonicWeight, McclainWeight,
    # Stats
    Counter, CountMap, CountMissing, CovMatrix, Extrema, FTSeries, Group, GroupBy, Mean, Moments,
    Series, Sum, Variance

@static if VERSION < v"1.1.0"
    eachrow(A::AbstractVecOrMat) = (view(A, i, :) for i in axes(A, 1))
    eachcol(A::AbstractVecOrMat) = (view(A, :, i) for i in axes(A, 2))
end

#-----------------------------------------------------------------------# OnlineStat
abstract type OnlineStat{T} end
input(o::OnlineStat{T}) where {T} = T
nobs(o::OnlineStat) = o.n

# Stats that hold a collection of other stats
abstract type StatCollection{T} <: OnlineStat{T} end
Base.show(io::IO, o::StatCollection) = AbstractTrees.print_tree(io, o)

AbstractTrees.printnode(io::IO, o::StatCollection) = print(io, name(o, false, false))
AbstractTrees.children(o::StatCollection) = collect(o.stats)

struct SameLine
    items
    sep
    SameLine(items, sep='|') = new(items, sep)
end
AbstractTrees.printnode(io::IO, o::SameLine) = print(io, join(o.items, o.sep))

"""
    value(stat::OnlineStat)

Calculate the value of `stat` from its "sufficient statistics".
"""
@generated function value(o::OnlineStat)
    r = first(fieldnames(o))
    return :(o.$r)
end

#-----------------------------------------------------------------------# Base
Base.:(==)(o::OnlineStat, o2::OnlineStat) = false
function Base.:(==)(o1::T, o2::T) where {T<:OnlineStat}
    nms = fieldnames(typeof(o1))
    all(getfield.(Ref(o1), nms) .== getfield.(Ref(o2), nms))
end

Base.copy(o::OnlineStat) = deepcopy(o)

"""
    merge!(stat1, stat2)

Merge `stat1` into `stat2` (supported by most `OnlineStat` types).

# Example

    a = fit!(Mean(), 1:10)
    b = fit!(Mean(), 11:20)
    merge!(a, b)
"""
function Base.merge!(o::OnlineStat, o2::OnlineStat)
    (nobs(o) > 0 || nobs(o2) > 0) && _merge!(o, o2)
    o
end
_merge!(o, o2) = @warn("Merging $(name(o2)) into $(name(o)) is not well-defined.  No merging occurred.")
Base.merge(o::OnlineStat, o2::OnlineStat) = merge!(copy(o), o2)

#-----------------------------------------------------------------------# Show
function Base.show(io::IO, o::OnlineStat)
    print(io, name(o, false, false), ": ")
    print(io, "n=", nobs(o))
    print(io, " | value=")
    show(IOContext(io, :compact => true), value(o))
end
function name(T::Type, withmodule = false, withparams = true)
    s = string(T)
    if !withmodule
        s = replace(s, r"([a-zA-Z]*\.)" => "")  # remove text that ends in period
    end
    if !withparams
        s = replace(s, r"\{(.*)" => "")  # remove "{" to the end of the string
    end
    s
end
name(o, args...) = name(typeof(o), args...)

#-----------------------------------------------------------------------# fit!
"""
    fit!(stat::OnlineStat, data)

Update the "sufficient statistics" of a `stat` with more data.   If `typeof(data)` is not
the type of a single observation for the provided `stat`, `fit!` will attempt to iterate
through and `fit!` each item in `data`.  Therefore, `fit!(Mean(), 1:10)` translates
roughly to:

```
o = Mean()
for x in 1:10
    fit!(o, x)
end
```
"""
fit!(o::OnlineStat{T}, yi::T) where {T} = (_fit!(o, yi); return o)

function fit!(o::OnlineStat{I}, y::T) where {I, T}
    T == eltype(y) && error("The input for $(name(o,false,false)) is a $I.  Found $T.")
    for yi in y
        fit!(o, yi)
    end
    o
end

#-----------------------------------------------------------------------# utils
"""
    smooth(a, b, γ)

Weighted average of `a` and `b` with weight `γ`.
"""
smooth(a, b, γ) = a + γ * (b - a)

"""
    smooth!(a, b, γ)

Update `a` in place by applying the [`smooth`](@ref) function elementwise with `b`.
"""
function smooth!(a, b, γ)
    for (i, bi) in zip(eachindex(a), b)
        a[i] = smooth(a[i], bi, γ)
    end
end

"""
    smooth_syr!(A::AbstractMatrix, x, γ::Number)

Weighted average of symmetric rank-1 update.  Updates the upper triangle of:

`A = (1 - γ) * A + γ * x * x'`
"""
function smooth_syr!(A::AbstractMatrix, x, γ)
    for j in 1:size(A, 2), i in 1:j
        A[i, j] = smooth(A[i,j], x[i] * conj(x[j]), γ)
    end
end

# bessel correction
bessel(o) = nobs(o) / (nobs(o) - 1)

Statistics.std(o::OnlineStat; kw...) = sqrt.(var(o; kw...))

const TwoThings{T,S} = Union{Tuple{T,S}, Pair{<:T,<:S}, NamedTuple{names, Tuple{T,S}}} where names

neighbors(x) = @inbounds ((x[i], x[i+1]) for i in eachindex(x)[1:end-1])

#-----------------------------------------------------------------------# includes
include("weight.jl")
include("stats.jl")
end


text:
"""
mode.jl
"""

"""
 	AbstractModel

Abstraction of a model of a dynamical system of the form ẋ = f(x,u), where x is the n-dimensional state vector
and u is the m-dimensional control vector.

Any inherited type must define the following interface:
ẋ = dynamics(model, x, u)
n,m = size(model)
"""
abstract type AbstractModel end

"""
	LieGroupModel <: AbstractModel

Abstraction of a dynamical system whose state contains at least one arbitrary rotation.
"""
abstract type LieGroupModel <: AbstractModel end

"""
	RigidBody{R<:Rotation} <: LieGroupModel

Abstraction of a dynamical system with free-body dynamics, with a 12 or 13-dimensional state
vector: `[p; q; v; ω]`
where `p` is the 3D position, `q` is the 3 or 4-dimension attitude representation, `v` is the
3D linear velocity, and `ω` is the 3D angular velocity.

# Interface
Any single-body system can leverage the `RigidBody` type by inheriting from it and defining the
following interface:
```julia
forces(::MyRigidBody, x, u)  # return the forces in the world frame
moments(::MyRigidBody, x, u) # return the moments in the body frame
inertia(::MyRigidBody, x, u) # return the 3x3 inertia matrix
mass(::MyRigidBody, x, u)  # return the mass as a real scalar
```

Instead of defining `forces` and `moments` you can define the higher-level `wrenches` function
	wrenches(model::MyRigidbody, z::AbstractKnotPoint)
	wrenches(model::MyRigidbody, x, u)

# Rotation Parameterization
A `RigidBody` model must specify the rotational representation being used. Any `Rotations.Rotation{3}`
can be used, but we suggest one of the following:
* `UnitQuaternion`
* `MRP`
* `RodriguesParam`
"""
# abstract type RigidBody{R<:Rotation} <: LieGroupModel end

"Integration rule for approximating the continuous integrals for the equations of motion"
abstract type QuadratureRule end

"Specifier for continuous systems (i.e. no integration)"
abstract type Continuous <: QuadratureRule end

"Integration rules of the form x′ = f(x,u), where x′ is the next state"
abstract type Explicit <: QuadratureRule end

"Integration rules of the form x′ = f(x,u,x′,u′), where x′,u′ are the states and controls at the next time step."
abstract type Implicit <: QuadratureRule end

"Fourth-order Runge-Kutta method with zero-order-old on the controls"
abstract type RK4 <: Explicit end

"Second-order Runge-Kutta method with zero-order-old on the controls"
abstract type RK3 <: Explicit end

"Second-order Runge-Kutta method with zero-order-old on the controls (i.e. midpoint)"
abstract type RK2 <: Explicit end

abstract type Euler <: Explicit end

"Third-order Runge-Kutta method with first-order-hold on the controls"
abstract type HermiteSimpson <: Implicit end

"Default quadrature rule"
const DEFAULT_Q = RK3

"""Default size method for model"""
@inline Base.size(model::AbstractModel) = throw("unimplemented")

"""
Continuous time dynamics
"""
@inline dynamics(model::AbstractModel, x::AbstractVector, u::AbstractVector, t::Real, dt::Real) = (
    throw("unimplemented")
)

""" Compute the discretized dynamics of `model` using
explicit integration scheme `Q<:QuadratureRule`.

Methods:
```
x′ = discrete_dynamics(model, model, z)  # uses $(DEFAULT_Q) as the default integration scheme
x′ = discrete_dynamics(Q, model, x, u, t, dt)
x′ = discrete_dynamics(Q, model, z::KnotPoint)
```

The default integration scheme is stored in `TrajectoryOptimization.DEFAULT_Q`
"""
@inline discrete_dynamics(::Type{Q}, model::AbstractModel, x, u, t, dt) where Q =
    integrate(Q, model, x, u, t, dt)

@inline discrete_dynamics!(x_::AbstractVector, ::Type{Q}, model::AbstractModel, x::AbstractVector,
                           u::AbstractVector, t::Real, dt::Real) where {Q} = (
                               x_ .= discrete_dynamics(Q, model, x, u, t, dt)
)

"""
	        discrete_jacobian!(Q, ∇f, model, z::AbstractKnotPoint)

Compute the `n × (n+m)` discrete dynamics Jacobian `∇f` of `model` using explicit
integration scheme `Q<:QuadratureRule`.
"""
function discrete_jacobian!(A::AbstractMatrix, B::AbstractMatrix,
                            IR, model::AbstractModel, x::AbstractVector,
                            u::AbstractVector, t::T, dt::T) where {T}
    fx(x_) = discrete_dynamics(IR, model, x_, u, t, dt)
    ForwardDiff.jacobian!(A, fx, x)
    fu(u_) = discrete_dynamics(IR, model, x, u_, t, dt)
    ForwardDiff.jacobian!(B, fu, u)
    return nothing
end

############################################################################################
#                               STATE DIFFERENTIALS                                        #
############################################################################################

state_diff(model::AbstractModel, x, x0) = x - x0
function state_diff!(δx::AbstractVector, model::AbstractModel, x::AbstractVector,
                     x0::AbstractVector)
    δx .= x
    δx .-= x0
    return nothing
end
@inline state_diff_jacobian(model::AbstractModel, x::SVector{N,T}) where {N,T} = I
@inline state_diff_size(model::AbstractModel) = size(model)[1]
function state_diff_jacobian!(G::AbstractMatrix, model::AbstractModel, x::AbstractVector)
	for i in 1:length(x)
		G[i,i] = 1
	end
end


text:
### ChainGradient

# Stores the output of a Monte Carlo run
type ChainGradient{N<:Number,T<:AbstractFloat,V<:AbstractVector,A<:AbstractArray} <: AbstractChain
    values::A
    loglikelihood::V
    gradloglikelihood::A
    numburnin::Int
    numaccepted::Int
    numproposed::Int
    runtime::Real
    ChainGradient(v::AbstractArray{N},ll::AbstractVector{T},gl::AbstractArray{T},b::Int,a::Int,p::Int,r::Real) = new(v,ll,gl,b,a,p,r)
end

@inline function _chain{N<:Number,T<:AbstractFloat}(::Type{Val{:gradient}},nparas::Int,nsamples::Int,::Type{N},::Type{T};numburnin::Int =0)
    v = zeros(N,_valuestuple(nparas,nsamples))
    ChainGradient{N,T,Vector,Array}(v,Vector{T}(nsamples),similar(v,T),numburnin,0,0,0.0)
end

function store!{O<:GradientOrder}(c::ChainGradient,s::AbstractSample{O},j::Int)
    nparas = numparas(s)
    @assert numparas(c) == nparas && j <= numsamples(s)
    if c.numproposed < length(c.loglikelihood)
        c.numproposed += 1
        copy!(c.values,(c.numproposed-1)*nparas+1,s.values,(j-1)*nparas+1,nparas)
        copy!(c.gradloglikelihood,(c.numproposed-1)*nparas+1,s.gradloglikelihood,(j-1)*nparas+1,nparas)
        c.loglikelihood[c.numproposed] = s.loglikelihood[j]
    else
        warn("Chain is full. Additional results cannot be stored")
    end
end

function show(io::IO,c::ChainGradient)
  println("ChainGradient with numparas = $(numparas(c)) and numsamples = $(numsamples(c))")
  println("Samples proposed = $(c.numproposed), samples accepted = $(c.numaccepted), acceptance rate = $(c.numaccepted/c.numproposed)")
  println("Total runtime = $(c.runtime)")
  println("Additional fields: :values, :loglikelihood, :gradloglikelihood")
end


text:
using RoME
using Test

@testset "Basic Pose2 initialization" begin
  global fg = initfg()
  initFactorGraph!(fg, lbl=:x0, solvable=0)

  global N = 100
  global fg = initfg()
  initFactorGraph!(fg, init=zeros(3), P0=0.1*Matrix{Float64}(LinearAlgebra.I, 3,3), N=N, lbl=:x0, solvable=0,   firstPoseType=Pose2)

end

# test Pose3 initialization
@testset "Base Pose3 initialization" begin
  global N = 100
  global fg = initfg()
  global initCov = Matrix{Float64}(LinearAlgebra.I, 6,6)
  [initCov[i,i] = 0.01^2 for i in 4:6];
  initFactorGraph!(fg, P0=initCov, init=zeros(6), N=N, lbl=:x0, solvable=0, firstPoseType=Pose3)
  @test true
end


text:
export num_theta, num_pauli, pauli_coeff, theta_offset, UCCQuantumCircuit, add_parametric_circuit_using_generator!
export update_circuit_param!, update_quantum_state!, gen_t1, gen_p_t2
export uccgsd

################################################################################
############################# QUANTUM  CIRCUIT #################################
################################################################################
struct UCCQuantumCircuit <: VariationalQuantumCircuit
    circuit::ParametricQuantumCircuit
    thetas::Vector{Float64}
    # Vector of (num_term_count::Int64, ioff::Int64, pauli_coeffs::Float64)
    theta_offsets::Vector{Tuple{Int64, Int64, Vector{Float64}}}
end

#function get_n_qubit(circuit::UCCQuantumCircuit)
    #get_n_qubit(circuit.circuit)
#end

function num_theta(circuit::UCCQuantumCircuit)
    size(circuit.theta_offsets)[1]
end

function get_thetas(circuit::UCCQuantumCircuit)
    copy(circuit.thetas)
end

function num_pauli(circuit::UCCQuantumCircuit, idx_theta::Int)
    circuit.theta_offsets[idx_theta][1]
end

function pauli_coeff(circuit::UCCQuantumCircuit, idx_theta::Int, idx_pauli::Int)
    circuit.theta_offsets[idx_theta][3][idx_pauli]
end

function theta_offset(circuit::UCCQuantumCircuit, idx_theta::Int)
    circuit.theta_offsets[idx_theta][2]
end

function UCCQuantumCircuit(n_qubit::Int)
    UCCQuantumCircuit(QulacsParametricQuantumCircuit(n_qubit), [], [])
end

function Base.copy(uc::UCCQuantumCircuit)
    UCCQuantumCircuit(copy(uc.circuit), copy(uc.thetas), copy(uc.theta_offsets))
end

function add_parametric_circuit_using_generator!(circuit::UCCQuantumCircuit,
    generator::QubitOperator, theta::Float64)
    pauli_coeffs = Float64[]
    for (pauli_str, pauli_coef) in terms_dict(generator)
        pauli_index_list, pauli_id_list = parse_pauli_str(pauli_str)
        if !all(1 .<= pauli_index_list)
            error("Pauli indies are out of range!")
        end
        if length(pauli_index_list) == 0
            continue
        end
        #println(pauli_str, pauli_coef)
        pauli_coef = imag(pauli_coef) #coef should be pure imaginary
        push!(pauli_coeffs, pauli_coef)
        add_parametric_multi_Pauli_rotation_gate!(
            circuit.circuit, pauli_index_list, pauli_id_list, pauli_coef*theta)
    end
    if length(pauli_coeffs) == 0
        return
    end
    num_thetas = num_theta(circuit)
    ioff = num_thetas == 0 ? 0 : theta_offset(circuit, num_thetas) + num_pauli(circuit, num_thetas)
    push!(circuit.thetas, theta)
    push!(circuit.theta_offsets, (get_term_count(generator), ioff, pauli_coeffs))
end

"""
Update circuit parameters

thetas wil be copied.
"""
function update_circuit_param!(circuit::UCCQuantumCircuit, thetas::Vector{Float64})
    if num_theta(circuit) != length(thetas)
        error("Invalid length of thetas!")
    end
    for (idx, theta) in enumerate(thetas)
        for ioff in 1:num_pauli(circuit, idx)
            pauli_coef = pauli_coeff(circuit, idx, ioff)
            set_parameter!(circuit.circuit,
                theta_offset(circuit, idx)+ioff, theta*pauli_coef)
        end
    end
    circuit.thetas .= thetas
end

"""
Update a state using a circuit
"""
function update_quantum_state!(ucccirc::UCCQuantumCircuit, state::QulacsQuantumState)
    update_quantum_state!(ucccirc.circuit, state)
end

"""
Generate single excitations
"""
function gen_t1(a, i)
    #a^\dagger_a a_i (excitation)
    generator = FermionOperator([(a, 1), (i, 0)], 1.0)
    #-a^\dagger_i a_a (de-exciation)
    generator += FermionOperator([(i, 1), (a, 0)], -1.0)
    #JW-transformation of a^\dagger_a a_i - -a^\dagger_i a_a
    jordan_wigner(generator)
end

"""
Generate pair dobule excitations
"""
function gen_p_t2(aa, ia, ab, ib)
    generator = FermionOperator([
        (aa, 1),
        (ab, 1),
        (ib, 0),
        (ia, 0)],
        1.0)
    generator += FermionOperator([
        (ia, 1),
        (ib, 1),
        (ab, 0),
        (aa, 0)],
        -1.0)
    jordan_wigner(generator)
end

"""
Returns UCCGSD circuit.
"""
function uccgsd(n_qubit; nocc=-1, orbital_rot=false, conserv_Sz_doubles=true, conserv_Sz_singles=true, Doubles=true, uccgsd = true, p_uccgsd=false)
    if n_qubit <= 0 || n_qubit % 2 != 0
        error("Invalid n_qubit: $(n_qubit)")
    end
    if !orbital_rot && nocc < 0
        error("nocc must be given when orbital_rot = false!")
    end
    circuit = UCCQuantumCircuit(n_qubit)

    norb = n_qubit ÷ 2
    cr_range = orbital_rot ? (1:norb) : (1+nocc:norb)
    anh_range = orbital_rot ? (1:norb) : (1:nocc)

    spin_index_functions = [up_index, down_index]
    so_idx(iorb, ispin) = spin_index_functions[ispin](iorb)
    sz = [1, -1]

    # Singles
    for (a_spatial, i_spatial) in (Iterators.product(cr_range, anh_range))
        for ispin1 in 1:2, ispin2 in 1:2
            if conserv_Sz_singles && sz[ispin1] + sz[ispin2] != 0
                continue
            end
            #Spatial Orbital Indices
            a_spin_orbital = so_idx(a_spatial, ispin1)
            i_spin_orbital = so_idx(i_spatial, ispin2)
            #t1 operator
            generator = gen_t1(a_spin_orbital, i_spin_orbital)
            #Add t1 into the circuit
            add_parametric_circuit_using_generator!(circuit, generator, 0.0)
        end
    end

    if Doubles
        if uccgsd
            #Doubles
            for (spin_a, spin_i, spin_b, spin_j) in Iterators.product(1:2, 1:2, 1:2, 1:2)
                for (a, i, b, j) in Iterators.product(1:norb, 1:norb, 1:norb, 1:norb)
                    if conserv_Sz_doubles && sz[spin_a] + sz[spin_i] + sz[spin_b] + sz[spin_j] != 0
                        continue
                    end
                    #Spatial Orbital Indices
                    aa = so_idx(a, spin_a)
                    ia = so_idx(i, spin_i)
                    bb = so_idx(b, spin_b)
                    jb = so_idx(j, spin_j)
                    #perform loop only if ia>jb && aa>bb

                    if aa<=bb || ia <= jb
                        continue
                    end

                    #t2 operator
                    generator = gen_p_t2(aa, ia, bb, jb)
                    #Add p-t2 into the circuit
                    add_parametric_circuit_using_generator!(circuit, generator, 0.0)
                end
            end
        end

        if p_uccgsd
            spin_a = 1
            spin_b = 2
            for (a,i) in Iterators.product(1:norb, 1:norb)
                aa = so_idx(a, spin_a)
                ia = so_idx(i, spin_a)
                bb = so_idx(a, spin_b)
                jb = so_idx(i, spin_b)

                generator = gen_p_t2(aa, ia, bb, jb)
                #Add p-t2 into the circuit
                add_parametric_circuit_using_generator!(circuit, generator, 0.0)
            end
        end
    end

    circuit
end

max_stars_repo_name: sakurairihito/QCMaterialNew

max_issues_repo_name: sakurairihito/QCMaterialNew

max_forks_repo_name: sakurairihito/QCMaterialNew


text:
# Analyze samples generated in pmean/a-samples.jl
using EstimateSDE
using DynamicHMC
using DynamicHMC.Diagnostics
using Parameters
using Statistics
using DataStructures
using Printf
using MCMCDiagnostics
using Serialization
using Plots
using StatsBase
using Random

## Functions
format_plot!() = plot!(yaxis=:log,xlabel="f",ylabel="h",title="Power spectrum",
  fg_legend=:transparent, bg_legend=:transparent)

## Analysis settings
nspec = 1000

## Load settings, data and results
d = EstimateSDE.resultsdir("a-samples")
fn = joinpath(d,"samples.jld")
res = deserialize(fn)
@unpack settings,proc_ml,problem,procm,procs,R = res
@unpack proc,N,Tav,Tkld = settings

## Reported processes
pr = OrderedDict(
  "actual"=>proc,
  "ML"=>proc_ml,
  "PMean"=>procm,
)

## Sampling
for (i,r) in enumerate(R)
  println("Chain $i")
  println(summarize_tree_statistics(r.inference.tree_statistics))
end

## Rhat
𝓣 = transformation(problem,proc_ml)
θss = [𝓣.(r.inference.chain) for r in R]
R̂ = potential_scale_reduction(θss...)
println("R̂:")
println.("$n : $v" for (n,v) in pairs(R̂))

## Errors
tkld = 0:Tkld:N*Tav
D = OrderedDict(k=>kldiv(proc,v,tkld) for (k,v) in pr)

## Power spectrum
fkld = 1/Tkld/2
f = (0:nspec-1)/nspec*fkld
H = OrderedDict(k=>powerspectrum(proc.eq,f) for (k,proc) in pr)

## Plot results
P = plot()
for (k,h) in H
  lw = k=="actual" ? 2 : 1
  label = k
  if label≠"actual"
    label *= @sprintf " % 4.1f" D[k]
  end
  plot!(f,h,linewidth=lw,label=label)
end
format_plot!()
display(P)

## Posterior power spectrum
S = length(procs)
hall = Matrix{Float64}(undef,S,nspec)
for (i,proc) in enumerate(procs)
  hall[i,:] = powerspectrum(proc.eq,f)
end
prob_quantile = [0.1,0.5,0.9]
hqs = Matrix{Float64}(undef,nspec,length(prob_quantile))
for (i,x) in enumerate(eachcol(hall))
  hqs[i,:] = quantile(x,prob_quantile)
end
hmedian = hqs[:,2]
hlow = hqs[:,begin]
hhigh = hqs[:,end]

## Plot posterior power spectrum
# Method 1: uncertainty interval
P = plot(f,H["actual"],linewidth=2,label="actual")
plot!(f,hmedian,ribbon=(hlow,hhigh),fillalpha=0.1,label="posterior")
format_plot!(); display(P)

## Method 2: sample spectra
Splot = 20
ii = sample(MersenneTwister(785478),1:S,Splot;replace=false,ordered=true)
P = plot(f,H["actual"],linewidth=2,label="actual")
isfirst = true
for h in eachrow(hall[ii,:])
  global isfirst
  label = isfirst ? "posterior ($Splot)" : false
  plot!(f,h,color=:red,alpha=0.3,label=label)
  isfirst = false
end
format_plot!(); display(P)


text:
my_f(x,y) = 2x + 3y
my_g(x,y) = x^2 + y^2


text:
module BoardGamesStrategies

using BoardGames

export
    # Types
    RandomStrategy,
    MCTSStrategy,
    Minimax,
    MinimaxAlphaBeta

include("RandomStrategy.jl")
include("MCTSStrategy.jl")
include("Minimax.jl")
include("MinimaxAlphaBeta.jl")

end


text:
mutable struct WC
    words
    weights
    imgs
    svgs
    mask
    svgmask
    qtrees
    maskqtree
    params::Dict{Symbol,Any}
end

"""
## Positional Arguments
Positional arguments are used to specify words and weights, and can be in different forms, such as Tuple or Dict, etc.
* words::AbstractVector{<:AbstractString}, weights::AbstractVector{<:Real}
* words_weights::Tuple
* counter::AbstractDict
* counter::AbstractVector{<:Pair}
## Optional Keyword Arguments
### style keyword arguments
* colors = "black" #all same color
* colors = ("black", (0.5,0.5,0.7), "yellow", "#ff0000", 0.2) #choose entries randomly
* colors = ["black", (0.5,0.5,0.7), "yellow", "red", (0.5,0.5,0.7), 0.2, ......] #use entries sequentially in cycle
* colors = :seaborn_dark #using a preset scheme. see `WordCloud.colorschemes` for all supported Symbols. and `WordCloud.displayschemes()` may be helpful.
* angles = 0 #all same angle
* angles = (0, 90, 45) #choose entries randomly
* angles = 0:180 #choose entries randomly
* angles = [0, 22, 4, 1, 100, 10, ......] #use entries sequentially in cycle
* density = 0.55 #default 0.5
* spacing = 1  #minimum spacing between words

### mask keyword arguments
* mask = loadmask("res/heart.jpg", 256, 256) #see doc of `loadmask`
* mask = loadmask("res/heart.jpg", color="red", ratio=2) #see doc of `loadmask`
* mask = shape(ellipse, 800, 600, color="white", backgroundcolor=(0,0,0,0)) #see doc of `shape`
* maskshape: `box`, `ellipse`, or `squircle`.  See `shape`. Take effect only when the `mask` argument is not given.
* masksize: Can be a tuple `(width, height)`, tuple `(width, height, cornerradius)` (for `box` only) or just a single number as hint.
* backgroundsize: See `shape`. Take effect only when the `mask` argument is not given.
* maskcolor: like "black", "#ff0000", (0.5,0.5,0.7), 0.2, or :default, :original (keep it unchanged), :auto (auto recolor the mask).
* backgroundcolor: like "black", "#ff0000", (0.5,0.5,0.7), 0.2, or :default, :original, :maskcolor, :auto (random choose between :original and :maskcolor)
* outline, linecolor, smoothness: See function `shape` and `outline`.
* transparent = (1,0,0) #set the transparent color in mask
* transparent = nothing #no transparent color
* transparent = c->(c[1]+c[2]+c[3])/3*(c[4]/255)>128) #set transparent with a Function. `c` is a (r,g,b,a) Tuple.
---NOTE
Some arguments depend on whether or not the `mask` is given or the type of the `mask` given.

### other keyword arguments
The keyword argument `run` is a function. It will be called after the `wordcloud` object constructed.
* run = placewords! #default setting, will initialize word's position
* run = generate! #get result directly
* run = initwords! #only initialize resources, such as rendering word images
* run = x->nothing #do nothing
---NOTE
* After getting the `wordcloud` object, these steps are needed to get the result picture: initwords! -> placewords! -> generate! -> paint
* You can skip `placewords!` and/or `initwords!`, and the default action will be performed
"""
wordcloud(wordsweights::Tuple; kargs...) = wordcloud(wordsweights...; kargs...)
wordcloud(counter::AbstractDict; kargs...) = wordcloud(keys(counter)|>collect, values(counter)|>collect; kargs...)
wordcloud(counter::AbstractVector{<:Union{Pair, Tuple, AbstractVector}}; kargs...) = wordcloud(first.(counter), [v[2] for v in counter]; kargs...)
wordcloud(text; kargs...) = wordcloud(processtext(text); kargs...)
function wordcloud(words::AbstractVector{<:AbstractString}, weights::AbstractVector{<:Real};
                colors=:auto, angles=:auto,
                mask=:auto, font=:auto,
                transparent=:auto, minfontsize=:auto, maxfontsize=:auto, spacing=1, density=0.5,
                run=placewords!, kargs...)
    @assert length(words) == length(weights) > 0
    params = Dict{Symbol, Any}()
    colors, angles, mask, svgmask, font, transparent = getstylescheme(length(words); colors=colors, angles=angles,
                                                    mask=mask, font=font, transparent=transparent, params=params, kargs...)
    params[:colors] = Any[colors...]
    params[:angles] = angles
    params[:transparent] = transparent
    mask, maskqtree, groundsize, maskoccupying = preparemask(mask, transparent)
    println("mask size ", size(mask))
    params[:groundsize] = groundsize
    params[:maskoccupying] = maskoccupying
    if maskoccupying == 0
        error("Have you set the right `transparent`? e.g. `transparent=mask[1,1]`")
    end
    @assert maskoccupying > 0
    if minfontsize==:auto
        minfontsize = min(8, sqrt(maskoccupying/length(words)/8))
        @show maskoccupying length(words)
    end
    if maxfontsize==:auto
        maxfontsize = minimum(size(mask)) / 2
    end
    println("set fontsize ∈ [$minfontsize, $maxfontsize]")
    params[:minfontsize] = minfontsize
    params[:maxfontsize] = maxfontsize
    params[:spacing] = spacing
    params[:density] = density
    params[:font] = font

    params[:state] = nameof(wordcloud)
    params[:epoch] = 0
    params[:indsmap] = nothing
    params[:custom] = Dict(:fontsize=>Dict(), :font=>Dict())
    params[:scale] = -1
    params[:wordids] = collect(1:length(words))
    l = length(words)
    wc = WC(copy(words), float.(weights), Vector(undef, l), Vector{SVGImageType}(undef, l),
    mask, svgmask, Vector(undef, l), maskqtree, params)
    run(wc)
    wc
end
function getstylescheme(lengthwords; colors=:auto, angles=:auto, mask=:auto,
                masksize=:default, maskcolor=:default,
                backgroundcolor=:default, padding=:default,
                outline=:default, linecolor=:auto, font=:auto,
                transparent=:auto, params=Dict{Symbol, Any}(), kargs...)
    merge!(params, kargs)
    colors = colors in DEFAULTSYMBOLS ? randomscheme() : colors
    angles = angles in DEFAULTSYMBOLS ? randomangles() : angles
    maskcolor0 = maskcolor
    backgroundcolor0 = backgroundcolor
    colors = colors isa Symbol ? (colorschemes[colors].colors..., ) : colors
    colors = Iterators.take(iter_expand(colors), lengthwords) |> collect
    angles = Iterators.take(iter_expand(angles), lengthwords) |> collect
    if mask == :auto
        if maskcolor in DEFAULTSYMBOLS
            if backgroundcolor in DEFAULTSYMBOLS || backgroundcolor == :maskcolor
                maskcolor = randommaskcolor(colors)
            else
                maskcolor = backgroundcolor
            end
        end
        masksize = masksize in DEFAULTSYMBOLS ? 40*√lengthwords : masksize
        if backgroundcolor in DEFAULTSYMBOLS
            backgroundcolor = maskcolor0 in DEFAULTSYMBOLS ? rand(((1,1,1,0), :maskcolor)) : (1, 1, 1, 0)
        end
        backgroundcolor == :maskcolor && @show backgroundcolor
        kg = []
        if outline in DEFAULTSYMBOLS
            if maskcolor0 in DEFAULTSYMBOLS && backgroundcolor0 in DEFAULTSYMBOLS
                outline = randomoutline()
            else
                outline = 0
            end
        end
        if linecolor in DEFAULTSYMBOLS && outline != 0
            linecolor = randomlinecolor(colors)
        end
        if outline != 0
            push!(kg, :outline=>outline)
            push!(kg, :linecolor=>linecolor)
        end
        padding = padding in DEFAULTSYMBOLS ? maximum(masksize)÷10 : padding
        mask = randommask(masksize, color=maskcolor; padding=padding, kg..., kargs...)
    else
        ms = masksize in DEFAULTSYMBOLS ? () : masksize
        if maskcolor == :auto && !issvg(loadmask(mask))
            maskcolor = randommaskcolor(colors)
            println("Recolor the mask with color $maskcolor.")
        end
        if backgroundcolor == :auto
            if maskcolor == :default
                backgroundcolor = randommaskcolor(colors)
                maskcolor = backgroundcolor
            else
                backgroundcolor = rand(((1,1,1,0), :maskcolor, :original))
            end
        end
        bc = backgroundcolor
        if backgroundcolor ∉ [:default, :original]
            @show backgroundcolor
            bc = (1,1,1,0) #to remove the original background in mask
        end
        if outline == :auto
            outline = randomoutline()
            outline != 0 && @show outline
        elseif outline in DEFAULTSYMBOLS
            outline = 0
        end
        if linecolor in DEFAULTSYMBOLS && outline != 0
            linecolor = randomlinecolor(colors)
        end
        padding = padding in DEFAULTSYMBOLS ? 0 : padding
        mask = loadmask(mask, ms...; color=maskcolor, transparent=transparent, backgroundcolor=bc,
            outline=outline, linecolor=linecolor,padding=padding, kargs...)
    end
    if transparent == :auto
        if maskcolor ∉ DEFAULTSYMBOLS
            transparent = c->c!=WordCloud.torgba(maskcolor)
        end
    end
    params[:masksize] = masksize
    params[:maskcolor] = maskcolor
    params[:backgroundcolor] = backgroundcolor
    params[:outline] = outline
    params[:linecolor] = linecolor
    params[:padding] = padding
    svgmask = nothing
    if issvg(mask)
        svgmask = mask
        mask = svg2bitmap(mask)
        if maskcolor ∉ DEFAULTSYMBOLS && (:outline ∉ keys(params) || params[:outline] <= 0)
            Render.recolor!(mask, maskcolor) #svg2bitmap后有杂色 https://github.com/JuliaGraphics/Luxor.jl/issues/160
        end
    end
    font = font in DEFAULTSYMBOLS ? randomfont() : font
    colors, angles, mask, svgmask, font, transparent
end
Base.getindex(wc::WC, inds...) = wc.words[inds...]=>wc.weights[inds...]
Base.lastindex(wc::WC) = lastindex(wc.words)
Base.broadcastable(wc::WC) = Ref(wc)
getstate(wc::WC) = wc.params[:state]
setstate!(wc::WC, st::Symbol) = wc.params[:state] = st
function getindsmap(wc::WC)
    if wc.params[:indsmap] === nothing
        wc.params[:indsmap] = Dict(zip(wc.words, Iterators.countfrom(1)))
    end
    wc.params[:indsmap]
end
function index(wc::WC, w::AbstractString)
    getindsmap(wc)[w]
end
index(wc::WC, w::AbstractVector) = index.(wc, w)
index(wc::WC, i::Colon) = eachindex(wc.words)
index(wc::WC, i) = i
wordid(wc, i::Integer) = wc.params[:wordids][i]
wordid(wc, w) = wordid.(wc, index(wc, w))
getparameter(wc, args...) = getindex(wc.params, args...)
setparameter!(wc, args...) = setindex!(wc.params, args...)
hasparameter(wc, args...) = haskey(wc.params, args...)
getdoc = "The 1st arg is a wordcloud, the 2nd arg can be a word string(list) or a standard supported index and ignored to return all."
setdoc = "The 1st arg is a wordcloud, the 2nd arg can be a word string(list) or a standard supported index, the 3rd arg is the value to assign."
@doc getdoc getcolors(wc::WC, w=:) = wc.params[:colors][index(wc, w)]
@doc getdoc getangles(wc::WC, w=:) = wc.params[:angles][index(wc, w)]
@doc getdoc getwords(wc::WC, w=:) = wc.words[index(wc, w)]
@doc getdoc getweights(wc::WC, w=:) = wc.weights[index(wc, w)]
@doc setdoc setcolors!(wc::WC, w, c) = @view(wc.params[:colors][index(wc, w)]) .= parsecolor(c)
@doc setdoc setangles!(wc::WC, w, a::Union{Number, AbstractVector{<:Number}}) = @view(wc.params[:angles][index(wc, w)]) .= a
@doc setdoc
function setwords!(wc::WC, w, v::Union{AbstractString, AbstractVector{<:AbstractString}})
    m = getindsmap(wc)
    @assert !any(v .∈ Ref(keys(m)))
    i = index(wc, w)
    Broadcast.broadcast((old,new)->m[new]=pop!(m,old), wc.words[i], v)
    @view(wc.words[i]) .= v
    v
end
@doc setdoc setweights!(wc::WC, w, v::Union{Number, AbstractVector{<:Number}}) = @view(wc.weights[index(wc, w)]) .= v
@doc getdoc getimages(wc::WC, w=:) = wc.imgs[index(wc, w)]
@doc getdoc getsvgimages(wc::WC, w=:) = wc.svgs[index(wc, w)]

@doc setdoc
function setimages!(wc::WC, w, v::AbstractMatrix)
    @view(wc.imgs[index(wc, w)]) .= Ref(v)
    initqtree!(wc, w)
    v
end
setimages!(wc::WC, w, v::AbstractVector) = setimages!.(wc, index(wc,w), v)
@doc setdoc
function setsvgimages!(wc::WC, w, v)
    @view(wc.svgs[index(wc, w)]) .= v
    setimages!(wc::WC, w, svg2bitmap.(v))
end

@doc getdoc
function getfontsizes(wc::WC, w=:)
    inds = index(wc, w)
    ids = wordid(wc, inds)
    Broadcast.broadcast(inds, ids) do ind, id
        cf = wc.params[:custom][:fontsize]
        if id in keys(cf)
            return cf[id]
        else
            return clamp(getweights(wc, ind)*wc.params[:scale], wc.params[:minfontsize], wc.params[:maxfontsize])
        end
    end
end
@doc setdoc
function setfontsizes!(wc::WC, w, v::Union{Number, AbstractVector{<:Number}})
    push!.(Ref(wc.params[:custom][:fontsize]), wordid(wc, w) .=> v)
end
@doc getdoc
function getfonts(wc::WC, w=:)
    get.(Ref(wc.params[:custom][:font]), wordid(wc, w), wc.params[:font])
end
@doc setdoc
function setfonts!(wc::WC, w, v::Union{AbstractString, AbstractVector{<:AbstractString}})
    push!.(Ref(wc.params[:custom][:font]), wordid(wc, w) .=> v)
end
getmask(wc::WC) = wc.mask
getsvgmask(wc::WC) = wc.svgmask
getmaskcolor(wc::WC) = getparameter(wc, :maskcolor)
function getbackgroundcolor(wc::WC)
    c = getparameter(wc, :backgroundcolor)
    c = c == :maskcolor ? getmaskcolor(wc) : c
end
setbackgroundcolor!(wc::WC, v) = (setparameter!(wc, v, :backgroundcolor); v)
@doc getdoc * " Keyword argment `type` can be `getshift` or `getcenter`."
function getpositions(wc::WC, w=:; type=getshift)
    Stuffing.getpositions(wc.maskqtree, wc.qtrees, index(wc, w), type=type)
end

@doc setdoc * " Keyword argment `type` can be `setshift!` or `setcenter!`."
function setpositions!(wc::WC, w, x_y; type=setshift!)
    Stuffing.setpositions!(wc.maskqtree, wc.qtrees, index(wc, w), x_y, type=type)
end

Base.show(io::IO, m::MIME"image/png", wc::WC) = Base.show(io, m, paint(wc::WC))
Base.show(io::IO, m::MIME"image/svg+xml", wc::WC) = Base.show(io, m, paintsvg(wc::WC))
Base.show(io::IO, m::MIME"text/plain", wc::WC) = print(io, "wordcloud(", wc.words, ") #", length(wc.words), "words")
function Base.showable(::MIME"image/png", wc::WC)
    STATEIDS[getstate(wc)] >= STATEIDS[:initwords!] && showable("image/png", zeros(ARGB,(1,1)))
end
function Base.showable(::MIME"image/svg+xml", wc::WC)
    STATEIDS[getstate(wc)] >= STATEIDS[:initwords!] && (wc.svgmask !== nothing || !showable("image/png", wc))
end
Base.show(io::IO, wc::WC) = Base.show(io, "text/plain", wc)


text:
function part1(input)
    return sum(overhead1.(eachline(input)))
end

function part2(input)
    return sum(overhead2.(eachline(input)))
end

function overhead1(line)
    i = 2
    overhead = 2
    while i < length(line)
        if line[i] == '\\'
            if line[i + 1] == 'x'
                i += 4
                overhead += 3
            else
                i += 2
                overhead += 1
            end
        else
            i += 1
        end
    end
    return overhead
end

function overhead2(line)
    overhead = 2
    for c in line
        overhead += c in "\\\""
    end
    return overhead
end


text:
function Axis(view::View, xaxis::Bool)
	axis = RectangleShape()

	set_fillcolor(axis, Color(128, 128, 128))
	set_size(axis, Vector2f(get_size(view).x, 2))
	set_origin(axis, Vector2f(get_size(view).x/2, 1))
	if !xaxis
		set_rotation(axis, 90)
	end

	marks = RectangleShape[]
	numbers = RenderText[]

	tic = RectangleShape()
	set_fillcolor(tic, Color(128, 128, 128))
	set_size(tic, Vector2f(10, 1))
	set_origin(tic, Vector2f(5, 0.5))

	number = RenderText()
	set_charactersize(number, 15)
	set_scale(number, Vector2f(1, -1))
	set_color(number, Color(128, 128, 128))

	Axis(axis, marks, numbers, xaxis, number, tic, 5)
end

function update(axis::Axis, window::PlotWindow)
	if axis.xaxis
		set_position(axis.axis, Vector2f(get_center(window.view).x, 0))
	else
		set_position(axis.axis, Vector2f(0, get_center(window.view).y))
	end
	ppu = window.ppu
	view = window.view
	empty!(axis.marks)
	empty!(axis.numbers)
	center = get_center(view)
	# axis.tic_period = round(1/ppu * 100)
	tic_period = axis.tic_period

	if axis.xaxis
		right = Int(round((center.x + get_size(view).x/2)/ppu))
		left = Int(round((center.x - get_size(view).x/2)/ppu))
		while left % tic_period != 0
			left += 1
		end
		for i = left:tic_period:right
			if i % axis.tic_period == 0
				tic = copy(axis.tic)
				set_rotation(tic, 90)

				number = copy(axis.number)
				set_string(number, "$i")
				bounds = get_globalbounds(number)
				set_origin(number, Vector2f(bounds.width / 2, bounds.height / 2))

				set_position(number, Vector2f(i*ppu, 20))
				if center.y < 0
					ypos = min(center.y - get_size(view).y/2, 0)
					set_position(tic, Vector2f(i*ppu, ypos))
					set_position(number, Vector2f(i*ppu, -20+ypos))
				else
					ypos = max(center.y + get_size(view).y/2, 0)
					set_position(tic, Vector2f(i*ppu, ypos))
					set_position(number, Vector2f(i*ppu, 20+ypos))
				end
				push!(axis.marks, tic)
				push!(axis.numbers, number)
			end
		end
	else
		up = Int(round((center.y - get_size(view).y/2)/ppu))
		down = Int(round((center.y + get_size(view).y/2)/ppu))
		while down % tic_period != 0
			down += 1
		end
		for i = down:tic_period:up
			if i % axis.tic_period == 0
				tic = copy(axis.tic)

				number = copy(axis.number)
				set_string(number, "$i")
				bounds = get_globalbounds(number)
				set_origin(number, Vector2f(bounds.width / 2, bounds.height / 2))

				if center.x < 0
					xpos = min(center.x + get_size(view).x/2, 0)
					set_position(tic, Vector2f(xpos, i*ppu))
					set_position(number, Vector2f(-20+xpos, i*ppu))
				else
					xpos = max(center.x - get_size(view).x/2, 0)
					set_position(tic, Vector2f(xpos, i*ppu))
					set_position(number, Vector2f(20+xpos, i*ppu))
				end
				push!(axis.marks, tic)
				push!(axis.numbers, number)
			end
		end
	end
end

function draw(window::PlotWindow, axis::Axis)
	SFML.draw(window.renderwindow, axis.axis)
	for i = 1:length(axis.marks)
		SFML.draw(window.renderwindow, axis.marks[i])
		SFML.draw(window.renderwindow, axis.numbers[i])
	end
end