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 CHANGED
@@ -90,4 +90,4 @@ class Domain:
90
90
  -------
91
91
  str
92
92
  """
93
- return utils._get_domain_str(self.sets)[1:-1]
93
+ return utils._get_domain_str(self.sets, latex=True)[1:-1]
@@ -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 GAMS expression
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):
@@ -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, self.domain
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.name})"
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.name})"
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 | str] | Set | Alias | str | None = None,
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 | str] | Set | Alias | str, optional
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 = str((path / f"{model.name}_data.gdx").resolve())
392
- self.gms_path = str((path / f"{model.name}.gms").resolve())
393
- self.g00_path = str((path / f"{model.name}.g00").resolve())
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
- logger.info("Converter will not copy external module files")
442
- logger.info(
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
- logger.info(f"GAMS (.gms) file has been generated under {self.gms_path}")
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
- for name in self.model._autogen_symbols:
518
- if name in self.symbols:
519
- self.symbols.remove(name)
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()}}} ${self.model._objective_variable.name}$\\\\" # type: ignore
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
- logger.info(
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
- process = subprocess.run(["pdflatex", "-v"])
583
- if process.returncode:
588
+ try:
589
+ subprocess.run(["xelatex", "-version"], check=True, text=True)
590
+ except subprocess.CalledProcessError as e:
584
591
  raise ValidationError(
585
- "`pdflatex` is required to generate the pdf! Please install `pdflatex` and add it to the path."
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
- process = subprocess.run(
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)[1:-1]
620
+ domain_str = utils._get_domain_str(elem.domain, latex=True)[
621
+ 1:-1
622
+ ]
608
623
 
609
- row = f"{summary['name']} & {domain_str} & {summary['description']}\\\\"
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.name for elem in equation.domain])
624
- header = "\\subsubsection*{$" + equation.name.replace("_", "\\_")
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 += "$}\n"
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 = ["\\bigskip"]
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 = "$" + symbol.latexRepr()
656
+ constraint = "&" + symbol.latexRepr()
643
657
  if symbol.type == "binary":
644
- constraint += (
645
- "\\in "
646
- + r"\{0,1\}"
647
- + " ~ \\forall "
648
- + ",".join(symbol.domain_names)
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}_{+} \\forall " + ",".join(
652
- symbol.domain_names
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 ~ \\forall " + ",".join(symbol.domain_names)
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 ~ \\forall " + ",".join(symbol.domain_names)
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 = """\\documentclass[11pt]{article}
676
- \\usepackage{geometry}
677
- \\usepackage[american]{babel}
678
- \\usepackage{amsmath}
679
- \\usepackage{amssymb}
680
- \\usepackage[hidelinks]{hyperref}
681
- \\usepackage{tabularx}
682
- \\usepackage{ltablex}
683
- \\keepXColumns
684
-
685
- \\begin{document}
686
- \\section*{Symbols}
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
- return self.gamsRepr()
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', or 'MPSGE',
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[Variable | Equation]] = 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("output_directory", gp.FileFormat.GAMS)
1217
- >>> my_model.convert("output_directory", [gp.FileFormat.GAMS, gp.FileFormat.AMPL])
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(self, path: str | Path, generate_pdf: bool = False) -> None:
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)
@@ -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 | str] | Set | Alias | str | None = None,
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, str)):
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.name for symbol in self._definition.left.domain]
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.name
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
- constraint_str = str(self._definition.left.condition)
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() # type: ignore
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.name.replace("_", "\\_")
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.name.replace("_", "\\_")
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) + "}"
@@ -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
@@ -47,8 +47,7 @@ class Symbol:
47
47
  -------
48
48
  str
