def serialize_paulisum(paulisum): """Constructs a pauli_sum proto from `cirq.PauliSum` or `cirq.PauliString`. Args: paulisum: A `cirq.PauliSum` object. Returns: A pauli_sum proto object. """ if isinstance(paulisum, cirq.PauliString): paulisum = cirq.PauliSum.from_pauli_strings(paulisum) if not isinstance(paulisum, cirq.PauliSum): raise TypeError("serialize requires a cirq.PauliSum object." " Given: " + str(type(paulisum))) if any(not isinstance(qubit, cirq.GridQubit) for qubit in paulisum.qubits): raise ValueError("Attempted to serialize a paulisum that doesn't use " "only cirq.GridQubits.") paulisum_proto = pauli_sum_pb2.PauliSum() for term in paulisum: pauliterm_proto = pauli_sum_pb2.PauliTerm() pauliterm_proto.coefficient_real = term.coefficient.real pauliterm_proto.coefficient_imag = term.coefficient.imag for t in sorted(term.items()): # sort to keep qubits ordered. pauliterm_proto.paulis.add( qubit_id=v2.qubit_to_proto_id(t[0]), pauli_type=str(t[1]), ) paulisum_proto.terms.extend([pauliterm_proto]) return paulisum_proto
def _build_pauli_proto(coefs, ops, qubit_ids): """Construct pauli_sum proto explicitly.""" terms = [] for i in range(len(coefs)): term = pauli_sum_pb2.PauliTerm() term.coefficient_real = coefs[i].real term.coefficient_imag = coefs[i].imag for j in range(len(qubit_ids[i])): term.paulis.add(qubit_id=qubit_ids[i][j], pauli_type=ops[i][j]) terms.append(term) a = pauli_sum_pb2.PauliSum() a.terms.extend(terms) return a
def _parse_single(item): try: if b'tfq_gate_set' in item: # Return a circuit parsing obj = cirq.google.api.v2.program_pb2.Program() obj.ParseFromString(item) out = serializer.deserialize_circuit(obj) return out # Return a PauliSum parsing. obj = pauli_sum_pb2.PauliSum() obj.ParseFromString(item) out = serializer.deserialize_paulisum(obj) return out except Exception: raise TypeError('Error decoding item: ' + str(item))
def cirq_sampled_expectation(programs, symbol_names, symbol_values, pauli_sums, num_samples): """Calculate the sampled expectation value of circuits wrt some operator(s). Estimates the expectation value for all the `cirq.PauliSum`s in `pauli_sums` on each `cirq.Circuit` in `programs`. Each circuit will have the values in `symbol_values` resolved into the symbols in the circuit (with the ordering defined by `symbol_names`). ```python symbol_names = ['a', 'b', 'c'] programs = tfq.convert_to_tensor( [cirq.Circuit(H(q0) ** sympy.Symbol('a'), X(q1) ** sympy.Symbol('b'), Y(q2) ** sympy.Symbol('c'))] ) symbol_values = [[3,2,1]] pauli_sums = tfq.convert_to_tensor( [1.5 * cirq.Z(q0) * cirq.Z(q1)] ) n_samples = [[100]] cirq_sampled_expectation( programs, symbol_names, sybmol_values, pauli_sums, n_samples) ``` Would place the values of 3 into the Symbol labeled 'a', 2 into the symbol labeled 'b' and 1 into the symbol labeled 'c'. Then it would estimate the ZZ expectation on this circuit by draw samples from the circuit 100 times. Args: programs: `tf.Tensor` of strings with shape [batch_size] containing the string representations of the circuits to be executed. symbol_names: `tf.Tensor` of strings with shape [n_params], 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 [batch_size, n_params] specifying parameter values to resolve into the circuits specified by programs, following the ordering dictated by `symbol_names`. pauli_sums: `tf.Tensor` of strings with shape [batch_size, n_ops] containing the string representation of the operators that will be used on all of the circuits in the expectation calculations. num_samples: `tf.Tensor` with `n_samples[i][j]` is equal to the number of samples to draw in each term of `pauli_sums[i][j]` when estimating the expectation. Returns: `tf.Tensor` with shape [batch_size, n_ops] that holds the expectation value for each circuit with each op applied to it (after resolving the corresponding parameters in). """ _input_check_helper(programs, symbol_names, symbol_values) if not (pauli_sums.dtype == tf.dtypes.string): raise TypeError('pauli_sums tensor must be of type string.') if not (pauli_sums.shape[0] == programs.shape[0]) or \ len(pauli_sums.shape) != 2: raise TypeError('pauli_sums tensor must have the same batch shape ' 'as programs tensor.') if not (num_samples.dtype == tf.dtypes.int32 or num_samples.dtype == tf.dtypes.int64): raise TypeError('num_samples tensor must be of type int32 of ' 'int64.') if not (num_samples.shape == pauli_sums.shape): raise TypeError('num_samples tensor must have the same shape ' 'as pauli_sums tensor. got: {} expected: {}'.format( num_samples.shape, pauli_sums.shape)) if tf.less_equal(num_samples, 0).numpy().any(): raise TypeError('num_samples contains sample value <= 0.') programs, resolvers = _batch_deserialize_helper(programs, symbol_names, symbol_values) num_samples = num_samples.numpy().tolist() sum_inputs = [] for sub_list in pauli_sums.numpy(): to_append = [] for x in sub_list: obj = pauli_sum_pb2.PauliSum() obj.ParseFromString(x) to_append.append(serializer.deserialize_paulisum(obj)) sum_inputs.append(to_append) expectations = batch_util.batch_calculate_sampled_expectation( programs, resolvers, sum_inputs, num_samples, sampler) return expectations
def cirq_analytical_expectation(programs, symbol_names, symbol_values, pauli_sums): """Calculate the expectation value of circuits wrt some operator(s). Calculate the expectation value for all the `cirq.PauliSum`s in `pauli_sums` on each `cirq.Circuit` in `programs`. Each circuit will have the values in `symbol_values` resolved into the symbols in the circuit (with the ordering defined by `symbol_names`). ```python symbol_names = ['a', 'b', 'c'] programs = tfq.convert_to_tensor( [cirq.Circuit(H(q0) ** sympy.Symbol('a'), X(q1) ** sympy.Symbol('b'), Y(q2) ** sympy.Symbol('c'))] ) symbol_values = [[3,2,1]] pauli_sums = tfq.convert_to_tensor( [1.5 * cirq.Z(q0) * cirq.Z(q1)] ) cirq_analytical_expectation( programs, symbol_names, sybmol_values, pauli_sums) ``` Would place the values of 3 into the Symbol labeled 'a', 2 into the symbol labeled 'b' and 1 into the symbol labeled 'c'. Then it would calculate the ZZ expectation on this circuit. Args: programs: `tf.Tensor` of strings with shape [batch_size] containing the string representations of the circuits to be executed. symbol_names: `tf.Tensor` of strings with shape [n_params], 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 [batch_size, n_params] specifying parameter values to resolve into the circuits specified by programs, following the ordering dictated by `symbol_names`. pauli_sums: `tf.Tensor` of strings with shape [batch_size, n_ops] containing the string representation of the operators that will be used on all of the circuits in the expectation calculations. Returns: `tf.Tensor` with shape [batch_size, n_ops] that holds the expectation value for each circuit with each op applied to it (after resolving the corresponding parameters in). """ _input_check_helper(programs, symbol_names, symbol_values) if not (pauli_sums.dtype == tf.dtypes.string): raise TypeError('pauli_sums tensor must be of type string.') if not (pauli_sums.shape[0] == programs.shape[0]): raise TypeError('pauli_sums tensor must have the same batch shape ' 'as programs tensor.') programs, resolvers = _batch_deserialize_helper(programs, symbol_names, symbol_values) sum_inputs = [] for sub_list in pauli_sums.numpy(): to_append = [] for x in sub_list: obj = pauli_sum_pb2.PauliSum() obj.ParseFromString(x) to_append.append(serializer.deserialize_paulisum(obj)) sum_inputs.append(to_append) expectations = batch_util.batch_calculate_expectation( programs, resolvers, sum_inputs, simulator) return expectations