def _variable_step_method_standard_tests(self, method): """tests to run on a variable step solver.""" results = solve_ode(self.basic_rhs, t_span=self.t_span, y0=self.y0, method=method, atol=1e-10, rtol=1e-10) expected = expm(-1j * np.pi * self.X.data) self.assertAllClose(results.y[-1], expected) # pylint: disable=unused-argument def quad_rhs(t, y): return Array([t**2], dtype=float) results = solve_ode(quad_rhs, t_span=[0.0, 1.0], y0=Array([0.0]), method=method, atol=1e-10, rtol=1e-10) expected = Array([1.0 / 3]) self.assertAllClose(results.y[-1], expected)
def setUp(self): self.t_span = [0.0, 1.0] self.y0 = Array(np.eye(2, dtype=complex)) self.X = Array([[0.0, 1.0], [1.0, 0.0]], dtype=complex) self.Y = Array([[0.0, -1j], [1j, 0.0]], dtype=complex) self.Z = Array([[1.0, 0.0], [0.0, -1.0]], dtype=complex) # simple generator and rhs # pylint: disable=unused-argument def generator(t): return -1j * 2 * np.pi * self.X / 2 def rhs(t, y): return generator(t) @ y self.basic_generator = generator self.basic_rhs = rhs # define simple model self.w = 2.0 self.r = 0.1 signals = [Constant(self.w), Signal(lambda t: 1.0, self.w)] operators = [ -1j * 2 * np.pi * self.Z / 2, -1j * 2 * np.pi * self.r * self.X / 2 ] self.basic_model = GeneratorModel(operators=operators, signals=signals)
def __init__( self, dt: float, samples: Union[Array, List], start_time: float = 0.0, duration: int = None, carrier_freq: float = 0.0, phase: float = 0.0, name: str = None, ): """Initialize a piecewise constant signal. Args: dt: The duration of each sample. samples: The array of samples. start_time: The time at which the signal starts. duration: The duration of the signal in samples. carrier_freq: The frequency of the carrier. phase: The phase of the carrier. name: name of the signal. """ super().__init__(name) self._dt = dt if samples is not None: self._samples = Array(samples) else: self._samples = Array([0.0] * duration) self._start_time = start_time self._carrier_freq = Array(carrier_freq) self._phase = Array(phase)
def initial_state_converter( obj: Any, return_class: bool = False) -> Union[Array, Tuple[Array, Type]]: """Convert initial state object to an Array. Args: obj: An initial state. return_class: Optional. If True return the class to use for converting the output y Array. Returns: Array: the converted initial state if ``return_class=False``. tuple: (Array, class) if ``return_class=True``. """ # pylint: disable=invalid-name y0_cls = None if isinstance(obj, Array): y0, y0_cls = obj, None if isinstance(obj, QuantumState): y0, y0_cls = Array(obj.data), obj.__class__ elif isinstance(obj, QuantumChannel): y0, y0_cls = Array(SuperOp(obj).data), SuperOp elif isinstance(obj, (BaseOperator, Gate, QuantumCircuit)): y0, y0_cls = Array(Operator(obj.data)), Operator else: y0, y0_cls = Array(obj), None if return_class: return y0, y0_cls return y0
def __init__( self, envelope: Callable, carrier_freqs: Array, phases: Array, drift_array: Optional[Array] = None, ): """Initialize with vector-valued envelope, carrier frequencies for each entry, and a drift_array, which corresponds to the value of the signal when the "time-dependent terms" are "off". Args: envelope: function of a single float returning an array. carrier_freqs: list of carrier frequencies for each component of the envelope. phases: list of carrier phases for each component of the envelope. drift_array: a default array meant to be the value of the envelope when all "time-dependent terms" are off. """ carrier_freqs = Array(carrier_freqs) phases = Array(phases) self.envelope = envelope self.carrier_freqs = carrier_freqs self.phases = phases self._im_angular_freqs = 1j * 2 * np.pi * carrier_freqs # if not supplied nothing is assumed, constant array is taken as all # zeros if drift_array is None: self.drift_array = Array(np.zeros(len(self.carrier_freqs))) else: self.drift_array = Array(drift_array)
def test_transform_rhs_funcs_order_F(self): """Test rhs function conversion""" inner_spec = {"type": "array", "shape": (4,)} outer_spec = {"type": "array", "shape": (2, 2)} converter = StateTypeConverter(inner_spec, outer_spec) X = Array([[0.0, 1.0], [1.0, 0.0]]) # do matrix multiplication (a truly '2d' operation) def rhs(t, y): return t * (y @ y) # pylint: disable=unused-argument def generator(t): return X new_rhs = converter.rhs_outer_to_inner(rhs) test_t = np.pi y_2d = Array([[1, 2], [3, 4]]) y_1d = y_2d.flatten(order="F") expected_output = rhs(test_t, y_2d).flatten(order="F") output = new_rhs(test_t, y_1d) self.assertAllClose(output, expected_output) new_generator = converter.generator_outer_to_inner(generator) # verify generator vectorization expected_output = np.kron(Array(np.eye(2)), X) output = new_generator(test_t) self.assertAllClose(output, expected_output)
def vec_commutator(A: Array): r"""Linear algebraic vectorization of the linear map X -> [A, X] in column-stacking convention. In column-stacking convention we have .. math:: vec(ABC) = C^T \otimes A vec(B), so for the commutator we have .. math:: [A, \cdot] = A \cdot - \cdot A \mapsto id \otimes A - A^T \otimes id Note: this function is also "vectorized" in the programming sense. Args: A: Either a 2d array representing the matrix A described above, or a 3d array representing a list of matrices. Returns: Array: vectorized version of the map. """ iden = Array(np.eye(A.shape[-1])) axes = list(range(A.ndim)) axes[-1] = axes[-2] axes[-2] += 1 return np.kron(iden, A) - np.kron(A.transpose(axes), iden)
def trim_t_results( results: OdeResult, t_span: Union[List, Tuple, Array], t_eval: Optional[Union[List, Tuple, Array]] = None, ) -> OdeResult: """Trim ``OdeResult`` object based on value of ``t_span`` and ``t_eval``. Args: results: Result object, assumed to contain solution at time points from the output of ``validate_and_merge_t_span_t_eval(t_span, t_eval)``. t_span: Interval to solve over. t_eval: Time points to include in returned results. Returns: OdeResult: Results with only times/solutions in ``t_eval``. If ``t_eval`` is ``None``, does nothing, returning solver default output. """ if t_eval is None: return results t_span = Array(t_span, backend="numpy") # remove endpoints if not included in t_eval if t_eval[0] != t_span[0]: results.t = results.t[1:] results.y = Array(results.y[1:]) if t_eval[-1] != t_span[1]: results.t = results.t[:-1] results.y = Array(results.y[:-1]) return results
def test_diag_frame_operator_basic_hamiltonian(self): """Test setting a diagonal frame operator for the internally set up basic hamiltonian. """ self._basic_frame_evaluate_test(Array([1.0, -1.0]), 1.123) self._basic_frame_evaluate_test(Array([1.0, -1.0]), np.pi)
def jax_odeint( rhs: Callable, t_span: Array, y0: Array, t_eval: Optional[Union[Tuple, List, Array]] = None, **kwargs, ): """Routine for calling `jax.experimental.ode.odeint` Args: rhs: Callable of the form :math:`f(t, y)` t_span: Interval to solve over. y0: Initial state. t_eval: Optional list of time points at which to return the solution. kwargs: Optional arguments to be passed to ``odeint``. Returns: OdeResult: Results object. """ t_list = merge_t_args(t_span, t_eval) # determine direction of integration t_direction = np.sign(Array(t_list[-1] - t_list[0], backend="jax")).data results = odeint( lambda y, t: t_direction * rhs(t_direction * t, y), y0=y0, t=t_direction * t_list.data, **kwargs, ) results = OdeResult(t=t_list, y=Array(results, backend="jax")) return trim_t_results(results, t_span, t_eval)
def test_generator_out_of_frame(self): """Test operator_out_of_frame.""" rng = np.random.default_rng(111) rand_op = rng.uniform(low=-10, high=10, size=( 6, 6)) + 1j * rng.uniform(low=-10, high=10, size=(6, 6)) frame_op = Array(rand_op - rand_op.conj().transpose()) t = rng.uniform(low=-100, high=100) y0 = Array( rng.uniform(low=-10, high=10, size=(6, 6)) + 1j * rng.uniform(low=-10, high=10, size=(6, 6))) self._test_generator_out_of_frame(t, frame_op, y0) self._test_generator_out_of_frame(t, frame_op, y0, y_in_frame_basis=True) self._test_generator_out_of_frame(t, frame_op, y0, return_in_frame_basis=True) self._test_generator_out_of_frame(t, frame_op, y0, y_in_frame_basis=True, return_in_frame_basis=True)
def to_array(op: Union[Operator, Array, List[Operator], List[Array]]): """Convert an operator or list of operators to an Array. Args: op: Either an Operator to be converted to an array, a list of Operators to be converted to a 3d array, or an array (which simply gets returned) Returns: Array: Array version of input """ if op is None or isinstance(op, Array): return op if isinstance(op, list) and isinstance(op[0], Operator): shape = op[0].data.shape dtype = op[0].data.dtype arr = np.empty((len(op), *shape), dtype=dtype) for i, sub_op in enumerate(op): arr[i] = sub_op.data return Array(arr) if isinstance(op, Operator): return Array(op.data) return Array(op)
def setUp(self): """Set up a basic parameterized simulation.""" self.w = 5.0 self.r = 0.1 operators = [ 2 * np.pi * self.w * Array(Operator.from_label("Z").data) / 2, 2 * np.pi * self.r * Array(Operator.from_label("X").data) / 2, ] ham = HamiltonianModel(operators=operators) self.ham = ham def param_sim(amp, drive_freq): signals = [ Constant(1.0), Signal(lambda t: amp, carrier_freq=drive_freq) ] ham_copy = ham.copy() ham_copy.signals = signals results = solve_lmde( ham_copy, t_span=[0.0, 1 / self.r], y0=Array([0.0, 1.0], dtype=complex), method="jax_odeint", atol=1e-10, rtol=1e-10, ) return results.y[-1] self.param_sim = param_sim
def test_diag_frame_operator_basic_model(self): """Test setting a diagonal frame operator for the internally set up basic model. """ self._basic_frame_evaluate_test(Array([1j, -1j]), 1.123) self._basic_frame_evaluate_test(Array([1j, -1j]), np.pi)
def _apply(self, signal: BaseSignal) -> BaseSignal: """ Applies a transformation on a signal, such as a convolution, low pass filter, etc. Once a convolution is applied the signal can longer have a carrier as the carrier is part of the signal value and gets convolved. Args: signal: A signal or list of signals to which the transfer function will be applied. Returns: signal: The transformed signal or list of signals. Raises: QiskitError: if the signal is not pwc. """ if isinstance(signal, PiecewiseConstant): # Perform a discrete time convolution. dt = signal.dt func_samples = Array([self._func(dt * i) for i in range(signal.duration)]) func_samples = func_samples / sum(func_samples) sig_samples = Array([signal.value(dt * i) for i in range(signal.duration)]) convoluted_samples = list(np.convolve(func_samples, sig_samples)) return PiecewiseConstant(dt, convoluted_samples, carrier_freq=0.0, phase=0.0) else: raise QiskitError("Transfer function not defined on input.")
def vec_dissipator(L: Array): r"""Linear algebraic vectorization of the linear map X -> L X L^\dagger - 0.5 * (L^\dagger L X + X L^\dagger L) in column stacking convention. This gives .. math:: \overline{L} \otimes L - 0.5(id \otimes L^\dagger L + (L^\dagger L)^T \otimes id) Note: this function is also "vectorized" in the programming sense. """ iden = Array(np.eye(L.shape[-1])) axes = list(range(L.ndim)) axes[-1] = axes[-2] axes[-2] += 1 Lconj = L.conj() LdagL = Lconj.transpose(axes) @ L LdagLtrans = LdagL.transpose(axes) return np.kron(Lconj, iden) @ np.kron(iden, L) - 0.5 * ( np.kron(iden, LdagL) + np.kron(LdagLtrans, iden) )
def __init__( self, envelope: Union[Callable, complex, float, int], carrier_freq: float = 0.0, phase: float = 0.0, name: str = None, ): """ Initializes a signal given by an envelop and an optional carrier. Args: envelope: Envelope function of the signal. carrier_freq: Frequency of the carrier. phase: The phase of the carrier. name: name of signal. """ super().__init__(name) if isinstance(envelope, (float, int)): envelope = complex(envelope) if isinstance(envelope, complex): self.envelope = lambda t: envelope else: self.envelope = envelope self._carrier_freq = Array(carrier_freq) self._phase = Array(phase)
def fixed_step_solver_template( take_step: Callable, rhs_func: Callable, t_span: Array, y0: Array, max_dt: float, t_eval: Optional[Union[Tuple, List, Array]] = None, ): """Helper function for implementing fixed-step solvers supporting both ``t_span`` and ``max_dt`` arguments. ``take_step`` is assumed to be a function implementing a single step of size h of a fixed-step method. The signature of ``take_step`` is assumed to be: - rhs_func: Either a generator :math:`G(t)` or RHS function :math:`f(t,y)`. - t0: The current time. - y0: The current state. - h: The size of the step to take. It returns: - y: The state of the DE at time t0 + h. ``take_step`` is used to integrate the DE specified by ``rhs_func`` through all points in ``t_eval``, taking steps no larger than ``max_dt``. Each interval in ``t_eval`` is divided into the least number of sub-intervals of equal length so that the sub-intervals are smaller than ``max_dt``. Args: take_step: Callable for fixed step integration. rhs_func: Callable, either a generator or rhs function. t_span: Interval to solve over. y0: Initial state. max_dt: Maximum step size. t_eval: Optional list of time points at which to return the solution. Returns: OdeResult: Results object. """ # ensure the output of rhs_func is a raw array def wrapped_rhs_func(*args): return Array(rhs_func(*args)).data y0 = Array(y0).data t_list, h_list, n_steps_list = get_fixed_step_sizes(t_span, t_eval, max_dt) ys = [y0] for current_t, h, n_steps in zip(t_list, h_list, n_steps_list): y = ys[-1] inner_t = current_t for _ in range(n_steps): y = take_step(wrapped_rhs_func, inner_t, y, h) inner_t = inner_t + h ys.append(y) ys = Array(ys) results = OdeResult(t=t_list, y=ys) return trim_t_results(results, t_span, t_eval)
def test_addition(self): """Tests the multiplication of signals.""" # Test Constant const1 = Constant(0.3) const2 = Constant(0.5) self.assertTrue(isinstance(const1 + const2, Signal)) self.assertEqual((const1 + const2).value(), 0.8) # Test Signal signal1 = Signal(3.0, carrier_freq=0.1) signal2 = Signal(lambda t: 2.0 * t ** 2, carrier_freq=0.1) self.assertTrue(isinstance(const1 + signal1, Signal)) self.assertTrue(isinstance(signal1 + const1, Signal)) self.assertTrue(isinstance(signal1 + signal2, Signal)) self.assertEqual((signal1 + signal2).carrier_freq, 0.0) self.assertEqual((signal1 + const1).carrier_freq, 0.0) self.assertEqual((signal1 + signal2).envelope_value(), 3.0) expected = 21.0 * np.cos(0.1 * 2.0 * np.pi * 3.0) self.assertAlmostEqual((signal1 + signal2).envelope_value(3.0), expected, places=8) self.assertEqual((signal1 + signal2).value(), 3.0) self.assertEqual((signal1 + signal2).value(2.0), 11.0 * np.cos(0.1 * 2.0 * np.pi * 2.0)) # Test piecewise constant dt = 1.0 samples = Array([0.0, 0.0, 1.0, 2.0, 1.0, 0.0, 0.0]) carrier_freq = 0.5 pwc1 = PiecewiseConstant(dt=dt, samples=samples, carrier_freq=carrier_freq) dt = 1.0 samples = Array([0.0, 0.0, 1.0, 2.0, 1.0, 0.0, 0.0]) carrier_freq = 0.1 pwc2 = PiecewiseConstant(dt=dt, samples=samples, carrier_freq=carrier_freq) # Test types self.assertTrue(isinstance(const1 + pwc1, Signal)) self.assertTrue(isinstance(signal1 + pwc1, Signal)) self.assertTrue(isinstance(pwc1 + pwc2, Signal)) self.assertTrue(isinstance(pwc1 + const1, Signal)) self.assertTrue(isinstance(pwc1 + signal1, Signal)) # Test values self.assertEqual((pwc1 + pwc2).carrier_freq, 0.0) self.assertEqual((pwc1 + pwc2).envelope_value(), 0.0) expected = 1.0 * np.cos(0.5 * 2.0 * np.pi * 4.0) + 1.0 * np.cos(0.1 * 2.0 * np.pi * 4.0) self.assertAlmostEqual((pwc1 + pwc2).envelope_value(4.0), expected, places=8) self.assertEqual((pwc1 + pwc2).value(), 0.0) expected = 1.0 * np.cos(0.5 * 2.0 * np.pi * 4.0) + 1.0 * np.cos(0.1 * 2.0 * np.pi * 4.0) self.assertAlmostEqual((pwc1 + pwc2).value(4.0), expected, places=8) # Test phase pwc2 = PiecewiseConstant(dt=dt, samples=samples, carrier_freq=carrier_freq, phase=0.5) expected = 1.0 * np.cos(0.5 * 2.0 * np.pi * 4.0) + 1.0 * np.cos( 0.1 * 2.0 * np.pi * 4.0 + 0.5 ) self.assertAlmostEqual((pwc1 + pwc2).envelope_value(4.0), expected, places=8)
def __init__( self, frame_operator: Union[BaseFrame, Operator, Array], atol: float = 1e-10, rtol: float = 1e-10, ): """Initialize with a frame operator. Args: frame_operator: the frame operator, must be either Hermitian or anti-Hermitian. atol: absolute tolerance when verifying that the frame_operator is Hermitian or anti-Hermitian. rtol: relative tolerance when verifying that the frame_operator is Hermitian or anti-Hermitian. """ if issubclass(type(frame_operator), BaseFrame): frame_operator = frame_operator.frame_operator self._frame_operator = frame_operator frame_operator = to_array(frame_operator) if frame_operator is None: self._dim = None self._frame_diag = None self._frame_basis = None self._frame_basis_adjoint = None # if frame_operator is a 1d array, assume already diagonalized elif frame_operator.ndim == 1: # verify Hermitian or anti-Hermitian # if Hermitian convert to anti-Hermitian frame_operator = _is_herm_or_anti_herm(frame_operator, atol=atol, rtol=rtol) self._frame_diag = Array(frame_operator) self._frame_basis = Array(np.eye(len(frame_operator))) self._frame_basis_adjoint = self.frame_basis self._dim = len(self._frame_diag) # if not, diagonalize it else: # verify Hermitian or anti-Hermitian # if Hermitian convert to anti-Hermitian frame_operator = _is_herm_or_anti_herm(frame_operator, atol=atol, rtol=rtol) # diagonalize with eigh, utilizing assumption of anti-hermiticity frame_diag, frame_basis = np.linalg.eigh(1j * frame_operator) self._frame_diag = Array(-1j * frame_diag) self._frame_basis = Array(frame_basis) self._frame_basis_adjoint = frame_basis.conj().transpose() self._dim = len(self._frame_diag)
def test_y0_reshape(self): """Test automatic detection of vectorized LMDE.""" y0 = Array(np.eye(2)) output = lmde_y0_reshape(4, y0) expected = y0.flatten(order="F") self.assertAllClose(output, expected)
def from_outer_instance_inner_type_spec(cls, outer_y, inner_type_spec=None, order="F"): """Instantiate from concrete instance of the outer type, and an inner type-spec. The inner type spec can be either be fully specified, or be more general (i.e. to facilitate the situation in which a solver needs a 1d array). Accepted general data types: - {'type': 'array'} - {'type': 'array', 'ndim': 1} Args: outer_y (array): concrete outer data type inner_type_spec (dict): inner, potentially general, type spec order (str): order argument to be used in array reshaping. Returns: StateTypeConverter: type converter as specified by args Raises: Exception: if inner_type_spec is not properly specified or is not a handled type """ # if no inner_type_spec given just instantiate both inner # and outer to the outer_y if inner_type_spec is None: return cls.from_instances(outer_y, order=order) inner_type = inner_type_spec.get("type") if inner_type is None: raise Exception("inner_type_spec needs a 'type' key.") if inner_type == "array": outer_y_as_array = Array(outer_y) # if a specific shape is given attempt to instantiate from a # reshaped outer_y shape = inner_type_spec.get("shape") if shape is not None: return cls.from_instances( outer_y_as_array.reshape(shape, order=order), outer_y, order=order ) # handle the case that ndim == 1 is given ndim = inner_type_spec.get("ndim") if ndim == 1: return cls.from_instances( outer_y_as_array.flatten(order=order), outer_y, order=order ) # if neither shape nor ndim is given, assume it can be an array # of any shape return cls.from_instances(outer_y_as_array, outer_y, order=order) raise Exception("inner_type_spec not a handled type.")
def test_instantiation_errors(self): """Check different modes of error raising for frame setting.""" with self.assertRaises(QiskitError): Frame(Array([1.0, 1j])) with self.assertRaises(QiskitError): Frame(Array([[1.0, 0.0], [0.0, 1j]])) with self.assertRaises(QiskitError): Frame(self.Z + 1j * self.X)
def merge_t_args( t_span: Union[List, Tuple, Array], t_eval: Optional[Union[List, Tuple, Array]] = None ) -> Array: """Merge ``t_span`` and ``t_eval`` into a single array without duplicates. Validity of the passed ``t_span`` and ``t_eval`` follow scipy ``solve_ivp`` validation logic: ``t_eval`` must be contained in ``t_span``, and be strictly increasing if ``t_span[1] > t_span[0]`` or strictly decreasing if ``t_span[1] < t_span[0]``. Note: this is done explicitly with ``numpy``, and hence this is not differentiable or compilable using jax. Args: t_span: Interval to solve over. t_eval: Time points to include in returned results. Returns: Array: Combined list of times. Raises: ValueError: If one of several validation checks fail. """ if t_eval is None: return Array(t_span) t_span = Array(t_span, backend="numpy") t_min = np.min(t_span) t_max = np.max(t_span) t_direction = np.sign(t_span[1] - t_span[0]) t_eval = Array(t_eval, backend="numpy") if t_eval.ndim > 1: raise ValueError("t_eval must be 1 dimensional.") if np.min(t_eval) < t_min or np.max(t_eval) > t_max: raise ValueError("t_eval entries must lie in t_span.") diff = np.diff(t_eval) if np.any(t_direction * diff <= 0.0): raise ValueError("t_eval must be ordered according to the direction of integration.") # if endpoints are not included in t_span, add them if t_eval[0] != t_span[0]: t_eval = np.append(t_span[0], t_eval) if t_span[1] != t_eval[-1]: t_eval = np.append(t_eval, t_span[1]) return Array(t_eval, backend="numpy")
def test_type_spec_from_instance(self): """Test type_spec_from_instance""" y = Array([1, 2, 3, 4]) type_spec = type_spec_from_instance(y) self.assertEqual(type_spec, {"type": "array", "shape": (4,)}) y = Array([[1, 2], [3, 4], [5, 6]]) type_spec = type_spec_from_instance(y) self.assertEqual(type_spec, {"type": "array", "shape": (3, 2)})
def test_basic_lindblad_lmult(self): """Test lmult method of Lindblad generator OperatorModel.""" A = Array([[1.0, 2.0], [3.0, 4.0]]) t = 1.123 ham = (2 * np.pi * self.w * self.Z.data / 2 + 2 * np.pi * self.r * np.cos(2 * np.pi * self.w * t) * self.X.data / 2) sm = Array([[0.0, 0.0], [1.0, 0.0]]) expected = self._evaluate_lindblad_rhs(A, ham, [sm]) value = self.basic_lindblad.lmult(t, A.flatten(order="F")) self.assertAllClose(expected, value.reshape(2, 2, order="F"))
def test_multiplication(self): """Tests the multiplication of signals.""" # Test Constant const1 = Constant(0.3) const2 = Constant(0.5) self.assertTrue(isinstance(const1 * const2, Signal)) self.assertEqual((const1 * const2).value(), 0.15) self.assertEqual((const1 * const2).value(10.0), 0.15) # Test Signal signal1 = Signal(3.0, carrier_freq=0.1) signal2 = Signal(lambda t: 2.0 * t ** 2, carrier_freq=0.1) self.assertTrue(isinstance(const1 * signal1, Signal)) self.assertTrue(isinstance(signal1 * const1, Signal)) self.assertTrue(isinstance(signal1 * signal2, Signal)) self.assertEqual((signal1 * signal2).carrier_freq, 0.2) self.assertEqual((signal1 * const1).carrier_freq, 0.1) self.assertEqual((signal1 * signal2).envelope_value(), 0.0) self.assertEqual((signal1 * signal2).envelope_value(3.0), 3.0 * 18.0) self.assertEqual((signal1 * signal2).value(), 0.0) self.assertEqual((signal1 * signal2).value(2.0), 24.0 * np.cos(0.2 * 2.0 * np.pi * 2.0)) # Test piecewise constant dt = 1.0 samples = Array([0.0, 0.0, 1.0, 2.0, 1.0, 0.0, 0.0]) carrier_freq = 0.5 pwc1 = PiecewiseConstant(dt=dt, samples=samples, carrier_freq=carrier_freq) dt = 2.0 samples = Array([0.0, 0.0, 1.0, 2.0, 1.0, 0.0, 0.0]) carrier_freq = 0.1 pwc2 = PiecewiseConstant(dt=dt, samples=samples, carrier_freq=carrier_freq) # Test types self.assertTrue(isinstance(const1 * pwc1, Signal)) self.assertTrue(isinstance(signal1 * pwc1, Signal)) self.assertTrue(isinstance(pwc1 * pwc2, Signal)) self.assertTrue(isinstance(pwc1 * const1, Signal)) self.assertTrue(isinstance(pwc1 * signal1, Signal)) # Test values self.assertEqual((pwc1 * pwc2).carrier_freq, 0.6) self.assertEqual((pwc1 * pwc2).envelope_value(), 0.0) self.assertEqual((pwc1 * pwc2).envelope_value(4.0), 1.0) self.assertEqual((pwc1 * pwc2).value(), 0.0) self.assertEqual((pwc1 * pwc2).value(4.0), 1.0 * np.cos(0.6 * 2.0 * np.pi * 4.0)) # Test phase pwc2 = PiecewiseConstant(dt=dt, samples=samples, carrier_freq=carrier_freq, phase=0.5) self.assertEqual((pwc1 * pwc2).value(4.0), 1.0 * np.cos(0.6 * 2.0 * np.pi * 4.0 + 0.5))
def test_convert_state_order_C(self): """Test convert_state with order parameter 'C'.""" type_spec = {"type": "array", "shape": (4,)} y = Array([[1, 2], [3, 4]]) expected = Array([1, 2, 3, 4]) self.assertAllClose(convert_state(y, type_spec, order="C"), expected) type_spec = {"type": "array"} y = [[1, 2], [3, 4]] expected = Array([[1, 2], [3, 4]]) self.assertAllClose(convert_state(y, type_spec, order="C"), expected)
def setUp(self): self.X = Array(Operator.from_label("X").data) self.Y = Array(Operator.from_label("Y").data) self.Z = Array(Operator.from_label("Z").data) # define a basic hamiltonian w = 2.0 r = 0.5 operators = [2 * np.pi * self.Z / 2, 2 * np.pi * r * self.X / 2] signals = [Constant(w), Signal(1.0, w)] self.w = w self.r = r self.basic_hamiltonian = HamiltonianModel(operators=operators, signals=signals)
def setUp(self): self.t_span = [0.0, 1.0] self.y0 = Array(np.eye(2, dtype=complex)) self.X = Array([[0.0, 1.0], [1.0, 0.0]], dtype=complex) self.Y = Array([[0.0, -1j], [1j, 0.0]], dtype=complex) self.Z = Array([[1.0, 0.0], [0.0, -1.0]], dtype=complex) # simple generator and rhs # pylint: disable=unused-argument def generator(t): return -1j * 2 * np.pi * self.X / 2 self.basic_generator = generator