Skip to content

Commit d5a3421

Browse files
authored
Merge pull request #515 from sandialabs/simplify-TimeIndependentMDCObjectiveFunction
Simplify the TimeIndependentMDCObjectiveFunction class
2 parents 0d859ce + 59ab4d3 commit d5a3421

File tree

8 files changed

+248
-555
lines changed

8 files changed

+248
-555
lines changed

pygsti/objectivefns/objectivefns.py

Lines changed: 178 additions & 534 deletions
Large diffs are not rendered by default.

pygsti/optimize/customlm.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,13 +1124,22 @@ def dclip(ar): return ar
11241124
printer.log(" Accepted%s! gain ratio=%g mu * %g => %g"
11251125
% (" UPHILL" if uphill_ok else "", dF / dL, mu_factor, mu), 2)
11261126
last_accepted_dx = dx.copy()
1127-
if new_x_is_known_inbounds and norm_f < min_norm_f:
1128-
min_norm_f = norm_f
1129-
best_x[:] = x[:]
1130-
best_x_state = (mu, nu, norm_f, f.copy(), spow, None)
1131-
#Note: we use rawJTJ=None above because the current `JTJ` was evaluated
1132-
# at the *last* x-value -- we need to wait for the next outer loop
1133-
# to compute the JTJ for this best_x_state
1127+
if norm_f < min_norm_f:
1128+
if not new_x_is_known_inbounds:
1129+
try:
1130+
_ = obj_fn(global_x, oob_check=True)
1131+
# ^ Dead-store the return value.
1132+
new_x_is_known_inbounds = True
1133+
except ValueError:
1134+
# Then we keep new_x_is_known_inbounds==False.
1135+
pass
1136+
if new_x_is_known_inbounds:
1137+
min_norm_f = norm_f
1138+
best_x[:] = x[:]
1139+
best_x_state = (mu, nu, norm_f, f.copy(), spow, None)
1140+
# ^ Note: we use rawJTJ=None above because the current `JTJ` was evaluated
1141+
# at the *last* x-value -- we need to wait for the next outer loop
1142+
# to compute the JTJ for this best_x_state
11341143

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

pygsti/optimize/simplerlm.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,6 @@ def simplish_leastsq(
600600

601601
#determing increment using adaptive damping
602602
while True: # inner loop
603-
604603
if profiler: profiler.memory_check("simplish_leastsq: begin inner iter")
605604

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

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

794802
break
795803
# ^ exit inner loop normally ...
796804
# end of inner loop
805+
#
806+
# x[:] = best_x[:]
807+
# mu, nu, norm_f, f[:] = best_x_state
808+
#
797809
# end of outer loop
798810
else:
799811
#if no break stmt hit, then we've exceeded max_iter

test/performance/mpi_2D_scaling/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ export MKL_NUM_THREADS=1
2929
# Note: This flags are useful on Kahuna to avoid error messages
3030
# But the --mca flags are not necessary for performance
3131
mpirun -np ${NUM_PROCS} --mca pml ucx --mca btl '^openib' \
32-
python ./mpi_test.py &> ${PREFIX}.out
32+
python ./run_me_with_mpirun.py &> ${PREFIX}.out
File renamed without changes.

test/test_packages/mpi/test_mpi.py renamed to test/unit/mpi/run_me_with_mpiexec.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# This file is designed to be run via: mpiexec -np 4 python -W ignore testMPI.py
1+
# This file is designed to be run via: mpiexec -np 4 python -W ignore run_me_with_mpiexec.py
22
# This does not use nosetests because I want to set verbosity differently based on rank (quiet if not rank 0)
33
# By wrapping asserts in comm.rank == 0, only rank 0 should fail (should help with output)
44
# Can run with different number of procs, but 4 is minimum to test all modes (pure MPI, pure shared mem, and mixed)
@@ -226,7 +226,7 @@ def run_fills(self, sim, natoms, nparams):
226226
else:
227227
raise RuntimeError("Improper sim type passed by test_fills_generator")
228228

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

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

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

252252
vp_local = local_layout.allocate_local_array('e', 'd')
@@ -334,7 +334,7 @@ def setup_class(cls):
334334
tester = PureMPIParallel_Test()
335335
tester.setup_class()
336336
tester.ralloc = pygsti.baseobjs.ResourceAllocation(wcomm)
337-
#tester.run_objfn_values('matrix','logl',4)
337+
tester.run_objfn_values('matrix','logl',4)
338338
tester.run_fills('map', 1, None)
339339
tester.run_fills('map', 4, None)
340340
tester.run_fills('matrix', 4, 15)

test/unit/mpi/test_mpi.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import subprocess
2+
import pytest
3+
import os
4+
from pathlib import Path
5+
6+
try:
7+
from mpi4py import MPI
8+
except (ImportError, RuntimeError):
9+
MPI = None
10+
11+
12+
class MPITester:
13+
14+
@pytest.mark.skipif(MPI is None, reason="mpi4py could not be imported")
15+
def test_all(self, capfd: pytest.LogCaptureFixture):
16+
current_filepath = Path(os.path.abspath(__file__))
17+
to_run = current_filepath.parents[0] / Path('run_me_with_mpiexec.py')
18+
subprocess_args = (f"mpiexec -np 4 python -W ignore {str(to_run)}").split(' ')
19+
20+
result = subprocess.run(subprocess_args, capture_output=False, text=True)
21+
out, err = capfd.readouterr()
22+
if len(out) + len(err) > 0:
23+
msg = out + '\n'+ 80*'-' + err
24+
raise RuntimeError(msg)
25+
return
26+

test/unit/objects/test_objectivefns.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,12 @@ def test_derivative(self):
300300
places=3) # each *element* should match to 3 places
301301

302302
if self.computes_lsvec:
303-
lsvec = objfn.lsvec().copy()
304-
dlsvec = objfn.dlsvec().copy()
305-
self.assertArraysAlmostEqual(dterms / nEls, 2 * lsvec[:, None] * dlsvec / nEls,
306-
places=4) # each *element* should match to 4 places
303+
arg1 = dterms / nEls
304+
lsvec = objfn.lsvec(v0).copy()
305+
dlsvec = objfn.dlsvec(v0).copy()
306+
arg2 = 2 * lsvec[:, None] * dlsvec / nEls
307+
self.assertArraysAlmostEqual(arg1, arg2, places=4) # each *element* should match to 4 places
308+
return
307309

308310
def test_approximate_hessian(self):
309311
if not self.enable_hessian_tests:

0 commit comments

Comments
 (0)