Skip to content
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

Simplify the TimeIndependentMDCObjectiveFunction class #515

Merged
merged 18 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
712 changes: 178 additions & 534 deletions pygsti/objectivefns/objectivefns.py

Large diffs are not rendered by default.

23 changes: 16 additions & 7 deletions pygsti/optimize/customlm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1124,13 +1124,22 @@ def dclip(ar): return ar
printer.log(" Accepted%s! gain ratio=%g mu * %g => %g"
% (" UPHILL" if uphill_ok else "", dF / dL, mu_factor, mu), 2)
last_accepted_dx = dx.copy()
if new_x_is_known_inbounds and norm_f < min_norm_f:
min_norm_f = norm_f
best_x[:] = x[:]
best_x_state = (mu, nu, norm_f, f.copy(), spow, None)
#Note: we use rawJTJ=None above because the current `JTJ` was evaluated
# at the *last* x-value -- we need to wait for the next outer loop
# to compute the JTJ for this best_x_state
if norm_f < min_norm_f:
if not new_x_is_known_inbounds:
try:
_ = obj_fn(global_x, oob_check=True)
# ^ Dead-store the return value.
new_x_is_known_inbounds = True
except ValueError:
# Then we keep new_x_is_known_inbounds==False.
pass
if new_x_is_known_inbounds:
min_norm_f = norm_f
best_x[:] = x[:]
best_x_state = (mu, nu, norm_f, f.copy(), spow, None)
# ^ Note: we use rawJTJ=None above because the current `JTJ` was evaluated
# at the *last* x-value -- we need to wait for the next outer loop
# to compute the JTJ for this best_x_state

