예제 #1
0
    def test_addcircuit_op_error(self):
        """Test that addcircuit will error inside of ops correctly."""
        add = elementary.AddCircuit()
        circuit = cirq.Circuit(cirq.X(cirq.GridQubit(0, 0)))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex="matching sizes"):
            # append is wrong shape.
            add(circuit, append=[circuit, circuit])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex="matching sizes"):
            # prepend is wrong shape.
            add(circuit, prepend=[circuit, circuit])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex="rank 1"):
            # prepend is wrong shape.
            add(circuit, prepend=[[circuit]])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex="rank 1"):
            # append is wrong shape.
            add(circuit, append=[[circuit]])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex="rank 1"):
            # circuit is wrong shape.
            add([[circuit]], append=[circuit])
예제 #2
0
 def test_addcircuit_simple_inputs(self):
     """Test the valid cases."""
     add = elementary.AddCircuit()
     circuit = cirq.Circuit(
         cirq.X(cirq.GridQubit(0, 0))**(sympy.Symbol('alpha') * sympy.pi))
     add([circuit, circuit], append=circuit)
     add([circuit, circuit], prepend=circuit)
     add(circuit, append=circuit)
     add(circuit, prepend=circuit)
예제 #3
0
    def test_addcircuit_modify(self):
        """Test that a addcircuit layer correctly modifies input circuits."""
        bits = cirq.GridQubit.rect(1, 20)
        circuit_a = cirq.testing.random_circuit(bits, 10, 0.9,
                                                util.get_supported_gates())
        circuit_b = cirq.testing.random_circuit(bits, 10, 0.9,
                                                util.get_supported_gates())

        expected_append = util.convert_to_tensor([circuit_a + circuit_b])
        expected_prepend = util.convert_to_tensor([circuit_b + circuit_a])

        append_layer = elementary.AddCircuit()
        prepend_layer = elementary.AddCircuit()

        actual_append = util.convert_to_tensor(
            util.from_tensor(append_layer(circuit_a, append=circuit_b)))
        actual_prepend = util.convert_to_tensor(
            util.from_tensor(prepend_layer(circuit_a, prepend=circuit_b)))

        self.assertEqual(expected_append.numpy()[0], actual_append.numpy()[0])
        self.assertEqual(expected_prepend.numpy()[0],
                         actual_prepend.numpy()[0])
예제 #4
0
    def test_addcircuit_keras_error(self):
        """Test that addcircuit layer errors in keras call."""
        add = elementary.AddCircuit()
        circuit = cirq.Circuit(cirq.X(cirq.GridQubit(0, 0)))

        with self.assertRaisesRegex(TypeError,
                                    expected_regex="cannot be parsed"):
            add(circuit, append='junk')

        with self.assertRaisesRegex(TypeError,
                                    expected_regex="cannot be parsed"):
            add(circuit, prepend='junk')

        with self.assertRaisesRegex(TypeError,
                                    expected_regex="cannot be parsed"):
            add('junk', prepend=circuit)

        with self.assertRaisesRegex(ValueError,
                                    expected_regex="append or prepend"):
            add(circuit)

        with self.assertRaisesRegex(ValueError,
                                    expected_regex="append and prepend"):
            add(circuit, append=circuit, prepend=circuit)