49
49
  """
50
- name = self.name.replace("_", "\\_")
51
- return name
50
+ return self._latex_name
52
51
 
53
52
  @property
54
53
  def synchronize(
@@ -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 = validation.validate_name(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
@@ -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
- assert self.container is not None
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
- self.container, temp_name, self.domain
65
+ container, temp_name, self.domain
62
66
  )
63
67
  temp_param[...] = self
64
- del self.container.data[temp_name]
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([_stringify(elem) for elem in self.elements])
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
- return f"{self.op_name}({operands_str})"
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(domain: Iterable[Set | Alias | ImplicitSet | str]) -> 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
- set_strs = []
605
- for set in domain:
606
- if isinstance(set, (gt.Set, gt.Alias, gt.UniverseAlias, implicits.ImplicitSet)):
607
- set_strs.append(set.gamsRepr())
608
- elif isinstance(set, str):
609
- if set == "*":
610
- set_strs.append(set)
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
- set_strs.append('"' + set + '"')
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(set)}"
626
+ f"Domain type must be str, Set or Alias but found {type(elem)}"
616
627
  )
617
628
 
618
- return "(" + ",".join(set_strs) + ")"
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.1
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.1.0
35
- Requires-Dist: gamspy_base<53.0.0,>=52.1.0
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=w5zftBCrgFSkZEOgwh2zyFjiDA4AohzNHi-BuF0Hjas,45884
6
- gamspy/_convert.py,sha256=z_ju0T2duAAeYE0ahW7E2GMdMMVZsQ5936HV583hXzs,22294
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=6pBam_ruzKaYjEpALjAQ5d9uPrlOf1lVMYjRYqHH8o0,4337
8
+ gamspy/_extrinsic.py,sha256=OGrlNzcSQjoIZw8lpsk_4SObEAhGX5bkc_D0d3lPZMQ,4807
9
9
  gamspy/_miro.py,sha256=MeFGcaFtNgtydWjH0KS0l9y3mNy7tPyXwm43jwomodg,12245
10
- gamspy/_model.py,sha256=Qd8JdDDUUSjWXQUKGR4N0-2J_PHnzh8sjSG3U7A4aKk,51359
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=k4e8M8X32hEFybJyISyXLNrzO1mmWXQPnSThT7rOC5U,21608
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=6eO4R0iBLRm2oTRCz_croiQhKpiIyF8bOa0NDfw9aUU,19777
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=WN9ftyz8DPwPOtlECo_E8Cz3Qxk-0hBPGIuu5bzvX6Y,2929
24
- gamspy/_algebra/expression.py,sha256=rBG4chXXjP9AtbCkQG8XK419kOTHjLhc3l5T5o1ZGMs,25392
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=e3gYxS5OPh8JYGAnAS1wEpzafFpfBt0UbcL4PKZyoY0,22990
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=a4AtD-VI5jk0ZcO0JAwD0f0KJRwmxA8MzR_2MmhPWpg,1580
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=lIoNynvLd-tfXrVBs8Asy0TEkhs-xkTeNl4yLtzehiA,8795
46
- gamspy/_symbols/equation.py,sha256=W_8eQdZ9Mou9YVI1l0X_gwFB--TVNOK02OGpWmO3Xek,39719
47
- gamspy/_symbols/parameter.py,sha256=i5UWz8KQEHDBOjGV7JmL8GhnLnL-CiFMUhfSrBZOqQs,19721
48
- gamspy/_symbols/set.py,sha256=j3Izvgs470xiauwCbgXZOelZy-KAzslDGXuKeHn_g3g,29130
49
- gamspy/_symbols/symbol.py,sha256=Mn_O51nW99_d0G395JQ4C9SwXnMvdwqY7P6j_YyFL8E,10921
50
- gamspy/_symbols/universe_alias.py,sha256=8xoVhG9GGdl06tj56-NgN7T0dXwhp4rgKbCkjn8WhC8,4059
51
- gamspy/_symbols/variable.py,sha256=_yarP4aD-f76btWyGsGohuAgqQh1fcRWBGOngdehnic,30524
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=ec1qXcbc1FKZ1s46cbycek7SJKrhC6LCF5FMgMLy0OE,3728
56
- gamspy/_symbols/implicits/implicit_symbol.py,sha256=YDt2DVH4WOd88gOgbqYZzq8Wm5UPRmrwg8Og4vuektM,9009
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=FaSRYFjMN6AULqOqGIF6_AXDw6KVqgxm2EtZsDcBFmE,37432
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.1.dist-info/licenses/LICENSE,sha256=D4HfHbHRs3LVWo3uXq44WQc1FkBP5srUCEa-vO0W9tE,1189
85
- gamspy-1.18.1.dist-info/METADATA,sha256=E7-RHCJZIutvTFYwaNd7NtgGD35BKwa-RV-IBFyoG5Y,5301
86
- gamspy-1.18.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
87
- gamspy-1.18.1.dist-info/entry_points.txt,sha256=tzgC7L0Y_BiyagBCaYOPK7lE4olRJKM_PH2inmMvj60,48
88
- gamspy-1.18.1.dist-info/top_level.txt,sha256=fsq4q5lfdb2GEZC9O3PUih38s7TfIgolIaO5NgR3Hf8,7
89
- gamspy-1.18.1.dist-info/RECORD,,
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,,