Skip to content

Commit

Permalink
Merge branch 'master' into noisy_samples
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelBroughton authored Mar 25, 2021
2 parents 69bbd4e + d22d0ea commit 01c07d5
Show file tree
Hide file tree
Showing 26 changed files with 348 additions and 180 deletions.
11 changes: 11 additions & 0 deletions tensorflow_quantum/core/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@ licenses(["notice"])

# Export for the PIP package.
exports_files(["__init__.py"])

py_library(
name = "core",
srcs = ["__init__.py"],
srcs_version = "PY3",
deps = [
"//tensorflow_quantum/core/ops",
"//tensorflow_quantum/core/proto:pauli_sum_py_proto",
"//tensorflow_quantum/core/serialize",
],
)
68 changes: 55 additions & 13 deletions tensorflow_quantum/core/ops/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# load op_wrapper

package(default_visibility = ["//visibility:public"])

licenses(["notice"])
Expand All @@ -10,6 +12,26 @@ config_setting(
constraint_values = ["@bazel_tools//platforms:windows"],
)

py_library(
name = "ops",
srcs = ["__init__.py"],
srcs_version = "PY3",
deps = [
":batch_util",
":circuit_execution_ops",
":cirq_ops",
":load_module",
":tfq_adj_grad_op_py",
":tfq_ps_util_ops_py",
":tfq_simulate_ops_py",
":tfq_unitary_op_py",
":tfq_utility_ops_py",
# test addons
"//tensorflow_quantum/core/ops/math_ops:inner_product_op_py",
"//tensorflow_quantum/core/ops/noise:noisy_expectation_op_py",
],
)

