Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions pygridsynth/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse

from .config import GridsynthConfig
from .gridsynth import gridsynth_gates

helps = {
Expand All @@ -22,28 +23,41 @@ def main():

parser.add_argument("theta", type=str)
parser.add_argument("epsilon", type=str)
parser.add_argument("--dps", type=int, default=None)
parser.add_argument("--dtimeout", "-dt", type=float, default=None, help=helps["dt"])
parser.add_argument("--ftimeout", "-ft", type=float, default=None, help=helps["ft"])
parser.add_argument("--dloop", "-dl", type=int, default=10, help=helps["dl"])
parser.add_argument("--floop", "-fl", type=int, default=10, help=helps["fl"])
parser.add_argument("--seed", type=int, default=0, help=helps["seed"])
parser.add_argument("--dps", type=int)
parser.add_argument("--dtimeout", "-dt", type=float, help=helps["dt"])
parser.add_argument("--ftimeout", "-ft", type=float, help=helps["ft"])
parser.add_argument("--dloop", "-dl", type=int, help=helps["dl"])
parser.add_argument("--floop", "-fl", type=int, help=helps["fl"])
parser.add_argument("--seed", type=int, help=helps["seed"])
parser.add_argument("--verbose", "-v", action="store_true")
parser.add_argument("--time", "-t", action="store_true")
parser.add_argument("--showgraph", "-g", action="store_true")
parser.add_argument("--upto_phase", "-ph", action="store_true")
args = parser.parse_args()

gates = gridsynth_gates(
theta=args.theta,
epsilon=args.epsilon,
dps=args.dps,
dtimeout=args.dtimeout,
ftimeout=args.ftimeout,
dloop=args.dloop,
floop=args.floop,
seed=args.seed,
verbose=args.verbose,
measure_time=args.time,
show_graph=args.showgraph,
)
cfg_args = dict()
if args.dps is not None:
cfg_args["dps"] = args.dps
if args.dtimeout is not None:
cfg_args["dtimeout"] = args.dtimeout
if args.ftimeout is not None:
cfg_args["ftimeout"] = args.ftimeout
if args.dloop is not None:
cfg_args["dloop"] = args.dloop
if args.floop is not None:
cfg_args["floop"] = args
if args.seed is not None:
cfg_args["seed"] = args.seed
if args.verbose:
cfg_args["verbose"] = args.verbose
if args.time:
cfg_args["measure_time"] = args.time
if args.showgraph:
cfg_args["show_graph"] = args.showgraph
if args.upto_phase:
cfg_args["upto_phase"] = args.upto_phase

cfg = GridsynthConfig(**cfg_args)

gates = gridsynth_gates(theta=args.theta, epsilon=args.epsilon, cfg=cfg)
return gates
28 changes: 28 additions & 0 deletions pygridsynth/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from dataclasses import dataclass, field
from typing import Optional

from .loop_controller import LoopController


@dataclass
class GridsynthConfig:
dps: Optional[int] = None
seed: int = 0
dloop: int = 10
floop: int = 10
dtimeout: Optional[float] = None
ftimeout: Optional[float] = None
verbose: bool = False
measure_time: bool = False
show_graph: bool = False
upto_phase: bool = False

loop_controller: LoopController = field(init=False)

def __post_init__(self):
self.loop_controller = LoopController(
dloop=self.dloop,
floop=self.floop,
dtimeout=self.dtimeout,
ftimeout=self.ftimeout,
)
6 changes: 3 additions & 3 deletions pygridsynth/diophantine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import random
import warnings

from pygridsynth.loop_controller import LoopController

from .loop_controller import LoopController
from .ring import DOmega, ZOmega, ZRootTwo

NO_SOLUTION = "no solution"
Expand Down Expand Up @@ -454,7 +453,8 @@ def _diophantine(xi, loop_controller: LoopController):
return v * t


def diophantine_dyadic(xi, loop_controller=None):
def diophantine_dyadic(xi, seed=0, loop_controller=None):
set_random_seed(seed)
if loop_controller is None:
loop_controller = LoopController()

Expand Down
176 changes: 51 additions & 125 deletions pygridsynth/gridsynth.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import mpmath

from .diophantine import NO_SOLUTION, diophantine_dyadic, set_random_seed
from .config import GridsynthConfig
from .diophantine import NO_SOLUTION, diophantine_dyadic
from .loop_controller import LoopController
from .mymath import solve_quadratic, sqrt
from .quantum_gate import Rz
Expand Down Expand Up @@ -115,15 +116,18 @@ def get_synthesized_unitary(gates):
return DOmegaUnitary.from_gates(gates).to_complex_matrix


def gridsynth(
theta,
epsilon,
dps=None,
loop_controller=None,
verbose=False,
measure_time=False,
show_graph=False,
):
def gridsynth(theta, epsilon, cfg=None, **kwargs):
if cfg is None:
cfg = GridsynthConfig(**kwargs)
elif kwargs:
warnings.warn(
"When 'cfg' is provided, 'kwargs' are ignored.",
stacklevel=2,
)

if cfg.dps is None:
cfg.dps = _dps_for_epsilon(epsilon)

if isinstance(theta, float):
warnings.warn(
(
Expand All @@ -148,50 +152,48 @@ def gridsynth(
stacklevel=2,
)

if dps is None:
dps = _dps_for_epsilon(epsilon)
with mpmath.workdps(dps):
with mpmath.workdps(cfg.dps):
theta = mpmath.mpmathify(theta)
epsilon = mpmath.mpmathify(epsilon)
if loop_controller is None:
loop_controller = LoopController()

epsilon_region = EpsilonRegion(theta, epsilon)
unit_disk = UnitDisk()
k = 0

if measure_time:
if cfg.measure_time:
start = time.time()
transformed = to_upright_set_pair(
epsilon_region, unit_disk, verbose=verbose, show_graph=show_graph
epsilon_region, unit_disk, verbose=cfg.verbose, show_graph=cfg.show_graph
)
if measure_time:
if cfg.measure_time:
print(f"to_upright_set_pair: {time.time() - start} s")
if verbose:
if cfg.verbose:
print("------------------")

time_of_solve_TDGP = 0
time_of_diophantine_dyadic = 0
while True:
if measure_time:
if cfg.measure_time:
start = time.time()
sol = solve_TDGP(
epsilon_region,
unit_disk,
*transformed,
k,
verbose=verbose,
show_graph=show_graph,
verbose=cfg.verbose,
show_graph=cfg.show_graph,
)
if measure_time:
if cfg.measure_time:
time_of_solve_TDGP += time.time() - start
start = time.time()

for z in sol:
if (z * z.conj).residue == 0:
continue
xi = 1 - DRootTwo.fromDOmega(z.conj * z)
w = diophantine_dyadic(xi, loop_controller=loop_controller)
w = diophantine_dyadic(
xi, seed=cfg.seed, loop_controller=cfg.loop_controller
)
if w != NO_SOLUTION:
z = z.reduce_denomexp()
w = w.reduce_denomexp()
Expand All @@ -203,78 +205,43 @@ def gridsynth(
u_approx = DOmegaUnitary(z, w, 0)
else:
u_approx = DOmegaUnitary(z, w.mul_by_omega(), 0)
if measure_time:
if cfg.measure_time:
time_of_diophantine_dyadic += time.time() - start
print(f"time of solve_TDGP: {time_of_solve_TDGP * 1000} ms")
print(
"time of diophantine_dyadic: "
f"{time_of_diophantine_dyadic * 1000} ms"
)
if verbose:
if cfg.verbose:
print(f"{z=}, {w=}")
print("------------------")
return u_approx
if measure_time:
if cfg.measure_time:
time_of_diophantine_dyadic += time.time() - start
k += 1


def gridsynth_circuit(
theta,
epsilon,
wires=[0],
decompose_phase_gate=True,
dps=None,
loop_controller=None,
verbose=False,
measure_time=False,
show_graph=False,
):
if isinstance(theta, float):
def gridsynth_circuit(theta, epsilon, wires=[0], cfg=None, **kwargs):
if cfg is None:
cfg = GridsynthConfig(**kwargs)
elif kwargs:
warnings.warn(
(
f"pygridsynth is synthesizing the angle {theta}. "
"Please verify that this is the intended value. "
"Using float may introduce precision errors; "
"consider using mpmath.mpf for exact precision."
),
UserWarning,
"When 'cfg' is provided, 'kwargs' are ignored.",
stacklevel=2,
)

if isinstance(epsilon, float):
warnings.warn(
(
f"pygridsynth is using epsilon={epsilon} as the tolerance. "
"Please verify that this is the intended value. "
"Using float may introduce precision errors; "
"consider using mpmath.mpf for exact precision."
),
UserWarning,
stacklevel=2,
)
if cfg.dps is None:
cfg.dps = _dps_for_epsilon(epsilon)

if dps is None:
dps = _dps_for_epsilon(epsilon)
with mpmath.workdps(dps):
theta = mpmath.mpmathify(theta)
epsilon = mpmath.mpmathify(epsilon)
start_total = time.time() if measure_time else 0.0
u_approx = gridsynth(
theta=theta,
epsilon=epsilon,
dps=dps,
loop_controller=loop_controller,
verbose=verbose,
measure_time=measure_time,
show_graph=show_graph,
)
with mpmath.workdps(cfg.dps):
start_total = time.time() if cfg.measure_time else 0.0
u_approx = gridsynth(theta=theta, epsilon=epsilon, cfg=cfg)

start = time.time() if measure_time else 0.0
start = time.time() if cfg.measure_time else 0.0
circuit = decompose_domega_unitary(
u_approx, wires=wires, decompose_phase_gate=decompose_phase_gate
u_approx, wires=wires, upto_phase=cfg.upto_phase
)
if measure_time:
if cfg.measure_time:
print(
f"time of decompose_domega_unitary: {(time.time() - start) * 1000} ms"
)
Expand All @@ -283,65 +250,24 @@ def gridsynth_circuit(
return circuit


def gridsynth_gates(
theta,
epsilon,
dps=None,
dtimeout=None,
ftimeout=None,
dloop=10,
floop=10,
seed=0,
verbose=False,
measure_time=False,
show_graph=False,
decompose_phase_gate=True,
):
if isinstance(theta, float):
warnings.warn(
(
f"pygridsynth is synthesizing the angle {theta}. "
"Please verify that this is the intended value. "
"Using float may introduce precision errors; "
"consider using mpmath.mpf for exact precision."
),
UserWarning,
stacklevel=2,
)

if isinstance(epsilon, float):
def gridsynth_gates(theta, epsilon, cfg=None, **kwargs):
if cfg is None:
cfg = GridsynthConfig(**kwargs)
elif kwargs:
warnings.warn(
(
f"pygridsynth is using epsilon={epsilon} as the tolerance. "
"Please verify that this is the intended value. "
"Using float may introduce precision errors; "
"consider using mpmath.mpf for exact precision."
),
UserWarning,
"When 'cfg' is provided, 'kwargs' are ignored.",
stacklevel=2,
)

set_random_seed(seed)

loop_controller = LoopController(
dloop=dloop, floop=floop, dtimeout=dtimeout, ftimeout=ftimeout
)
if cfg.dps is None:
cfg.dps = _dps_for_epsilon(epsilon)

if dps is None:
dps = _dps_for_epsilon(epsilon)
with mpmath.workdps(dps):
theta = mpmath.mpmathify(theta)
epsilon = mpmath.mpmathify(epsilon)
with mpmath.workdps(cfg.dps):
circuit = gridsynth_circuit(
theta=theta,
epsilon=epsilon,
wires=[0],
decompose_phase_gate=decompose_phase_gate,
dps=dps,
loop_controller=loop_controller,
verbose=verbose,
measure_time=measure_time,
show_graph=show_graph,
cfg=cfg,
)
return circuit.to_simple_str()

Expand Down
Loading