def test_simulate_state_with_symbols(self, op_and_sim, n_qubits, symbol_names): """Compute states using cirq and tfq with symbols.""" op = op_and_sim[0] sim = op_and_sim[1] circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( cirq.GridQubit.rect(1, n_qubits), symbol_names, BATCH_SIZE) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) op_states = op(util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array).to_list() cirq_states = batch_util.batch_calculate_state(circuit_batch, resolver_batch, sim) self.assertAllClose(cirq_states, op_states, atol=1e-5, rtol=1e-5)
def test_resolve_parameters_consistency(self, n_qubits, symbol_names): """Compare tfq op to cirq resolving for randomized circuits.""" # Get random circuit batches qubits = cirq.GridQubit.rect(1, n_qubits) batch_size = 15 n_moments = 15 circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size, n_moments) # Remove one of the symbols from the resolvers symbol_names_partial = symbol_names[1:] symbol_values_array_partial = np.array( [[resolver[symbol] for symbol in symbol_names_partial] for resolver in resolver_batch]) resolver_batch_partial = [ cirq.ParamResolver( {symbol: resolver[symbol] for symbol in symbol_names_partial}) for resolver in resolver_batch ] # Resolve in two ways and compare results test_resolved_circuits = util.from_tensor( tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names_partial, symbol_values_array_partial)) expected_resolved_circuits = [] for circuit, resolver in zip(circuit_batch, resolver_batch_partial): expected_resolved_circuits.append( cirq.resolve_parameters(circuit, resolver)) # TODO(zaqqwerty): Find a way to eliminate parsing. for test_c, exp_c in zip(test_resolved_circuits, expected_resolved_circuits): for test_m, exp_m in zip(test_c, exp_c): for test_o, exp_o in zip(test_m, exp_m): self.assertTrue( util.gate_approx_eq(test_o.gate, exp_o.gate))
def test_correctness_with_symbols(self, n_qubits, batch_size, inner_dim_size): """Tests that inner_product works with symbols.""" symbol_names = ['alpha', 'beta', 'gamma'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) other_batch = [ util.random_circuit_resolver_batch(qubits, inner_dim_size)[0] for i in range(batch_size) ] symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) programs = util.convert_to_tensor(circuit_batch) other_programs = util.convert_to_tensor(other_batch) symbol_names = tf.convert_to_tensor(symbol_names, dtype=tf.dtypes.string) symbol_values = tf.convert_to_tensor(symbol_values_array) out = fidelity_op.fidelity(programs, symbol_names, symbol_values, other_programs) out_arr = np.empty((batch_size, inner_dim_size), dtype=np.complex64) for i in range(batch_size): final_circuit = cirq.resolve_parameters(circuit_batch[i], resolver_batch[i]) final_wf = cirq.final_state_vector(final_circuit) for j in range(inner_dim_size): internal_wf = cirq.final_state_vector(other_batch[i][j]) out_arr[i][j] = np.abs(np.vdot(final_wf, internal_wf))**2 self.assertAllClose(out, out_arr, atol=1e-5) self.assertDTypeEqual(out, tf.float32.as_numpy_dtype)
def test_calculate_unitary_consistency(self, n_qubits, unitary_op): """Test that calculate_unitary works with symbols.""" unitary_op = tfq_unitary_op.get_unitary_op() qubits = cirq.GridQubit.rect(1, n_qubits) symbols = ['alpha', 'beta', 'gamma'] circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch(qubits, symbols, 25) values = np.empty((len(circuit_batch), len(symbols))) for i in range(len(circuit_batch)): for j in range(len(symbols)): values[i][j] = resolver_batch[i][symbols[j]] tfq_results = unitary_op(util.convert_to_tensor(circuit_batch), symbols, values) results = [] for circuit, resolver in zip(circuit_batch, resolver_batch): resolved_circuit = cirq.resolve_parameters(circuit, resolver) results.append(cirq.unitary(resolved_circuit)) self.assertAllClose(tfq_results, results, atol=1e-5)
def test_resolve_parameters_input_checking(self): """Check that the resolve parameters op has correct input checking.""" n_qubits = 5 batch_size = 5 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'must be rank 1'): # programs tensor has the wrong shape (too many dims). tfq_utility_ops.resolve_parameters( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'must be rank 1'): # programs tensor has the wrong shape (too few dims). tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch)[0], symbol_names, symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'must be rank 1'): # symbol_names tensor has the wrong shape (too many dims). tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'must be rank 1'): # symbol_names tensor has the wrong shape (too few dims). tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names[0], symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2'): # symbol_values tensor has the wrong shape (too many dims). tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2'): # symbol_values tensor has the wrong shape (too few dims). tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # programs tensor has the right type, but invalid value. tfq_utility_ops.resolve_parameters(['junk'] * batch_size, symbol_names, symbol_values_array) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # programs tensor has the wrong type. tfq_utility_ops.resolve_parameters([1] * batch_size, symbol_names, symbol_values_array) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # symbol_names tensor has the wrong type. tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), [1], symbol_values_array) with self.assertRaisesRegex(tf.errors.UnimplementedError, 'Cast string to float is not supported'): # symbol_values tensor has the wrong type. tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size) with self.assertRaisesRegex(TypeError, 'missing'): # too few tensors. # pylint: disable=no-value-for-parameter tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names)
def test_simulate_samples_inputs(self): """Make sure the sample op fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 num_samples = 10 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) with self.assertRaisesRegex(ValueError, 'rank 1 but is rank 2'): # programs tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array, [num_samples]) with self.assertRaisesRegex(ValueError, 'rank 1 but is rank 2'): # symbol_names tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array, [num_samples]) with self.assertRaisesRegex(ValueError, 'rank 2 but is rank 3'): # symbol_values tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array]), [num_samples]) with self.assertRaisesRegex(ValueError, 'rank 2 but is rank 1'): # symbol_values tensor has the wrong shape 2. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0], [num_samples]) with self.assertRaisesRegex(ValueError, 'rank 0 but is rank 1'): # num_samples tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [[num_samples]]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # programs tensor has the right type, but invalid value. tfq_simulate_ops.tfq_simulate_samples(['junk'] * batch_size, symbol_names, symbol_values_array, [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type, but invalid value. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), ['junk'], symbol_values_array, [num_samples]) with self.assertRaisesRegex(TypeError, 'Expected string'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_samples([1] * batch_size, symbol_names, symbol_values_array, [num_samples]) with self.assertRaisesRegex(TypeError, 'Expected string'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), [1], symbol_values_array, [num_samples]) with self.assertRaisesRegex(tf.errors.UnimplementedError, 'Cast string to float is not supported'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size, [num_samples]) with self.assertRaisesRegex(Exception, 'not supported'): # num_samples tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, ['junk']) with self.assertRaisesRegex(TypeError, 'missing'): # too few tensors. # pylint: disable=no-value-for-parameter tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array)
def test_simulate_expectation_inputs(self): """Make sure the the expectation op fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) pauli_sums = util.random_pauli_sums(qubits, 3, batch_size) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'programs must be rank 1'): # Circuit tensor has too many dimensions. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_names must be rank 1.'): # symbol_names tensor has too many dimensions. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too many dimensions. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array]), util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too few dimensions. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0], util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'pauli_sums must be rank 2.'): # pauli_sums tensor has too few dimensions. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([x for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'pauli_sums must be rank 2.'): # pauli_sums tensor has too many dimensions. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[[x]] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # circuit tensor has the right type but invalid values. tfq_simulate_ops.tfq_simulate_expectation( ['junk'] * batch_size, symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type but invalid values. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), ['junk'], symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'qubits not found in circuit'): # pauli_sums tensor has the right type but invalid values. new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)] new_pauli_sums = util.random_pauli_sums(new_qubits, 2, batch_size) tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in new_pauli_sums])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # pauli_sums tensor has the right type but invalid values 2. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [['junk']] * batch_size) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # circuits tensor has the wrong type. tfq_simulate_ops.tfq_simulate_expectation( [1.0] * batch_size, symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # symbol_names tensor has the wrong type. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), [0.1234], symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(tf.errors.UnimplementedError, ''): # symbol_values tensor has the wrong type. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size, util.convert_to_tensor([[x] for x in pauli_sums])) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # pauli_sums tensor has the wrong type. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [[1.0]] * batch_size) with self.assertRaisesRegex(TypeError, 'missing'): # we are missing an argument. # pylint: disable=no-value-for-parameter tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array) # pylint: enable=no-value-for-parameter with self.assertRaisesRegex(TypeError, 'positional arguments'): # pylint: disable=too-many-function-args tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), []) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # wrong op size. tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor([cirq.Circuit()]), symbol_names, symbol_values_array.astype(np.float64), util.convert_to_tensor([[x] for x in pauli_sums])) res = tfq_simulate_ops.tfq_simulate_expectation( util.convert_to_tensor([cirq.Circuit() for _ in pauli_sums]), symbol_names, symbol_values_array.astype(np.float64), util.convert_to_tensor([[x] for x in pauli_sums])) self.assertDTypeEqual(res, np.float32)
def test_simulate_state_inputs(self): """Make sure the state op fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'programs must be rank 1'): # programs tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_names must be rank 1'): # symbol_names tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2'): # symbol_values tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2'): # symbol_values tensor has the wrong shape 2. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # programs tensor has the right type, but invalid value. tfq_simulate_ops.tfq_simulate_state(['junk'] * batch_size, symbol_names, symbol_values_array) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type, but invalid value. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), ['junk'], symbol_values_array) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_state([1] * batch_size, symbol_names, symbol_values_array) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # symbol_names tensor has the wrong type. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), [1], symbol_values_array) with self.assertRaisesRegex(tf.errors.UnimplementedError, ''): # symbol_values tensor has the wrong type. tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size) with self.assertRaisesRegex(TypeError, 'missing'): # too few tensors. # pylint: disable=no-value-for-parameter tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), symbol_names) # pylint: enable=no-value-for-parameter # TODO (mbbrough): determine if we should allow extra arguments ? with self.assertRaisesRegex(TypeError, 'positional arguments'): # pylint: disable=too-many-function-args tfq_simulate_ops.tfq_simulate_state( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [])
def test_inner_product_inputs(self): """Make sure that inner_product fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) other_batch = [ util.random_circuit_resolver_batch(qubits, 3)[0] for i in range(batch_size) ] with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'programs must be rank 1'): # Circuit tensor has too many dimensions. inner_product_op.inner_product( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_names must be rank 1.'): # symbol_names tensor has too many dimensions. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too many dimensions. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array]), util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too few dimensions. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0], util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'other_programs must be rank 2.'): # other_programs tensor has too few dimensions. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor(circuit_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'other_programs must be rank 2.'): # pauli_sums tensor has too many dimensions. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in other_batch])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # circuit tensor has the right type but invalid values. inner_product_op.inner_product(['junk'] * batch_size, symbol_names, symbol_values_array, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type but invalid values. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), ['junk'], symbol_values_array, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'not found in reference circuit'): # other_programs tensor has the right type but operates on # qubits that the reference ciruit doesn't have. new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)] new_circuits, _ = util.random_circuit_resolver_batch( new_qubits, batch_size) inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in new_circuits])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'not found in paired circuit'): # other_programs tensor has the right type but operates on # qubits that the reference ciruit doesn't have. new_qubits = cirq.GridQubit.rect(1, n_qubits - 1) new_circuits, _ = util.random_circuit_resolver_batch( new_qubits, batch_size) inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in new_circuits])) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # circuits tensor has the wrong type. inner_product_op.inner_product([1.0] * batch_size, symbol_names, symbol_values_array, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # symbol_names tensor has the wrong type. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), [0.1234], symbol_values_array, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(tf.errors.UnimplementedError, ''): # symbol_values tensor has the wrong type. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size, util.convert_to_tensor(other_batch)) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # other_programs tensor has the wrong type. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [[1.0]] * batch_size) with self.assertRaisesRegex(TypeError, 'missing'): # we are missing an argument. # pylint: disable=no-value-for-parameter inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array) # pylint: enable=no-value-for-parameter with self.assertRaisesRegex(TypeError, 'positional arguments'): # pylint: disable=too-many-function-args inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor(other_batch), []) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # batch programs has wrong batch size. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor(other_batch[:int(batch_size * 0.5)])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # batch programs has wrong batch size. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[::int(batch_size * 0.5)], util.convert_to_tensor(other_batch)) with self.assertRaisesRegex( tf.errors.InvalidArgumentError, expected_regex='Found symbols in other_programs'): # other_programs has symbols. inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in circuit_batch])) res = inner_product_op.inner_product( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array.astype(np.float64), util.convert_to_tensor(other_batch)) self.assertDTypeEqual(res, np.complex64)
def test_noisy_expectation_inputs(self): """Make sure noisy expectation op fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size, include_channels=True) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) pauli_sums = util.random_pauli_sums(qubits, 3, batch_size) num_samples = [[10]] * batch_size with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'programs must be rank 1'): # Circuit tensor has too many dimensions. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_names must be rank 1.'): # symbol_names tensor has too many dimensions. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too many dimensions. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array]), util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too few dimensions. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0], util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'pauli_sums must be rank 2.'): # pauli_sums tensor has too few dimensions. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor(list(pauli_sums)), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'pauli_sums must be rank 2.'): # pauli_sums tensor has too many dimensions. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [util.convert_to_tensor([[x] for x in pauli_sums])], num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'num_samples must be rank 2'): # num_samples tensor has the wrong shape. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'num_samples must be rank 2'): # num_samples tensor has the wrong shape. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples[0]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # circuit tensor has the right type but invalid values. noisy_sampled_expectation_op.sampled_expectation( ['junk'] * batch_size, symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type but invalid values. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), ['junk'], symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'qubits not found in circuit'): # pauli_sums tensor has the right type but invalid values. new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)] new_pauli_sums = util.random_pauli_sums(new_qubits, 2, batch_size) noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in new_pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # pauli_sums tensor has the right type but invalid values 2. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [['junk']] * batch_size, num_samples) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # circuits tensor has the wrong type. noisy_sampled_expectation_op.sampled_expectation( [1.0] * batch_size, symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # symbol_names tensor has the wrong type. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), [0.1234], symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.UnimplementedError, ''): # symbol_values tensor has the wrong type. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size, util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # pauli_sums tensor has the wrong type. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [[1.0]] * batch_size, num_samples) with self.assertRaisesRegex(TypeError, 'missing'): # we are missing an argument. # pylint: disable=no-value-for-parameter noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, num_samples) # pylint: enable=no-value-for-parameter with self.assertRaisesRegex(TypeError, 'positional arguments'): # pylint: disable=too-many-function-args noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), [], num_samples) # pylint: enable=too-many-function-args with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # wrong op size. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor([cirq.Circuit()]), symbol_names, symbol_values_array.astype(np.float64), util.convert_to_tensor([[x] for x in pauli_sums]), num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'greater than 0'): # pylint: disable=too-many-function-args noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, util.convert_to_tensor([[x] for x in pauli_sums]), [[-1]] * batch_size) # pylint: enable=too-many-function-args with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # wrong symbol_values size. noisy_sampled_expectation_op.sampled_expectation( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[:int(batch_size * 0.5)], util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)
def test_adj_grad_inputs(self): """Make sure that the expectation op fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) pauli_sums = util.random_pauli_sums(qubits, 3, batch_size) upstream_grads = np.ones((batch_size, len(symbol_names))) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'programs must be rank 1'): # Circuit tensor has too many dimensions. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor([circuit_batch]), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_names must be rank 1.'): # symbol_names tensor has too many dimensions. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too many dimensions. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(np.array([symbol_values_array])), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'symbol_values must be rank 2.'): # symbol_values_array tensor has too few dimensions. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array[0]), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'pauli_sums must be rank 2.'): # pauli_sums tensor has too few dimensions. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([x for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'pauli_sums must be rank 2.'): # pauli_sums tensor has too many dimensions. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[[x]] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # circuit tensor has the right type but invalid values. tfq_adj_grad_op.tfq_adj_grad( ['junk'] * batch_size, symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type but invalid values. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), ['junk'], tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'qubits not found in circuit'): # pauli_sums tensor has the right type but invalid values. new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)] new_pauli_sums = util.random_pauli_sums(new_qubits, 2, batch_size) tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in new_pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # pauli_sums tensor has the right type but invalid values 2. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), [['junk']] * batch_size, tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # circuits tensor has the wrong type. tfq_adj_grad_op.tfq_adj_grad( [1.0] * batch_size, symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # symbol_names tensor has the wrong type. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), [0.1234], tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.UnimplementedError, ''): # symbol_values tensor has the wrong type. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size, util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # pauli_sums tensor has the wrong type. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), [[1.0]] * batch_size, tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(TypeError, 'missing'): # we are missing an argument. # pylint: disable=no-value-for-parameter tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), tf.convert_to_tensor(upstream_grads)) # pylint: enable=no-value-for-parameter with self.assertRaisesRegex(TypeError, 'positional arguments'): # pylint: disable=too-many-function-args tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads), []) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # wrong op size. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor([cirq.Circuit()]), symbol_names, symbol_values_array.astype(np.float64), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads)) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='rank 2'): # wrong grad shape. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor([upstream_grads])) with self.assertRaisesRegex( tf.errors.InvalidArgumentError, expected_regex='gradients and circuits do not match'): # wrong grad batch size. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor([[0 for i in range(len(symbol_names))]])) with self.assertRaisesRegex( tf.errors.InvalidArgumentError, expected_regex='gradients and pauli sum dimension do not match' ): # wrong grad inner size. tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor(circuit_batch), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor([[0, 0] for _ in range(len(circuit_batch))])) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='cirq.Channel'): # attempting to use noisy circuit. noisy_circuit = cirq.Circuit(cirq.depolarize(0.3).on_each(*qubits)) tfq_adj_grad_op.tfq_adj_grad( util.convert_to_tensor([noisy_circuit for _ in circuit_batch]), symbol_names, tf.convert_to_tensor(symbol_values_array), util.convert_to_tensor([[x] for x in pauli_sums]), tf.convert_to_tensor(upstream_grads))
def _get_mixed_batch(qubits, symbols, size): circuit1, resolver1 = util.random_circuit_resolver_batch(qubits, size // 2) circuit2, resolver2 = util.random_symbol_circuit_resolver_batch( qubits, symbols, size // 2) return circuit1 + circuit2, resolver1 + resolver2
def test_resolve_parameters_consistency(self, n_qubits, symbol_names): """Compare tfq op to cirq resolving for randomized circuits.""" # Get random circuit batches qubits = cirq.GridQubit.rect(1, n_qubits) batch_size = 15 n_moments = 15 circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size, n_moments) # Remove one of the symbols from the resolvers symbol_names_partial = symbol_names[1:] symbol_values_array_partial = np.array( [[resolver[symbol] for symbol in symbol_names_partial] for resolver in resolver_batch]) resolver_batch_partial = [ cirq.ParamResolver( {symbol: resolver[symbol] for symbol in symbol_names_partial}) for resolver in resolver_batch ] # Resolve in two ways and compare results test_resolved_circuits = util.from_tensor( tfq_utility_ops.resolve_parameters( util.convert_to_tensor(circuit_batch), symbol_names_partial, symbol_values_array_partial)) expected_resolved_circuits = [] for circuit, resolver in zip(circuit_batch, resolver_batch_partial): expected_resolved_circuits.append( cirq.resolve_parameters(circuit, resolver)) # TODO(zaqqwerty): Find a way to eliminate parsing. for test_c, exp_c in zip(test_resolved_circuits, expected_resolved_circuits): for test_m, exp_m in zip(test_c, exp_c): for test_o, exp_o in zip(test_m, exp_m): tg = test_o.gate eg = exp_o.gate self.assertEqual(type(tg), type(eg)) # TODO(zaqqwerty): simplify parsing when cirq build parser # see core/serialize/serializer.py if isinstance(tg, cirq.IdentityGate): # all identity gates are the same continue elif isinstance(tg, cirq.EigenGate): self._compare_gate_parameters(tg._global_shift, eg._global_shift) self._compare_gate_parameters(tg._exponent, eg._exponent) elif isinstance(tg, cirq.FSimGate): self._compare_gate_parameters(tg.theta, eg.theta) self._compare_gate_parameters(tg.phi, eg.phi) elif isinstance( tg, (cirq.PhasedXPowGate, cirq.PhasedISwapPowGate)): self._compare_gate_parameters(tg._global_shift, eg._global_shift) self._compare_gate_parameters(tg._exponent, eg._exponent) self._compare_gate_parameters(tg._phase_exponent, eg._phase_exponent) else: self.assertTrue(False, msg="Some gate in the randomizer " "is not being checked: " "{}".format(type(tg)))
def gradients_vs_cirq_finite_difference(self, differentiator, op, n_qubits, n_programs, n_ops, symbol_names, stochastic_cost_eps): """Compare TFQ differentiators to fine-grained noiseless cirq finite differencing with a larger margin of error.""" # TODO (jaeyoo): cleanup this hacky wordkaround so variable # assignment doesn't need to take place like this. differentiator.stochastic_cost, eps = stochastic_cost_eps differentiator.refresh() op = differentiator.generate_differentiable_op(analytic_op=op) qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs) psums = [ util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch ] symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch], dtype=np.float32) # calculate tfq gradient symbol_values_tensor = tf.convert_to_tensor(symbol_values_array) programs = util.convert_to_tensor(circuit_batch) ops = util.convert_to_tensor(psums) # calculate gradients in cirq using a very simple forward differencing # scheme cirq_grads = _cirq_simple_finite_difference(circuit_batch, resolver_batch, symbol_names, psums) def _get_gradient(): with tf.GradientTape() as g: g.watch(symbol_values_tensor) expectations = op(programs, tf.convert_to_tesor(symbol_names), symbol_values_tensor, ops) return g.gradient(expectations, symbol_values_tensor) def _abs_diff(grad, mask): return np.sum(np.abs(grad - cirq_grads * mask)) def _get_nonzero_mask(grad): return (grad.numpy() != 0.0).astype(np.float32) # Get the non-zero mask because a few initial gradients have not sampled # zero values. tfq_grads_1 = _get_gradient() mask_1 = _get_nonzero_mask(tfq_grads_1) if not np.allclose(tfq_grads_1, cirq_grads * mask_1, atol=eps): tfq_grads_2 = 0.5 * (tfq_grads_1 + _get_gradient()) mask_2 = _get_nonzero_mask(tfq_grads_2) # Check if the 2nd error becomes smaller that 1st one. if not _abs_diff(tfq_grads_1, mask_1) > _abs_diff( tfq_grads_2, mask_2): cnt = 2 tfq_grads = (cnt * tfq_grads_2 + _get_gradient()) / (cnt + 1) while (cnt < 10 and not np.allclose(cirq_grads, tfq_grads, atol=eps)): cnt += 1 tfq_grads = (cnt * tfq_grads + _get_gradient()) / (cnt + 1) self.assertAllClose(cirq_grads, tfq_grads, atol=eps)
def test_simulate_samples_inputs(self): """Make sure the sample op fails gracefully on bad inputs.""" n_qubits = 5 batch_size = 5 num_samples = 10 symbol_names = ['alpha'] qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( qubits, symbol_names, batch_size) symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'rank 1. Got rank 2'): # programs tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor([circuit_batch]), symbol_names, symbol_values_array, [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'rank 1. Got rank 2'): # symbol_names tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), np.array([symbol_names]), symbol_values_array, [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'rank 2. Got rank 3'): # symbol_values tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, np.array([symbol_values_array]), [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'rank 2. Got rank 1'): # symbol_values tensor has the wrong shape 2. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[0], [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'rank 1. Got rank 2'): # num_samples tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, [[num_samples]]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Unparseable proto'): # programs tensor has the right type, but invalid value. tfq_simulate_ops.tfq_simulate_samples(['junk'] * batch_size, symbol_names, symbol_values_array, [num_samples]) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, 'Could not find symbol in parameter map'): # symbol_names tensor has the right type, but invalid value. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), ['junk'], symbol_values_array, [num_samples]) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_samples([1] * batch_size, symbol_names, symbol_values_array, [num_samples]) with self.assertRaisesRegex(TypeError, 'Cannot convert'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), [1], symbol_values_array, [num_samples]) with self.assertRaisesRegex(tf.errors.UnimplementedError, 'Cast string to float is not supported'): # programs tensor has the wrong type. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, [['junk']] * batch_size, [num_samples]) with self.assertRaisesRegex(Exception, 'junk'): # num_samples tensor has the wrong shape. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array, ['junk']) with self.assertRaisesRegex(TypeError, 'missing'): # too few tensors. # pylint: disable=no-value-for-parameter tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array) # pylint: enable=no-value-for-parameter with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='do not match'): # wrong symbol_values size. tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor(circuit_batch), symbol_names, symbol_values_array[:int(batch_size * 0.5)], num_samples) with self.assertRaisesRegex(tf.errors.InvalidArgumentError, expected_regex='cirq.Channel'): # attempting to use noisy circuit. noisy_circuit = cirq.Circuit(cirq.depolarize(0.3).on_each(*qubits)) tfq_simulate_ops.tfq_simulate_samples( util.convert_to_tensor([noisy_circuit for _ in circuit_batch]), symbol_names, symbol_values_array, [num_samples])
def test_gradients_vs_cirq_finite_difference(self, differentiator_num_runs, n_qubits, n_programs, n_ops, symbol_names, eps): """Convergence tests on SGDifferentiator variants.""" # TODO(trevormccrt): remove this once I build the user-facing op # interface differentiator, num_runs = differentiator_num_runs differentiator.refresh() op = differentiator.generate_differentiable_op( analytic_op=tfq_simulate_ops.tfq_simulate_expectation) qubits = cirq.GridQubit.rect(1, n_qubits) circuit_batch, resolver_batch = \ util.random_symbol_circuit_resolver_batch( cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs) psums = [ util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch ] symbol_values_array = np.array( [[resolver[symbol] for symbol in symbol_names] for resolver in resolver_batch], dtype=np.float32) # calculate tfq gradient symbol_values_tensor = tf.convert_to_tensor(symbol_values_array) programs = util.convert_to_tensor(circuit_batch) ops = util.convert_to_tensor(psums) def _get_gradient(): with tf.GradientTape() as g: g.watch(symbol_values_tensor) expectations = op(programs, symbol_names, symbol_values_tensor, ops) return tf.cast(g.gradient(expectations, symbol_values_tensor), dtype=tf.float64) # warm-up & initialize tfq_grads. grads_sum = _get_gradient() tfq_grads = grads_sum # calculate gradients in cirq using a very simple forward differencing # scheme cirq_grads = _cirq_simple_finite_difference(circuit_batch, resolver_batch, symbol_names, psums) cnt = 1 # Since self.assertAllClose() has more strict atol than that of # np.allclose(), it is required to set smaller value to np.allclose() total_time = 0 while cnt < num_runs and (not np.allclose( tfq_grads, cirq_grads, atol=eps * 0.9)): cnt = cnt + 1 s = time.time() grads_sum = grads_sum + _get_gradient() total_time += time.time() - s tfq_grads = grads_sum / cnt self.assertAllClose(cirq_grads, tfq_grads, atol=eps) print('Passed: count {}, total_time {} ({}sec/shot)'.format( cnt, total_time, total_time / cnt))