gamspy 1.18.2__py3-none-any.whl → 1.18.4__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/__init__.py +2 -14
- gamspy/_algebra/condition.py +59 -0
- gamspy/_algebra/domain.py +10 -0
- gamspy/_algebra/expression.py +29 -8
- gamspy/_algebra/number.py +9 -0
- gamspy/_cli/cli.py +2 -1
- gamspy/_cli/install.py +18 -13
- gamspy/_cli/mps2gms.py +128 -0
- gamspy/_cli/show.py +0 -9
- gamspy/_container.py +288 -62
- gamspy/_convert.py +25 -18
- gamspy/_model.py +85 -20
- gamspy/_options.py +91 -13
- gamspy/_serialization.py +13 -1
- gamspy/_symbols/alias.py +8 -2
- gamspy/_symbols/equation.py +158 -49
- gamspy/_symbols/parameter.py +72 -33
- gamspy/_symbols/set.py +121 -59
- gamspy/_symbols/universe_alias.py +5 -1
- gamspy/_symbols/variable.py +121 -37
- gamspy/_validation.py +9 -0
- gamspy/utils.py +20 -0
- {gamspy-1.18.2.dist-info → gamspy-1.18.4.dist-info}/METADATA +1 -1
- {gamspy-1.18.2.dist-info → gamspy-1.18.4.dist-info}/RECORD +28 -27
- {gamspy-1.18.2.dist-info → gamspy-1.18.4.dist-info}/WHEEL +0 -0
- {gamspy-1.18.2.dist-info → gamspy-1.18.4.dist-info}/entry_points.txt +0 -0
- {gamspy-1.18.2.dist-info → gamspy-1.18.4.dist-info}/licenses/LICENSE +0 -0
- {gamspy-1.18.2.dist-info → gamspy-1.18.4.dist-info}/top_level.txt +0 -0
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
|
|
@@ -101,28 +103,76 @@ def get_options_file_name(solver: str, file_number: int) -> str:
|
|
|
101
103
|
|
|
102
104
|
class Container(gt.Container):
|
|
103
105
|
"""
|
|
104
|
-
|
|
106
|
+
Central workspace for building, modifying, executing, and exchanging data
|
|
107
|
+
with GAMS models.
|
|
108
|
+
|
|
109
|
+
https://gamspy.readthedocs.io/en/latest/reference/gamspy._container.html
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
A :class:`Container` owns all GAMSPy symbols (sets, parameters, variables,
|
|
113
|
+
equations, models) and manages synchronization with the GAMS execution
|
|
114
|
+
engine.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
A container can:
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
* Create and store symbols
|
|
121
|
+
* Load symbols and records from GDX/G00 files
|
|
122
|
+
* Synchronize modified symbols with GAMS
|
|
123
|
+
* Generate and persist GAMS code and data files
|
|
124
|
+
* Act as a context manager.
|
|
105
125
|
|
|
106
126
|
Parameters
|
|
107
127
|
----------
|
|
108
128
|
load_from : str, os.PathLike, Container, gt.Container, optional
|
|
109
|
-
|
|
129
|
+
Source to initialize the container from:
|
|
130
|
+
|
|
131
|
+
* ``.gdx`` file: loads symbols and records from a GDX file.
|
|
132
|
+
* ``.g00`` file: restarts from a GAMS save file.
|
|
133
|
+
* Container: Copies symbols from the given container into the new container.
|
|
110
134
|
system_directory : str, os.PathLike, optional
|
|
111
135
|
Path to the directory that holds the GAMS installation, by default None
|
|
112
136
|
working_directory : str, os.PathLike, optional
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
debugging_level :
|
|
116
|
-
|
|
117
|
-
|
|
137
|
+
Directory used for temporary files (``.gms``, ``.lst``, ``.gdx``).
|
|
138
|
+
If omitted, a temporary directory is created.
|
|
139
|
+
debugging_level : {"keep", "keep_on_error", "delete"}, optional
|
|
140
|
+
Controls whether temporary files are retained:
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
* ``"keep"``: Keep files and generated GAMS code.
|
|
144
|
+
* ``"keep_on_error"``: Keep files only on errors (default).
|
|
145
|
+
* ``"delete"``: Always clean up.
|
|
118
146
|
options : Options, optional
|
|
119
147
|
Global options for the overall execution
|
|
148
|
+
output : io.TextIOWrapper, optional
|
|
149
|
+
Stream to which GAMS output is written.
|
|
120
150
|
|
|
121
151
|
Examples
|
|
122
152
|
--------
|
|
153
|
+
Basic usage
|
|
154
|
+
|
|
155
|
+
|
|
123
156
|
>>> import gamspy as gp
|
|
124
157
|
>>> m = gp.Container()
|
|
125
|
-
>>> i = gp.Set(m, "i")
|
|
158
|
+
>>> i = gp.Set(m, "i", records=["i1", "i2"])
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Loading from an existing GDX
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
>>> m.write("data.gdx")
|
|
165
|
+
>>> m2 = gp.Container(load_from="data.gdx")
|
|
166
|
+
>>> list(m2.data.keys()) == list(m.data.keys())
|
|
167
|
+
True
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
Using as a context manager
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
>>> with gp.Container() as m:
|
|
174
|
+
... i = gp.Set(m, "i")
|
|
175
|
+
... j = gp.Set(m, "j", domain=i)
|
|
126
176
|
|
|
127
177
|
"""
|
|
128
178
|
|
|
@@ -139,6 +189,7 @@ class Container(gt.Container):
|
|
|
139
189
|
self.output = output
|
|
140
190
|
self._gams_string = ""
|
|
141
191
|
self.models: dict[str, Model] = {}
|
|
192
|
+
self._mpsge_models: list[str] = []
|
|
142
193
|
if IS_MIRO_INIT:
|
|
143
194
|
atexit.register(self._write_miro_files)
|
|
144
195
|
|
|
@@ -241,26 +292,51 @@ class Container(gt.Container):
|
|
|
241
292
|
@property
|
|
242
293
|
def working_directory(self) -> str:
|
|
243
294
|
"""
|
|
244
|
-
|
|
295
|
+
Absolute path of the working directory used by this container.
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
The directory contains generated GAMS input/output files such as
|
|
299
|
+
``.gms``, ``.lst``, ``.gdx`` and temporary scratch files.
|
|
300
|
+
|
|
245
301
|
|
|
246
302
|
Returns
|
|
247
303
|
-------
|
|
248
304
|
str
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
Examples
|
|
308
|
+
--------
|
|
309
|
+
>>> import gamspy as gp
|
|
310
|
+
>>> m = gp.Container()
|
|
311
|
+
>>> m.working_directory # doctest: +ELLIPSIS
|
|
312
|
+
'...'
|
|
313
|
+
|
|
249
314
|
"""
|
|
250
315
|
return self._working_directory
|
|
251
316
|
|
|
252
317
|
@property
|
|
253
318
|
def in_miro(self) -> bool:
|
|
254
319
|
"""
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
320
|
+
Indicates whether the container is executed inside a GAMS MIRO context.
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
When running under MIRO, input data is typically provided by MIRO itself.
|
|
324
|
+
This flag can be used to skip expensive or redundant data-loading steps
|
|
325
|
+
(e.g., reading Excel files).
|
|
326
|
+
|
|
260
327
|
|
|
261
328
|
Returns
|
|
262
329
|
-------
|
|
263
330
|
bool
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
Examples
|
|
334
|
+
--------
|
|
335
|
+
>>> import gamspy as gp
|
|
336
|
+
>>> m = gp.Container()
|
|
337
|
+
>>> if not m.in_miro:
|
|
338
|
+
... pass # e.g. load data from files
|
|
339
|
+
|
|
264
340
|
"""
|
|
265
341
|
return MIRO_GDX_IN is not None
|
|
266
342
|
|
|
@@ -563,28 +639,51 @@ class Container(gt.Container):
|
|
|
563
639
|
encoding: str | None = None,
|
|
564
640
|
) -> None:
|
|
565
641
|
"""
|
|
566
|
-
|
|
567
|
-
|
|
642
|
+
Read symbols and records from a GDX file or another container.
|
|
643
|
+
|
|
568
644
|
|
|
569
645
|
Parameters
|
|
570
646
|
----------
|
|
571
|
-
load_from : str
|
|
572
|
-
|
|
573
|
-
|
|
647
|
+
load_from : str | os.PathLike | Container | gt.Container
|
|
648
|
+
Source to read from.
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
symbol_names : list[str], optional
|
|
652
|
+
Names of symbols to read. If omitted, all symbols are read.
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
load_records : bool, optional
|
|
656
|
+
Whether to load symbol records (default: True).
|
|
657
|
+
|
|
658
|
+
|
|
574
659
|
mode : str, optional
|
|
660
|
+
GDX read mode ("category", or "string", default: "category").
|
|
661
|
+
|
|
662
|
+
|
|
575
663
|
encoding : str, optional
|
|
664
|
+
Text encoding for symbol metadata.
|
|
665
|
+
|
|
576
666
|
|
|
577
667
|
Examples
|
|
578
668
|
--------
|
|
579
669
|
>>> import gamspy as gp
|
|
580
670
|
>>> m = gp.Container()
|
|
581
|
-
>>> i = gp.Set(m, "i", records=[
|
|
582
|
-
>>> m.write("
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
>>>
|
|
671
|
+
>>> i = gp.Set(m, "i", records=["a", "b"])
|
|
672
|
+
>>> m.write("example.gdx")
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
>>> m2 = gp.Container()
|
|
676
|
+
>>> m2.read("example.gdx")
|
|
677
|
+
>>> "i" in m2.data
|
|
586
678
|
True
|
|
587
679
|
|
|
680
|
+
|
|
681
|
+
Reading selected symbols only
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
>>> m2 = gp.Container()
|
|
685
|
+
>>> m2.read("example.gdx", symbol_names=["i"])
|
|
686
|
+
|
|
588
687
|
"""
|
|
589
688
|
if isinstance(load_from, os.PathLike):
|
|
590
689
|
load_from = os.fspath(load_from)
|
|
@@ -599,22 +698,37 @@ class Container(gt.Container):
|
|
|
599
698
|
uels_on_axes: bool | list[bool] = False,
|
|
600
699
|
) -> None:
|
|
601
700
|
"""
|
|
602
|
-
|
|
701
|
+
Set records for multiple symbols in a single batch operation.
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
This is functionally equivalent to calling ``symbol.setRecords`` for
|
|
705
|
+
each symbol, but triggers only one synchronization with GAMS.
|
|
706
|
+
|
|
603
707
|
|
|
604
708
|
Parameters
|
|
605
709
|
----------
|
|
606
710
|
records : dict[SymbolType, Any]
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
711
|
+
Mapping from symbols to their new records.
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
uels_on_axes : bool | list[bool], optional
|
|
715
|
+
Whether domain labels (UELs) are stored on pandas axes. Either a single
|
|
716
|
+
boolean applied to all symbols, or a list matching ``records`` order.
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
Raises
|
|
720
|
+
------
|
|
721
|
+
ValidationError
|
|
722
|
+
If ``uels_on_axes`` length does not match ``records`` length.
|
|
723
|
+
|
|
610
724
|
|
|
611
725
|
Examples
|
|
612
726
|
--------
|
|
613
727
|
>>> import gamspy as gp
|
|
614
728
|
>>> m = gp.Container()
|
|
615
729
|
>>> i = gp.Set(m, "i")
|
|
616
|
-
>>>
|
|
617
|
-
>>> m.setRecords({i:
|
|
730
|
+
>>> j = gp.Set(m, "j")
|
|
731
|
+
>>> m.setRecords({i: ["a", "b"], j: [1, 2, 3]})
|
|
618
732
|
|
|
619
733
|
"""
|
|
620
734
|
if not isinstance(uels_on_axes, list):
|
|
@@ -640,23 +754,37 @@ class Container(gt.Container):
|
|
|
640
754
|
eps_to_zero: bool = True,
|
|
641
755
|
) -> None:
|
|
642
756
|
"""
|
|
643
|
-
|
|
644
|
-
|
|
757
|
+
Write symbols and records to a GDX file.
|
|
758
|
+
|
|
645
759
|
|
|
646
760
|
Parameters
|
|
647
761
|
----------
|
|
648
762
|
write_to : str
|
|
649
|
-
|
|
650
|
-
|
|
763
|
+
Target GDX file path.
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
symbol_names : list[str], optional
|
|
767
|
+
Symbols to write. If omitted, all symbols are written.
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
compress : bool, optional
|
|
771
|
+
Whether to compress the GDX file.
|
|
772
|
+
|
|
773
|
+
|
|
651
774
|
mode : str, optional
|
|
652
|
-
|
|
775
|
+
Write mode (passed to GAMS Transfer).
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
eps_to_zero : bool, optional
|
|
779
|
+
Convert EPS values to zero before writing.
|
|
780
|
+
|
|
653
781
|
|
|
654
782
|
Examples
|
|
655
783
|
--------
|
|
656
784
|
>>> import gamspy as gp
|
|
657
785
|
>>> m = gp.Container()
|
|
658
|
-
>>> i = gp.Set(m, "i", records=[
|
|
659
|
-
>>> m.write("
|
|
786
|
+
>>> i = gp.Set(m, "i", records=["x", "y"])
|
|
787
|
+
>>> m.write("out.gdx")
|
|
660
788
|
|
|
661
789
|
"""
|
|
662
790
|
super().write(
|
|
@@ -733,26 +861,42 @@ class Container(gt.Container):
|
|
|
733
861
|
self, path: str | None = None, *, show_raw: bool = False
|
|
734
862
|
) -> str:
|
|
735
863
|
"""
|
|
736
|
-
|
|
864
|
+
Return the generated GAMS code executed by this container.
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
Only available when ``debugging_level='keep'`` was specified at
|
|
868
|
+
container creation time.
|
|
869
|
+
|
|
737
870
|
|
|
738
871
|
Parameters
|
|
739
872
|
----------
|
|
740
873
|
path : str, optional
|
|
741
|
-
|
|
874
|
+
File path to write the generated GAMS code to.
|
|
875
|
+
|
|
876
|
+
|
|
742
877
|
show_raw : bool, optional
|
|
743
|
-
|
|
744
|
-
|
|
878
|
+
If True, strips data-loading and auxiliary statements, leaving
|
|
879
|
+
the core model formulation.
|
|
880
|
+
|
|
745
881
|
|
|
746
882
|
Returns
|
|
747
883
|
-------
|
|
748
884
|
str
|
|
885
|
+
Generated GAMS code.
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
Raises
|
|
889
|
+
------
|
|
890
|
+
ValidationError
|
|
891
|
+
If debugging level is not ``"keep"``.
|
|
892
|
+
|
|
749
893
|
|
|
750
894
|
Examples
|
|
751
895
|
--------
|
|
752
896
|
>>> import gamspy as gp
|
|
753
897
|
>>> m = gp.Container(debugging_level="keep")
|
|
754
|
-
>>> i = gp.Set(m,
|
|
755
|
-
>>>
|
|
898
|
+
>>> i = gp.Set(m, "i")
|
|
899
|
+
>>> gams = m.generateGamsString()
|
|
756
900
|
|
|
757
901
|
"""
|
|
758
902
|
if self._debugging_level != "keep":
|
|
@@ -838,13 +982,31 @@ class Container(gt.Container):
|
|
|
838
982
|
|
|
839
983
|
for _, symbol in self:
|
|
840
984
|
symbol.modified = False
|
|
985
|
+
|
|
986
|
+
# Unfortunately MPSGE requires a dirty trick
|
|
987
|
+
pattern = re.compile(r"^\$sysInclude\s+mpsgeset\s+(\w+)\s*$", re.MULTILINE)
|
|
988
|
+
match = pattern.search(gams_code)
|
|
989
|
+
if match:
|
|
990
|
+
model_name = match.group(1)
|
|
991
|
+
self._mpsge_models.append(model_name.lower())
|
|
992
|
+
|
|
841
993
|
self._unsaved_statements = []
|
|
842
994
|
|
|
843
995
|
def close(self) -> None:
|
|
844
996
|
"""
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
997
|
+
Close the connection to the GAMS execution engine and release resources.
|
|
998
|
+
|
|
999
|
+
After calling this method, the container must not be used for further
|
|
1000
|
+
model execution or data synchronization. Symbol data remains accessible
|
|
1001
|
+
for read-only inspection.
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
Examples
|
|
1005
|
+
--------
|
|
1006
|
+
>>> import gamspy as gp
|
|
1007
|
+
>>> m = gp.Container() # Starts running the GAMS execution engine.
|
|
1008
|
+
>>> m.close() # Closes the connection to the execution engine.
|
|
1009
|
+
|
|
848
1010
|
"""
|
|
849
1011
|
close_connection(self._comm_pair_id)
|
|
850
1012
|
|
|
@@ -888,6 +1050,37 @@ class Container(gt.Container):
|
|
|
888
1050
|
|
|
889
1051
|
return gp.Alias(self, name, alias_with)
|
|
890
1052
|
|
|
1053
|
+
def addUniverseAlias(self, name: str | None = None) -> UniverseAlias:
|
|
1054
|
+
"""
|
|
1055
|
+
Creates a new UniverseAlias and adds it to the container
|
|
1056
|
+
|
|
1057
|
+
Parameters
|
|
1058
|
+
----------
|
|
1059
|
+
name : str, optional
|
|
1060
|
+
Name of the universe alias.
|
|
1061
|
+
|
|
1062
|
+
Returns
|
|
1063
|
+
-------
|
|
1064
|
+
UniverseAlias
|
|
1065
|
+
|
|
1066
|
+
Raises
|
|
1067
|
+
------
|
|
1068
|
+
ValueError
|
|
1069
|
+
If there is symbol with same name but different type in the
|
|
1070
|
+
Container
|
|
1071
|
+
|
|
1072
|
+
Examples
|
|
1073
|
+
--------
|
|
1074
|
+
>>> import gamspy as gp
|
|
1075
|
+
>>> m = gp.Container()
|
|
1076
|
+
>>> a = m.addUniverseAlias("a")
|
|
1077
|
+
|
|
1078
|
+
"""
|
|
1079
|
+
if name is None:
|
|
1080
|
+
name = self._get_symbol_name(prefix="u")
|
|
1081
|
+
|
|
1082
|
+
return gp.UniverseAlias(self, name)
|
|
1083
|
+
|
|
891
1084
|
def addSet(
|
|
892
1085
|
self,
|
|
893
1086
|
name: str | None = None,
|
|
@@ -901,22 +1094,22 @@ class Container(gt.Container):
|
|
|
901
1094
|
is_miro_output: bool = False,
|
|
902
1095
|
) -> Set:
|
|
903
1096
|
"""
|
|
904
|
-
Creates a Set and adds it to the container
|
|
1097
|
+
Creates a Set and adds it to the container.
|
|
905
1098
|
|
|
906
1099
|
Parameters
|
|
907
1100
|
----------
|
|
908
1101
|
name : str, optional
|
|
909
|
-
Name of the set.
|
|
1102
|
+
Name of the set. If omitted, a unique name is generated.
|
|
910
1103
|
domain : Sequence[Set | Alias | str] | Set | Alias | str, optional
|
|
911
|
-
Domain
|
|
1104
|
+
Domain over which the set is defined.
|
|
912
1105
|
is_singleton : bool, optional
|
|
913
|
-
|
|
1106
|
+
If True, the set may contain at most one element.
|
|
914
1107
|
records : pd.DataFrame | np.ndarray | list, optional
|
|
915
|
-
|
|
1108
|
+
Initial elements of the set.
|
|
916
1109
|
domain_forwarding : bool | list[bool], optional
|
|
917
|
-
|
|
1110
|
+
Enable domain forwarding.
|
|
918
1111
|
description : str, optional
|
|
919
|
-
|
|
1112
|
+
Human-readable description.
|
|
920
1113
|
uels_on_axes : bool
|
|
921
1114
|
Assume that symbol domain information is contained in the axes of the given records.
|
|
922
1115
|
is_miro_input : bool
|
|
@@ -938,9 +1131,24 @@ class Container(gt.Container):
|
|
|
938
1131
|
|
|
939
1132
|
Examples
|
|
940
1133
|
--------
|
|
1134
|
+
Simple set:
|
|
1135
|
+
|
|
1136
|
+
|
|
941
1137
|
>>> import gamspy as gp
|
|
942
1138
|
>>> m = gp.Container()
|
|
943
|
-
>>> i = m.addSet("i")
|
|
1139
|
+
>>> i = m.addSet("i", records=["a", "b"])
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
Indexed set:
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
>>> j = m.addSet("j", domain=i)
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
Singleton set:
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
>>> s = m.addSet("s", is_singleton=True, records=["s1"])
|
|
944
1152
|
|
|
945
1153
|
"""
|
|
946
1154
|
if name is None:
|
|
@@ -977,15 +1185,15 @@ class Container(gt.Container):
|
|
|
977
1185
|
Parameters
|
|
978
1186
|
----------
|
|
979
1187
|
name : str, optional
|
|
980
|
-
Name of the parameter.
|
|
1188
|
+
Name of the parameter. If omitted, a unique name is generated.
|
|
981
1189
|
domain : Sequence[Set | Alias | str] | Set | Alias | Dim | str, optional
|
|
982
|
-
Domain
|
|
1190
|
+
Domain over which the parameter is defined.
|
|
983
1191
|
records : int | float | pd.DataFrame | np.ndarray | list, optional
|
|
984
1192
|
Records of the parameter.
|
|
985
1193
|
domain_forwarding : bool | list[bool], optional
|
|
986
1194
|
Whether the parameter forwards the domain.
|
|
987
1195
|
description : str, optional
|
|
988
|
-
|
|
1196
|
+
Human-readable description.
|
|
989
1197
|
uels_on_axes : bool
|
|
990
1198
|
Assume that symbol domain information is contained in the axes of the given records.
|
|
991
1199
|
is_miro_input : bool
|
|
@@ -1047,7 +1255,7 @@ class Container(gt.Container):
|
|
|
1047
1255
|
Parameters
|
|
1048
1256
|
----------
|
|
1049
1257
|
name : str, optional
|
|
1050
|
-
Name of the variable.
|
|
1258
|
+
Name of the variable. If omitted, a unique name is generated.
|
|
1051
1259
|
type : str, optional
|
|
1052
1260
|
Type of the variable. "free" by default.
|
|
1053
1261
|
domain : Sequence[Set | Alias | str] | Set | Alias | Dim | str, optional
|
|
@@ -1114,7 +1322,7 @@ class Container(gt.Container):
|
|
|
1114
1322
|
Parameters
|
|
1115
1323
|
----------
|
|
1116
1324
|
name : str, optional
|
|
1117
|
-
Name of the equation.
|
|
1325
|
+
Name of the equation. If omitted, a unique name is generated.
|
|
1118
1326
|
type : str
|
|
1119
1327
|
Type of the equation. "regular" by default.
|
|
1120
1328
|
domain : Sequence[Set | Alias] | Set | Alias, optional
|
|
@@ -1192,7 +1400,7 @@ class Container(gt.Container):
|
|
|
1192
1400
|
Parameters
|
|
1193
1401
|
----------
|
|
1194
1402
|
name : str, optional
|
|
1195
|
-
Name of the model.
|
|
1403
|
+
Name of the model. If omitted, a unique name is generated.
|
|
1196
1404
|
description : str, optional
|
|
1197
1405
|
Description of the model.
|
|
1198
1406
|
equations : Sequence[Equation]
|
|
@@ -1219,8 +1427,9 @@ class Container(gt.Container):
|
|
|
1219
1427
|
--------
|
|
1220
1428
|
>>> import gamspy as gp
|
|
1221
1429
|
>>> m = gp.Container()
|
|
1222
|
-
>>>
|
|
1223
|
-
>>>
|
|
1430
|
+
>>> x = gp.Variable(m, "x")
|
|
1431
|
+
>>> e = gp.Equation(m, "e", definition=x >= 1)
|
|
1432
|
+
>>> model = m.addModel(name="demo", equations=[e], problem="LP", sense="MIN", objective=x)
|
|
1224
1433
|
|
|
1225
1434
|
"""
|
|
1226
1435
|
if name is None:
|
|
@@ -1295,6 +1504,14 @@ class Container(gt.Container):
|
|
|
1295
1504
|
----------
|
|
1296
1505
|
path : str
|
|
1297
1506
|
Path to the zip file.
|
|
1507
|
+
|
|
1508
|
+
Examples
|
|
1509
|
+
--------
|
|
1510
|
+
>>> import gamspy as gp
|
|
1511
|
+
>>> m = gp.Container()
|
|
1512
|
+
>>> i = gp.Set(m, "i", records=range(3))
|
|
1513
|
+
>>> gp.serialize(m, "serialization_path.zip")
|
|
1514
|
+
|
|
1298
1515
|
"""
|
|
1299
1516
|
gp.serialize(self, path)
|
|
1300
1517
|
|
|
@@ -1344,6 +1561,15 @@ class Container(gt.Container):
|
|
|
1344
1561
|
------
|
|
1345
1562
|
FileNotFoundError
|
|
1346
1563
|
In case the extrinsic library does not exist in the given path.
|
|
1564
|
+
|
|
1565
|
+
Examples
|
|
1566
|
+
--------
|
|
1567
|
+
>>> import gamspy as gp
|
|
1568
|
+
>>> m = gp.Container()
|
|
1569
|
+
>>> # Assuming 'trilib.so' is a valid library path
|
|
1570
|
+
>>> # lib = m.importExtrinsicLibrary("trilib.so", {"my_cos": "Cosine", "my_sin": "Sine"})
|
|
1571
|
+
>>> # c = lib.my_cos(0)
|
|
1572
|
+
|
|
1347
1573
|
"""
|
|
1348
1574
|
if not os.path.exists(lib_path):
|
|
1349
1575
|
raise FileNotFoundError(f"`{lib_path}` is not a valid path.")
|
gamspy/_convert.py
CHANGED
|
@@ -585,20 +585,26 @@ class LatexConverter:
|
|
|
585
585
|
self.latex_str = latex_str
|
|
586
586
|
|
|
587
587
|
def to_pdf(self) -> None:
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
588
|
+
try:
|
|
589
|
+
subprocess.run(["xelatex", "-version"], check=True, text=True)
|
|
590
|
+
except subprocess.CalledProcessError as e:
|
|
591
591
|
raise ValidationError(
|
|
592
|
-
"`
|
|
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,
|
|
593
605
|
)
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
["pdflatex", f"-output-directory={self.path}", self.tex_path],
|
|
597
|
-
capture_output=True,
|
|
598
|
-
text=True,
|
|
599
|
-
)
|
|
600
|
-
if process.returncode:
|
|
601
|
-
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
|
|
602
608
|
|
|
603
609
|
def get_table(self, symbol_type) -> str:
|
|
604
610
|
table = [TABLE_HEADER]
|
|
@@ -629,10 +635,10 @@ class LatexConverter:
|
|
|
629
635
|
continue
|
|
630
636
|
|
|
631
637
|
domain_str = ",".join([elem.latexRepr() for elem in equation.domain])
|
|
632
|
-
header = "\\subsubsection*{
|
|
638
|
+
header = "\\subsubsection*{" + equation._latex_name
|
|
633
639
|
if domain_str:
|
|
634
|
-
header += f"_{{{domain_str}}}"
|
|
635
|
-
header += "
|
|
640
|
+
header += f"$_{{{domain_str}}}$"
|
|
641
|
+
header += "}\n"
|
|
636
642
|
|
|
637
643
|
footer = "\n\\vspace{5pt}\n\\hrule"
|
|
638
644
|
latex_repr = f"{header}{equation.latexRepr()}{footer}"
|
|
@@ -641,13 +647,13 @@ class LatexConverter:
|
|
|
641
647
|
return "\n".join(definitions)
|
|
642
648
|
|
|
643
649
|
def get_constraints(self) -> str:
|
|
644
|
-
constraints = ["
|
|
650
|
+
constraints = [r"\begin{flalign*}"]
|
|
645
651
|
for name in self.symbols:
|
|
646
652
|
symbol = self.container[name]
|
|
647
653
|
if not isinstance(symbol, syms.Variable):
|
|
648
654
|
continue
|
|
649
655
|
|
|
650
|
-
constraint = "
|
|
656
|
+
constraint = "&" + symbol.latexRepr()
|
|
651
657
|
if symbol.type == "binary":
|
|
652
658
|
constraint += "\\in " + r"\{0,1\}"
|
|
653
659
|
if symbol.domain:
|
|
@@ -687,9 +693,10 @@ class LatexConverter:
|
|
|
687
693
|
else:
|
|
688
694
|
continue
|
|
689
695
|
|
|
690
|
-
constraint += "
|
|
696
|
+
constraint += "&\\\\"
|
|
691
697
|
constraints.append(constraint)
|
|
692
698
|
|
|
699
|
+
constraints.append(r"\end{flalign*}")
|
|
693
700
|
return "\n".join(constraints)
|
|
694
701
|
|
|
695
702
|
def get_header(self) -> str:
|