-
Notifications
You must be signed in to change notification settings - Fork 126
Add Experiment Class for Discrete Time Crystal Experiments #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
f93cd08
08ef8a7
e5d91c7
bd8cf76
edee86b
924ec20
20304c1
4074275
5897f26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Copyright 2021 Google | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| from recirq.time_crystals.dtcexperiment import (DTCExperiment, comparison_experiments, | ||
| EXPERIMENT_NAME, DEFAULT_BASE_DIR) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| # Copyright 2021 Google | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import cirq | ||
| import itertools | ||
| import numpy as np | ||
| from typing import Sequence, Optional, Generator | ||
augustehirth marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import os | ||
|
|
||
| EXPERIMENT_NAME = "time_crystals" | ||
| DEFAULT_BASE_DIR = os.path.expanduser(f'~/cirq_results/{EXPERIMENT_NAME}') | ||
|
|
||
| class DTCExperiment: | ||
| """ Manage inputs to a DTC experiment, over some number of disorder instances | ||
|
|
||
| Attributes: | ||
| qubits: a chain of connected qubits available for the circuit | ||
| disorder_instances: number of disorder instances averaged over | ||
| initial_states: initial state of the system used in circuit | ||
| g: thermalization constant used in circuit | ||
| local_fields: random noise used in circuit | ||
| thetas: theta parameters for FSim Gate used in circuit | ||
| zetas: zeta parameters for FSim Gate used in circuit | ||
| chis: chi parameters for FSim Gate used in circuit | ||
| phis: phi parameters for FSim Gate used in circuit | ||
| gammas: gamma parameters for FSim Gate used in circuit | ||
|
|
||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| qubits: Optional[Sequence[cirq.Qid]] = None, | ||
| disorder_instances: Optional[int] = 36, | ||
| g: Optional[int] = 0.94, | ||
| initial_states: Optional[np.ndarray] = None, | ||
| local_fields: Optional[np.ndarray] = None, | ||
| thetas: Optional[np.ndarray] = None, | ||
| zetas: Optional[np.ndarray] = None, | ||
| chis: Optional[np.ndarray] = None, | ||
| gammas: Optional[np.ndarray] = None, | ||
| phis: Optional[np.ndarray] = None | ||
| ): | ||
|
|
||
| self.qubits = qubits | ||
| self.disorder_instances = disorder_instances | ||
| self.g = g | ||
|
|
||
| if qubits is None: | ||
| qubit_locations = [(3, 9), (3, 8), (3, 7), (4, 7), (4, 8), (5, 8), (5, 7), (5, 6), | ||
| (6, 6), (6, 5), (7, 5), (8, 5), (8, 4), (8, 3), (7, 3), (6, 3)] | ||
| self.qubits = [cirq.GridQubit(*idx) for idx in qubit_locations] | ||
| else: | ||
| self.qubits = qubits | ||
|
|
||
| num_qubits = len(self.qubits) | ||
|
|
||
| if initial_states is None: | ||
| self.initial_states = np.random.choice(2, (self.disorder_instances, num_qubits)) | ||
| else: | ||
| self.initial_states = initial_states | ||
|
|
||
| if local_fields is None: | ||
| self.local_fields = np.random.uniform(-1.0, 1.0, (self.disorder_instances, num_qubits)) | ||
augustehirth marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| else: | ||
| self.local_fields = local_fields | ||
|
|
||
| zero_params = [thetas, zetas, chis] | ||
| for index, zero_param in enumerate(zero_params): | ||
| if zero_param is None: | ||
| zero_params[index] = np.zeros((self.disorder_instances, num_qubits - 1)) | ||
| else: | ||
| zero_params[index] = zero_param | ||
| self.thetas, self.zetas, self.chis = zero_params | ||
|
|
||
| # if gamma or phi is not supplied, generate it from the other such that phis == -2*gammas | ||
| if gammas is None and phis is None: | ||
| self.gammas = -np.random.uniform(0.5*np.pi, 1.5*np.pi, | ||
| (self.disorder_instances, num_qubits - 1)) | ||
| self.phis = -2*self.gammas | ||
| elif phis is None: | ||
| self.gammas = gammas | ||
| self.phis = -2*self.gammas | ||
| elif gammas is None: | ||
| self.phis = phis | ||
| self.gammas = -1/2*self.phis | ||
| else: | ||
| self.phis = phis | ||
| self.gammas = gammas | ||
|
|
||
| def param_resolvers(self) -> cirq.Zip: | ||
| """ return a sweep over disorder instances for the parameters of this experiment | ||
| Returns: | ||
| `cirq.Zip` object with self.disorder_instances many `cirq.ParamResolver`s | ||
| """ | ||
|
|
||
| # initialize the dict and add the first, non-qubit-dependent parameter, g | ||
| factor_dict = {'g': np.full(self.disorder_instances, self.g).tolist()} | ||
|
|
||
| # iterate over the different parameters | ||
| qubit_varying_factors = ["initial_states", "local_fields", "thetas", | ||
| "zetas", "chis", "gammas", "phis"] | ||
| for factor in qubit_varying_factors: | ||
| parameter = getattr(self, factor) | ||
| # iterate over each index in the qubit chain and the various options for that qubit | ||
| for index, qubit_factor_options in enumerate(parameter.transpose()): | ||
| factor_name = factor[:-1] | ||
| factor_dict[f'{factor_name}_{index}'] = qubit_factor_options.tolist() | ||
|
|
||
| return cirq.study.dict_to_zip_sweep(factor_dict) | ||
|
|
||
| def comparison_experiments(qubits: Sequence[cirq.Qid], | ||
| disorder_instances: int, | ||
augustehirth marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| g_cases: Optional[Sequence[int]] = None, | ||
| initial_states_cases: Optional[Sequence[np.ndarray]] = None, | ||
| local_fields_cases: Optional[Sequence[np.ndarray]] = None, | ||
| phis_cases: Optional[Sequence[np.ndarray]] = None, | ||
| ) -> Generator[DTCExperiment, None, None]: | ||
augustehirth marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ Yield DTCExperiments with parameters taken from the cartesian product of input parameters | ||
| Args: | ||
augustehirth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Any number of (parameter, parameter_values) pairs | ||
| Yields: | ||
| DTCTasks with parameters taken from self.options_dict | ||
| """ | ||
|
|
||
| # take product over elements of options_dict, in the order of options_order | ||
| items = [([x] if x is None else x) | ||
| for x in [g_cases, initial_states_cases, local_fields_cases, phis_cases]] | ||
| for components in itertools.product(*items): | ||
| # prepare arguments for DTCExperiment | ||
| kwargs = dict(zip(['g', 'initial_states', 'local_fields', 'phis'], components)) | ||
| yield DTCExperiment(qubits=qubits, | ||
| disorder_instances=disorder_instances, | ||
| **kwargs) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Copyright 2021 Google | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import recirq.time_crystals as time_crystals | ||
| import cirq | ||
| import numpy as np | ||
| import itertools | ||
|
|
||
| def test_DTCExperiment(): | ||
| np.random.seed(5) | ||
| qubit_locations = [(3, 9), (3, 8), (3, 7), (4, 7), (4, 8), (5, 8), (5, 7), (5, 6), (6, 6), | ||
| (6, 5), (7, 5), (8, 5), (8, 4), (8, 3), (7, 3), (6, 3)] | ||
|
|
||
| qubits = [cirq.GridQubit(*idx) for idx in qubit_locations] | ||
| num_qubits = len(qubits) | ||
| g = 0.94 | ||
| instances = 36 | ||
| initial_state = np.random.choice(2, num_qubits) | ||
| local_fields = np.random.uniform(-1.0, 1.0, (instances, num_qubits)) | ||
| thetas = np.zeros((instances, num_qubits - 1)) | ||
| zetas = np.zeros((instances, num_qubits - 1)) | ||
| chis = np.zeros((instances, num_qubits - 1)) | ||
| gammas = -np.random.uniform(0.5*np.pi, 1.5*np.pi, (instances, num_qubits - 1)) | ||
| phis = -2*gammas | ||
| args = ['qubits', 'g', 'initial_state', 'local_fields', | ||
| 'thetas', 'zetas', 'chis', 'gammas', 'phis'] | ||
| default_resolvers = time_crystals.DTCExperiment().param_resolvers() | ||
| for arg in args: | ||
| kwargs = {} | ||
| for name in args: | ||
| kwargs[name] = None if name is arg else locals()[name] | ||
|
||
| dtcexperiment = time_crystals.DTCExperiment(disorder_instances=instances, **kwargs) | ||
| param_resolvers = dtcexperiment.param_resolvers() | ||
|
|
||
| def test_comparison_experiments(): | ||
| np.random.seed(5) | ||
| qubit_locations = [(3, 9), (3, 8), (3, 7), (4, 7), (4, 8), (5, 8), (5, 7), (5, 6), (6, 6), | ||
| (6, 5), (7, 5), (8, 5), (8, 4), (8, 3), (7, 3), (6, 3)] | ||
|
|
||
| qubits = [cirq.GridQubit(*idx) for idx in qubit_locations] | ||
| num_qubits = len(qubits) | ||
| g_cases = [0.94, 0.6] | ||
| instances = 36 | ||
| initial_states_cases = [np.random.choice(2, (instances, num_qubits)), | ||
| np.tile(np.random.choice(2, num_qubits), (instances,1))] | ||
| local_fields_cases = [np.random.uniform(-1.0, 1.0, (instances, num_qubits)), | ||
| np.tile(np.random.uniform(-1.0, 1.0, num_qubits), (instances,1))] | ||
| phis_cases = [np.random.uniform(np.pi, 3*np.pi, (instances, num_qubits - 1)), | ||
| np.full((instances, num_qubits - 1), 0.4)] | ||
| names = ['g_cases', 'initial_states_cases', 'local_fields_cases', 'phis_cases'] | ||
| args = [g_cases, initial_states_cases, local_fields_cases, phis_cases] | ||
| for cases in itertools.product(*zip([None]*4, args)): | ||
| kwargs = dict(zip(names, cases)) | ||
| for experiment in time_crystals.comparison_experiments(qubits, instances, **kwargs): | ||
| param_resolvers = experiment.param_resolvers() | ||
Uh oh!
There was an error while loading. Please reload this page.