#assert(_np.isfinite(x).all()), "Non-finite x!" # NaNs tracking
#assert(_np.isfinite(f).all()), "Non-finite f!" # NaNs tracking
Expand Down
22 changes: 17 additions & 5 deletions pygsti/optimize/simplerlm.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,6 @@ def simplish_leastsq(

#determing increment using adaptive damping
while True: # inner loop

if profiler: profiler.memory_check("simplish_leastsq: begin inner iter")

# ok if assume fine-param-proc.size == 1 (otherwise need to sync setting local JTJ)
Expand Down Expand Up @@ -783,17 +782,30 @@ def simplish_leastsq(
norm_f = norm_new_f
global_x[:] = global_new_x[:]
printer.log(" Accepted%s! gain ratio=%g mu * %g => %g" % ("", dF / dL, mu_factor, mu), 2)
if new_x_is_known_inbounds and norm_f < min_norm_f:
min_norm_f = norm_f
best_x[:] = x[:]
best_x_state = (mu, nu, norm_f, f.copy())
if norm_f < min_norm_f:
if not new_x_is_known_inbounds:
try:
_ = obj_fn(global_x, oob_check=True)
# ^ Dead-store the return value.
new_x_is_known_inbounds = True
except ValueError:
# Then we keep new_x_is_known_inbounds==False.
pass
if new_x_is_known_inbounds:
min_norm_f = norm_f
best_x[:] = x[:]
best_x_state = (mu, nu, norm_f, f.copy())

#assert(_np.isfinite(x).all()), "Non-finite x!" # NaNs tracking
#assert(_np.isfinite(f).all()), "Non-finite f!" # NaNs tracking

break
# ^ exit inner loop normally ...
# end of inner loop
#
# x[:] = best_x[:]
# mu, nu, norm_f, f[:] = best_x_state
#
# end of outer loop
else:
#if no break stmt hit, then we've exceeded max_iter
Expand Down
2 changes: 1 addition & 1 deletion test/performance/mpi_2D_scaling/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ export MKL_NUM_THREADS=1
# Note: This flags are useful on Kahuna to avoid error messages
# But the --mca flags are not necessary for performance
mpirun -np ${NUM_PROCS} --mca pml ucx --mca btl '^openib' \
python ./mpi_test.py &> ${PREFIX}.out
python ./run_me_with_mpirun.py &> ${PREFIX}.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file is designed to be run via: mpiexec -np 4 python -W ignore testMPI.py
# This file is designed to be run via: mpiexec -np 4 python -W ignore run_me_with_mpiexec.py
# This does not use nosetests because I want to set verbosity differently based on rank (quiet if not rank 0)
# By wrapping asserts in comm.rank == 0, only rank 0 should fail (should help with output)
# Can run with different number of procs, but 4 is minimum to test all modes (pure MPI, pure shared mem, and mixed)
Expand Down Expand Up @@ -226,7 +226,7 @@ def run_fills(self, sim, natoms, nparams):
else:
raise RuntimeError("Improper sim type passed by test_fills_generator")

serial_layout = mdl.sim.create_layout(circuits, array_types=('E','EP','EPP'), derivative_dimension=nP)
serial_layout = mdl.sim.create_layout(circuits, array_types=('E','EP','EPP'), derivative_dimensions=(nP,))

nE = serial_layout.num_elements
nC = len(circuits)
Expand All @@ -246,7 +246,7 @@ def run_fills(self, sim, natoms, nparams):
global_serial_layout = serial_layout.global_layout

#Use a parallel layout to compute the same probabilities & their derivatives
local_layout = mdl.sim.create_layout(circuits, array_types=('E','EP','EPP'), derivative_dimension=nP,
local_layout = mdl.sim.create_layout(circuits, array_types=('E','EP','EPP'), derivative_dimensions=(nP,),
resource_alloc=self.ralloc)

vp_local = local_layout.allocate_local_array('e', 'd')
Expand Down Expand Up @@ -334,7 +334,7 @@ def setup_class(cls):
tester = PureMPIParallel_Test()
tester.setup_class()
tester.ralloc = pygsti.baseobjs.ResourceAllocation(wcomm)
#tester.run_objfn_values('matrix','logl',4)
tester.run_objfn_values('matrix','logl',4)
tester.run_fills('map', 1, None)
tester.run_fills('map', 4, None)
tester.run_fills('matrix', 4, 15)
26 changes: 26 additions & 0 deletions test/unit/mpi/test_mpi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import subprocess
import pytest
import os
from pathlib import Path

try:
from mpi4py import MPI
except (ImportError, RuntimeError):
rileyjmurray marked this conversation as resolved.
Show resolved Hide resolved
MPI = None


class MPITester:

@pytest.mark.skipif(MPI is None, reason="mpi4py could not be imported")
def test_all(self, capfd: pytest.LogCaptureFixture):
current_filepath = Path(os.path.abspath(__file__))
to_run = current_filepath.parents[0] / Path('run_me_with_mpiexec.py')
subprocess_args = (f"mpiexec -np 4 python -W ignore {str(to_run)}").split(' ')

result = subprocess.run(subprocess_args, capture_output=False, text=True)
out, err = capfd.readouterr()
if len(out) + len(err) > 0:
msg = out + '\n'+ 80*'-' + err
raise RuntimeError(msg)
return

10 changes: 6 additions & 4 deletions test/unit/objects/test_objectivefns.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,12 @@ def test_derivative(self):
places=3) # each *element* should match to 3 places

if self.computes_lsvec:
lsvec = objfn.lsvec().copy()
dlsvec = objfn.dlsvec().copy()
self.assertArraysAlmostEqual(dterms / nEls, 2 * lsvec[:, None] * dlsvec / nEls,
places=4) # each *element* should match to 4 places
arg1 = dterms / nEls
lsvec = objfn.lsvec(v0).copy()
dlsvec = objfn.dlsvec(v0).copy()
arg2 = 2 * lsvec[:, None] * dlsvec / nEls
self.assertArraysAlmostEqual(arg1, arg2, places=4) # each *element* should match to 4 places
return

def test_approximate_hessian(self):
if not self.enable_hessian_tests:
Expand Down
Loading