Skip to content

Commit

Permalink
allow setting progress=False in solver to disable stdout even for lar…
Browse files Browse the repository at this point in the history
…ger models
  • Loading branch information
maurerle committed Nov 11, 2024
1 parent f785046 commit 4e0b2b3
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 39 deletions.
94 changes: 56 additions & 38 deletions linopy/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ def objective_write_quad_terms(


def objective_to_file(
m: Model, f: TextIOWrapper, log: bool = False, batch_size: int = 10000
m: Model, f: TextIOWrapper, progress: bool = False, batch_size: int = 10000
) -> None:
"""
Write out the objective of a model to a lp file.
"""
if log:
if progress:
logger.info("Writing objective.")

sense = m.objective.sense
Expand Down Expand Up @@ -129,7 +129,7 @@ def objective_to_file(
def constraints_to_file(
m: Model,
f: TextIOWrapper,
log: bool = False,
progress: bool = False,
batch_size: int = 50_000,
slice_size: int = 100_000,
) -> None:
Expand All @@ -138,7 +138,7 @@ def constraints_to_file(

f.write("\n\ns.t.\n\n")
names: Iterable = m.constraints
if log:
if progress:
names = tqdm(
list(names),
desc="Writing constraints.",
Expand Down Expand Up @@ -198,7 +198,7 @@ def constraints_to_file(
def bounds_to_file(
m: Model,
f: TextIOWrapper,
log: bool = False,
progress: bool = False,
batch_size: int = 10000,
slice_size: int = 100_000,
) -> None:
Expand All @@ -210,7 +210,7 @@ def bounds_to_file(
return

f.write("\n\nbounds\n\n")
if log:
if progress:
names = tqdm(
list(names),
desc="Writing continuous variables.",
Expand Down Expand Up @@ -241,7 +241,7 @@ def bounds_to_file(
def binaries_to_file(
m: Model,
f: TextIOWrapper,
log: bool = False,
progress: bool = False,
batch_size: int = 1000,
slice_size: int = 100_000,
) -> None:
Expand All @@ -253,7 +253,7 @@ def binaries_to_file(
return

f.write("\n\nbinary\n\n")
if log:
if progress:
names = tqdm(
list(names),
desc="Writing binary variables.",
Expand All @@ -277,7 +277,7 @@ def binaries_to_file(
def integers_to_file(
m: Model,
f: TextIOWrapper,
log: bool = False,
progress: bool = False,
batch_size: int = 1000,
slice_size: int = 100_000,
integer_label: str = "general",
Expand All @@ -290,7 +290,7 @@ def integers_to_file(
return

f.write(f"\n\n{integer_label}\n\n")
if log:
if progress:
names = tqdm(
list(names),
desc="Writing integer variables.",
Expand All @@ -311,9 +311,13 @@ def integers_to_file(
f.writelines(batch)


def to_lp_file(m: Model, fn: Path, integer_label: str, slice_size: int = 10_000_000):
log = m._xCounter > 10_000

def to_lp_file(
m: Model,
fn: Path,
integer_label: str,
slice_size: int = 10_000_000,
progress: bool = True,
) -> None:
batch_size = 5000

with open(fn, mode="w") as f:
Expand All @@ -322,17 +326,21 @@ def to_lp_file(m: Model, fn: Path, integer_label: str, slice_size: int = 10_000_
if isinstance(f, int):
raise ValueError("File not found.")

objective_to_file(m, f, log=log)
objective_to_file(m, f, progress=progress)
constraints_to_file(
m, f=f, log=log, batch_size=batch_size, slice_size=slice_size
m, f=f, progress=progress, batch_size=batch_size, slice_size=slice_size
)
bounds_to_file(
m, f=f, progress=progress, batch_size=batch_size, slice_size=slice_size
)
binaries_to_file(
m, f=f, progress=progress, batch_size=batch_size, slice_size=slice_size
)
bounds_to_file(m, f=f, log=log, batch_size=batch_size, slice_size=slice_size)
binaries_to_file(m, f=f, log=log, batch_size=batch_size, slice_size=slice_size)
integers_to_file(
m,
integer_label=integer_label,
f=f,
log=log,
progress=progress,
batch_size=batch_size,
slice_size=slice_size,
)
Expand Down Expand Up @@ -371,11 +379,11 @@ def objective_write_quadratic_terms_polars(f, df):
f.write(b"] / 2\n")


def objective_to_file_polars(m, f, log=False):
def objective_to_file_polars(m, f, progress=False):
"""
Write out the objective of a model to a lp file.
"""
if log:
if progress:
logger.info("Writing objective.")

sense = m.objective.sense
Expand All @@ -399,7 +407,7 @@ def objective_to_file_polars(m, f, log=False):
objective_write_quadratic_terms_polars(f, quads)


def bounds_to_file_polars(m, f, log=False, slice_size=2_000_000):
def bounds_to_file_polars(m, f, progress=False, slice_size=2_000_000):
"""
Write out variables of a model to a lp file.
"""
Expand All @@ -408,7 +416,7 @@ def bounds_to_file_polars(m, f, log=False, slice_size=2_000_000):
return

f.write(b"\n\nbounds\n\n")
if log:
if progress:
names = tqdm(
list(names),
desc="Writing continuous variables.",
Expand Down Expand Up @@ -437,7 +445,7 @@ def bounds_to_file_polars(m, f, log=False, slice_size=2_000_000):
formatted.write_csv(f, **kwargs)


def binaries_to_file_polars(m, f, log=False, slice_size=2_000_000):
def binaries_to_file_polars(m, f, progress=False, slice_size=2_000_000):
"""
Write out binaries of a model to a lp file.
"""
Expand All @@ -446,7 +454,7 @@ def binaries_to_file_polars(m, f, log=False, slice_size=2_000_000):
return

f.write(b"\n\nbinary\n\n")
if log:
if progress:
names = tqdm(
list(names),
desc="Writing binary variables.",
Expand All @@ -471,7 +479,7 @@ def binaries_to_file_polars(m, f, log=False, slice_size=2_000_000):


def integers_to_file_polars(
m, f, log=False, integer_label="general", slice_size=2_000_000
m, f, progress=False, integer_label="general", slice_size=2_000_000
):
"""
Write out integers of a model to a lp file.
Expand All @@ -481,7 +489,7 @@ def integers_to_file_polars(
return

f.write(f"\n\n{integer_label}\n\n".encode())
if log:
if progress:
names = tqdm(
list(names),
desc="Writing integer variables.",
Expand All @@ -505,13 +513,13 @@ def integers_to_file_polars(
formatted.write_csv(f, **kwargs)


def constraints_to_file_polars(m, f, log=False, lazy=False, slice_size=2_000_000):
def constraints_to_file_polars(m, f, progress=False, lazy=False, slice_size=2_000_000):
if not len(m.constraints):
return

f.write(b"\n\ns.t.\n\n")
names = m.constraints
if log:
if progress:
names = tqdm(
list(names),
desc="Writing constraints.",
Expand Down Expand Up @@ -559,18 +567,22 @@ def constraints_to_file_polars(m, f, log=False, lazy=False, slice_size=2_000_000
# formatted.sink_csv(f, **kwargs)


def to_lp_file_polars(m, fn, integer_label="general", slice_size=2_000_000):
log = m._xCounter > 10_000

def to_lp_file_polars(
m, fn, integer_label="general", slice_size=2_000_000, progress: bool = True
):
with open(fn, mode="wb") as f:
start = time.time()

objective_to_file_polars(m, f, log=log)
constraints_to_file_polars(m, f=f, log=log, slice_size=slice_size)
bounds_to_file_polars(m, f=f, log=log, slice_size=slice_size)
binaries_to_file_polars(m, f=f, log=log, slice_size=slice_size)
objective_to_file_polars(m, f, progress=progress)
constraints_to_file_polars(m, f=f, progress=progress, slice_size=slice_size)
bounds_to_file_polars(m, f=f, progress=progress, slice_size=slice_size)
binaries_to_file_polars(m, f=f, progress=progress, slice_size=slice_size)
integers_to_file_polars(
m, integer_label=integer_label, f=f, log=log, slice_size=slice_size
m,
integer_label=integer_label,
f=f,
progress=progress,
slice_size=slice_size,
)
f.write(b"end\n")

Expand All @@ -583,6 +595,7 @@ def to_file(
io_api: str | None = None,
integer_label: str = "general",
slice_size: int = 2_000_000,
progress: bool | None = None,
) -> Path:
"""
Write out a model to a lp or mps file.
Expand All @@ -597,10 +610,15 @@ def to_file(
if io_api is None:
io_api = fn.suffix[1:]

if progress is None:
progress = m._xCounter > 10_000

if io_api == "lp":
to_lp_file(m, fn, integer_label, slice_size=slice_size)
to_lp_file(m, fn, integer_label, slice_size=slice_size, progress=progress)
elif io_api == "lp-polars":
to_lp_file_polars(m, fn, integer_label, slice_size=slice_size)
to_lp_file_polars(
m, fn, integer_label, slice_size=slice_size, progress=progress
)

elif io_api == "mps":
if "highs" not in solvers.available_solvers:
Expand Down
7 changes: 6 additions & 1 deletion linopy/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,7 @@ def solve(
sanitize_infinities: bool = True,
slice_size: int = 2_000_000,
remote: None = None,
progress: bool | None = None,
**solver_options,
) -> tuple[str, str]:
"""
Expand Down Expand Up @@ -1027,6 +1028,10 @@ def solve(
Remote handler to use for solving model on a server. Note that when
solving on a rSee
linopy.remote.RemoteHandler for more details.
progress : bool, optional
Whether to show a progress bar of writing the lp file. The default is
None, which means that the progress bar is shown if the model has more
than 10000 variables and constraints.
**solver_options : kwargs
Options passed to the solver.
Expand Down Expand Up @@ -1124,7 +1129,7 @@ def solve(
env=env,
)
else:
problem_fn = self.to_file(to_path(problem_fn), io_api)
problem_fn = self.to_file(to_path(problem_fn), io_api, progress=progress)
result = solver.solve_problem_from_file(
problem_fn=to_path(problem_fn),
solution_fn=to_path(solution_fn),
Expand Down

0 comments on commit 4e0b2b3

Please sign in to comment.