Skip to content

Commit 67d34c1

Browse files
authored
Merge pull request #3767 from mrmundt/remove-iter
Remove `iteration_count` as a default Results object value
2 parents b1dc105 + 973224e commit 67d34c1

File tree

9 files changed

+28
-26
lines changed

9 files changed

+28
-26
lines changed

pyomo/contrib/solver/common/results.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,6 @@ def __init__(
197197
description="A tuple representing the version of the solver in use.",
198198
),
199199
)
200-
self.iteration_count: Optional[int] = self.declare(
201-
'iteration_count',
202-
ConfigValue(
203-
domain=NonNegativeInt,
204-
default=None,
205-
description="The total number of iterations.",
206-
),
207-
)
208200
self.timing_info: ConfigDict = self.declare(
209201
'timing_info', ConfigDict(implicit=True)
210202
)

pyomo/contrib/solver/solvers/gurobi_direct.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import math
1515
import operator
1616
import os
17+
import logging
1718

1819
from pyomo.common.collections import ComponentMap, ComponentSet
1920
from pyomo.common.config import ConfigValue
@@ -43,6 +44,7 @@
4344
)
4445
from pyomo.contrib.solver.common.solution_loader import SolutionLoaderBase
4546

47+
logger = logging.getLogger(__name__)
4648

4749
gurobipy, gurobipy_available = attempt_import('gurobipy')
4850

@@ -442,7 +444,9 @@ def _postsolve(self, timer: HierarchicalTimer, config, loader):
442444
results.incumbent_objective = None
443445
results.objective_bound = None
444446

445-
results.iteration_count = grb_model.getAttr('IterCount')
447+
results.extra_info.IterCount = grb_model.getAttr('IterCount')
448+
results.extra_info.BarIterCount = grb_model.getAttr('BarIterCount')
449+
results.extra_info.NodeCount = grb_model.getAttr('NodeCount')
446450

447451
timer.start('load solution')
448452
if config.load_solutions:

pyomo/contrib/solver/solvers/gurobi_persistent.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,9 @@ def _postsolve(self, timer: HierarchicalTimer):
857857
):
858858
results.incumbent_objective = None
859859

860-
results.iteration_count = gprob.getAttr('IterCount')
860+
results.extra_info.IterCount = gprob.getAttr('IterCount')
861+
results.extra_info.BarIterCount = gprob.getAttr('BarIterCount')
862+
results.extra_info.NodeCount = gprob.getAttr('NodeCount')
861863

862864
timer.start('load solution')
863865
if config.load_solutions:

pyomo/contrib/solver/solvers/highs.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,15 @@ def _postsolve(self, stream: io.StringIO):
750750
results.objective_bound = None
751751
else:
752752
results.objective_bound = info.mip_dual_bound
753-
results.iteration_count = info.simplex_iteration_count
753+
754+
if info.valid:
755+
results.extra_info.simplex_iteration_count = (
756+
info.simplex_iteration_count
757+
)
758+
results.extra_info.ipm_iteration_count = info.ipm_iteration_count
759+
results.extra_info.mip_node_count = info.mip_node_count
760+
results.extra_info.pdlp_iteration_count = info.pdlp_iteration_count
761+
results.extra_info.qp_iteration_count = info.qp_iteration_count
754762

755763
if config.load_solutions:
756764
if has_feasible_solution:

pyomo/contrib/solver/solvers/ipopt.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ def solve(self, model, **kwds) -> Results:
473473
results = Results()
474474
results.termination_condition = TerminationCondition.provenInfeasible
475475
results.solution_loader = SolSolutionLoader(None, None)
476-
results.iteration_count = 0
476+
results.extra_info.iteration_count = 0
477477
results.timing_info.total_seconds = 0
478478
elif len(nl_info.variables) == 0:
479479
if len(nl_info.eliminated_vars) == 0:
@@ -487,7 +487,7 @@ def solve(self, model, **kwds) -> Results:
487487
)
488488
results.solution_status = SolutionStatus.optimal
489489
results.solution_loader = SolSolutionLoader(None, nl_info=nl_info)
490-
results.iteration_count = 0
490+
results.extra_info.iteration_count = 0
491491
results.timing_info.total_seconds = 0
492492
else:
493493
if os.path.isfile(basename + '.sol'):
@@ -503,7 +503,9 @@ def solve(self, model, **kwds) -> Results:
503503
results.solution_loader = SolSolutionLoader(None, None)
504504
else:
505505
try:
506-
results.iteration_count = parsed_output_data.pop('iters')
506+
results.extra_info.iteration_count = parsed_output_data.pop(
507+
'iters'
508+
)
507509
cpu_seconds = parsed_output_data.pop('cpu_seconds')
508510
for k, v in cpu_seconds.items():
509511
results.timing_info[k] = v