예제 #5
0
    def __init__(
        self,
        model_circuit,
        operators,
        *,
        repetitions=None,
        backend='noiseless',
        differentiator=None,
        initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi),
        regularizer=None,
        constraint=None,
        **kwargs,
    ):
        """Instantiate this layer.

        Create a layer that will output expectation values of the given
        operators when fed quantum data to it's input layer. This layer will
        accept one input tensor representing a quantum data source (these
        circuits must not contain any symbols) and append the model_circuit to
        them, execute them and then finally output the expectation values.


        model_circuit: `cirq.Circuit` containing `sympy.Symbols` that will be
            used as the model which will be fed quantum data inputs.
        operators: `cirq.PauliSum` or Python `list` of `cirq.PauliSum` objects
            used as observables at the end of the model circuit.
        repetitions: Optional Python `int` indicating how many samples to use
            when estimating expectation values.  If `None` analytic expectation
            calculation is used.
        backend: Optional Backend to use to simulate states. Defaults to
            the noiseless TensorFlow simulator, however users may also
            specify a preconfigured cirq simulation object to use instead.
            If a cirq object is given it must inherit either
            `cirq.sim.simulator.SimulatesExpectationValues` if analytic
            expectations are desired or `cirq.Sampler` if sampled expectations
            are desired.
        differentiator: Optional `tfq.differentiator` object to specify how
            gradients of `model_circuit` should be calculated.
        initializer: Optional `tf.keras.initializer` object to specify how the
            symbols in `model_circuit` should be initialized when creating
            the managed variables.
        regularizer: Optional `tf.keras.regularizer` object applied to the
            managed variables parameterizing `model_circuit`.
        constraint: Optional `tf.keras.constraint` object applied to the
            managed variables parameterizing `model_circuit`.
        """
        super().__init__(**kwargs)

        # Ingest model_circuit.
        if not isinstance(model_circuit, cirq.Circuit):
            raise TypeError("model_circuit must be a cirq.Circuit object."
                            " Given: {}".format(model_circuit))

        self._symbols_list = list(
            sorted(util.get_circuit_symbols(model_circuit)))
        self._symbols = tf.constant([str(x) for x in self._symbols_list])

        self._model_circuit = util.convert_to_tensor([model_circuit])
        if len(self._symbols_list) == 0:
            raise ValueError("model_circuit has no sympy.Symbols. Please "
                             "provide a circuit that contains symbols so "
                             "that their values can be trained.")

        # Ingest operators.
        if isinstance(operators, (cirq.PauliString, cirq.PauliSum)):
            operators = [operators]
        if not isinstance(operators, (list, np.ndarray, tuple)):
            raise TypeError("operators must be a cirq.PauliSum or "
                            "cirq.PauliString, or a list, tuple, "
                            "or np.array containing them. "
                            "Got {}.".format(type(operators)))
        if not all([
                isinstance(op, (cirq.PauliString, cirq.PauliSum))
                for op in operators
        ]):
            raise TypeError("Each element in operators to measure "
                            "must be a cirq.PauliString"
                            " or cirq.PauliSum")
        self._operators = util.convert_to_tensor([operators])

        # Ingest and promote repetitions.
        self._analytic = False
        if repetitions is None:
            self._analytic = True
        if not self._analytic and not isinstance(repetitions,
                                                 numbers.Integral):
            raise TypeError("repetitions must be a positive integer value."
                            " Given: ".format(repetitions))
        if not self._analytic and repetitions <= 0:
            raise ValueError("Repetitions must be greater than zero.")
        if not self._analytic:
            self._repetitions = tf.constant(
                [[repetitions for _ in range(len(operators))]],
                dtype=tf.dtypes.int32)

        # Set backend and differentiator.
        if backend == 'noisy':
            raise ValueError("noisy backend value is not supported in "
                             "tfq.layers.PQC. Please use tfq.layers.NoisyPQC "
                             "instead.")

        not_default = backend is not 'noiseless'
        not_default &= backend is not None  # legacy backend=None support.
        if not isinstance(
                backend,
                cirq.Sampler) and repetitions is not None and not_default:
            raise TypeError("provided backend does not inherit cirq.Sampler "
                            "and repetitions!=None. Please provide a backend "
                            "that inherits cirq.Sampler or set "
                            "repetitions=None.")
        if not isinstance(backend,
                          cirq.sim.simulator.SimulatesExpectationValues
                          ) and repetitions is None and not_default:
            raise TypeError(
                "provided backend does not inherit "
                "cirq.sim.simulator.SimulatesExpectationValues and "
                "repetitions=None. Please provide a backend that "
                "inherits "
                "cirq.sim.simulator.SimulatesExpectationValues.")
        if self._analytic:
            self._executor = expectation.Expectation(
                backend=backend, differentiator=differentiator)
        else:
            self._executor = sampled_expectation.SampledExpectation(
                backend=backend, differentiator=differentiator)

        self._append_layer = elementary.AddCircuit()

        # Set additional parameter controls.
        self.initializer = tf.keras.initializers.get(initializer)
        self.regularizer = tf.keras.regularizers.get(regularizer)
        self.constraint = tf.keras.constraints.get(constraint)

        # Weight creation is not placed in a Build function because the number
        # of weights is independent of the input shape.
        self.parameters = self.add_weight('parameters',
                                          shape=self._symbols.shape,
                                          initializer=self.initializer,
                                          regularizer=self.regularizer,
                                          constraint=self.constraint,
                                          dtype=tf.float32,
                                          trainable=True)
