From e75850fab8fbcbe570b41dd635098fafa323f607 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Fri, 2 Feb 2024 14:34:20 -0600 Subject: [PATCH] LearningSolver: Keep original H5 file unmodified --- CHANGELOG.md | 13 ++++++++++++- docs/tutorials/getting-started-gurobipy.ipynb | 2 +- docs/tutorials/getting-started-jump.ipynb | 2 +- docs/tutorials/getting-started-pyomo.ipynb | 2 +- miplearn/solvers/learning.py | 14 ++++++++++---- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e21b8..b35342b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.0] - Unreleased + +### Added + +- Add ML strategies for user cuts +- Add ML strategies for lazy constraints + +### Changed + +- LearningSolver.solve no longer generates HDF5 files; use a collector instead. + ## [0.3.0] - 2023-06-08 This is a complete rewrite of the original prototype package, with an entirely new API, focused on performance, scalability and flexibility. @@ -31,4 +42,4 @@ This is a complete rewrite of the original prototype package, with an entirely n ## [0.1.0] - 2020-11-23 -- Initial public release \ No newline at end of file +- Initial public release diff --git a/docs/tutorials/getting-started-gurobipy.ipynb b/docs/tutorials/getting-started-gurobipy.ipynb index 39f757b..110e3f4 100644 --- a/docs/tutorials/getting-started-gurobipy.ipynb +++ b/docs/tutorials/getting-started-gurobipy.ipynb @@ -695,7 +695,7 @@ "source": [ "## Accessing the solution\n", "\n", - "In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver." + "In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver." ] }, { diff --git a/docs/tutorials/getting-started-jump.ipynb b/docs/tutorials/getting-started-jump.ipynb index ec76ac2..8dbf587 100644 --- a/docs/tutorials/getting-started-jump.ipynb +++ b/docs/tutorials/getting-started-jump.ipynb @@ -592,7 +592,7 @@ "source": [ "## Accessing the solution\n", "\n", - "In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a JuMP model entirely in-memory, using our trained solver." + "In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. In the following example, we show how to build and solve a JuMP model entirely in-memory, using our trained solver." ] }, { diff --git a/docs/tutorials/getting-started-pyomo.ipynb b/docs/tutorials/getting-started-pyomo.ipynb index 2618f74..e109ddb 100644 --- a/docs/tutorials/getting-started-pyomo.ipynb +++ b/docs/tutorials/getting-started-pyomo.ipynb @@ -712,7 +712,7 @@ "source": [ "## Accessing the solution\n", "\n", - "In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver." + "In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver." ] }, { diff --git a/miplearn/solvers/learning.py b/miplearn/solvers/learning.py index 66a808b..38d7b08 100644 --- a/miplearn/solvers/learning.py +++ b/miplearn/solvers/learning.py @@ -8,6 +8,7 @@ from typing import List, Any, Union, Dict, Callable, Optional from miplearn.h5 import H5File from miplearn.io import _to_h5_filename from miplearn.solvers.abstract import AbstractModel +import shutil class LearningSolver: @@ -25,15 +26,20 @@ class LearningSolver: model: Union[str, AbstractModel], build_model: Optional[Callable] = None, ) -> Dict[str, Any]: + h5_filename, mode = NamedTemporaryFile().name, "w" if isinstance(model, str): - h5_filename = _to_h5_filename(model) assert build_model is not None + old_h5_filename = _to_h5_filename(model) model = build_model(model) assert isinstance(model, AbstractModel) - else: - h5_filename = NamedTemporaryFile().name + + # If the instance has an associate H5 file, we make a temporary copy of it, + # then work on that copy. We keep the original file unmodified + if exists(old_h5_filename): + shutil.copy(old_h5_filename, h5_filename) + mode = "r+" + stats: Dict[str, Any] = {} - mode = "r+" if exists(h5_filename) else "w" with H5File(h5_filename, mode) as h5: model.extract_after_load(h5) if not self.skip_lp: