From 2f021072942ffe901ab17e41e35701d1c7580a0d Mon Sep 17 00:00:00 2001 From: Kazuki Tsuoka Date: Fri, 7 Jun 2024 02:40:33 +0900 Subject: [PATCH] Implement `braket.ahs.AnalogHamiltonianSimulation.from_ir()` (#983) * feature: implement `braket.ahs.AnalogHamiltonianSimulation.from_ir()` * change: improve tests, remove duplicate codes * change: change variable name in field.py * change: Update field.py * fix: fix coverage --- .../ahs/analog_hamiltonian_simulation.py | 47 +++++ src/braket/ahs/field.py | 27 +++ .../ahs/test_analog_hamiltonian_simulation.py | 166 ++++++++++++++++++ test/unit_tests/braket/ahs/test_field.py | 20 +++ 4 files changed, 260 insertions(+) diff --git a/src/braket/ahs/analog_hamiltonian_simulation.py b/src/braket/ahs/analog_hamiltonian_simulation.py index af02471e2..f11675d41 100644 --- a/src/braket/ahs/analog_hamiltonian_simulation.py +++ b/src/braket/ahs/analog_hamiltonian_simulation.py @@ -23,6 +23,7 @@ from braket.ahs.hamiltonian import Hamiltonian from braket.ahs.local_detuning import LocalDetuning from braket.device_schema import DeviceActionType +from braket.timings.time_series import TimeSeries class AnalogHamiltonianSimulation: @@ -49,6 +50,52 @@ def hamiltonian(self) -> Hamiltonian: """Hamiltonian: The hamiltonian to simulate.""" return self._hamiltonian + @staticmethod + def from_ir(source: ir.Program) -> AnalogHamiltonianSimulation: + """Converts the canonical intermediate representation into + the Analog Hamiltonian Simulation. + + Args: + source (ir.Program): The IR representation of the circuit. + + Returns: + AnalogHamiltonianSimulation: The Analog Hamiltonian Simulation. + """ + atom_arrangement = AtomArrangement() + for site, fill in zip(source.setup.ahs_register.sites, source.setup.ahs_register.filling): + atom_arrangement.add( + coordinate=site, site_type=SiteType.FILLED if fill == 1 else SiteType.VACANT + ) + hamiltonian = Hamiltonian() + for term in source.hamiltonian.drivingFields: + amplitude = TimeSeries.from_lists( + times=term.amplitude.time_series.times, + values=term.amplitude.time_series.values, + ) + phase = TimeSeries.from_lists( + times=term.phase.time_series.times, + values=term.phase.time_series.values, + ) + detuning = TimeSeries.from_lists( + times=term.detuning.time_series.times, + values=term.detuning.time_series.values, + ) + hamiltonian += DrivingField( + amplitude=amplitude, + phase=phase, + detuning=detuning, + ) + for term in source.hamiltonian.localDetuning: + hamiltonian += LocalDetuning.from_lists( + times=term.magnitude.time_series.times, + values=term.magnitude.time_series.values, + pattern=term.magnitude.pattern, + ) + return AnalogHamiltonianSimulation( + register=atom_arrangement, + hamiltonian=hamiltonian, + ) + def to_ir(self) -> ir.Program: """Converts the Analog Hamiltonian Simulation into the canonical intermediate representation. diff --git a/src/braket/ahs/field.py b/src/braket/ahs/field.py index 1522b9d65..28319cc99 100644 --- a/src/braket/ahs/field.py +++ b/src/braket/ahs/field.py @@ -66,3 +66,30 @@ def discretize( discretized_pattern = self.pattern.discretize(pattern_resolution) discretized_field = Field(time_series=discretized_time_series, pattern=discretized_pattern) return discretized_field + + @staticmethod + def from_lists(times: list[Decimal], values: list[Decimal], pattern: list[Decimal]) -> Field: + """Builds Field from lists of time points, values and pattern. + + Args: + times (list[Decimal]): The time points of the field + values (list[Decimal]): The values of the field + pattern (list[Decimal]): The pattern of the field + + Raises: + ValueError: If the length of times and values differs. + + Returns: + Field: Field. + """ + if not (len(times) == len(values)): + raise ValueError( + f"The lengths of the lists for times({len(times)}) and values({len(values)})\ + are not equal" + ) + + time_series = TimeSeries.from_lists(times=times, values=values) + + field = Field(time_series=time_series, pattern=Pattern(pattern)) + + return field diff --git a/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py b/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py index 83178c120..3af8554a1 100644 --- a/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py +++ b/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py @@ -70,6 +70,140 @@ def local_detuning(): ) +@pytest.fixture +def ir(): + return Program.parse_raw_schema( + """ +{ + "braketSchemaHeader": { + "name": "braket.ir.ahs.program", + "version": "1" + }, + "setup": { + "ahs_register": { + "sites": [ + [ + "0.0", + "0.0" + ], + [ + "0.0", + "0.000003" + ], + [ + "0.0", + "0.000006" + ], + [ + "0.000003", + "0.0" + ], + [ + "0.000003", + "0.000003" + ], + [ + "0.000003", + "0.000003" + ], + [ + "0.000003", + "0.000006" + ] + ], + "filling": [ + 1, + 1, + 1, + 1, + 1, + 0, + 0 + ] + } + }, + "hamiltonian": { + "drivingFields": [ + { + "amplitude": { + "time_series": { + "values": [ + "0.0", + "25132700.0", + "25132700.0", + "0.0" + ], + "times": [ + "0.0", + "3E-7", + "0.0000027", + "0.000003" + ] + }, + "pattern": "uniform" + }, + "phase": { + "time_series": { + "values": [ + "0", + "0" + ], + "times": [ + "0.0", + "0.000003" + ] + }, + "pattern": "uniform" + }, + "detuning": { + "time_series": { + "values": [ + "-125664000.0", + "-125664000.0", + "125664000.0", + "125664000.0" + ], + "times": [ + "0.0", + "3E-7", + "0.0000027", + "0.000003" + ] + }, + "pattern": "uniform" + } + } + ], + "localDetuning": [ + { + "magnitude": { + "time_series": { + "values": [ + "-125664000.0", + "125664000.0" + ], + "times": [ + "0.0", + "0.000003" + ] + }, + "pattern": [ + "0.5", + "1.0", + "0.5", + "0.5", + "0.5", + "0.5" + ] + } + } + ] + } +} +""" + ) + + def test_create(): mock0 = Mock() mock1 = Mock() @@ -95,6 +229,38 @@ def test_to_ir_empty(): assert problem == Program.parse_raw_schema(problem.json()) +def test_from_ir(ir): + problem = AnalogHamiltonianSimulation.from_ir(ir).to_ir() + assert problem == ir + assert problem == Program.parse_raw_schema(problem.json()) + + +def test_from_ir_empty(): + empty_ir = Program.parse_raw_schema( + """ +{ + "braketSchemaHeader": { + "name": "braket.ir.ahs.program", + "version": "1" + }, + "setup": { + "ahs_register": { + "sites": [], + "filling": [] + } + }, + "hamiltonian": { + "drivingFields": [], + "localDetuning": [] + } +} +""" + ) + problem = AnalogHamiltonianSimulation.from_ir(empty_ir).to_ir() + assert problem == empty_ir + assert problem == Program.parse_raw_schema(problem.json()) + + @pytest.mark.xfail(raises=TypeError) def test_to_ir_invalid_hamiltonian(register): hamiltonian = Mock() diff --git a/test/unit_tests/braket/ahs/test_field.py b/test/unit_tests/braket/ahs/test_field.py index 2ff6714ce..21006fa6d 100644 --- a/test/unit_tests/braket/ahs/test_field.py +++ b/test/unit_tests/braket/ahs/test_field.py @@ -98,3 +98,23 @@ def test_uniform_field( ) or expected.pattern.series == actual.pattern.series assert expected.time_series.times() == actual.time_series.times() assert expected.time_series.values() == actual.time_series.values() + + +def test_from_lists(): + times = [0, 0.1, 0.2, 0.3] + values = [0.5, 0.8, 0.9, 1.0] + pattern = [0.3, 0.7, 0.6, -0.5, 0, 1.6] + + sh_field = Field.from_lists(times, values, pattern) + assert sh_field.time_series.times() == times + assert sh_field.time_series.values() == values + assert sh_field.pattern.series == pattern + + +@pytest.mark.xfail(raises=ValueError) +def test_from_lists_not_eq_length(): + times = [0, 0.1, 0.2] + values = [0.5, 0.8, 0.9, 1.0] + pattern = [0.3, 0.7, 0.6, -0.5, 0, 1.6] + + Field.from_lists(times, values, pattern)