# Copyright 2020 Q-CTRL Pty Ltd & Q-CTRL Inc. All rights reserved.
#
# Licensed under the Q-CTRL Terms of service (the "License"). Unauthorized
# copying or use of this file, via any medium, is strictly prohibited.
# Proprietary and confidential. You may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://q-ctrl.com/terms
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS. See the
# License for the specific language.
"""Module for CoreNode."""
from typing import Callable, List, Optional, Any
import forge
import numpy as np
from qctrlcommons.node.module import ModuleNode
from . import types
class CoreNode(ModuleNode):
"""Abstract class to represent the module is qctrlcore."""
_module_name = "qctrlcore"
class TensorPwc(CoreNode):
"""
Creates a Tensor-valued piecewise-constant function of time.
Parameters
----------
durations : np.ndarray (1D, real)
The durations of the segments.
values: tf.Tensor
The values of the segments. First dimension guaranteed
to be the same length as `durations`.
Returns
-------
TensorPwc
An tf.Tensor-valued piecewise-constant function of time.
"""
name = "tensor_pwc"
_module_attr = "TensorPwc"
args = [
forge.arg("durations", type=np.ndarray),
forge.arg("values", type=types.Tensor),
]
rtype = types.TensorPwc
class PwcSignal(CoreNode):
"""Creates a ``TensorPwc`` representing a piecewise-constant signal.
Parameters
----------
values : tf.Tensor(1D)
The tensor containing the value of each segment.
duration : float
The total duration of the signal. The provided ``values`` are assumed to correspond to
segments of equal length, such that the total duration is ``duration``.
Returns
-------
TensorPwc(1D)
A ``TensorPwc`` representing the signal.
"""
name = "pwc_signal"
_module_attr = "create_pwc_signal"
args = [forge.arg("values", type=types.Tensor), forge.arg("duration", type=float)]
rtype = types.TensorPwc
class ComplexPwcSignal(CoreNode):
"""Creates a ``TensorPwc`` representing a complex piecewise-constant signal.
Parameters
----------
moduli : tf.Tensor(1D, real)
The tensor containing piecewise-constant modulus segments of the signal.
phases : tf.Tensor(1D, real)
The tensor containing the piecewise-constant phase segments of the signal.
duration : float
The total duration of the signal.
Returns
-------
TensorPwc(1D, complex)
A ``TensorPwc`` representing the signal.
"""
name = "complex_pwc_signal"
_module_attr = "create_complex_pwc_signal"
args = [
forge.arg("moduli", type=types.Tensor),
forge.arg("phases", type=types.Tensor),
forge.arg("duration", type=float),
]
rtype = types.TensorPwc
class PwcOperatorHermitianPart(CoreNode):
"""Gets the Hermitian part of the given piecewise-constant operator.
Parameters
----------
operator : TensorPwc(3D)
The operator from which the Hermitian part should be taken.
Returns
-------
TensorPwc(3D)
A ``TensorPwc`` representing the piecewise-constant operator. Same shape as ``operator``.
"""
name = "pwc_operator_hermitian_part"
_module_attr = "get_pwc_operator_hermitian_part"
args = [
forge.arg("operator", type=types.TensorPwc),
]
rtype = types.TensorPwc
class PwcSum(CoreNode):
"""
Creates a new piecewise-constant object by summing multiple individual terms.
Parameters
----------
terms : list[TensorPwc(nD)]
The individual piecewise-constant terms to sum in order to create the total operator. All
terms must have the same duration and values of the same shape, but may have different
segmentations.
Returns
-------
TensorPwc(nD)
A ``TensorPwc`` representing the combined object.
"""
name = "pwc_sum"
_module_attr = "get_pwc_sum"
args = [forge.arg("terms", type=List[types.TensorPwc])]
rtype = types.TensorPwc
class TargetOperator(CoreNode):
"""
The target is the desired time evolution operation the controls implement in an ideal case.
Attributes
----------
operator : np.ndarray
The target operation. Must be a non-zero partial isometry. Equivalently, must be
expressible in the form sum_j |psi_j><phi_j|, where {|psi_j>} and {|phi_j>} both form
(non-empty) orthonormal, but not necessarily complete, sets. Conceptually, such a target
represents a target state |psi_j> for each initial state |phi_j>. The operational
infidelity is 0 iff, up to global phase, each initial state |phi_j> maps exactly to the
corresponding final state |psi_j>.
projector : np.ndarray, optional
DEPRECATED, please modify ``operator`` manually and pass ``filter_function_projector``
instead.
Must not be passed if ``filter_function_projector`` is passed.
This value is used for both the operational and filter function (if relevant) fidelity
calculations. Specifically, for the operational fidelity calculation, if a target T and
projector P are specified then the actual target used for the calculation is TP. That is,
the call ``target(operator=operator, projector=projector)`` is equivalent to
``target(operator=operator.dot(projector), filter_function_projector=projector)``.
filter_function_projector : np.ndarray, optional
The orthogonal projection matrix onto the subspace used for the filter function calculation
(if any such calculation is performed). Defaults to the identity. Must be Hermitian and
idempotent if passed.
"""
name = "target"
_module_attr = "Target"
args = [
forge.arg("operator", type=np.ndarray),
forge.arg("projector", type=Optional[np.ndarray], default=None),
forge.arg("filter_function_projector", type=Optional[np.ndarray], default=None),
]
rtype = types.TargetOperator
class RealFourierPwcSignal(CoreNode):
"""
Creates a real piecewise-constant signal constructed from sine/cosine Fourier components.
Parameters
----------
variable_factory : VariableFactory
The factory to use to create optimization variables.
duration : float
The total duration of the signal.
segments_count : int
The number of segments to use for the piecewise-constant approximation.
initial_coefficient_lower_bound : float, optional
The lower bound on the initial coefficient values. Defaults to -1 if not provided.
initial_coefficient_upper_bound : float, optional
The upper bound on the initial coefficient values. Defaults to 1 if not provided.
fixed_frequencies : list[float], optional
The fixed non-zero frequencies to use for the Fourier basis. Must be non-empty if provided.
Should be specified in the inverse units of ``duration`` (e.g. if duration is in seconds,
frequencies should be given in Hertz (not rad/s)).
optimizable_frequencies_count : int, optional
The number of non-zero frequencies to use, if the frequencies can be optimized. Must be
greater than zero if provided. The initial values of the frequencies are chosen in the
ranges [0, 1/duration], [1/duration, 2/duration], [2/duration, 3/duration] and so on. The
frequencies may move outside these ranges after the optimization starts (i.e. the frequency
variables are unbounded).
randomized_frequencies_count : int, optional
The number of non-zero frequencies to use, if the frequencies are to be randomized but
fixed. Must be greated than zero if provided. The values of th