示例#1
0
 def test_moment_preservation(self):
     """Test Moment-structure preservation."""
     t = sympy.Symbol('t')
     r = sympy.Symbol('r')
     qubits = cirq.GridQubit.rect(1, 6)
     circuit_batch = [
         cirq.Circuit(
             cirq.Moment([cirq.H(q) for q in qubits]),
             cirq.Moment([
                 cirq.X(qubits[4]),
                 cirq.PhasedXPowGate(phase_exponent=np.random.random() *
                                     t).on(qubits[5]),
                 cirq.ISwapPowGate(exponent=np.random.random() * t).on(
                     qubits[0], qubits[1]),
                 cirq.FSimGate(theta=np.random.random() * t,
                               phi=np.random.random() * r).on(
                                   qubits[2], qubits[3])
             ]), cirq.Moment([cirq.H(q) for q in qubits]))
     ]
     inputs = util.convert_to_tensor(circuit_batch)
     outputs = tfq_ps_util_ops.tfq_ps_decompose(inputs)
     decomposed_programs = util.from_tensor(outputs)
     # Now all programs don't have ISWAP & PhasedXPowGate because ISWAP has
     # 3 eigenvalues and PhasedXPowGate doesn't have _eigen_components.
     # Check if two programs are identical.
     rand_resolver = {'t': np.random.random(), 'r': np.random.random()}
     self.assertAllClose(cirq.unitary(
         cirq.resolve_parameters(circuit_batch[0], rand_resolver)),
                         cirq.unitary(
                             cirq.resolve_parameters(decomposed_programs[0],
                                                     rand_resolver)),
                         atol=1e-5)
     # Check if the Moments are conserved.
     max_decomposed_length = 3
     n_non_decomposed_moments = 2
     self.assertEqual(len(decomposed_programs[0]),
                      n_non_decomposed_moments + max_decomposed_length)
     # Total length of Moments = 5
     # The non-decomposed moments should be the same.
     self.assertEqual(decomposed_programs[0][0], circuit_batch[0][0])
     self.assertEqual(decomposed_programs[0][-1], circuit_batch[0][-1])
     # Check paralellized decompose gates in Moment[1]~[3].
     # The target ops are replaced by the first decomposition gates. It means
     # the first Moment has exactly the same number of gate ops.
     self.assertEqual(len(decomposed_programs[0][1]),
                      len(circuit_batch[0][1]))
     # From the second Moments, the Moments only have decomposition gates.
     # In this example, two ISwapPowGate & one PhasedXPowGate are located.
     # Since PhasedXPowGate, ISwapPowGate, FSimGate has 3, 2, 3 result gates
     # Moment[2] have 3 gate ops and Moment[3] have 2 gate ops.
     self.assertEqual(len(decomposed_programs[0][2]), 3)
     self.assertEqual(len(decomposed_programs[0][3]), 2)
