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 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_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 lmde_y0_reshape(generator_dim: int, y0: Array) -> Array: """Either: G(t)y0 is already well defined, or we assume that y0 is the input state of the more general form of lmde f(t, y) with f linear in y, and we assume the generator has been vectorized in column stacking convention. Args: generator_dim: dimension of the generator y0: input state Return: y0: Appropriately reshaped input state. Raises: QiskitError: If shape of y0 does not conform to any interpretation of the generator dim. """ if y0.shape[0] != generator_dim: if y0.shape[0] * y0.shape[1] == generator_dim: y0 = y0.flatten(order="F") else: raise QiskitError( "y0.shape is incompatible with specified generator.") return y0
def test_lindblad_lmult_pseudorandom(self): """Test lmult of Lindblad OperatorModel with structureless pseudorandom model parameters. """ rng = np.random.default_rng(9848) dim = 10 num_ham = 4 num_diss = 3 b = 1.0 # bound on size of random terms # generate random hamiltonian randoperators = rng.uniform(low=-b, high=b, size=( num_ham, dim, dim)) + 1j * rng.uniform(low=-b, high=b, size=(num_ham, dim, dim)) rand_ham_ops = Array(randoperators + randoperators.conj().transpose([0, 2, 1])) # generate random hamiltonian coefficients rand_ham_coeffs = rng.uniform(low=-b, high=b, size=( num_ham)) + 1j * rng.uniform(low=-b, high=b, size=(num_ham)) rand_ham_carriers = Array(rng.uniform(low=-b, high=b, size=(num_ham))) rand_ham_phases = Array(rng.uniform(low=-b, high=b, size=(num_ham))) ham_sigs = VectorSignal(lambda t: rand_ham_coeffs, rand_ham_carriers, rand_ham_phases) # generate random dissipators rand_diss = Array( rng.uniform(low=-b, high=b, size=(num_diss, dim, dim)) + 1j * rng.uniform(low=-b, high=b, size=(num_diss, dim, dim))) # random dissipator coefficients rand_diss_coeffs = rng.uniform(low=-b, high=b, size=( num_diss)) + 1j * rng.uniform(low=-b, high=b, size=(num_diss)) rand_diss_carriers = Array(rng.uniform(low=-b, high=b, size=(num_diss))) rand_diss_phases = Array(rng.uniform(low=-b, high=b, size=(num_diss))) diss_sigs = VectorSignal(lambda t: rand_diss_coeffs, rand_diss_carriers, rand_diss_phases) # random anti-hermitian frame operator rand_op = rng.uniform(low=-b, high=b, size=( dim, dim)) + 1j * rng.uniform(low=-b, high=b, size=(dim, dim)) frame_op = Array(rand_op - rand_op.conj().transpose()) lindblad_frame_op = np.kron(Array(np.eye(dim)), frame_op) - np.kron( frame_op.transpose(), Array(np.eye(dim))) # construct model hamiltonian = HamiltonianModel(operators=rand_ham_ops, signals=ham_sigs) lindblad_model = LindbladModel.from_hamiltonian( hamiltonian=hamiltonian, noise_operators=rand_diss, noise_signals=diss_sigs) lindblad_model.frame = lindblad_frame_op A = Array( rng.uniform(low=-b, high=b, size=(dim, dim)) + 1j * rng.uniform(low=-b, high=b, size=(dim, dim))) t = rng.uniform(low=-b, high=b) value = lindblad_model.lmult(t, A.flatten(order="F")) ham_coeffs = np.real(rand_ham_coeffs * np.exp(1j * 2 * np.pi * rand_ham_carriers * t + 1j * rand_ham_phases)) ham = np.tensordot(ham_coeffs, rand_ham_ops, axes=1) diss_coeffs = np.real(rand_diss_coeffs * np.exp(1j * 2 * np.pi * rand_diss_carriers * t + 1j * rand_diss_phases)) expected = self._evaluate_lindblad_rhs(A, ham, rand_diss, diss_coeffs, frame_op, t) self.assertAllClose(expected, value.reshape(dim, dim, order="F"))