예제 #6
0
 def test_addcircuit_instantiate(self):
     """Test that a addcircuit layer can be instantiated correctly."""
     elementary.AddCircuit()
예제 #7
0
    def __init__(self,
                 model_circuit,
                 operators,
                 *,
                 repetitions=None,
                 backend=None,
                 differentiator=None,
                 **kwargs):
        """Instantiate this layer.

        Create a layer that will output expectation values of the given
        operators when fed quantum data to it's input layer. This layer will
        take two input tensors, one representing a quantum data source (these
        circuits must not contain any symbols) and the other representing
        control parameters for the model circuit that gets appended to the
        datapoints.

        model_circuit: `cirq.Circuit` containing `sympy.Symbols` that will be
            used as the model which will be fed quantum data inputs.
        operators: `cirq.PauliSum` or Python `list` of `cirq.PauliSum` objects
            used as observables at the end of the model circuit.
        repetitions: Optional Python `int` indicating how many samples to use
            when estimating expectation values. If `None` analytic expectation
            calculation is used.
        backend: Optional Backend to use to simulate states. Defaults to
            the native TensorFlow simulator (None), however users may also
            specify a preconfigured cirq simulation object to use instead.
            If a cirq object is given it must inherit `cirq.SimulatesFinalState`
            if `sampled_based` is True or it must inherit `cirq.Sampler` if
            `sample_based` is False.
        differentiator: Optional `tfq.differentiator` object to specify how
            gradients of `model_circuit` should be calculated.
        """
        super().__init__(**kwargs)
        # Ingest model_circuit.
        if not isinstance(model_circuit, cirq.Circuit):
            raise TypeError("model_circuit must be a cirq.Circuit object."
                            " Given: ".format(model_circuit))

        self._symbols_list = list(
            sorted(util.get_circuit_symbols(model_circuit)))
        self._symbols = tf.constant([str(x) for x in self._symbols_list])

        self._circuit = util.convert_to_tensor([model_circuit])

        if len(self._symbols_list) == 0:
            raise ValueError("model_circuit has no sympy.Symbols. Please "
                             "provide a circuit that contains symbols so "
                             "that their values can be trained.")

        # Ingest operators.
        if isinstance(operators, (cirq.PauliString, cirq.PauliSum)):
            operators = [operators]

        if not isinstance(operators, (list, np.ndarray, tuple)):
            raise TypeError("operators must be a cirq.PauliSum or "
                            "cirq.PauliString, or a list, tuple, "
                            "or np.array containing them. "
                            "Got {}.".format(type(operators)))
        if not all([
                isinstance(op, (cirq.PauliString, cirq.PauliSum))
                for op in operators
        ]):
            raise TypeError("Each element in operators to measure "
                            "must be a cirq.PauliString"
                            " or cirq.PauliSum")

        self._operators = util.convert_to_tensor([operators])

        # Ingest and promote reptitions.
        self._analytic = False
        if repetitions is None:
            self._analytic = True

        if not self._analytic and not isinstance(repetitions,
                                                 numbers.Integral):
            raise TypeError("repetitions must be a positive integer value."
                            " Given: ".format(repetitions))

        if not self._analytic and repetitions <= 0:
            raise ValueError("Repetitions must be greater than zero.")

        if not self._analytic:
            self._repetitions = tf.constant(
                [[repetitions for _ in range(len(operators))]],
                dtype=tf.dtypes.int32)

        if not isinstance(
                backend, cirq.Sampler
        ) and repetitions is not None and backend is not None:
            raise TypeError("provided backend does not inherit cirq.Sampler "
                            "and repetitions!=None. Please provide a backend "
                            "that inherits cirq.Sampler or set "
                            "repetitions=None.")

        if not isinstance(backend, cirq.SimulatesFinalState
                          ) and repetitions is None and backend is not None:
            raise TypeError("provided backend does not inherit "
                            "cirq.SimulatesFinalState and repetitions=None. "
                            "Please provide a backend that inherits "
                            "cirq.SimulatesFinalState.")

        # Ingest backend and differentiator.
        if self._analytic:
            self._layer = expectation.Expectation(
                backend=backend, differentiator=differentiator)
        else:
            self._layer = sampled_expectation.SampledExpectation(
                backend=backend, differentiator=differentiator)

        self._append_layer = elementary.AddCircuit()