示例#2
0
 def test_iswap_gate_test(self):
     """Test 1 ISwapPowGate decomposition."""
     t = sympy.Symbol('t')
     qubits = cirq.GridQubit.rect(1, 2)
     circuit = cirq.Circuit(
         cirq.ISwapPowGate(exponent=np.random.random() * t).on(*qubits))
     inputs = util.convert_to_tensor([circuit])
     outputs = tfq_ps_util_ops.tfq_ps_decompose(inputs)
     decomposed_programs = util.from_tensor(outputs)
     rand_resolver = {'t': np.random.random()}
     self.assertAllClose(cirq.unitary(
         cirq.resolve_parameters(circuit, rand_resolver)),
                         cirq.unitary(
                             cirq.resolve_parameters(decomposed_programs[0],
                                                     rand_resolver)),
                         atol=1e-5)
    def test_more_complex_moment_preservation(self):
        """Test Moment-structure preservation."""
        circuit_batch = _complex_test_circuit()
        inputs = util.convert_to_tensor(circuit_batch)
        outputs = tfq_ps_util_ops.tfq_ps_decompose(inputs)
        decomposed_programs = util.from_tensor(outputs)
        # Now all programs don't have ISWAP & PhasedXPowGate because ISWAP has
        # 3 eigenvalues and PhasedXPowGate doesn't have _eigen_components.
        # Check if two programs are identical.
        rand_resolver = {'t': np.random.random(), 'r': np.random.random()}
        for i in range(3):
            self.assertAllClose(cirq.unitary(
                cirq.resolve_parameters(circuit_batch[i], rand_resolver)),
                                cirq.unitary(
                                    cirq.resolve_parameters(
                                        decomposed_programs[i],
                                        rand_resolver)),
                                atol=1e-5)
        # Check if the Moments are conserved.
        # Circuit 1.
        max_decomposed_length = 3
        n_non_decomposed_moments = 2
        self.assertEqual(len(decomposed_programs[0]),
                         n_non_decomposed_moments + max_decomposed_length)
        # Total length of Moments = 5
        # The non-decomposed moments should be the same.
        self.assertEqual(decomposed_programs[0][0], circuit_batch[0][0])
        self.assertEqual(decomposed_programs[0][-1], circuit_batch[0][-1])
        # Check paralellized decompose gates in Moment[1]~[3].
        # The target ops are replaced by the first decomposition gates. It means
        # the first Moment has exactly the same number of gate ops.
        self.assertEqual(len(decomposed_programs[0][1]),
                         len(circuit_batch[0][1]))
        # From the second Moments, the Moments only have decomposition gates.
        # In this example, two ISwapPowGate & one PhasedXPowGate are located.
        # Since PhasedXPowGate, ISwapPowGate, FSimGate has 3, 2, 3 result gates
        # Moment[2] have 3 gate ops and Moment[3] have 2 gate ops.
        self.assertEqual(len(decomposed_programs[0][2]), 3)
        self.assertEqual(len(decomposed_programs[0][3]), 2)

        # Circuit 2. two FSimGates.
        self.assertEqual(len(decomposed_programs[1]),
                         2 * max_decomposed_length)

        # Circuit 3. one PXP between two ISwapPowGates.
        self.assertEqual(len(decomposed_programs[2]), max_decomposed_length)
示例#4
0
 def test_phased_x_pow_gate_test(self):
     """Test 1 PhasedXPowGate decomposition."""
     t = sympy.Symbol('t')
     r = sympy.Symbol('r')
     q = cirq.GridQubit(0, 0)
     circuit = cirq.Circuit(
         cirq.PhasedXPowGate(phase_exponent=np.random.random() * r,
                             exponent=np.random.random() * t).on(q))
     inputs = util.convert_to_tensor([circuit])
     outputs = tfq_ps_util_ops.tfq_ps_decompose(inputs)
     decomposed_programs = util.from_tensor(outputs)
     rand_resolver = {'t': np.random.random(), 'r': np.random.random()}
     self.assertAllClose(cirq.unitary(
         cirq.resolve_parameters(circuit, rand_resolver)),
                         cirq.unitary(
                             cirq.resolve_parameters(decomposed_programs[0],
                                                     rand_resolver)),
                         atol=1e-5)
