gamspy 1.18.1__py3-none-any.whl → 1.18.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gamspy/_algebra/domain.py +1 -1
- gamspy/_algebra/expression.py +1 -1
- gamspy/_algebra/operation.py +10 -3
- gamspy/_cli/cli.py +2 -1
- gamspy/_cli/mps2gms.py +128 -0
- gamspy/_container.py +44 -2
- gamspy/_convert.py +97 -66
- gamspy/_extrinsic.py +17 -1
- gamspy/_model.py +44 -9
- gamspy/_symbols/alias.py +2 -0
- gamspy/_symbols/equation.py +15 -7
- gamspy/_symbols/implicits/implicit_set.py +2 -1
- gamspy/_symbols/implicits/implicit_symbol.py +6 -1
- gamspy/_symbols/parameter.py +2 -0
- gamspy/_symbols/set.py +2 -0
- gamspy/_symbols/symbol.py +1 -2
- gamspy/_symbols/universe_alias.py +26 -1
- gamspy/_symbols/variable.py +2 -0
- gamspy/_validation.py +10 -1
- gamspy/math/misc.py +19 -6
- gamspy/utils.py +22 -11
- {gamspy-1.18.1.dist-info → gamspy-1.18.3.dist-info}/METADATA +3 -3
- {gamspy-1.18.1.dist-info → gamspy-1.18.3.dist-info}/RECORD +27 -26
- {gamspy-1.18.1.dist-info → gamspy-1.18.3.dist-info}/WHEEL +0 -0
- {gamspy-1.18.1.dist-info → gamspy-1.18.3.dist-info}/entry_points.txt +0 -0
- {gamspy-1.18.1.dist-info → gamspy-1.18.3.dist-info}/licenses/LICENSE +0 -0
- {gamspy-1.18.1.dist-info → gamspy-1.18.3.dist-info}/top_level.txt +0 -0
gamspy/_algebra/domain.py
CHANGED
gamspy/_algebra/expression.py
CHANGED
|
@@ -234,7 +234,7 @@ def create_latex_expression(root_node: Expression) -> str:
|
|
|
234
234
|
if node.right is not None:
|
|
235
235
|
s1.append(node.right)
|
|
236
236
|
|
|
237
|
-
# 2. Build the
|
|
237
|
+
# 2. Build the LaTeX expression
|
|
238
238
|
eval_stack: list[tuple[str, float]] = []
|
|
239
239
|
for node in reversed(post_order_nodes):
|
|
240
240
|
if not isinstance(node, Expression):
|
gamspy/_algebra/operation.py
CHANGED
|
@@ -96,8 +96,15 @@ class Operation(operable.Operable):
|
|
|
96
96
|
"""
|
|
97
97
|
assert self.container is not None
|
|
98
98
|
temp_name = "a" + utils._get_unique_name()
|
|
99
|
+
domain: list[Set | Alias] = []
|
|
100
|
+
for elem in self.domain:
|
|
101
|
+
if hasattr(elem, "dimension") and elem.dimension > 1:
|
|
102
|
+
domain.extend(elem.domain)
|
|
103
|
+
else:
|
|
104
|
+
domain.append(elem)
|
|
105
|
+
|
|
99
106
|
temp_param = syms.Parameter._constructor_bypass(
|
|
100
|
-
self.container, temp_name,
|
|
107
|
+
self.container, temp_name, domain
|
|
101
108
|
)
|
|
102
109
|
temp_param[...] = self
|
|
103
110
|
del self.container.data[temp_name]
|
|
@@ -756,7 +763,7 @@ class Ord(operable.Operable):
|
|
|
756
763
|
-------
|
|
757
764
|
str
|
|
758
765
|
"""
|
|
759
|
-
return f"ord({self._symbol.
|
|
766
|
+
return f"ord({self._symbol._latex_name})"
|
|
760
767
|
|
|
761
768
|
|
|
762
769
|
class Card(operable.Operable):
|
|
@@ -835,4 +842,4 @@ class Card(operable.Operable):
|
|
|
835
842
|
-------
|
|
836
843
|
str
|
|
837
844
|
"""
|
|
838
|
-
return f"card({self._symbol.
|
|
845
|
+
return f"card({self._symbol._latex_name})"
|
gamspy/_cli/cli.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typer
|
|
4
4
|
|
|
5
|
-
from . import gdx, install, list, probe, retrieve, run, show, uninstall
|
|
5
|
+
from . import gdx, install, list, mps2gms, probe, retrieve, run, show, uninstall
|
|
6
6
|
|
|
7
7
|
app = typer.Typer(
|
|
8
8
|
rich_markup_mode="rich",
|
|
@@ -16,6 +16,7 @@ app.add_typer(retrieve.app, name="retrieve")
|
|
|
16
16
|
app.add_typer(run.app, name="run")
|
|
17
17
|
app.add_typer(show.app, name="show")
|
|
18
18
|
app.add_typer(uninstall.app, name="uninstall")
|
|
19
|
+
app.command(name="mps2gms")(mps2gms.mps2gms)
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def version_callback(value: bool):
|
gamspy/_cli/mps2gms.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path # noqa: TC003
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
import gamspy_base
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
# Valid values for categorical parameters based on help string
|
|
13
|
+
VALID_YN = {"0", "N", "1", "Y"}
|
|
14
|
+
VALID_DUPLICATES = {"NOCHECK", "ADD", "IGNORE", "ERROR"}
|
|
15
|
+
VALID_ORIGNAMES = {"NO", "MODIFIED", "ALL"}
|
|
16
|
+
VALID_CONVERTSENSE = {"0", "N", "1", "Y", "MIN", "-1", "MAX"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Completion functions for Typer
|
|
20
|
+
def complete_yn(ctx: typer.Context, incomplete: str):
|
|
21
|
+
return [v for v in VALID_YN if v.lower().startswith(incomplete.lower())]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def complete_duplicates(ctx: typer.Context, incomplete: str):
|
|
25
|
+
return [v for v in VALID_DUPLICATES if v.lower().startswith(incomplete.lower())]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def complete_orignames(ctx: typer.Context, incomplete: str):
|
|
29
|
+
return [v for v in VALID_ORIGNAMES if v.lower().startswith(incomplete.lower())]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def complete_convertsense(ctx: typer.Context, incomplete: str):
|
|
33
|
+
return [v for v in VALID_CONVERTSENSE if v.lower().startswith(incomplete.lower())]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def mps2gms(
|
|
37
|
+
input_file: Annotated[
|
|
38
|
+
Path, typer.Argument(help="MPS or LP file to translate.", exists=True)
|
|
39
|
+
],
|
|
40
|
+
gdx_file: Annotated[
|
|
41
|
+
Path | None, typer.Argument(help="Name of GDX output file.")
|
|
42
|
+
] = None,
|
|
43
|
+
gms_file: Annotated[
|
|
44
|
+
Path | None, typer.Argument(help="Name of GAMS program output file.")
|
|
45
|
+
] = None,
|
|
46
|
+
py_file: Annotated[
|
|
47
|
+
str | None, typer.Option("--py", help="Name of GAMSPy program output file.")
|
|
48
|
+
] = None,
|
|
49
|
+
dec_file: Annotated[
|
|
50
|
+
str | None, typer.Option("--dec", help="DEC file for decomposition info.")
|
|
51
|
+
] = None,
|
|
52
|
+
column_int_vars_binary: Annotated[
|
|
53
|
+
str | None,
|
|
54
|
+
typer.Option(
|
|
55
|
+
"--columnintvarsarebinary",
|
|
56
|
+
help="Integer variables appearing first are binary.",
|
|
57
|
+
autocompletion=complete_yn,
|
|
58
|
+
),
|
|
59
|
+
] = None,
|
|
60
|
+
duplicates: Annotated[
|
|
61
|
+
str | None,
|
|
62
|
+
typer.Option(
|
|
63
|
+
help="How to handle multiple coefficients.",
|
|
64
|
+
autocompletion=complete_duplicates,
|
|
65
|
+
),
|
|
66
|
+
] = None,
|
|
67
|
+
orignames: Annotated[
|
|
68
|
+
str | None,
|
|
69
|
+
typer.Option(
|
|
70
|
+
help="Whether to make original names available.",
|
|
71
|
+
autocompletion=complete_orignames,
|
|
72
|
+
),
|
|
73
|
+
] = None,
|
|
74
|
+
stageshift: Annotated[
|
|
75
|
+
int | None, typer.Option(help="Shift block numbers by this integer.")
|
|
76
|
+
] = None,
|
|
77
|
+
convertsense: Annotated[
|
|
78
|
+
str | None,
|
|
79
|
+
typer.Option(
|
|
80
|
+
help="Convert the objective function sense.",
|
|
81
|
+
autocompletion=complete_convertsense,
|
|
82
|
+
),
|
|
83
|
+
] = None,
|
|
84
|
+
):
|
|
85
|
+
"""
|
|
86
|
+
Translates an MPS or LP file into equivalent generic GAMS and GAMSPy programs.
|
|
87
|
+
Defaults to writing .py and .gdx files if no outputs are specified.
|
|
88
|
+
"""
|
|
89
|
+
binary_name = "mps2gms.exe" if platform.system() == "Windows" else "mps2gms"
|
|
90
|
+
MPS2GMS_PATH = os.path.join(gamspy_base.directory, binary_name)
|
|
91
|
+
|
|
92
|
+
if not os.path.exists(MPS2GMS_PATH):
|
|
93
|
+
typer.echo(f"Binary not found: {MPS2GMS_PATH}", err=True)
|
|
94
|
+
raise typer.Exit(code=1)
|
|
95
|
+
|
|
96
|
+
# Determine default names based on input stem
|
|
97
|
+
input_name = input_file.with_suffix("")
|
|
98
|
+
actual_gdx = gdx_file if gdx_file else f"{input_name}.gdx"
|
|
99
|
+
actual_py = py_file if py_file else f"{input_name}.py"
|
|
100
|
+
|
|
101
|
+
# mps2gms <input> <gdx>
|
|
102
|
+
cmd = [MPS2GMS_PATH, str(input_file), str(actual_gdx)]
|
|
103
|
+
|
|
104
|
+
# If gms_file is provided, add it as the third positional;
|
|
105
|
+
# otherwise, explicitly disable GMS output to prioritize py/gdx.
|
|
106
|
+
if gms_file:
|
|
107
|
+
cmd.append(str(gms_file))
|
|
108
|
+
else:
|
|
109
|
+
cmd.append("GMS=")
|
|
110
|
+
|
|
111
|
+
# Construct key=value parameters for the binary call
|
|
112
|
+
params = {
|
|
113
|
+
"PY": actual_py,
|
|
114
|
+
"DEC": dec_file,
|
|
115
|
+
"COLUMNINTVARSAREBINARY": column_int_vars_binary,
|
|
116
|
+
"DUPLICATES": duplicates,
|
|
117
|
+
"ORIGNAMES": orignames,
|
|
118
|
+
"STAGESHIFT": stageshift,
|
|
119
|
+
"CONVERTSENSE": convertsense,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for key, value in params.items():
|
|
123
|
+
if value is not None:
|
|
124
|
+
cmd.append(f"{key}={value}")
|
|
125
|
+
|
|
126
|
+
print(f"Running command: {' '.join(cmd)}")
|
|
127
|
+
result = subprocess.run(cmd, text=True)
|
|
128
|
+
raise typer.Exit(code=result.returncode)
|
gamspy/_container.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import atexit
|
|
4
4
|
import os
|
|
5
5
|
import platform
|
|
6
|
+
import re
|
|
6
7
|
import shutil
|
|
7
8
|
import signal
|
|
8
9
|
import sys
|
|
@@ -42,6 +43,7 @@ if TYPE_CHECKING:
|
|
|
42
43
|
Model,
|
|
43
44
|
Parameter,
|
|
44
45
|
Set,
|
|
46
|
+
UniverseAlias,
|
|
45
47
|
Variable,
|
|
46
48
|
)
|
|
47
49
|
from gamspy._algebra.expression import Expression
|
|
@@ -139,6 +141,7 @@ class Container(gt.Container):
|
|
|
139
141
|
self.output = output
|
|
140
142
|
self._gams_string = ""
|
|
141
143
|
self.models: dict[str, Model] = {}
|
|
144
|
+
self._mpsge_models: list[str] = []
|
|
142
145
|
if IS_MIRO_INIT:
|
|
143
146
|
atexit.register(self._write_miro_files)
|
|
144
147
|
|
|
@@ -838,6 +841,14 @@ class Container(gt.Container):
|
|
|
838
841
|
|
|
839
842
|
for _, symbol in self:
|
|
840
843
|
symbol.modified = False
|
|
844
|
+
|
|
845
|
+
# Unfortunately MPSGE requires a dirty trick
|
|
846
|
+
pattern = re.compile(r"^\$sysInclude\s+mpsgeset\s+(\w+)\s*$", re.MULTILINE)
|
|
847
|
+
match = pattern.search(gams_code)
|
|
848
|
+
if match:
|
|
849
|
+
model_name = match.group(1)
|
|
850
|
+
self._mpsge_models.append(model_name.lower())
|
|
851
|
+
|
|
841
852
|
self._unsaved_statements = []
|
|
842
853
|
|
|
843
854
|
def close(self) -> None:
|
|
@@ -888,6 +899,37 @@ class Container(gt.Container):
|
|
|
888
899
|
|
|
889
900
|
return gp.Alias(self, name, alias_with)
|
|
890
901
|
|
|
902
|
+
def addUniverseAlias(self, name: str | None = None) -> UniverseAlias:
|
|
903
|
+
"""
|
|
904
|
+
Creates a new UniverseAlias and adds it to the container
|
|
905
|
+
|
|
906
|
+
Parameters
|
|
907
|
+
----------
|
|
908
|
+
name : str, optional
|
|
909
|
+
Name of the universe alias.
|
|
910
|
+
|
|
911
|
+
Returns
|
|
912
|
+
-------
|
|
913
|
+
UniverseAlias
|
|
914
|
+
|
|
915
|
+
Raises
|
|
916
|
+
------
|
|
917
|
+
ValueError
|
|
918
|
+
If there is symbol with same name but different type in the
|
|
919
|
+
Container
|
|
920
|
+
|
|
921
|
+
Examples
|
|
922
|
+
--------
|
|
923
|
+
>>> import gamspy as gp
|
|
924
|
+
>>> m = gp.Container()
|
|
925
|
+
>>> a = m.addUniverseAlias("a")
|
|
926
|
+
|
|
927
|
+
"""
|
|
928
|
+
if name is None:
|
|
929
|
+
name = self._get_symbol_name(prefix="u")
|
|
930
|
+
|
|
931
|
+
return gp.UniverseAlias(self, name)
|
|
932
|
+
|
|
891
933
|
def addSet(
|
|
892
934
|
self,
|
|
893
935
|
name: str | None = None,
|
|
@@ -1099,7 +1141,7 @@ class Container(gt.Container):
|
|
|
1099
1141
|
self,
|
|
1100
1142
|
name: str | None = None,
|
|
1101
1143
|
type: str | EquationType = "regular",
|
|
1102
|
-
domain: Sequence[Set | Alias
|
|
1144
|
+
domain: Sequence[Set | Alias] | Set | Alias | None = None,
|
|
1103
1145
|
definition: Variable | Operation | Expression | None = None,
|
|
1104
1146
|
records: Any | None = None,
|
|
1105
1147
|
domain_forwarding: bool | list[bool] = False,
|
|
@@ -1117,7 +1159,7 @@ class Container(gt.Container):
|
|
|
1117
1159
|
Name of the equation. Name is autogenerated by default.
|
|
1118
1160
|
type : str
|
|
1119
1161
|
Type of the equation. "regular" by default.
|
|
1120
|
-
domain : Sequence[Set | Alias
|
|
1162
|
+
domain : Sequence[Set | Alias] | Set | Alias, optional
|
|
1121
1163
|
Domain of the variable.
|
|
1122
1164
|
definition: Expression, optional
|
|
1123
1165
|
Definition of the equation.
|
gamspy/_convert.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import logging
|
|
4
3
|
import os
|
|
5
4
|
import subprocess
|
|
6
5
|
from collections.abc import Sequence
|
|
@@ -28,14 +27,6 @@ if TYPE_CHECKING:
|
|
|
28
27
|
|
|
29
28
|
SymbolType: TypeAlias = Alias | Set | Parameter | Variable | Equation
|
|
30
29
|
|
|
31
|
-
logger = logging.getLogger("CONVERTER")
|
|
32
|
-
logger.setLevel(logging.INFO)
|
|
33
|
-
stream_handler = logging.StreamHandler()
|
|
34
|
-
stream_handler.setLevel(logging.INFO)
|
|
35
|
-
formatter = logging.Formatter("[%(name)s - %(levelname)s] %(message)s")
|
|
36
|
-
stream_handler.setFormatter(formatter)
|
|
37
|
-
logger.addHandler(stream_handler)
|
|
38
|
-
|
|
39
30
|
GAMS_JACOBIAN_TEMPLATE = """$onEmpty
|
|
40
31
|
Set
|
|
41
32
|
i 'equations index'
|
|
@@ -388,9 +379,9 @@ class GamsConverter:
|
|
|
388
379
|
self.path = path
|
|
389
380
|
self.options = options
|
|
390
381
|
self.dump_gams_state = dump_gams_state
|
|
391
|
-
self.gdx_path =
|
|
392
|
-
self.gms_path =
|
|
393
|
-
self.g00_path =
|
|
382
|
+
self.gdx_path = path / f"{model.name}_data.gdx"
|
|
383
|
+
self.gms_path = path / f"{model.name}.gms"
|
|
384
|
+
self.g00_path = path / f"{model.name}.g00"
|
|
394
385
|
|
|
395
386
|
def get_definitions(self) -> list[str]:
|
|
396
387
|
definitions = []
|
|
@@ -438,8 +429,8 @@ class GamsConverter:
|
|
|
438
429
|
em_name = self.model._external_module
|
|
439
430
|
em_file = self.model._external_module_file
|
|
440
431
|
declarations.append(f"File {em_file} /{em_name}/;")
|
|
441
|
-
|
|
442
|
-
|
|
432
|
+
print("Converter will not copy external module files")
|
|
433
|
+
print(
|
|
443
434
|
f"You need to ensure your external module is accessible from {self.path}"
|
|
444
435
|
)
|
|
445
436
|
|
|
@@ -482,7 +473,9 @@ class GamsConverter:
|
|
|
482
473
|
with open(self.gms_path, "w", encoding="utf-8") as file:
|
|
483
474
|
file.write(gams_string)
|
|
484
475
|
|
|
485
|
-
|
|
476
|
+
print("=" * 80)
|
|
477
|
+
print(f"GAMS (.gms) file has been generated under {self.gms_path}")
|
|
478
|
+
print("=" * 80)
|
|
486
479
|
|
|
487
480
|
|
|
488
481
|
TABLE_HEADER = """\\begin{tabularx}{\\textwidth}{| l | l | X |}
|
|
@@ -496,7 +489,7 @@ TABLE_FOOTER = "\\hline\n\\end{tabularx}"
|
|
|
496
489
|
|
|
497
490
|
|
|
498
491
|
class LatexConverter:
|
|
499
|
-
def __init__(self, model: Model, path: Path) -> None:
|
|
492
|
+
def __init__(self, model: Model, path: Path, rename: dict[str, str] | None) -> None:
|
|
500
493
|
os.makedirs(path, exist_ok=True)
|
|
501
494
|
self.model = model
|
|
502
495
|
self.container = model.container
|
|
@@ -512,11 +505,21 @@ class LatexConverter:
|
|
|
512
505
|
):
|
|
513
506
|
symbols.append(elem.name)
|
|
514
507
|
|
|
508
|
+
for name in self.model._autogen_symbols:
|
|
509
|
+
if name in symbols:
|
|
510
|
+
symbols.remove(name)
|
|
511
|
+
|
|
515
512
|
self.symbols = sorted(symbols, key=list(self.container.data.keys()).index)
|
|
516
513
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
514
|
+
if rename is not None:
|
|
515
|
+
for name, latex_name in rename.items():
|
|
516
|
+
try:
|
|
517
|
+
symbol = self.container[name]
|
|
518
|
+
symbol._latex_name = latex_name
|
|
519
|
+
except KeyError as e:
|
|
520
|
+
raise KeyError(
|
|
521
|
+
f"`{name}` does not exist in the Container. You can only rename symbols that already exist in the container."
|
|
522
|
+
) from e
|
|
520
523
|
|
|
521
524
|
self.header = self.get_header()
|
|
522
525
|
self.set_header = "\\subsection*{Sets}"
|
|
@@ -551,8 +554,9 @@ class LatexConverter:
|
|
|
551
554
|
if self.model._objective is None:
|
|
552
555
|
...
|
|
553
556
|
elif isinstance(self.model._objective, syms.Variable):
|
|
557
|
+
var_name = self.model._objective._latex_name
|
|
554
558
|
latex_strs.append(
|
|
555
|
-
f"\\textbf{{{str(self.model.sense).lower()}}} ${
|
|
559
|
+
f"\\textbf{{{str(self.model.sense).lower()}}} ${var_name}$\\\\"
|
|
556
560
|
)
|
|
557
561
|
latex_strs.append("\\textbf{s.t.}")
|
|
558
562
|
else:
|
|
@@ -572,26 +576,35 @@ class LatexConverter:
|
|
|
572
576
|
with open(self.tex_path, "w", encoding="utf-8") as file: # Write the TEX file
|
|
573
577
|
file.write(latex_str)
|
|
574
578
|
|
|
575
|
-
|
|
579
|
+
print("=" * 80)
|
|
580
|
+
print(
|
|
576
581
|
f"LaTeX (.tex) file has been generated under {os.path.join(self.path, self.model.name + '.tex')}"
|
|
577
582
|
)
|
|
583
|
+
print("=" * 80)
|
|
578
584
|
|
|
579
585
|
self.latex_str = latex_str
|
|
580
586
|
|
|
581
587
|
def to_pdf(self) -> None:
|
|
582
|
-
|
|
583
|
-
|
|
588
|
+
try:
|
|
589
|
+
subprocess.run(["xelatex", "-version"], check=True, text=True)
|
|
590
|
+
except subprocess.CalledProcessError as e:
|
|
584
591
|
raise ValidationError(
|
|
585
|
-
"`
|
|
592
|
+
"`xelatex` is required to generate the pdf! Please install `xelatex` and add it to the path."
|
|
593
|
+
) from e
|
|
594
|
+
|
|
595
|
+
try:
|
|
596
|
+
subprocess.run(
|
|
597
|
+
[
|
|
598
|
+
"xelatex",
|
|
599
|
+
"-verbose",
|
|
600
|
+
f"-output-directory={self.path}",
|
|
601
|
+
self.tex_path,
|
|
602
|
+
],
|
|
603
|
+
check=True,
|
|
604
|
+
text=True,
|
|
586
605
|
)
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
["pdflatex", f"-output-directory={self.path}", self.tex_path],
|
|
590
|
-
capture_output=True,
|
|
591
|
-
text=True,
|
|
592
|
-
)
|
|
593
|
-
if process.returncode:
|
|
594
|
-
raise LatexException(f"Could not generate pdf file: {process.stderr}")
|
|
606
|
+
except subprocess.CalledProcessError as e:
|
|
607
|
+
raise LatexException(f"Could not generate pdf file: {e}") from e
|
|
595
608
|
|
|
596
609
|
def get_table(self, symbol_type) -> str:
|
|
597
610
|
table = [TABLE_HEADER]
|
|
@@ -604,10 +617,11 @@ class LatexConverter:
|
|
|
604
617
|
if isinstance(symbol, syms.Variable) and self.model._limited_variables:
|
|
605
618
|
for elem in self.model._limited_variables:
|
|
606
619
|
if elem.name == symbol.name:
|
|
607
|
-
domain_str = utils._get_domain_str(elem.domain)[
|
|
620
|
+
domain_str = utils._get_domain_str(elem.domain, latex=True)[
|
|
621
|
+
1:-1
|
|
622
|
+
]
|
|
608
623
|
|
|
609
|
-
row = f"{
|
|
610
|
-
row = row.replace("_", "\\_")
|
|
624
|
+
row = f"{symbol._latex_name} & {domain_str} & {summary['description']}\\\\"
|
|
611
625
|
table.append(row)
|
|
612
626
|
|
|
613
627
|
table.append(TABLE_FOOTER)
|
|
@@ -615,16 +629,16 @@ class LatexConverter:
|
|
|
615
629
|
return "\n".join(table)
|
|
616
630
|
|
|
617
631
|
def get_definitions(self) -> str:
|
|
618
|
-
definitions = []
|
|
632
|
+
definitions: list[str] = []
|
|
619
633
|
for equation in self.model.equations:
|
|
620
634
|
if equation.name in self.model._autogen_symbols:
|
|
621
635
|
continue
|
|
622
636
|
|
|
623
|
-
domain_str = ",".join([elem.
|
|
624
|
-
header = "\\subsubsection*{
|
|
637
|
+
domain_str = ",".join([elem.latexRepr() for elem in equation.domain])
|
|
638
|
+
header = "\\subsubsection*{" + equation._latex_name
|
|
625
639
|
if domain_str:
|
|
626
|
-
header += f"_{{{domain_str}}}"
|
|
627
|
-
header += "
|
|
640
|
+
header += f"$_{{{domain_str}}}$"
|
|
641
|
+
header += "}\n"
|
|
628
642
|
|
|
629
643
|
footer = "\n\\vspace{5pt}\n\\hrule"
|
|
630
644
|
latex_repr = f"{header}{equation.latexRepr()}{footer}"
|
|
@@ -633,28 +647,41 @@ class LatexConverter:
|
|
|
633
647
|
return "\n".join(definitions)
|
|
634
648
|
|
|
635
649
|
def get_constraints(self) -> str:
|
|
636
|
-
constraints = ["
|
|
650
|
+
constraints = [r"\begin{flalign*}"]
|
|
637
651
|
for name in self.symbols:
|
|
638
652
|
symbol = self.container[name]
|
|
639
653
|
if not isinstance(symbol, syms.Variable):
|
|
640
654
|
continue
|
|
641
655
|
|
|
642
|
-
constraint = "
|
|
656
|
+
constraint = "&" + symbol.latexRepr()
|
|
643
657
|
if symbol.type == "binary":
|
|
644
|
-
constraint +=
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
658
|
+
constraint += "\\in " + r"\{0,1\}"
|
|
659
|
+
if symbol.domain:
|
|
660
|
+
constraint += (
|
|
661
|
+
" ~ \\forall "
|
|
662
|
+
+ utils._get_domain_str(symbol.domain, latex=True)[1:-1]
|
|
663
|
+
)
|
|
650
664
|
elif symbol.type == "integer":
|
|
651
|
-
constraint += "\\in \\mathbb{Z}_{+}
|
|
652
|
-
|
|
653
|
-
|
|
665
|
+
constraint += "\\in \\mathbb{Z}_{+}"
|
|
666
|
+
if symbol.domain:
|
|
667
|
+
constraint += (
|
|
668
|
+
" ~ \\forall "
|
|
669
|
+
+ utils._get_domain_str(symbol.domain, latex=True)[1:-1]
|
|
670
|
+
)
|
|
654
671
|
elif symbol.type == "positive":
|
|
655
|
-
constraint += "\\geq 0
|
|
672
|
+
constraint += "\\geq 0"
|
|
673
|
+
if symbol.domain:
|
|
674
|
+
constraint += (
|
|
675
|
+
" ~ \\forall "
|
|
676
|
+
+ utils._get_domain_str(symbol.domain, latex=True)[1:-1]
|
|
677
|
+
)
|
|
656
678
|
elif symbol.type == "negative":
|
|
657
|
-
constraint += "\\leq 0
|
|
679
|
+
constraint += "\\leq 0"
|
|
680
|
+
if symbol.domain:
|
|
681
|
+
constraint += (
|
|
682
|
+
" ~ \\forall "
|
|
683
|
+
+ utils._get_domain_str(symbol.domain, latex=True)[1:-1]
|
|
684
|
+
)
|
|
658
685
|
elif symbol.type == "sos1":
|
|
659
686
|
constraint += "SOS1"
|
|
660
687
|
elif symbol.type == "sos2":
|
|
@@ -666,24 +693,28 @@ class LatexConverter:
|
|
|
666
693
|
else:
|
|
667
694
|
continue
|
|
668
695
|
|
|
669
|
-
constraint += "
|
|
696
|
+
constraint += "&\\\\"
|
|
670
697
|
constraints.append(constraint)
|
|
671
698
|
|
|
699
|
+
constraints.append(r"\end{flalign*}")
|
|
672
700
|
return "\n".join(constraints)
|
|
673
701
|
|
|
674
702
|
def get_header(self) -> str:
|
|
675
|
-
header = """
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
703
|
+
header = r"""\documentclass[11pt]{article}
|
|
704
|
+
\usepackage{geometry}
|
|
705
|
+
\usepackage[american]{babel}
|
|
706
|
+
\usepackage{amsmath}
|
|
707
|
+
\usepackage{amssymb}
|
|
708
|
+
\usepackage{fontspec}
|
|
709
|
+
\setmainfont{CMU Serif} % 1. Sets a font that knows Greek in text mode
|
|
710
|
+
\usepackage{unicode-math} % 2. Allows Greek keys to work in math mode
|
|
711
|
+
\usepackage[hidelinks]{hyperref}
|
|
712
|
+
\usepackage{tabularx}
|
|
713
|
+
\usepackage{ltablex}
|
|
714
|
+
\keepXColumns
|
|
715
|
+
|
|
716
|
+
\begin{document}
|
|
717
|
+
\section*{Symbols}
|
|
687
718
|
|
|
688
719
|
"""
|
|
689
720
|
return header
|
gamspy/_extrinsic.py
CHANGED
|
@@ -120,7 +120,23 @@ class ExtrinsicFunction(operable.Operable):
|
|
|
120
120
|
-------
|
|
121
121
|
str
|
|
122
122
|
"""
|
|
123
|
-
|
|
123
|
+
representation = self.name.replace("_", r"\_")
|
|
124
|
+
|
|
125
|
+
if self.args:
|
|
126
|
+
arg_strs = []
|
|
127
|
+
for arg in self.args:
|
|
128
|
+
arg_str = (
|
|
129
|
+
str(arg).replace("_", r"\_")
|
|
130
|
+
if isinstance(arg, (int, float, str))
|
|
131
|
+
else arg.latexRepr()
|
|
132
|
+
)
|
|
133
|
+
arg_strs.append(arg_str)
|
|
134
|
+
|
|
135
|
+
args = ",".join(arg_strs)
|
|
136
|
+
|
|
137
|
+
representation = f"{representation}({args})"
|
|
138
|
+
|
|
139
|
+
return representation
|
|
124
140
|
|
|
125
141
|
|
|
126
142
|
class ExtrinsicLibrary:
|
gamspy/_model.py
CHANGED
|
@@ -114,9 +114,6 @@ class Problem(Enum):
|
|
|
114
114
|
EMP = "EMP"
|
|
115
115
|
"""Extended Mathematical Program"""
|
|
116
116
|
|
|
117
|
-
MPSGE = "MPSGE"
|
|
118
|
-
"""General Equilibrium"""
|
|
119
|
-
|
|
120
117
|
@classmethod
|
|
121
118
|
def values(cls):
|
|
122
119
|
"""Convenience function to return all values of enum"""
|
|
@@ -371,7 +368,7 @@ class Model:
|
|
|
371
368
|
equations : Sequence[Equation]
|
|
372
369
|
Sequence of Equation objects.
|
|
373
370
|
problem : Problem | str, optional
|
|
374
|
-
'LP', 'NLP', 'QCP', 'DNLP', 'MIP', 'RMIP', 'MINLP', 'RMINLP', 'MIQCP', 'RMIQCP', 'MCP', 'CNS', 'MPEC', 'RMPEC', 'EMP',
|
|
371
|
+
'LP', 'NLP', 'QCP', 'DNLP', 'MIP', 'RMIP', 'MINLP', 'RMINLP', 'MIQCP', 'RMIQCP', 'MCP', 'CNS', 'MPEC', 'RMPEC', 'EMP',
|
|
375
372
|
by default Problem.LP.
|
|
376
373
|
sense : Sense | str, optional
|
|
377
374
|
"MIN", "MAX", or "FEASIBILITY". By default, Sense.FEASIBILITY
|
|
@@ -396,7 +393,7 @@ class Model:
|
|
|
396
393
|
|
|
397
394
|
# Prefix for auto-generated symbols
|
|
398
395
|
_generate_prefix = "autogenerated_"
|
|
399
|
-
_autogen_symbols: ClassVar[set[
|
|
396
|
+
_autogen_symbols: ClassVar[set[str]] = set()
|
|
400
397
|
|
|
401
398
|
def __init__(
|
|
402
399
|
self,
|
|
@@ -415,6 +412,7 @@ class Model:
|
|
|
415
412
|
limited_variables: Sequence[ImplicitVariable] | None = None,
|
|
416
413
|
external_module: str | None = None,
|
|
417
414
|
):
|
|
415
|
+
self._is_mpsge = False
|
|
418
416
|
self._auto_id = "m" + utils._get_unique_name()
|
|
419
417
|
if equations is None:
|
|
420
418
|
equations = []
|
|
@@ -1213,8 +1211,8 @@ class Model:
|
|
|
1213
1211
|
>>> v = gp.Variable(m, "v")
|
|
1214
1212
|
>>> e = gp.Equation(m, "e", definition= v == 5)
|
|
1215
1213
|
>>> my_model = gp.Model(m, "my_model", problem="LP", equations=[e])
|
|
1216
|
-
>>> my_model.convert("
|
|
1217
|
-
>>> my_model.convert("
|
|
1214
|
+
>>> my_model.convert("tmp", gp.FileFormat.GAMS)
|
|
1215
|
+
>>> my_model.convert("tmp", [gp.FileFormat.GAMS, gp.FileFormat.AMPL])
|
|
1218
1216
|
|
|
1219
1217
|
"""
|
|
1220
1218
|
path = Path(path)
|
|
@@ -1553,6 +1551,19 @@ class Model:
|
|
|
1553
1551
|
------
|
|
1554
1552
|
ValidationError
|
|
1555
1553
|
In case the given options is not of type gp.Options.
|
|
1554
|
+
|
|
1555
|
+
Examples
|
|
1556
|
+
--------
|
|
1557
|
+
>>> import gamspy as gp
|
|
1558
|
+
>>> m = gp.Container()
|
|
1559
|
+
>>> v = gp.Variable(m, "v")
|
|
1560
|
+
>>> e = gp.Equation(m, "e", definition= v == 5)
|
|
1561
|
+
>>> my_model = gp.Model(m, "my_model", problem="LP", equations=[e])
|
|
1562
|
+
>>> my_model.toGams("tmp") # doctest: +ELLIPSIS
|
|
1563
|
+
================================================================================
|
|
1564
|
+
GAMS (.gms) file has been generated under ...
|
|
1565
|
+
================================================================================
|
|
1566
|
+
|
|
1556
1567
|
"""
|
|
1557
1568
|
if options is not None and not isinstance(options, gp.Options):
|
|
1558
1569
|
raise ValidationError(
|
|
@@ -1563,7 +1574,13 @@ class Model:
|
|
|
1563
1574
|
converter = GamsConverter(self, path, options, dump_gams_state)
|
|
1564
1575
|
converter.convert()
|
|
1565
1576
|
|
|
1566
|
-
def toLatex(
|
|
1577
|
+
def toLatex(
|
|
1578
|
+
self,
|
|
1579
|
+
path: str | Path,
|
|
1580
|
+
rename: dict[str, str] | None = None,
|
|
1581
|
+
*,
|
|
1582
|
+
generate_pdf: bool = False,
|
|
1583
|
+
) -> None:
|
|
1567
1584
|
"""
|
|
1568
1585
|
Generates a latex file that contains the model definition under path/<model_name>.tex
|
|
1569
1586
|
|
|
@@ -1571,9 +1588,27 @@ class Model:
|
|
|
1571
1588
|
----------
|
|
1572
1589
|
path : str | Path
|
|
1573
1590
|
Path to the directory which will contain the .tex file.
|
|
1591
|
+
rename: dict[str, str], optional
|
|
1592
|
+
A dictionary to rename symbols in the LaTeX file. Keys are GAMSPy symbol names
|
|
1593
|
+
and values are the names that will be used in the LaTeX file.
|
|
1594
|
+
generate_pdf: bool, False by default
|
|
1595
|
+
Generates a pdf file if it is set. Requires pdflatex to be installed.
|
|
1596
|
+
|
|
1597
|
+
Examples
|
|
1598
|
+
--------
|
|
1599
|
+
>>> import gamspy as gp
|
|
1600
|
+
>>> m = gp.Container()
|
|
1601
|
+
>>> v = gp.Variable(m, "v")
|
|
1602
|
+
>>> e = gp.Equation(m, "e", definition= v == 5)
|
|
1603
|
+
>>> my_model = gp.Model(m, "my_model", problem="LP", equations=[e])
|
|
1604
|
+
>>> my_model.toLatex("tmp") # doctest: +ELLIPSIS
|
|
1605
|
+
================================================================================
|
|
1606
|
+
LaTeX (.tex) file has been generated under ...
|
|
1607
|
+
================================================================================
|
|
1608
|
+
|
|
1574
1609
|
"""
|
|
1575
1610
|
path = Path(path)
|
|
1576
|
-
converter = LatexConverter(self, path)
|
|
1611
|
+
converter = LatexConverter(self, path, rename)
|
|
1577
1612
|
converter.convert()
|
|
1578
1613
|
|
|
1579
1614
|
if generate_pdf:
|
gamspy/_symbols/alias.py
CHANGED
|
@@ -72,6 +72,7 @@ class Alias(gt.Alias, operable.Operable, Symbol, SetMixin):
|
|
|
72
72
|
|
|
73
73
|
# gamspy attributes
|
|
74
74
|
obj.where = condition.Condition(obj)
|
|
75
|
+
obj._latex_name = name.replace("_", r"\_")
|
|
75
76
|
obj.container._add_statement(obj)
|
|
76
77
|
obj._metadata = {}
|
|
77
78
|
|
|
@@ -145,6 +146,7 @@ class Alias(gt.Alias, operable.Operable, Symbol, SetMixin):
|
|
|
145
146
|
name = container._get_symbol_name(prefix="a")
|
|
146
147
|
|
|
147
148
|
super().__init__(container, name, alias_with)
|
|
149
|
+
self._latex_name = self.name.replace("_", r"\_")
|
|
148
150
|
|
|
149
151
|
validation.validate_container(self, self.domain)
|
|
150
152
|
self.where = condition.Condition(self)
|
gamspy/_symbols/equation.py
CHANGED
|
@@ -160,6 +160,7 @@ class Equation(gt.Equation, Symbol):
|
|
|
160
160
|
# gamspy attributes
|
|
161
161
|
obj._definition = None
|
|
162
162
|
obj.where = condition.Condition(obj)
|
|
163
|
+
obj._latex_name = name.replace("_", r"\_")
|
|
163
164
|
obj.container._add_statement(obj)
|
|
164
165
|
obj._synchronize = True
|
|
165
166
|
obj._metadata = {}
|
|
@@ -225,7 +226,7 @@ class Equation(gt.Equation, Symbol):
|
|
|
225
226
|
container: Container | None = None,
|
|
226
227
|
name: str | None = None,
|
|
227
228
|
type: str | EquationType = "regular",
|
|
228
|
-
domain: Sequence[Set | Alias
|
|
229
|
+
domain: Sequence[Set | Alias] | Set | Alias | None = None,
|
|
229
230
|
definition: Variable | Operation | Expression | None = None,
|
|
230
231
|
records: Any | None = None,
|
|
231
232
|
domain_forwarding: bool | list[bool] = False,
|
|
@@ -250,7 +251,7 @@ class Equation(gt.Equation, Symbol):
|
|
|
250
251
|
if domain is None:
|
|
251
252
|
domain = []
|
|
252
253
|
|
|
253
|
-
if isinstance(domain, (gp.Set, gp.Alias
|
|
254
|
+
if isinstance(domain, (gp.Set, gp.Alias)):
|
|
254
255
|
domain = [domain]
|
|
255
256
|
|
|
256
257
|
if isinstance(domain, gp.math.Dim):
|
|
@@ -330,6 +331,7 @@ class Equation(gt.Equation, Symbol):
|
|
|
330
331
|
description=description,
|
|
331
332
|
uels_on_axes=uels_on_axes,
|
|
332
333
|
)
|
|
334
|
+
self._latex_name = self.name.replace("_", r"\_")
|
|
333
335
|
|
|
334
336
|
if is_miro_output:
|
|
335
337
|
container._miro_output_symbols.append(self.name)
|
|
@@ -532,7 +534,7 @@ class Equation(gt.Equation, Symbol):
|
|
|
532
534
|
eq_type in rhs_repr for eq_type in EQ_TYPES
|
|
533
535
|
):
|
|
534
536
|
# x - c -> x - c == 0
|
|
535
|
-
rhs = rhs == 0
|
|
537
|
+
rhs = rhs == gp.Number(0)
|
|
536
538
|
|
|
537
539
|
rhs_repr = rhs.gamsRepr()
|
|
538
540
|
if not any(eq_type in rhs_repr for eq_type in EQ_TYPES):
|
|
@@ -1143,6 +1145,8 @@ class Equation(gt.Equation, Symbol):
|
|
|
1143
1145
|
"Equation must be defined to get its latex representation."
|
|
1144
1146
|
)
|
|
1145
1147
|
|
|
1148
|
+
# The LHS of an equation definition can either be an ImplicitEquation or a condition.
|
|
1149
|
+
# e.g. e[i] = ... or e[i].where[b[i]] = ...
|
|
1146
1150
|
assert isinstance(
|
|
1147
1151
|
self._definition.left,
|
|
1148
1152
|
(implicits.ImplicitEquation, condition.Condition),
|
|
@@ -1152,21 +1156,25 @@ class Equation(gt.Equation, Symbol):
|
|
|
1152
1156
|
if isinstance(self._definition.left, implicits.ImplicitEquation):
|
|
1153
1157
|
if len(self._definition.left.domain) > 0:
|
|
1154
1158
|
domain_str = ",".join(
|
|
1155
|
-
[symbol.
|
|
1159
|
+
[symbol.latexRepr() for symbol in self._definition.left.domain]
|
|
1156
1160
|
)
|
|
1157
1161
|
right_side = f"\\hfill \\forall {domain_str}"
|
|
1158
1162
|
else:
|
|
1159
1163
|
domain_str = ",".join(
|
|
1160
1164
|
[
|
|
1161
|
-
symbol.
|
|
1165
|
+
symbol.latexRepr()
|
|
1162
1166
|
for symbol in self._definition.left.conditioning_on.domain # type: ignore
|
|
1163
1167
|
]
|
|
1164
1168
|
)
|
|
1165
1169
|
domain_str = f"\\forall {domain_str}"
|
|
1166
1170
|
|
|
1167
|
-
|
|
1171
|
+
assert self._definition.left.condition is not None
|
|
1168
1172
|
if hasattr(self._definition.left.condition, "latexRepr"):
|
|
1169
|
-
constraint_str = self._definition.left.condition.latexRepr()
|
|
1173
|
+
constraint_str = self._definition.left.condition.latexRepr()
|
|
1174
|
+
else:
|
|
1175
|
+
assert isinstance(self._definition.left.condition, (int, float))
|
|
1176
|
+
constraint_str = str(self._definition.left.condition)
|
|
1177
|
+
|
|
1170
1178
|
right_side = f"\\hfill {domain_str} ~ | ~ {constraint_str}"
|
|
1171
1179
|
|
|
1172
1180
|
assert self._definition.right is not None
|
|
@@ -83,7 +83,7 @@ class ImplicitSet(ImplicitSymbol, operable.Operable):
|
|
|
83
83
|
return temp_param.records
|
|
84
84
|
|
|
85
85
|
def latexRepr(self):
|
|
86
|
-
name = self.
|
|
86
|
+
name = self._latex_name
|
|
87
87
|
representation = name
|
|
88
88
|
|
|
89
89
|
if self.extension is not None:
|
|
@@ -100,6 +100,7 @@ class ImplicitSet(ImplicitSymbol, operable.Operable):
|
|
|
100
100
|
if isinstance(elem, (syms.Set, syms.Alias, ImplicitSet)):
|
|
101
101
|
set_strs.append(elem.latexRepr())
|
|
102
102
|
elif isinstance(elem, str):
|
|
103
|
+
elem = elem.replace("_", r"\_")
|
|
103
104
|
set_strs.append(f"\\textquotesingle {elem} \\textquotesingle")
|
|
104
105
|
|
|
105
106
|
domain_str = "{" + ",".join(set_strs) + "}"
|
|
@@ -46,6 +46,10 @@ class ImplicitSymbol(ABC):
|
|
|
46
46
|
|
|
47
47
|
self.fix_domain_scalars(parent_scalar_domains)
|
|
48
48
|
|
|
49
|
+
@property
|
|
50
|
+
def _latex_name(self) -> str:
|
|
51
|
+
return self.parent._latex_name
|
|
52
|
+
|
|
49
53
|
def __bool__(self):
|
|
50
54
|
raise ValidationError("A symbol cannot be used as a truth value.")
|
|
51
55
|
|
|
@@ -101,7 +105,7 @@ class ImplicitSymbol(ABC):
|
|
|
101
105
|
def latexRepr(self):
|
|
102
106
|
from .implicit_set import ImplicitSet
|
|
103
107
|
|
|
104
|
-
name = self.
|
|
108
|
+
name = self._latex_name
|
|
105
109
|
representation = name
|
|
106
110
|
domain = list(self.domain)
|
|
107
111
|
|
|
@@ -114,6 +118,7 @@ class ImplicitSymbol(ABC):
|
|
|
114
118
|
if isinstance(elem, (gp.Set, gp.Alias, ImplicitSet)):
|
|
115
119
|
set_strs.append(elem.latexRepr())
|
|
116
120
|
elif isinstance(elem, str):
|
|
121
|
+
elem = elem.replace("_", r"\_")
|
|
117
122
|
set_strs.append(f"\\textquotesingle {elem} \\textquotesingle")
|
|
118
123
|
|
|
119
124
|
domain_str = "{" + ",".join(set_strs) + "}"
|
gamspy/_symbols/parameter.py
CHANGED
|
@@ -113,6 +113,7 @@ class Parameter(gt.Parameter, operable.Operable, Symbol):
|
|
|
113
113
|
# gamspy attributes
|
|
114
114
|
obj._synchronize = True
|
|
115
115
|
obj.where = condition.Condition(obj)
|
|
116
|
+
obj._latex_name = name.replace("_", r"\_")
|
|
116
117
|
obj.container._add_statement(obj)
|
|
117
118
|
obj._metadata = {}
|
|
118
119
|
obj._winner = "python"
|
|
@@ -263,6 +264,7 @@ class Parameter(gt.Parameter, operable.Operable, Symbol):
|
|
|
263
264
|
description=description,
|
|
264
265
|
uels_on_axes=uels_on_axes,
|
|
265
266
|
)
|
|
267
|
+
self._latex_name = self.name.replace("_", r"\_")
|
|
266
268
|
|
|
267
269
|
if is_miro_input:
|
|
268
270
|
self._already_loaded = False
|
gamspy/_symbols/set.py
CHANGED
|
@@ -482,6 +482,7 @@ class Set(gt.Set, operable.Operable, Symbol, SetMixin):
|
|
|
482
482
|
|
|
483
483
|
# gamspy attributes
|
|
484
484
|
obj.where = condition.Condition(obj)
|
|
485
|
+
obj._latex_name = name.replace("_", r"\_")
|
|
485
486
|
obj.container._add_statement(obj)
|
|
486
487
|
obj._synchronize = True
|
|
487
488
|
obj._metadata = {}
|
|
@@ -642,6 +643,7 @@ class Set(gt.Set, operable.Operable, Symbol, SetMixin):
|
|
|
642
643
|
description=description,
|
|
643
644
|
uels_on_axes=uels_on_axes,
|
|
644
645
|
)
|
|
646
|
+
self._latex_name = self.name.replace("_", r"\_")
|
|
645
647
|
|
|
646
648
|
if is_miro_input:
|
|
647
649
|
self._already_loaded = False
|
gamspy/_symbols/symbol.py
CHANGED
|
@@ -63,6 +63,7 @@ class UniverseAlias(gt.UniverseAlias):
|
|
|
63
63
|
|
|
64
64
|
# gamspy attributes
|
|
65
65
|
obj.where = condition.Condition(obj)
|
|
66
|
+
obj._latex_name = name.replace("_", r"\_")
|
|
66
67
|
|
|
67
68
|
# add statement
|
|
68
69
|
obj.container._add_statement(obj)
|
|
@@ -95,7 +96,11 @@ class UniverseAlias(gt.UniverseAlias):
|
|
|
95
96
|
|
|
96
97
|
def __init__(self, container: Container | None = None, name: str = "universe"):
|
|
97
98
|
# check if the name is a reserved word
|
|
98
|
-
name
|
|
99
|
+
if name is not None:
|
|
100
|
+
name = validation.validate_name(name)
|
|
101
|
+
else:
|
|
102
|
+
name = container._get_symbol_name(prefix="u")
|
|
103
|
+
|
|
99
104
|
if container is None:
|
|
100
105
|
try:
|
|
101
106
|
container = gp._ctx_managers[(os.getpid(), threading.get_native_id())]
|
|
@@ -103,6 +108,7 @@ class UniverseAlias(gt.UniverseAlias):
|
|
|
103
108
|
raise ValidationError("UniverseAlias requires a container.") from e
|
|
104
109
|
|
|
105
110
|
super().__init__(container, name)
|
|
111
|
+
self._latex_name = self.name.replace("_", r"\_")
|
|
106
112
|
|
|
107
113
|
# allow conditions
|
|
108
114
|
self.where = condition.Condition(self)
|
|
@@ -137,6 +143,25 @@ class UniverseAlias(gt.UniverseAlias):
|
|
|
137
143
|
"""
|
|
138
144
|
return self.name
|
|
139
145
|
|
|
146
|
+
def latexRepr(self) -> str:
|
|
147
|
+
"""
|
|
148
|
+
Representation of the UniverseAlias in LaTeX.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
str
|
|
153
|
+
|
|
154
|
+
Examples
|
|
155
|
+
--------
|
|
156
|
+
>>> import gamspy as gp
|
|
157
|
+
>>> m = gp.Container()
|
|
158
|
+
>>> i = gp.UniverseAlias(m, name="universe_alias")
|
|
159
|
+
>>> i.latexRepr()
|
|
160
|
+
'universe\\_alias'
|
|
161
|
+
|
|
162
|
+
"""
|
|
163
|
+
return self._latex_name
|
|
164
|
+
|
|
140
165
|
def getDeclaration(self) -> str:
|
|
141
166
|
"""
|
|
142
167
|
Declaration of the UniverseAlias in GAMS
|
gamspy/_symbols/variable.py
CHANGED
|
@@ -155,6 +155,7 @@ class Variable(gt.Variable, operable.Operable, Symbol):
|
|
|
155
155
|
|
|
156
156
|
# gamspy attributes
|
|
157
157
|
obj.where = condition.Condition(obj)
|
|
158
|
+
obj._latex_name = name.replace("_", r"\_")
|
|
158
159
|
obj.container._add_statement(obj)
|
|
159
160
|
obj._synchronize = True
|
|
160
161
|
obj._metadata = {}
|
|
@@ -319,6 +320,7 @@ class Variable(gt.Variable, operable.Operable, Symbol):
|
|
|
319
320
|
description=description,
|
|
320
321
|
uels_on_axes=uels_on_axes,
|
|
321
322
|
)
|
|
323
|
+
self._latex_name = self.name.replace("_", r"\_")
|
|
322
324
|
|
|
323
325
|
if is_miro_output:
|
|
324
326
|
container._miro_output_symbols.append(self.name)
|
gamspy/_validation.py
CHANGED
|
@@ -187,7 +187,7 @@ def validate_dimension(
|
|
|
187
187
|
|
|
188
188
|
if dimension != symbol.dimension:
|
|
189
189
|
raise ValidationError(
|
|
190
|
-
f"The `{symbol}` is referenced with"
|
|
190
|
+
f"The `{symbol.gamsRepr()}` is referenced with"
|
|
191
191
|
f" {'more' if dimension > symbol.dimension else 'less'} indices"
|
|
192
192
|
f" than declared. Declared dimension is {symbol.dimension} but"
|
|
193
193
|
f" given dimension is {dimension}"
|
|
@@ -584,9 +584,18 @@ def validate_equations(model: Model) -> None:
|
|
|
584
584
|
if not get_option("VALIDATION"):
|
|
585
585
|
return
|
|
586
586
|
|
|
587
|
+
# We don't have the definitions of equations as an expression tree if the container
|
|
588
|
+
# is restarted. We have it instead as a string. Hence, do not try to do validation.
|
|
587
589
|
if model.container._is_restarted:
|
|
588
590
|
return
|
|
589
591
|
|
|
592
|
+
# We don't have the definition of MPSGE equations since they are autogenerated on the GAMS side.
|
|
593
|
+
if (
|
|
594
|
+
model.problem == Problem.MCP
|
|
595
|
+
and model.name.lower() in model.container._mpsge_models
|
|
596
|
+
):
|
|
597
|
+
return
|
|
598
|
+
|
|
590
599
|
allow_ambiguous_equations = get_option("ALLOW_AMBIGUOUS_EQUATIONS").lower()
|
|
591
600
|
|
|
592
601
|
for equation in model.equations:
|
gamspy/math/misc.py
CHANGED
|
@@ -8,6 +8,7 @@ import gamspy._algebra.operable as operable
|
|
|
8
8
|
import gamspy._symbols as syms
|
|
9
9
|
import gamspy._validation as validation
|
|
10
10
|
import gamspy.utils as utils
|
|
11
|
+
from gamspy._container import Container
|
|
11
12
|
from gamspy.exceptions import ValidationError
|
|
12
13
|
|
|
13
14
|
if TYPE_CHECKING:
|
|
@@ -55,13 +56,16 @@ class MathOp(operable.Operable):
|
|
|
55
56
|
-------
|
|
56
57
|
pd.DataFrame | None
|
|
57
58
|
"""
|
|
58
|
-
|
|
59
|
+
container = self.container
|
|
60
|
+
if container is None:
|
|
61
|
+
container = Container()
|
|
62
|
+
|
|
59
63
|
temp_name = "a" + utils._get_unique_name()
|
|
60
64
|
temp_param = syms.Parameter._constructor_bypass(
|
|
61
|
-
|
|
65
|
+
container, temp_name, self.domain
|
|
62
66
|
)
|
|
63
67
|
temp_param[...] = self
|
|
64
|
-
del
|
|
68
|
+
del container.data[temp_name]
|
|
65
69
|
return temp_param.records
|
|
66
70
|
|
|
67
71
|
def toValue(self) -> float | None:
|
|
@@ -121,11 +125,14 @@ class MathOp(operable.Operable):
|
|
|
121
125
|
"abs": "\\lvert",
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
operands_str = ",".join(
|
|
128
|
+
operands_str = ",".join(
|
|
129
|
+
[_stringify(elem, latex=True) for elem in self.elements]
|
|
130
|
+
)
|
|
125
131
|
if self.op_name in op_map:
|
|
126
132
|
return f"{op_map[self.op_name]}{{{operands_str}}}"
|
|
127
133
|
|
|
128
|
-
|
|
134
|
+
op_name = self.op_name.replace("_", r"\_")
|
|
135
|
+
return f"{op_name}({operands_str})"
|
|
129
136
|
|
|
130
137
|
def __str__(self):
|
|
131
138
|
return self.gamsRepr()
|
|
@@ -134,14 +141,20 @@ class MathOp(operable.Operable):
|
|
|
134
141
|
return len(self.gamsRepr())
|
|
135
142
|
|
|
136
143
|
|
|
137
|
-
def _stringify(x: str | int | float | Symbol | ImplicitSymbol):
|
|
144
|
+
def _stringify(x: str | int | float | Symbol | ImplicitSymbol, *, latex: bool = False):
|
|
138
145
|
if isinstance(x, (int, float)):
|
|
139
146
|
x = utils._map_special_values(x)
|
|
140
147
|
|
|
141
148
|
return str(x)
|
|
142
149
|
elif isinstance(x, str):
|
|
150
|
+
if latex:
|
|
151
|
+
x = x.replace("_", r"\_")
|
|
152
|
+
|
|
143
153
|
return f'"{x}"'
|
|
144
154
|
|
|
155
|
+
if latex:
|
|
156
|
+
return x.latexRepr()
|
|
157
|
+
|
|
145
158
|
return x.gamsRepr() # type: ignore
|
|
146
159
|
|
|
147
160
|
|
gamspy/utils.py
CHANGED
|
@@ -137,6 +137,7 @@ def getSolverCapabilities(system_directory: str) -> dict[str, list[str]]:
|
|
|
137
137
|
|
|
138
138
|
capabilities[solver] = problem_types
|
|
139
139
|
|
|
140
|
+
capabilities.pop("MPSGE", None)
|
|
140
141
|
_capabilities[system_directory] = capabilities
|
|
141
142
|
return capabilities
|
|
142
143
|
|
|
@@ -584,7 +585,9 @@ def _map_special_values(value: float):
|
|
|
584
585
|
return value
|
|
585
586
|
|
|
586
587
|
|
|
587
|
-
def _get_domain_str(
|
|
588
|
+
def _get_domain_str(
|
|
589
|
+
domain: Iterable[Set | Alias | ImplicitSet | str], *, latex: bool = False
|
|
590
|
+
) -> str:
|
|
588
591
|
"""
|
|
589
592
|
Creates the string format of a given domain
|
|
590
593
|
|
|
@@ -601,21 +604,29 @@ def _get_domain_str(domain: Iterable[Set | Alias | ImplicitSet | str]) -> str:
|
|
|
601
604
|
Exception
|
|
602
605
|
Given domain must contain only sets, aliases or strings
|
|
603
606
|
"""
|
|
604
|
-
|
|
605
|
-
for
|
|
606
|
-
if isinstance(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if
|
|
610
|
-
|
|
607
|
+
domain_strs = []
|
|
608
|
+
for elem in domain:
|
|
609
|
+
if isinstance(
|
|
610
|
+
elem, (gt.Set, gt.Alias, gt.UniverseAlias, implicits.ImplicitSet)
|
|
611
|
+
):
|
|
612
|
+
if latex:
|
|
613
|
+
domain_strs.append(elem.latexRepr())
|
|
614
|
+
else:
|
|
615
|
+
domain_strs.append(elem.gamsRepr())
|
|
616
|
+
elif isinstance(elem, str):
|
|
617
|
+
if elem == "*":
|
|
618
|
+
domain_strs.append(elem)
|
|
611
619
|
else:
|
|
612
|
-
|
|
620
|
+
if latex:
|
|
621
|
+
domain_strs.append('"' + elem.replace("_", r"\_") + '"')
|
|
622
|
+
else:
|
|
623
|
+
domain_strs.append('"' + elem + '"')
|
|
613
624
|
else:
|
|
614
625
|
raise ValidationError(
|
|
615
|
-
f"Domain type must be str, Set or Alias but found {type(
|
|
626
|
+
f"Domain type must be str, Set or Alias but found {type(elem)}"
|
|
616
627
|
)
|
|
617
628
|
|
|
618
|
-
return "(" + ",".join(
|
|
629
|
+
return "(" + ",".join(domain_strs) + ")"
|
|
619
630
|
|
|
620
631
|
|
|
621
632
|
def _permute_domain(domain, dims):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gamspy
|
|
3
|
-
Version: 1.18.
|
|
3
|
+
Version: 1.18.3
|
|
4
4
|
Summary: Python-based algebraic modeling interface to GAMS
|
|
5
5
|
Author-email: GAMS Development Corporation <support@gams.com>
|
|
6
6
|
Project-URL: homepage, https://gams.com/sales/gamspy_facts/
|
|
@@ -31,8 +31,8 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
31
31
|
Requires-Python: >=3.10
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
License-File: LICENSE
|
|
34
|
-
Requires-Dist: gamsapi<53.0.0,>=52.
|
|
35
|
-
Requires-Dist: gamspy_base<53.0.0,>=52.
|
|
34
|
+
Requires-Dist: gamsapi<53.0.0,>=52.2.0
|
|
35
|
+
Requires-Dist: gamspy_base<53.0.0,>=52.2.0
|
|
36
36
|
Requires-Dist: pandas<2.4,>=2.2.2
|
|
37
37
|
Requires-Dist: pydantic>=2.0
|
|
38
38
|
Requires-Dist: requests>=2.28.0
|
|
@@ -2,39 +2,40 @@ gamspy/__init__.py,sha256=HZulKBgt2ubfX6r6v6Xv3MJVI6Prm40j5W45aUetQok,1797
|
|
|
2
2
|
gamspy/__main__.py,sha256=3HW3NYEe4pZnGhJ10s1G0vaZAkI9Zl_lXqHT9iDNXQg,108
|
|
3
3
|
gamspy/_communication.py,sha256=18drDsKxi1Iv6oAKZfKGJcPYYWebBQsyeOxiEKXZngE,7148
|
|
4
4
|
gamspy/_config.py,sha256=n7RXUFczIlol15-mxhnj54fHXHet8HcOnWiGm3mpMgg,3589
|
|
5
|
-
gamspy/_container.py,sha256=
|
|
6
|
-
gamspy/_convert.py,sha256=
|
|
5
|
+
gamspy/_container.py,sha256=r4-uGBy2yxBl7yPaxAPdgmJ-bkb7moeXJtx8xupY9DE,46966
|
|
6
|
+
gamspy/_convert.py,sha256=3_agmO6QPXqy-wyiEncdMk9B2KuqK73G2d5T9SB3phM,23456
|
|
7
7
|
gamspy/_database.py,sha256=SVo4lEfS0Q2f80uMu7k71BBQNRwUei-2KFc_EGxsOcw,6873
|
|
8
|
-
gamspy/_extrinsic.py,sha256=
|
|
8
|
+
gamspy/_extrinsic.py,sha256=OGrlNzcSQjoIZw8lpsk_4SObEAhGX5bkc_D0d3lPZMQ,4807
|
|
9
9
|
gamspy/_miro.py,sha256=MeFGcaFtNgtydWjH0KS0l9y3mNy7tPyXwm43jwomodg,12245
|
|
10
|
-
gamspy/_model.py,sha256=
|
|
10
|
+
gamspy/_model.py,sha256=CPupNZ8Hpkco9DgC_0cuPSRI1qnccQtOlx57sCQ8iZE,52828
|
|
11
11
|
gamspy/_model_instance.py,sha256=ZHG3-inc6vDx7F2Oo9HYWYAi8hki6upIgAQn5II_o1U,24384
|
|
12
12
|
gamspy/_options.py,sha256=FTty65WRdikvnhPyWSTuwuUz0Rs6aZwDFWL-UsfEgd0,27211
|
|
13
13
|
gamspy/_serialization.py,sha256=fwAQpABCZQyxtAkddsvCDjtyQyPUT3EJy19r9BKR6aY,4062
|
|
14
14
|
gamspy/_types.py,sha256=_KQjRntvIAicc9_sZ5BYWAHjs-WBURf2NJwTpJQT5xw,162
|
|
15
|
-
gamspy/_validation.py,sha256=
|
|
15
|
+
gamspy/_validation.py,sha256=uaLzEeXE2h-1_9-x_Gv28qio08vk1q52vgtr-lahq3E,22029
|
|
16
16
|
gamspy/_workspace.py,sha256=QrnC8aPN5C9zyqbaYvfuPlRHvBrDx_i4Imw1AzsJs7k,2175
|
|
17
17
|
gamspy/exceptions.py,sha256=q-Cb6syXv1abf2JBfNFidGkvOWkp9FXU5NzJwkR5W7o,2929
|
|
18
18
|
gamspy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
gamspy/utils.py,sha256=
|
|
19
|
+
gamspy/utils.py,sha256=nDmyhkCv5yk40jf3OL-HtW-wWTWh20UDC3bO4D5Vc4k,20114
|
|
20
20
|
gamspy/version.py,sha256=GsqTw9rQ4Zz80ZSlIo44vYqgcVBJSbGOqJFJW3j_z88,109
|
|
21
21
|
gamspy/_algebra/__init__.py,sha256=HdTHRBzfOGXihibQOAOAHGHKinlMuHVnpuP4pJWSQCc,479
|
|
22
22
|
gamspy/_algebra/condition.py,sha256=mVJeCk65dvLgYalTQHfZt0bEFFf9yoTWLXjhODf7gvg,6229
|
|
23
|
-
gamspy/_algebra/domain.py,sha256=
|
|
24
|
-
gamspy/_algebra/expression.py,sha256=
|
|
23
|
+
gamspy/_algebra/domain.py,sha256=6hBYxxZuQ-tJ5QcjEpW68SxI3i0SkgxbwgSsK93wLRc,2941
|
|
24
|
+
gamspy/_algebra/expression.py,sha256=yOrPeDhB-tkyfgp27U6VbyArmGQo6SnQUipyYcL8agg,25393
|
|
25
25
|
gamspy/_algebra/number.py,sha256=Yf7kYLwkmXCipiAzQP7LtTchMMK7OccChuXnTIYl1w4,1680
|
|
26
26
|
gamspy/_algebra/operable.py,sha256=1sFr29_7A9RKVxDlTY9fC_g4sNRavNOYpjACWzvyjRc,6315
|
|
27
|
-
gamspy/_algebra/operation.py,sha256=
|
|
27
|
+
gamspy/_algebra/operation.py,sha256=SRFHnAFRqciR5cLnrxfTQXvjYNO1fxyci5oVQAb_L6M,23235
|
|
28
28
|
gamspy/_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
gamspy/_backend/backend.py,sha256=VgLL3CiFydkf1ZF8ttaOlWsDtkJIoRdi_md4tVh789Q,9217
|
|
30
30
|
gamspy/_backend/engine.py,sha256=N3BIb4CDmH76CQIj87JSJBNnMLln3jsUuLy9_O5sEJ0,31826
|
|
31
31
|
gamspy/_backend/local.py,sha256=-LE7obmZT3zdB-0LJHJ9xfulMBw5vvzFIS9WJ7ISE-4,3804
|
|
32
32
|
gamspy/_backend/neos.py,sha256=I21TOqPZC5cBp_rQpz5S9cmLPRJcizIT0KuncwMcUrw,17762
|
|
33
33
|
gamspy/_cli/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
34
|
-
gamspy/_cli/cli.py,sha256=
|
|
34
|
+
gamspy/_cli/cli.py,sha256=SUnkhiReUirVZBJoGxSZ_mvENzHqhSKmS0gr3sEsacs,1634
|
|
35
35
|
gamspy/_cli/gdx.py,sha256=YRu1delsmDh-dpzEr8n1kTK0JFdXlNqz4YuUQzK1mvo,12024
|
|
36
36
|
gamspy/_cli/install.py,sha256=Kr09kp146LujiO64GpoJxMPRZmY9GnhxuhWm-ZU2l4w,13257
|
|
37
37
|
gamspy/_cli/list.py,sha256=fMmaIZcZf-Tf_-J37tJ4zrk2bcVO9cPSfs08mQyGWiY,2907
|
|
38
|
+
gamspy/_cli/mps2gms.py,sha256=4zmM5gS_YlgkzBcgHDzjM6F_r2vKJTi0P_ZYgZxjoEw,4192
|
|
38
39
|
gamspy/_cli/probe.py,sha256=K7fYwfdk-2mGGQKAxXFvkWMRJ1qYTUpX2tvklU56JZU,1122
|
|
39
40
|
gamspy/_cli/retrieve.py,sha256=bnTcIbHJfkq-dvrFitdkxsjQNZz-Cx4-LiaRfhe0cYM,2446
|
|
40
41
|
gamspy/_cli/run.py,sha256=oaWT4alxSXqPDF2mRYmfy5aOWCKoEExUfqYoAT_zSUM,4387
|
|
@@ -42,18 +43,18 @@ gamspy/_cli/show.py,sha256=NTZJBtdns0Bd6UOdlTDIelhU92xmLJjT9HuDLqS3YJ4,11144
|
|
|
42
43
|
gamspy/_cli/uninstall.py,sha256=_g3SbT6G7DZcYgtmHLhaGl1B9jY1K3D0sStifxIyqxQ,5183
|
|
43
44
|
gamspy/_cli/util.py,sha256=ey3Wn7tCEggkr-sjcLqrVBda-jdadjWOn-APhSe4toE,2849
|
|
44
45
|
gamspy/_symbols/__init__.py,sha256=p0Zd7XytuOe8kRclN1lFrRFaN_btFSSGdIBSXrlp03E,450
|
|
45
|
-
gamspy/_symbols/alias.py,sha256=
|
|
46
|
-
gamspy/_symbols/equation.py,sha256=
|
|
47
|
-
gamspy/_symbols/parameter.py,sha256=
|
|
48
|
-
gamspy/_symbols/set.py,sha256=
|
|
49
|
-
gamspy/_symbols/symbol.py,sha256=
|
|
50
|
-
gamspy/_symbols/universe_alias.py,sha256=
|
|
51
|
-
gamspy/_symbols/variable.py,sha256=
|
|
46
|
+
gamspy/_symbols/alias.py,sha256=BidmqvYxqMXLxU9tSJHJ484P1R-7pq9J-cP0ITNmkVc,8907
|
|
47
|
+
gamspy/_symbols/equation.py,sha256=qQi24g9GD3qpMOMl2R-bQJbVYWHIy3bbsoHt6ZgD2oQ,40136
|
|
48
|
+
gamspy/_symbols/parameter.py,sha256=nZVE_AEbY2vyQ6OedrH8TC6ffPtSZk75MRstV-zY1z8,19833
|
|
49
|
+
gamspy/_symbols/set.py,sha256=aUw8AO72sEmZlH-BpGBlMXMvJHLc-Skx0cpPvPJxOag,29242
|
|
50
|
+
gamspy/_symbols/symbol.py,sha256=azKG8vJzrBrjGXCcKe865I5rEEbT1ZqQ02khQXPtiGs,10888
|
|
51
|
+
gamspy/_symbols/universe_alias.py,sha256=3JBG710YIJi6jmNp9tKKqW6IoiXsUaSUf8flj9woFiU,4672
|
|
52
|
+
gamspy/_symbols/variable.py,sha256=T6cMVz2pYgJIIY8_HxUkH7PgcDJhC-pMCcRPWplYe2s,30636
|
|
52
53
|
gamspy/_symbols/implicits/__init__.py,sha256=bvYl_lYtnTztfNUTMxqteIztotwh1T2CUQpidQITSMQ,391
|
|
53
54
|
gamspy/_symbols/implicits/implicit_equation.py,sha256=V28B9kJBpeCYekFPEvHKFwxNxkX3VEPSoMcXP6fEvzo,5070
|
|
54
55
|
gamspy/_symbols/implicits/implicit_parameter.py,sha256=6w1O1-jSFH2J2S4FhssSs4ksAGwq281SodXCTzTFQQ0,8600
|
|
55
|
-
gamspy/_symbols/implicits/implicit_set.py,sha256=
|
|
56
|
-
gamspy/_symbols/implicits/implicit_symbol.py,sha256=
|
|
56
|
+
gamspy/_symbols/implicits/implicit_set.py,sha256=T-gYrvuvJwbkJxWNac8EdrMP3SQxhN5LjXqElgrm0A4,3767
|
|
57
|
+
gamspy/_symbols/implicits/implicit_symbol.py,sha256=dGK7vN2rCabuj1UXReO8PppbgbjcUu-lKv3IJ8_tgJo,9136
|
|
57
58
|
gamspy/_symbols/implicits/implicit_variable.py,sha256=a1deGojPLXW7OLiOAOErgAGdRNlRCrBHt6r0WNchQVs,7662
|
|
58
59
|
gamspy/formulations/__init__.py,sha256=-FZiCsc0Uydyc3j1nXpPvIUkB5H2dBs7FdWgFSJln2g,990
|
|
59
60
|
gamspy/formulations/piecewise.py,sha256=uSyxylMEZuIhrqVdv3wuv4FAHegLf3rD9KCIdiHvALc,24421
|
|
@@ -78,12 +79,12 @@ gamspy/math/__init__.py,sha256=pyYOIEAi1I4h8gu0pCAnMh389566Ygrl0BtQh1P3OB0,3120
|
|
|
78
79
|
gamspy/math/activation.py,sha256=XQHTKUKIT7d4-JqJdWwhyxBtnAJ6MajCjx3FWBi3k1s,24569
|
|
79
80
|
gamspy/math/log_power.py,sha256=oXQmHNdaDPLdhtmv8znmSzq0MPa4fHkxGdx8hSaQq-Y,9184
|
|
80
81
|
gamspy/math/matrix.py,sha256=PmYsMhF8Pq3bcgtyINryq4xV36i4KW0BtcFApOvt8GQ,16365
|
|
81
|
-
gamspy/math/misc.py,sha256=
|
|
82
|
+
gamspy/math/misc.py,sha256=qrduVOZ7CmD9wjUJx86t2J_2XMQzTz2vhd40sFwuRUk,37727
|
|
82
83
|
gamspy/math/probability.py,sha256=gAVU_PTfbjXuN6i8XNjZpIYvFg8dPk1imZCbKQloSG0,4290
|
|
83
84
|
gamspy/math/trigonometric.py,sha256=VBWQcP3ggl1oGDEzRs2M_T88HPJn9N0QfMJZwEUkx4w,4276
|
|
84
|
-
gamspy-1.18.
|
|
85
|
-
gamspy-1.18.
|
|
86
|
-
gamspy-1.18.
|
|
87
|
-
gamspy-1.18.
|
|
88
|
-
gamspy-1.18.
|
|
89
|
-
gamspy-1.18.
|
|
85
|
+
gamspy-1.18.3.dist-info/licenses/LICENSE,sha256=D4HfHbHRs3LVWo3uXq44WQc1FkBP5srUCEa-vO0W9tE,1189
|
|
86
|
+
gamspy-1.18.3.dist-info/METADATA,sha256=-2s1hRKHXEJuOl3HvHz3ggCLxXcEfXjzD10KOBDb9us,5301
|
|
87
|
+
gamspy-1.18.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
88
|
+
gamspy-1.18.3.dist-info/entry_points.txt,sha256=tzgC7L0Y_BiyagBCaYOPK7lE4olRJKM_PH2inmMvj60,48
|
|
89
|
+
gamspy-1.18.3.dist-info/top_level.txt,sha256=fsq4q5lfdb2GEZC9O3PUih38s7TfIgolIaO5NgR3Hf8,7
|
|
90
|
+
gamspy-1.18.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|