예제 #8
0
    def __init__(self,
                 model_circuit,
                 operators,
                 *,
                 repetitions=None,
                 sample_based=None,
                 differentiator=None,
                 **kwargs):
        """Instantiate this layer.

        Create a layer that will output noisy expectation values of the given
        operators when fed quantum data to it's input layer. This layer will
        take two input tensors, one representing a quantum data source (these
        circuits must not contain any symbols) and the other representing
        control parameters for the model circuit that gets appended to the
        datapoints.

        model_circuit: `cirq.Circuit` containing `sympy.Symbols` that will be
            used as the model which will be fed quantum data inputs.
        operators: `cirq.PauliSum` or Python `list` of `cirq.PauliSum` objects
            used as observables at the end of the model circuit.
        repetitions: Python `int` indicating how many trajectories to use
            when estimating expectation values.
        sample_based: Python `bool` indicating whether to use sampling to
            estimate expectations or analytic calculations with each
            trajectory.
        differentiator: Optional `tfq.differentiator` object to specify how
            gradients of `model_circuit` should be calculated.
        """
        super().__init__(**kwargs)
        # Ingest model_circuit.
        if not isinstance(model_circuit, cirq.Circuit):
            raise TypeError("model_circuit must be a cirq.Circuit object."
                            " Given: ".format(model_circuit))

        self._symbols_list = list(
            sorted(util.get_circuit_symbols(model_circuit)))
        self._symbols = tf.constant([str(x) for x in self._symbols_list])

        self._circuit = util.convert_to_tensor([model_circuit])

        if len(self._symbols_list) == 0:
            raise ValueError("model_circuit has no sympy.Symbols. Please "
                             "provide a circuit that contains symbols so "
                             "that their values can be trained.")

        # Ingest operators.
        if isinstance(operators, (cirq.PauliString, cirq.PauliSum)):
            operators = [operators]

        if not isinstance(operators, (list, np.ndarray, tuple)):
            raise TypeError("operators must be a cirq.PauliSum or "
                            "cirq.PauliString, or a list, tuple, "
                            "or np.array containing them. "
                            "Got {}.".format(type(operators)))
        if not all([
                isinstance(op, (cirq.PauliString, cirq.PauliSum))
                for op in operators
        ]):
            raise TypeError("Each element in operators to measure "
                            "must be a cirq.PauliString"
                            " or cirq.PauliSum")

        self._operators = util.convert_to_tensor([operators])

        # Ingest and promote repetitions.
        if repetitions is None:
            raise ValueError("Value for repetitions must be provided when "
                             "using noisy simulation.")
        if not isinstance(repetitions, numbers.Integral):
            raise TypeError("repetitions must be a positive integer value."
                            " Given: ".format(repetitions))
        if repetitions <= 0:
            raise ValueError("Repetitions must be greater than zero.")

        self._repetitions = tf.constant(
            [[repetitions for _ in range(len(operators))]],
            dtype=tf.dtypes.int32)

        # Ingest differentiator.
        if differentiator is None:
            differentiator = parameter_shift.ParameterShift()

        # Ingest and promote sample based.
        if sample_based is None:
            raise ValueError("Please specify sample_based=False for analytic "
                             "calculations based on monte-carlo trajectories,"
                             " or sampled_based=True for measurement based "
                             "noisy estimates.")
        if not isinstance(sample_based, bool):
            raise TypeError("sample_based must be either True or False."
                            " received: {}".format(type(sample_based)))

        if not sample_based:
            self._executor = differentiator.generate_differentiable_op(
                sampled_op=noisy_expectation_op.expectation)
        else:
            self._executor = differentiator.generate_differentiable_op(
                sampled_op=noisy_sampled_expectation_op.sampled_expectation)

        self._append_layer = elementary.AddCircuit()