示例#5
0
    def test_decompose_with_complex_circuit(self):
        """Test decompose with complex circuit."""
        names = ['CLAE', 'HRYV', 'IRKB', 'LKRV', 'PJOU', 'CJKX', 'NASW']
        # Test circuit has a Moment with 1) FSimGate & PhasedXPowGate,
        # 2) PhasedXPowGate & ISwapPowGate and 3) FSimGate & ISwapPowGate.
        # Be careful, they are not decomposed if not parameterized.
        circuit_batch = [
            cirq.Circuit([
                cirq.Moment(operations=[
                    cirq.FSimGate(theta=0.10338130973488413 *
                                  sympy.Symbol('CLAE'),
                                  phi=0.10338130973488413 *
                                  sympy.Symbol('IRKB')).
                    on(cirq.GridQubit(0, 2), cirq.GridQubit(0, 3)),
                    cirq.PhasedXPowGate(phase_exponent=1.0,
                                        exponent=0.86426029696045281 *
                                        sympy.Symbol('HRYV')).on(
                                            cirq.GridQubit(0, 1)),
                ]),
                cirq.Moment(operations=[
                    cirq.Y.on(cirq.GridQubit(0, 3)),
                    cirq.Z.on(cirq.GridQubit(0, 0)),
                    cirq.FSimGate(theta=1, phi=1).on(cirq.GridQubit(0, 1),
                                                     cirq.GridQubit(0, 2)),
                ]),
                cirq.Moment(operations=[
                    (cirq.CNOT**(0.92874230274398684 * sympy.Symbol('IRKB'))
                    ).on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 2)),
                ]),
                cirq.Moment(operations=[
                    cirq.PhasedXPowGate(phase_exponent=sympy.Symbol('PJOU'),
                                        exponent=0.2081415255258906 *
                                        sympy.Symbol('LKRV')).on(
                                            cirq.GridQubit(0, 2)),
                    (cirq.ISWAP**(0.32860954996781722 * sympy.Symbol('PJOU'))
                    ).on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 3)),
                ]),
                cirq.Moment(operations=[
                    cirq.PhasedXPowGate(phase_exponent=sympy.Symbol('CJKX')).on(
                        cirq.GridQubit(0, 1)),
                    cirq.ZZ.on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 3)),
                    (cirq.X**(0.6826594585474709 *
                              sympy.Symbol('HRYV'))).on(cirq.GridQubit(0, 2)),
                ]),
                cirq.Moment(operations=[
                    (cirq.ZZ**(0.18781276022427218 * sympy.Symbol('PJOU'))
                    ).on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 3)),
                ]),
                cirq.Moment(operations=[
                    cirq.Y.on(cirq.GridQubit(0, 0)),
                ]),
                cirq.Moment(operations=[
                    cirq.FSimGate(theta=0.13793763138552417 *
                                  sympy.Symbol('CJKX'),
                                  phi=0.13793763138552417 *
                                  sympy.Symbol('PJOU')).
                    on(cirq.GridQubit(0, 2), cirq.GridQubit(0, 3)),
                    (cirq.ISWAP**(0.028165738453673095 * sympy.Symbol('NASW'))
                    ).on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)),
                ]),
                cirq.Moment(operations=[
                    cirq.FSimGate(theta=0.74356520426349459 *
                                  sympy.Symbol('CJKX'),
                                  phi=0.74356520426349459 *
                                  sympy.Symbol('NASW')).
                    on(cirq.GridQubit(0, 3), cirq.GridQubit(0, 0)),
                ]),
                cirq.Moment(operations=[
                    cirq.CNOT.on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 2)),
                    cirq.SWAP.on(cirq.GridQubit(0, 3), cirq.GridQubit(0, 1)),
                ]),
                cirq.Moment(operations=[
                    cirq.H.on(cirq.GridQubit(0, 3)),
                    cirq.H.on(cirq.GridQubit(0, 2)),
                    cirq.CNOT.on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 0)),
                ]),
                cirq.Moment(operations=[
                    cirq.CNOT.on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)),
                    cirq.YY.on(cirq.GridQubit(0, 2), cirq.GridQubit(0, 3)),
                ]),
                cirq.Moment(operations=[
                    cirq.CZ.on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 0)),
                    cirq.CNOT.on(cirq.GridQubit(0, 2), cirq.GridQubit(0, 3)),
                ]),
                cirq.Moment(operations=[
                    cirq.FSimGate(theta=1, phi=1).on(cirq.GridQubit(0, 0),
                                                     cirq.GridQubit(0, 2)),
                    cirq.CNOT.on(cirq.GridQubit(0, 3), cirq.GridQubit(0, 1)),
                ]),
                cirq.Moment(operations=[
                    cirq.FSimGate(theta=1, phi=1).on(cirq.GridQubit(0, 0),
                                                     cirq.GridQubit(0, 3)),
                    cirq.SWAP.on(cirq.GridQubit(0, 2), cirq.GridQubit(0, 1)),
                ]),
                cirq.Moment(operations=[
                    cirq.Y.on(cirq.GridQubit(0, 0)),
                    cirq.PhasedXPowGate(
                        phase_exponent=1.0).on(cirq.GridQubit(0, 2)),
                    cirq.FSimGate(theta=1, phi=1).on(cirq.GridQubit(0, 1),
                                                     cirq.GridQubit(0, 3)),
                ]),
            ])
        ]

        # Decompose programs.
        inputs = util.convert_to_tensor(circuit_batch)
        outputs = tfq_ps_util_ops.tfq_ps_decompose(inputs)
        decomposed_programs = util.from_tensor(outputs)
        self.assertEqual(len(decomposed_programs), len(circuit_batch))

        # Original programs has parameterized ISP, PXP, FSIM, but this result
        # has no such gates at all. All parameterized gates have at most two
        # eigenvalues. There are still ISwap and PhasedX(1.0) because they are
        # not parameterized, which doesn't affect ParameterShift differentiation
        # at all.
        for program in decomposed_programs:
            for moment in program:
                for gate_op in moment:
                    # Consider parameterized gates only
                    if cirq.is_parameterized(gate_op.gate):
                        # Check I. The gate should have _eigen_components.
                        self.assertTrue(
                            hasattr(gate_op.gate, '_eigen_components'))
                        # Check II. The gate should have two eigen values.
                        self.assertEqual(len(gate_op.gate._eigen_components()),
                                         2, gate_op.gate)
        # Now all programs don't have ISWAP & PhasedXPowGate because ISWAP has
        # 3 eigenvalues and PhasedXPowGate doesn't have _eigen_components.
        # Check if two programs are identical.
        rand_resolver = {name: np.random.random() for name in names}
        self.assertAllClose(cirq.unitary(
            cirq.resolve_parameters(circuit_batch[0], rand_resolver)),
                            cirq.unitary(
                                cirq.resolve_parameters(decomposed_programs[0],
                                                        rand_resolver)),
                            atol=1e-5)