pyomo/contrib/solver/solvers/knitro/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def _postsolve(self, config: KnitroConfig, timer: HierarchicalTimer) -> Results:
141141
results.solution_status = self._get_solution_status(status)
142142
results.termination_condition = self._get_termination_condition(status)
143143
results.incumbent_objective = self._engine.get_obj_value()
144-
results.iteration_count = self._engine.get_num_iters()
144+
results.extra_info.iteration_count = self._engine.get_num_iters()
145145
results.timing_info.solve_time = self._engine.get_solve_time()
146146
results.timing_info.timer = timer
147147

pyomo/contrib/solver/tests/solvers/test_ipopt.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -594,13 +594,13 @@ def test_ipopt_quiet_print_level(self):
594594
result = ipopt.Ipopt().solve(model, solver_options={'print_level': 0})
595595
# IPOPT doesn't tell us anything about the iters if the print level
596596
# is set to 0
597-
self.assertIsNone(result.iteration_count)
597+
self.assertFalse(hasattr(result.extra_info, 'iteration_count'))
598598
self.assertFalse(hasattr(result.extra_info, 'iteration_log'))
599599
model = self.create_model()
600600
result = ipopt.Ipopt().solve(model, solver_options={'print_level': 3})
601601
# At a slightly higher level, we get some of the info, like
602602
# iteration count, but NOT iteration_log
603-
self.assertEqual(result.iteration_count, 11)
603+
self.assertEqual(result.extra_info.iteration_count, 11)
604604
self.assertFalse(hasattr(result.extra_info, 'iteration_log'))
605605

606606
def test_ipopt_loud_print_level(self):
@@ -609,13 +609,13 @@ def test_ipopt_loud_print_level(self):
609609
result = ipopt.Ipopt().solve(model, solver_options={'print_level': 8})
610610
# Nothing unexpected should be in the results object at this point,
611611
# except that the solver_log is significantly longer
612-
self.assertEqual(result.iteration_count, 11)
612+
self.assertEqual(result.extra_info.iteration_count, 11)
613613
self.assertEqual(result.incumbent_objective, 7.013645951336496e-25)
614614
self.assertIn('Optimal Solution Found', result.extra_info.solver_message)
615615
self.assertTrue(hasattr(result.extra_info, 'iteration_log'))
616616
model = self.create_model()
617617
result = ipopt.Ipopt().solve(model, solver_options={'print_level': 12})
618-
self.assertEqual(result.iteration_count, 11)
618+
self.assertEqual(result.extra_info.iteration_count, 11)
619619
self.assertEqual(result.incumbent_objective, 7.013645951336496e-25)
620620
self.assertIn('Optimal Solution Found', result.extra_info.solver_message)
621621
self.assertTrue(hasattr(result.extra_info, 'iteration_log'))
@@ -624,7 +624,7 @@ def test_ipopt_results(self):
624624
model = self.create_model()
625625
results = ipopt.Ipopt().solve(model)
626626
self.assertEqual(results.solver_name, 'ipopt')
627-
self.assertEqual(results.iteration_count, 11)
627+
self.assertEqual(results.extra_info.iteration_count, 11)
628628
self.assertEqual(results.incumbent_objective, 7.013645951336496e-25)
629629
self.assertIn('Optimal Solution Found', results.extra_info.solver_message)
630630

pyomo/contrib/solver/tests/solvers/test_solvers.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,6 @@ def test_results_object_populated(
604604
for v in res.solver_version:
605605
self.assertIsInstance(v, int)
606606

607-
# iteration_count is nonnegative
608-
self.assertGreaterEqual(res.iteration_count, 0)
609-
610607
# timing_info should exist
611608
self.assertIsNotNone(res.timing_info)
612609

pyomo/contrib/solver/tests/unit/test_results.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ def test_member_list(self):
157157
expected_declared = {
158158
'extra_info',
159159
'incumbent_objective',
160-
'iteration_count',
161160
'objective_bound',
162161
'solution_loader',
163162
'solution_status',
@@ -182,7 +181,6 @@ def test_default_initialization(self):
182181
self.assertEqual(res.solution_status, results.SolutionStatus.noSolution)
183182
self.assertIsNone(res.solver_name)
184183
self.assertIsNone(res.solver_version)
185-
self.assertIsNone(res.iteration_count)
186184
self.assertIsInstance(res.timing_info, ConfigDict)
187185
self.assertIsInstance(res.extra_info, ConfigDict)
188186
self.assertIsNone(res.timing_info.start_timestamp)
@@ -198,7 +196,6 @@ def test_display(self):
198196
objective_bound: None
199197
solver_name: None
200198
solver_version: None
201-
iteration_count: None
202199
timing_info:
203200
start_timestamp: None
204201
wall_time: None

0 commit comments

Comments
 (0)