From 36e030b4e0179c153930f6d0085628ee93bc3cdd Mon Sep 17 00:00:00 2001 From: king-p3nguin Date: Mon, 3 Jun 2024 02:28:12 +0900 Subject: [PATCH 1/5] feature: implement `braket.ahs.AnalogHamiltonianSimulation.from_ir()` --- .../ahs/analog_hamiltonian_simulation.py | 78 ++++++++ .../ahs/test_analog_hamiltonian_simulation.py | 171 ++++++++++++++++++ 2 files changed, 249 insertions(+) diff --git a/src/braket/ahs/analog_hamiltonian_simulation.py b/src/braket/ahs/analog_hamiltonian_simulation.py index af02471e2..4c46b9567 100644 --- a/src/braket/ahs/analog_hamiltonian_simulation.py +++ b/src/braket/ahs/analog_hamiltonian_simulation.py @@ -20,9 +20,12 @@ from braket.ahs.atom_arrangement import AtomArrangement, SiteType from braket.ahs.discretization_types import DiscretizationError, DiscretizationProperties from braket.ahs.driving_field import DrivingField +from braket.ahs.field import Field from braket.ahs.hamiltonian import Hamiltonian from braket.ahs.local_detuning import LocalDetuning +from braket.ahs.pattern import Pattern from braket.device_schema import DeviceActionType +from braket.timings.time_series import TimeSeries class AnalogHamiltonianSimulation: @@ -49,6 +52,81 @@ 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 = ( + Field( + time_series=TimeSeries.from_lists( + term.amplitude.time_series.times, term.amplitude.time_series.values + ), + pattern=term.amplitude.pattern, + ) + if term.amplitude.pattern != "uniform" + else TimeSeries.from_lists( + term.amplitude.time_series.times, term.amplitude.time_series.values + ) + ) + phase = ( + Field( + time_series=TimeSeries.from_lists( + term.phase.time_series.times, term.phase.time_series.values + ), + pattern=term.phase.pattern, + ) + if term.phase.pattern != "uniform" + else TimeSeries.from_lists( + term.phase.time_series.times, term.phase.time_series.values + ) + ) + detuning = ( + Field( + time_series=TimeSeries.from_lists( + term.detuning.time_series.times, term.detuning.time_series.values + ), + pattern=term.detuning.pattern, + ) + if term.detuning.pattern != "uniform" + else TimeSeries.from_lists( + term.detuning.time_series.times, term.detuning.time_series.values + ) + ) + hamiltonian += DrivingField( + amplitude=amplitude, + phase=phase, + detuning=detuning, + ) + for term in source.hamiltonian.localDetuning: + magnitude = Field( + time_series=TimeSeries.from_lists( + times=term.magnitude.time_series.times, + values=term.magnitude.time_series.values, + ), + pattern=Pattern(term.magnitude.pattern), + ) + hamiltonian += LocalDetuning( + magnitude=magnitude, + ) + 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/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py b/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py index 83178c120..0ce0ca37e 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,43 @@ def test_to_ir_empty(): assert problem == Program.parse_raw_schema(problem.json()) +def test_from_ir(ir): + ahs = AnalogHamiltonianSimulation.from_ir(ir) + problem = ahs.to_ir() + assert Program.parse_raw(problem.json()) == problem + assert problem == Program.parse_raw_schema(problem.json()) + + +def test_from_ir_empty(): + hamiltonian = Mock() + hamiltonian.terms = [] + ahs = AnalogHamiltonianSimulation.from_ir( + Program.parse_raw_schema( + """ +{ + "braketSchemaHeader": { + "name": "braket.ir.ahs.program", + "version": "1" + }, + "setup": { + "ahs_register": { + "sites": [], + "filling": [] + } + }, + "hamiltonian": { + "drivingFields": [], + "localDetuning": [] + } +} +""" + ) + ) + problem = ahs.to_ir() + assert Program.parse_raw(problem.json()) == problem + assert problem == Program.parse_raw_schema(problem.json()) + + @pytest.mark.xfail(raises=TypeError) def test_to_ir_invalid_hamiltonian(register): hamiltonian = Mock() From 076db373c15ce9a6f70cdaa0dcb7cf3a9441f4e4 Mon Sep 17 00:00:00 2001 From: king-p3nguin Date: Thu, 6 Jun 2024 08:03:23 +0900 Subject: [PATCH 2/5] change: improve tests, remove duplicate codes --- .../ahs/analog_hamiltonian_simulation.py | 69 +++++++------------ src/braket/ahs/field.py | 27 ++++++++ .../ahs/test_analog_hamiltonian_simulation.py | 17 ++--- test/unit_tests/braket/ahs/test_field.py | 20 ++++++ 4 files changed, 79 insertions(+), 54 deletions(-) diff --git a/src/braket/ahs/analog_hamiltonian_simulation.py b/src/braket/ahs/analog_hamiltonian_simulation.py index 4c46b9567..a443bedd8 100644 --- a/src/braket/ahs/analog_hamiltonian_simulation.py +++ b/src/braket/ahs/analog_hamiltonian_simulation.py @@ -14,7 +14,9 @@ from __future__ import annotations from collections import defaultdict +from decimal import Decimal from functools import singledispatch +from typing import Union import braket.ir.ahs as ir from braket.ahs.atom_arrangement import AtomArrangement, SiteType @@ -23,7 +25,6 @@ from braket.ahs.field import Field from braket.ahs.hamiltonian import Hamiltonian from braket.ahs.local_detuning import LocalDetuning -from braket.ahs.pattern import Pattern from braket.device_schema import DeviceActionType from braket.timings.time_series import TimeSeries @@ -70,41 +71,20 @@ def from_ir(source: ir.Program) -> AnalogHamiltonianSimulation: ) hamiltonian = Hamiltonian() for term in source.hamiltonian.drivingFields: - amplitude = ( - Field( - time_series=TimeSeries.from_lists( - term.amplitude.time_series.times, term.amplitude.time_series.values - ), - pattern=term.amplitude.pattern, - ) - if term.amplitude.pattern != "uniform" - else TimeSeries.from_lists( - term.amplitude.time_series.times, term.amplitude.time_series.values - ) + amplitude = AnalogHamiltonianSimulation._field_or_time_series_from_ir( + times=term.amplitude.time_series.times, + values=term.amplitude.time_series.values, + pattern=term.amplitude.pattern, ) - phase = ( - Field( - time_series=TimeSeries.from_lists( - term.phase.time_series.times, term.phase.time_series.values - ), - pattern=term.phase.pattern, - ) - if term.phase.pattern != "uniform" - else TimeSeries.from_lists( - term.phase.time_series.times, term.phase.time_series.values - ) + phase = AnalogHamiltonianSimulation._field_or_time_series_from_ir( + times=term.phase.time_series.times, + values=term.phase.time_series.values, + pattern=term.phase.pattern, ) - detuning = ( - Field( - time_series=TimeSeries.from_lists( - term.detuning.time_series.times, term.detuning.time_series.values - ), - pattern=term.detuning.pattern, - ) - if term.detuning.pattern != "uniform" - else TimeSeries.from_lists( - term.detuning.time_series.times, term.detuning.time_series.values - ) + detuning = AnalogHamiltonianSimulation._field_or_time_series_from_ir( + times=term.detuning.time_series.times, + values=term.detuning.time_series.values, + pattern=term.detuning.pattern, ) hamiltonian += DrivingField( amplitude=amplitude, @@ -112,21 +92,24 @@ def from_ir(source: ir.Program) -> AnalogHamiltonianSimulation: detuning=detuning, ) for term in source.hamiltonian.localDetuning: - magnitude = Field( - time_series=TimeSeries.from_lists( - times=term.magnitude.time_series.times, - values=term.magnitude.time_series.values, - ), - pattern=Pattern(term.magnitude.pattern), - ) - hamiltonian += LocalDetuning( - magnitude=magnitude, + 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, ) + @staticmethod + def _field_or_time_series_from_ir( + times: list[Decimal], values: list[Decimal], pattern: Union[str, list[Decimal]] + ) -> Union[Field, TimeSeries]: + if not isinstance(pattern, str): + return Field.from_lists(times=times, values=values, pattern=pattern) + return TimeSeries.from_lists(times, values) + 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..e79c9a869 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) + + drive = Field(time_series=time_series, pattern=Pattern(pattern)) + + return drive 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 0ce0ca37e..3af8554a1 100644 --- a/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py +++ b/test/unit_tests/braket/ahs/test_analog_hamiltonian_simulation.py @@ -230,18 +230,14 @@ def test_to_ir_empty(): def test_from_ir(ir): - ahs = AnalogHamiltonianSimulation.from_ir(ir) - problem = ahs.to_ir() - assert Program.parse_raw(problem.json()) == problem + problem = AnalogHamiltonianSimulation.from_ir(ir).to_ir() + assert problem == ir assert problem == Program.parse_raw_schema(problem.json()) def test_from_ir_empty(): - hamiltonian = Mock() - hamiltonian.terms = [] - ahs = AnalogHamiltonianSimulation.from_ir( - Program.parse_raw_schema( - """ + empty_ir = Program.parse_raw_schema( + """ { "braketSchemaHeader": { "name": "braket.ir.ahs.program", @@ -259,10 +255,9 @@ def test_from_ir_empty(): } } """ - ) ) - problem = ahs.to_ir() - assert Program.parse_raw(problem.json()) == problem + problem = AnalogHamiltonianSimulation.from_ir(empty_ir).to_ir() + assert problem == empty_ir assert problem == Program.parse_raw_schema(problem.json()) 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) From 487056ed81418f09d0c4a3108e8c0bc5559a7a95 Mon Sep 17 00:00:00 2001 From: Kazuki Tsuoka Date: Thu, 6 Jun 2024 22:50:10 +0900 Subject: [PATCH 3/5] change: change variable name in field.py --- src/braket/ahs/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/ahs/field.py b/src/braket/ahs/field.py index e79c9a869..ff87fd3e8 100644 --- a/src/braket/ahs/field.py +++ b/src/braket/ahs/field.py @@ -90,6 +90,6 @@ def from_lists(times: list[Decimal], values: list[Decimal], pattern: list[Decima time_series = TimeSeries.from_lists(times=times, values=values) - drive = Field(time_series=time_series, pattern=Pattern(pattern)) + field = Field(time_series=time_series, pattern=Pattern(pattern)) return drive From 9f4fdcafe6e7f10431facdc0688e5bbb37d65270 Mon Sep 17 00:00:00 2001 From: Kazuki Tsuoka Date: Thu, 6 Jun 2024 22:50:57 +0900 Subject: [PATCH 4/5] change: Update field.py --- src/braket/ahs/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/ahs/field.py b/src/braket/ahs/field.py index ff87fd3e8..28319cc99 100644 --- a/src/braket/ahs/field.py +++ b/src/braket/ahs/field.py @@ -92,4 +92,4 @@ def from_lists(times: list[Decimal], values: list[Decimal], pattern: list[Decima field = Field(time_series=time_series, pattern=Pattern(pattern)) - return drive + return field From 8ccd0acfbb2f9bb954993b029ebfc298553aa3f1 Mon Sep 17 00:00:00 2001 From: king-p3nguin Date: Thu, 6 Jun 2024 23:48:12 +0900 Subject: [PATCH 5/5] fix: fix coverage --- .../ahs/analog_hamiltonian_simulation.py | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/braket/ahs/analog_hamiltonian_simulation.py b/src/braket/ahs/analog_hamiltonian_simulation.py index a443bedd8..f11675d41 100644 --- a/src/braket/ahs/analog_hamiltonian_simulation.py +++ b/src/braket/ahs/analog_hamiltonian_simulation.py @@ -14,15 +14,12 @@ from __future__ import annotations from collections import defaultdict -from decimal import Decimal from functools import singledispatch -from typing import Union import braket.ir.ahs as ir from braket.ahs.atom_arrangement import AtomArrangement, SiteType from braket.ahs.discretization_types import DiscretizationError, DiscretizationProperties from braket.ahs.driving_field import DrivingField -from braket.ahs.field import Field from braket.ahs.hamiltonian import Hamiltonian from braket.ahs.local_detuning import LocalDetuning from braket.device_schema import DeviceActionType @@ -71,20 +68,17 @@ def from_ir(source: ir.Program) -> AnalogHamiltonianSimulation: ) hamiltonian = Hamiltonian() for term in source.hamiltonian.drivingFields: - amplitude = AnalogHamiltonianSimulation._field_or_time_series_from_ir( + amplitude = TimeSeries.from_lists( times=term.amplitude.time_series.times, values=term.amplitude.time_series.values, - pattern=term.amplitude.pattern, ) - phase = AnalogHamiltonianSimulation._field_or_time_series_from_ir( + phase = TimeSeries.from_lists( times=term.phase.time_series.times, values=term.phase.time_series.values, - pattern=term.phase.pattern, ) - detuning = AnalogHamiltonianSimulation._field_or_time_series_from_ir( + detuning = TimeSeries.from_lists( times=term.detuning.time_series.times, values=term.detuning.time_series.values, - pattern=term.detuning.pattern, ) hamiltonian += DrivingField( amplitude=amplitude, @@ -102,14 +96,6 @@ def from_ir(source: ir.Program) -> AnalogHamiltonianSimulation: hamiltonian=hamiltonian, ) - @staticmethod - def _field_or_time_series_from_ir( - times: list[Decimal], values: list[Decimal], pattern: Union[str, list[Decimal]] - ) -> Union[Field, TimeSeries]: - if not isinstance(pattern, str): - return Field.from_lists(times=times, values=values, pattern=pattern) - return TimeSeries.from_lists(times, values) - def to_ir(self) -> ir.Program: """Converts the Analog Hamiltonian Simulation into the canonical intermediate representation.