def parse_programs(programs,
                   symbol_names,
                   symbol_values,
                   n_symbols,
                   n_shifts=2):
    """Helper function to get parameter-shifted programs after parsing programs.


    It follows:
    1. Decomposes given programs with `tfq_ps_decompose` c++ op.
    2. Construct new_programs with parameter-shifted copies of decomposed
        programs by `tfq_ps_symbol_replace` c++ op.
    3. Weights and shifts are also obtained by `tfq_ps_weights_from_symbols`
    3. Transpose the results to fed them into TensorFlow Quantum simulator.

    Args:
        programs: `tf.Tensor` of strings with shape [n_programs] containing
            the string representations of the circuits to be executed.
        symbol_names: `tf.Tensor` of strings with shape [n_symbols], which
            is used to specify the order in which the values in
            `symbol_values` should be placed inside of the circuits in
            `programs`.
        symbol_values: `tf.Tensor` of real numbers with shape
            [n_programs, n_symbols] specifying parameter values to resolve
            into the circuits specified by programs, following the ordering
            dictated by `symbol_names`.
        n_symbols: `tf.Tensor` of a positive integer representing the number of
            symbols.
        n_shifts: `tf.Tensor` of a positive integer representing the number of
            parameter-shift terms. Defaults to 2.

    Returns:
        new_programs: the new programs whose program has only one gate with
            impurity parameter-shift symbol name.
            [n_symbols, n_programs, n_param_gates, n_shifts]
        weights: parameter-shift coefficients of estimated observables.
            [n_symbols, n_programs, n_param_gates, n_shifts]
        shifts: parameter-shifted values (= matrix of symbol_values +/-shift)
            [n_symbols, n_programs, n_param_gates, n_shifts]
        n_param_gates: bypass of input n_param_gates to export it outside
    """
    decomposed_programs = tfq_ps_util_ops.tfq_ps_decompose(programs)
    delta_eig = 2.0

    # Collecting doped programs with impurity sympy.Symbol from all programs
    # with parameterized gates.
    impurity = tf.tile(tf.convert_to_tensor([PARAMETER_IMPURITY_NAME]),
                       [n_symbols])
    symbols = tf.convert_to_tensor(symbol_names)

    # Doping impurity sympy.Symbol into programs per gate per symbol.
    new_programs = tf.tile(
        tf.expand_dims(tf.transpose(
            tfq_ps_util_ops.tfq_ps_symbol_replace(decomposed_programs, symbols,
                                                  impurity), [1, 0, 2]),
                       axis=-1), [1, 1, 1, n_shifts])
    n_param_gates = tf.cast(tf.gather(tf.shape(new_programs), 2),
                            dtype=tf.int32)

    # This is a tensor of the `exponent_scalar`s of the shifted gates.
    coeff = tf.expand_dims(tf.transpose(
        tfq_ps_util_ops.tfq_ps_weights_from_symbols(decomposed_programs,
                                                    symbols), [1, 0, 2]),
                           axis=-1)

    weights_plus = coeff * np.pi * 0.5 * 0.5 * delta_eig
    weights = tf.concat([weights_plus, -weights_plus], axis=-1)
    shifts_plus = tf.math.divide_no_nan(tf.math.divide(1.0, delta_eig), coeff)

    val = tf.tile(
        tf.expand_dims(tf.expand_dims(tf.transpose(symbol_values, [1, 0]),
                                      axis=-1),
                       axis=-1), [1, 1, n_param_gates, n_shifts])

    shifts = val + tf.concat([shifts_plus, -shifts_plus], axis=-1)

    return new_programs, weights, shifts, n_param_gates