cc_binary(
name = "_tfq_adj_grad.so",
srcs = [
Expand Down Expand Up @@ -57,11 +79,15 @@ cc_binary(
linkshared = 1,
deps = [
":parse_context",
# cirq cc proto
":tfq_simulate_utils",
"//tensorflow_quantum/core/src:util_qsim",
"//tensorflow_quantum/core/src:circuit_parser_qsim",
"//tensorflow_quantum/core/src:adj_util",
"//tensorflow_quantum/core/src:circuit_parser_qsim",
"//tensorflow_quantum/core/src:util_qsim",
"@qsim//lib:qsim_lib",
# tensorflow core framework
# tensorflow core lib
# tensorflow core protos
],
)

Expand Down Expand Up @@ -115,6 +141,7 @@ cc_binary(
deps = [
":parse_context",
":tfq_simulate_utils",
# cirq cc proto
"//tensorflow_quantum/core/proto:program_cc_proto",
"@local_config_tf//:libtensorflow_framework",
"@local_config_tf//:tf_header_lib",
Expand All @@ -125,9 +152,9 @@ cc_binary(
name = "_tfq_simulate_ops.so",
srcs = [
"tfq_simulate_expectation_op.cc",
"tfq_simulate_samples_op.cc",
"tfq_simulate_sampled_expectation_op.cc",
"tfq_simulate_state_op.cc"
"tfq_simulate_samples_op.cc",
"tfq_simulate_state_op.cc",
],
copts = select({
":windows": [
Expand Down Expand Up @@ -172,20 +199,19 @@ cc_binary(
deps = [
":parse_context",
":tfq_simulate_utils",

"//tensorflow_quantum/core/src:util_qsim",
"//tensorflow_quantum/core/src:circuit_parser_qsim",
"@qsim//lib:qsim_lib",

# cirq cc proto
"//tensorflow_quantum/core/proto:pauli_sum_cc_proto",
"//tensorflow_quantum/core/proto:program_cc_proto",
"//tensorflow_quantum/core/src:circuit_parser_qsim",
"//tensorflow_quantum/core/src:program_resolution",
"//tensorflow_quantum/core/src:util_qsim",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:inlined_vector",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/types:span",
"@local_config_tf//:libtensorflow_framework",
"@local_config_tf//:tf_header_lib",
"@qsim//lib:qsim_lib",
],
)

Expand Down Expand Up @@ -238,6 +264,7 @@ cc_binary(
deps = [
":parse_context",
":tfq_simulate_utils",
# cirq cc proto
"//tensorflow_quantum/core/proto:program_cc_proto",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:inlined_vector",
Expand Down Expand Up @@ -267,7 +294,7 @@ cc_library(
cc_binary(
name = "_tfq_calculate_unitary_op.so",
srcs = [
"tfq_calculate_unitary_op.cc"
"tfq_calculate_unitary_op.cc",
],
copts = select({
":windows": [
Expand Down Expand Up @@ -311,10 +338,11 @@ cc_binary(
linkshared = 1,
deps = [
":parse_context",
# cirq cc proto
"//tensorflow_quantum/core/proto:pauli_sum_cc_proto",
"//tensorflow_quantum/core/proto:program_cc_proto",
"//tensorflow_quantum/core/src:util_qsim",
"//tensorflow_quantum/core/src:circuit_parser_qsim",
"//tensorflow_quantum/core/src:util_qsim",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:inlined_vector",
"@com_google_absl//absl/types:optional",
Expand All @@ -339,16 +367,20 @@ py_library(
name = "tfq_adj_grad_op_py",
srcs = ["tfq_adj_grad_op.py"],
data = [":_tfq_adj_grad.so"],
srcs_version = "PY3",
deps = [
# tensorflow framework for wrappers
":load_module",
]
],
)

py_library(
name = "tfq_unitary_op_py",
srcs = ["tfq_unitary_op.py"],
data = [":_tfq_calculate_unitary_op.so"],
srcs_version = "PY3",
deps = [
# tensorflow framework for wrappers
":load_module",
":tfq_utility_ops_py",
"//tensorflow_quantum/python:quantum_context",
Expand All @@ -362,7 +394,7 @@ py_test(
deps = [
":tfq_adj_grad_op_py",
"//tensorflow_quantum/python:util",
]
],
)

py_test(
Expand All @@ -379,7 +411,9 @@ py_library(
name = "tfq_simulate_ops_py",
srcs = ["tfq_simulate_ops.py"],
data = [":_tfq_simulate_ops.so"],
srcs_version = "PY3",
deps = [
# tensorflow framework for wrappers
":load_module",
],
)
Expand All @@ -397,6 +431,7 @@ py_test(
py_library(
name = "circuit_execution_ops",
srcs = ["circuit_execution_ops.py"],
srcs_version = "PY3",
deps = [
":cirq_ops",
":tfq_simulate_ops_py",
Expand All @@ -419,6 +454,7 @@ py_test(
py_library(
name = "cirq_ops",
srcs = ["cirq_ops.py"],
srcs_version = "PY3",
deps = [
":batch_util",
"//tensorflow_quantum/core/serialize:serializer",
Expand All @@ -440,6 +476,7 @@ py_test(
py_library(
name = "batch_util",
srcs = ["batch_util.py"],
srcs_version = "PY3",
deps = [
"//tensorflow_quantum/core/serialize:serializer",
],
Expand All @@ -460,7 +497,9 @@ py_library(
name = "tfq_ps_util_ops_py",
srcs = ["tfq_ps_util_ops.py"],
data = [":_tfq_ps_utils.so"],
srcs_version = "PY3",
deps = [
# tensorflow framework for wrappers
":load_module",
],
)
Expand All @@ -479,7 +518,9 @@ py_library(
name = "tfq_utility_ops_py",
srcs = ["tfq_utility_ops.py"],
data = [":_tfq_utility_ops.so"],
srcs_version = "PY3",
deps = [
# tensorflow framework for wrappers
":load_module",
],
)
Expand All @@ -498,5 +539,6 @@ py_test(
py_library(
name = "load_module",
srcs = ["load_module.py"],
srcs_version = "PY3",
deps = [],
)
118 changes: 39 additions & 79 deletions tensorflow_quantum/core/ops/batch_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,41 +221,6 @@ def _state_worker_func(indices, programs, params):
_update_complex_np(x_np, index, final_array)


def _analytical_expectation_worker_func(indices, programs, params, ops):
"""Compute the expectation of the op[batch_index], w.r.t
circuit[batch_index] where batch_index is calculated from indices."""
x_np = _convert_simple_view_to_np(INFO_DICT['arr'], np.float32,
INFO_DICT['shape'])
simulator = INFO_DICT['sim']

# TODO: remove this when picklable.
for i in range(len(ops)):
for j in range(len(ops[i])):
ops[i][j] = serializer.deserialize_paulisum(ops[i][j])

old_batch_index = -2
state = -1
for i, index_tuple in enumerate(indices):
batch_index = index_tuple[0]
op_index = index_tuple[1]
# (#679) Just ignore empty programs.
if len(programs[batch_index].all_qubits()) == 0:
continue

if old_batch_index != batch_index:
# must compute a new state vector.
qubit_oder = dict(
zip(sorted(programs[batch_index].all_qubits()),
list(range(len(programs[batch_index].all_qubits())))))
state = simulator.simulate(programs[batch_index],
params[batch_index])

result = INFO_DICT['post_process'](ops[batch_index][op_index], state,
qubit_oder)
_pointwise_update_simple_np(x_np, batch_index, op_index, result)
old_batch_index = batch_index


def _sample_expectation_worker_func(indices, programs, params, ops, n_samples):
x_np = _convert_simple_view_to_np(INFO_DICT['arr'], np.float32,
INFO_DICT['shape'])
Expand Down Expand Up @@ -333,6 +298,17 @@ def _validate_inputs(circuits, param_resolvers, simulator, sim_type):
raise TypeError('For analytic operations only'
' cirq.SimulatesFinalState'
' is required. Given: {}'.format(type(simulator)))

elif sim_type == 'expectation':
if not isinstance(simulator,
(cirq.sim.simulator.SimulatesExpectationValues,
cirq.DensityMatrixSimulator)):
# TODO(zaqqwerty): remove DM sim check once cirq #3964 is resolved.
raise TypeError('For expectation operations a '
'cirq.sim.simulator.SimulatesExpectationValues '
'or cirq.DensityMatrixSimulator'
'is required. Given: {}'.format(type(simulator)))

elif sim_type == 'sample':
if not isinstance(simulator, cirq.Sampler):
raise TypeError('For sample based operations a cirq.Sampler is '
Expand Down Expand Up @@ -406,16 +382,15 @@ def batch_calculate_state(circuits, param_resolvers, simulator):


def batch_calculate_expectation(circuits, param_resolvers, ops, simulator):
"""Compute expectations from circuits using parallel processing.
"""Compute expectations from a batch of circuits.
Returns a `np.ndarray` containing the expectation values of `ops`
applied to a specific circuit in `circuits`, given that the
corresponding `cirq.ParamResolver` in `param_resolvers` was used to resolve
any symbols in the circuit. Specifically the returned array at index `i,j`
will be equal to the expectation value of `ops[i][j]` on `circuits[i]` with
`param_resolvers[i]` used to resolve any symbols in `circuits[i]`.
Expectation calculations will be carried out using the simulator object
(`cirq.DensityMatrixSimulator` and `cirq.Simulator` are currently supported)
Expectation calculations will be carried out using the simulator object.
Args:
circuits: Python `list` of `cirq.Circuit`s.
Expand All @@ -425,14 +400,16 @@ def batch_calculate_expectation(circuits, param_resolvers, ops, simulator):
be used to calculate the expectation on `circuits[i]` for all `j`,
after `param_resolver[i]` is used to resolve any parameters
in the circuit.
simulator: Simulator object. Currently supported are
`cirq.DensityMatrixSimulator` and `cirq.Simulator`.
simulator: Simulator object. Must inherit
`cirq.sim.simulator.SimulatesExpectationValues` or
`cirq.DensityMatrixSimulator`.
Returns:
`np.ndarray` containing the expectation values. Shape is:
[len(circuits), len(ops[0])]
"""
_validate_inputs(circuits, param_resolvers, simulator, 'analytic')
_validate_inputs(circuits, param_resolvers, simulator, 'expectation')

if _check_empty(circuits):
return np.zeros((0, 0), dtype=np.float32)

Expand All @@ -451,45 +428,28 @@ def batch_calculate_expectation(circuits, param_resolvers, ops, simulator):
raise TypeError('ops must contain only cirq.PauliSum objects.'
' Given: {}'.format(type(x)))

return_mem_shape = (len(circuits), len(ops[0]))
if isinstance(simulator, cirq.DensityMatrixSimulator):
post_process = lambda op, state, order: sum(
x._expectation_from_density_matrix_no_validation(
state.final_density_matrix, order) for x in op).real
elif isinstance(simulator, cirq.Simulator):
post_process = \
lambda op, state, order: op.expectation_from_state_vector(
state.final_state_vector, order).real
else:
raise TypeError('Simulator {} is not supported by '
'batch_calculate_expectation.'.format(type(simulator)))

shared_array = _make_simple_view(return_mem_shape, -2, np.float32, 'f')

# avoid mutating ops array
ops = np.copy(ops)
# TODO (mbbrough): make cirq PauliSUms pickable at some point ?
for i in range(len(ops)):
for j in range(len(ops[i])):
ops[i][j] = serializer.serialize_paulisum(ops[i][j])

input_args = list(
_prep_pool_input_args(list(
itertools.product(range(len(circuits)), range(len(ops[0])))),
circuits,
param_resolvers,
ops,
slice_args=False))

with ProcessPool(processes=None,
initializer=_setup_dict,
initargs=(shared_array, return_mem_shape, simulator,
post_process)) as pool:

pool.starmap(_analytical_expectation_worker_func, input_args)
all_exp_vals = np.ones(shape=(len(circuits), len(ops[0])),
dtype=np.float32) * -2
for i, (c, p, op_row) in enumerate(zip(circuits, param_resolvers, ops)):
# Convention in TFQ is to set expectations of empty circuits to -2.
if len(c) == 0:
continue
# TODO(zaqqwerty): remove DM sim check once cirq #3964 is resolved.
if isinstance(simulator, cirq.DensityMatrixSimulator):
qubits = c.all_qubits()
pairs = zip(sorted(qubits), list(range(len(qubits))))
qubit_order = dict(pairs)
sim_result = simulator.simulate(c, p)
for j, op in enumerate(op_row):
dm = sim_result.final_density_matrix
all_exp_vals[i][j] = op.expectation_from_density_matrix(
dm, qubit_order, check_preconditions=False)
else:
# Valid observables always have real expectation values.
all_exp_vals[i] = np.real(
np.asarray(simulator.simulate_expectation_values(c, op_row, p)))

return _convert_simple_view_to_result(shared_array, np.float32,
return_mem_shape)
return all_exp_vals


def batch_calculate_sampled_expectation(circuits, param_resolvers, ops,
Expand Down
Loading

0 comments on commit 01c07d5

Please sign in to comment.