gamspy 1.17.0__py3-none-any.whl → 1.17.2__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.
Files changed (44) hide show
  1. gamspy/__init__.py +1 -1
  2. gamspy/_algebra/expression.py +12 -14
  3. gamspy/_algebra/operation.py +3 -2
  4. gamspy/_cli/install.py +4 -2
  5. gamspy/_cli/show.py +4 -1
  6. gamspy/_cli/uninstall.py +4 -2
  7. gamspy/_config.py +1 -1
  8. gamspy/_container.py +27 -7
  9. gamspy/_convert.py +18 -17
  10. gamspy/_database.py +1 -1
  11. gamspy/_miro.py +1 -1
  12. gamspy/_model.py +146 -13
  13. gamspy/_model_instance.py +3 -2
  14. gamspy/_options.py +6 -6
  15. gamspy/_serialization.py +8 -5
  16. gamspy/_symbols/alias.py +4 -3
  17. gamspy/_symbols/equation.py +10 -3
  18. gamspy/_symbols/implicits/implicit_parameter.py +4 -3
  19. gamspy/_symbols/implicits/implicit_set.py +3 -2
  20. gamspy/_symbols/implicits/implicit_symbol.py +7 -7
  21. gamspy/_symbols/implicits/implicit_variable.py +4 -3
  22. gamspy/_symbols/parameter.py +6 -5
  23. gamspy/_symbols/set.py +4 -3
  24. gamspy/_symbols/universe_alias.py +1 -1
  25. gamspy/_symbols/variable.py +23 -5
  26. gamspy/_types.py +0 -1
  27. gamspy/_validation.py +5 -10
  28. gamspy/exceptions.py +1 -1
  29. gamspy/formulations/__init__.py +2 -0
  30. gamspy/formulations/nn/maxpool2d.py +5 -1
  31. gamspy/formulations/nn/minpool2d.py +5 -1
  32. gamspy/formulations/nn/torch_sequential.py +80 -8
  33. gamspy/formulations/result.py +119 -0
  34. gamspy/math/__init__.py +4 -0
  35. gamspy/math/activation.py +195 -8
  36. gamspy/math/matrix.py +2 -2
  37. gamspy/math/misc.py +1 -1
  38. gamspy/utils.py +61 -47
  39. {gamspy-1.17.0.dist-info → gamspy-1.17.2.dist-info}/METADATA +3 -2
  40. {gamspy-1.17.0.dist-info → gamspy-1.17.2.dist-info}/RECORD +44 -43
  41. {gamspy-1.17.0.dist-info → gamspy-1.17.2.dist-info}/WHEEL +0 -0
  42. {gamspy-1.17.0.dist-info → gamspy-1.17.2.dist-info}/entry_points.txt +0 -0
  43. {gamspy-1.17.0.dist-info → gamspy-1.17.2.dist-info}/licenses/LICENSE +0 -0
  44. {gamspy-1.17.0.dist-info → gamspy-1.17.2.dist-info}/top_level.txt +0 -0
gamspy/__init__.py CHANGED
@@ -50,7 +50,7 @@ from gamspy._symbols import (
50
50
 
51
51
  from .version import __version__
52
52
 
53
- _ctx_managers: dict[tuple[int, int], Container] = dict()
53
+ _ctx_managers: dict[tuple[int, int], Container] = {}
54
54
  _set_default_options()
55
55
 
56
56
  __all__ = [
@@ -20,8 +20,6 @@ from gamspy.exceptions import ValidationError
20
20
  from gamspy.math.misc import MathOp
21
21
 
22
22
  if TYPE_CHECKING:
23
- from numbers import Real
24
-
25
23
  import pandas as pd
26
24
 
27
25
  from gamspy import Alias, Set
@@ -150,7 +148,7 @@ def create_gams_expression(root_node: Expression) -> str:
150
148
  s1.append(node.right)
151
149
 
152
150
  # 2. Build the GAMS expression
153
- eval_stack: list[tuple[str, Real]] = []
151
+ eval_stack: list[tuple[str, float]] = []
154
152
  for node in reversed(post_order_nodes):
155
153
  if not isinstance(node, Expression):
156
154
  eval_stack.append((get_operand_gams_repr(node), LEAF_PRECEDENCE))
@@ -237,7 +235,7 @@ def create_latex_expression(root_node: Expression) -> str:
237
235
  s1.append(node.right)
238
236
 
239
237
  # 2. Build the GAMS expression
240
- eval_stack: list[tuple[str, Real]] = []
238
+ eval_stack: list[tuple[str, float]] = []
241
239
  for node in reversed(post_order_nodes):
242
240
  if not isinstance(node, Expression):
243
241
  eval_stack.append((get_operand_latex_repr(node), LEAF_PRECEDENCE))
@@ -406,8 +404,8 @@ class Expression(operable.Operable):
406
404
 
407
405
  def __getitem__(self, indices):
408
406
  indices = validation.validate_domain(self, indices)
409
- left_domain = [d for d in self._left_domain]
410
- right_domain = [d for d in self._right_domain]
407
+ left_domain = list(self._left_domain)
408
+ right_domain = list(self._right_domain)
411
409
  for i, s in enumerate(indices):
412
410
  for lr, pos in self._shadow_domain[i].indices:
413
411
  if lr == "l":
@@ -638,16 +636,16 @@ class Expression(operable.Operable):
638
636
  symbols.append(node.alias_with.name)
639
637
 
640
638
  symbols.append(node.name)
641
- stack += node.domain
639
+ stack.extend(node.domain)
642
640
  node = None
643
641
  elif isinstance(node, ImplicitSymbol):
644
642
  if node.parent.name not in symbols:
645
643
  symbols.append(node.parent.name)
646
- stack += node.domain
647
- stack += node.container[node.parent.name].domain
644
+ stack.extend(node.domain)
645
+ stack.extend(node.container[node.parent.name].domain)
648
646
  node = None
649
647
  elif isinstance(node, operation.Operation):
650
- stack += node.op_domain
648
+ stack.extend(node.op_domain)
651
649
  node = node.rhs
652
650
  elif isinstance(node, condition.Condition):
653
651
  stack.append(node.conditioning_on)
@@ -664,10 +662,10 @@ class Expression(operable.Operable):
664
662
  if isinstance(node.elements[0], Expression):
665
663
  node = node.elements[0]
666
664
  else:
667
- stack += node.elements
665
+ stack.extend(node.elements)
668
666
  node = None
669
667
  elif isinstance(node, ExtrinsicFunction):
670
- stack += list(node.args)
668
+ stack.extend(list(node.args))
671
669
  node = None
672
670
  else:
673
671
  node = getattr(node, "right", None)
@@ -692,12 +690,12 @@ class Expression(operable.Operable):
692
690
  given_condition = node.condition
693
691
 
694
692
  if isinstance(given_condition, Expression):
695
- symbols += given_condition._find_all_symbols()
693
+ symbols.extend(given_condition._find_all_symbols())
696
694
  elif isinstance(given_condition, ImplicitSymbol):
697
695
  symbols.append(given_condition.parent.name)
698
696
 
699
697
  if isinstance(node, operation.Operation):
700
- stack += node.op_domain
698
+ stack.extend(node.op_domain)
701
699
  node = node.rhs
702
700
  else:
703
701
  node = getattr(node, "right", None)
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Sequence
4
3
  from typing import TYPE_CHECKING
5
4
 
6
5
  import gamspy._algebra.condition as condition
@@ -14,6 +13,8 @@ import gamspy.utils as utils
14
13
  from gamspy.exceptions import ValidationError
15
14
 
16
15
  if TYPE_CHECKING:
16
+ from collections.abc import Sequence
17
+
17
18
  import pandas as pd
18
19
 
19
20
  from gamspy._algebra import Domain
@@ -70,7 +71,7 @@ class Operation(operable.Operable):
70
71
  self.domain.append(x)
71
72
 
72
73
  self.dimension: int = validation.get_dimension(self.domain)
73
- controlled_domain = [d for d in self._bare_op_domain]
74
+ controlled_domain = list(self._bare_op_domain)
74
75
  controlled_domain.extend(getattr(rhs, "controlled_domain", []))
75
76
  self.controlled_domain = list(set(controlled_domain))
76
77
 
gamspy/_cli/install.py CHANGED
@@ -5,8 +5,7 @@ import os
5
5
  import shutil
6
6
  import subprocess
7
7
  import sys
8
- from collections.abc import Iterable
9
- from typing import Annotated
8
+ from typing import TYPE_CHECKING, Annotated
10
9
 
11
10
  import requests
12
11
  import typer
@@ -16,6 +15,9 @@ from gamspy.exceptions import GamspyException, ValidationError
16
15
 
17
16
  from .util import add_solver_entry
18
17
 
18
+ if TYPE_CHECKING:
19
+ from collections.abc import Iterable
20
+
19
21
  app = typer.Typer(
20
22
  rich_markup_mode="rich",
21
23
  short_help="To install licenses and solvers.",
gamspy/_cli/show.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Callable
4
3
  from datetime import datetime, timedelta
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  import rich
7
7
  import rich.table
@@ -10,6 +10,9 @@ import typer
10
10
  import gamspy.utils as utils
11
11
  from gamspy.exceptions import ValidationError
12
12
 
13
+ if TYPE_CHECKING:
14
+ from collections.abc import Callable
15
+
13
16
  app = typer.Typer(
14
17
  rich_markup_mode="rich",
15
18
  short_help="To show your license and gamspy_base directory.",
gamspy/_cli/uninstall.py CHANGED
@@ -3,8 +3,7 @@ from __future__ import annotations
3
3
  import os
4
4
  import subprocess
5
5
  import sys
6
- from collections.abc import Iterable
7
- from typing import Annotated
6
+ from typing import TYPE_CHECKING, Annotated
8
7
 
9
8
  import typer
10
9
 
@@ -13,6 +12,9 @@ from gamspy.exceptions import GamspyException, ValidationError
13
12
 
14
13
  from .util import remove_solver_entry
15
14
 
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Iterable
17
+
16
18
  app = typer.Typer(
17
19
  rich_markup_mode="rich",
18
20
  short_help="To uninstall licenses and solvers.",
gamspy/_config.py CHANGED
@@ -5,7 +5,7 @@ from typing import Any, Literal
5
5
 
6
6
  from gamspy.exceptions import ValidationError
7
7
 
8
- configuration: dict[str, Any] = dict()
8
+ configuration: dict[str, Any] = {}
9
9
 
10
10
 
11
11
  def _set_default_options() -> None:
gamspy/_container.py CHANGED
@@ -11,7 +11,6 @@ import threading
11
11
  import time
12
12
  import traceback
13
13
  import weakref
14
- from collections.abc import Iterable, Sequence
15
14
  from typing import TYPE_CHECKING
16
15
 
17
16
  import gams.transfer as gt
@@ -25,12 +24,12 @@ from gamspy._config import get_option
25
24
  from gamspy._extrinsic import ExtrinsicLibrary
26
25
  from gamspy._miro import MiroJSONEncoder
27
26
  from gamspy._model import Problem, Sense
28
- from gamspy._options import Options
29
27
  from gamspy._workspace import Workspace
30
28
  from gamspy.exceptions import FatalError, GamspyException, ValidationError
31
29
 
32
30
  if TYPE_CHECKING:
33
31
  import io
32
+ from collections.abc import Iterable, Sequence
34
33
  from typing import Any, Literal, TypeAlias
35
34
 
36
35
  from pandas import DataFrame
@@ -46,6 +45,8 @@ if TYPE_CHECKING:
46
45
  )
47
46
  from gamspy._algebra.expression import Expression
48
47
  from gamspy._algebra.operation import Operation
48
+ from gamspy._options import Options
49
+ from gamspy._symbols.implicits import ImplicitVariable
49
50
  from gamspy.math.matrix import Dim
50
51
 
51
52
  SymbolType: TypeAlias = Set | Alias | Parameter | Variable | Equation
@@ -267,7 +268,7 @@ class Container(gt.Container):
267
268
  ):
268
269
  self.output = output
269
270
  self._gams_string = ""
270
- self.models: dict[str, Model] = dict()
271
+ self.models: dict[str, Model] = {}
271
272
  if IS_MIRO_INIT:
272
273
  atexit.register(self._write_miro_files)
273
274
 
@@ -339,7 +340,7 @@ class Container(gt.Container):
339
340
  {"restart": load_from, "gdxSymbols": "all"}
340
341
  )
341
342
  self._synch_with_gams(gams_to_gamspy=True)
342
- self._options._set_debug_options(dict())
343
+ self._options._set_debug_options({})
343
344
  self._clean_modified_symbols()
344
345
  self._unsaved_statements = []
345
346
  self._is_restarted = True
@@ -679,7 +680,8 @@ class Container(gt.Container):
679
680
  strings.append("$offDotL")
680
681
  elif assume_suffix == 2:
681
682
  strings.append("$offDotScale")
682
- strings += ["$offUNDF", "$offMulti"]
683
+
684
+ strings.extend(["$offUNDF", "$offMulti"])
683
685
 
684
686
  if not IS_MIRO_INIT and MIRO_GDX_OUT:
685
687
  if len(self._miro_output_symbols) == 0:
@@ -1062,6 +1064,9 @@ class Container(gt.Container):
1062
1064
  >>> a = m.addAlias("a", i)
1063
1065
 
1064
1066
  """
1067
+ if name is None:
1068
+ name = self._get_symbol_name(prefix="a")
1069
+
1065
1070
  return gp.Alias(self, name, alias_with)
1066
1071
 
1067
1072
  def addSet(
@@ -1119,6 +1124,9 @@ class Container(gt.Container):
1119
1124
  >>> i = m.addSet("i")
1120
1125
 
1121
1126
  """
1127
+ if name is None:
1128
+ name = self._get_symbol_name(prefix="s")
1129
+
1122
1130
  return gp.Set(
1123
1131
  self,
1124
1132
  name,
@@ -1187,6 +1195,9 @@ class Container(gt.Container):
1187
1195
  >>> a = m.addParameter("a")
1188
1196
 
1189
1197
  """
1198
+ if name is None:
1199
+ name = self._get_symbol_name(prefix="p")
1200
+
1190
1201
  return gp.Parameter(
1191
1202
  self,
1192
1203
  name,
@@ -1250,6 +1261,9 @@ class Container(gt.Container):
1250
1261
  >>> v = m.addVariable("v")
1251
1262
 
1252
1263
  """
1264
+ if name is None:
1265
+ name = self._get_symbol_name(prefix="v")
1266
+
1253
1267
  return gp.Variable(
1254
1268
  self,
1255
1269
  name,
@@ -1320,6 +1334,9 @@ class Container(gt.Container):
1320
1334
  >>> i = m.addEquation("i")
1321
1335
 
1322
1336
  """
1337
+ if name is None:
1338
+ name = self._get_symbol_name(prefix="e")
1339
+
1323
1340
  return gp.Equation(
1324
1341
  self,
1325
1342
  name,
@@ -1347,7 +1364,7 @@ class Container(gt.Container):
1347
1364
  Variable | Sequence[Variable],
1348
1365
  ]
1349
1366
  | None = None,
1350
- limited_variables: Sequence[Variable] | None = None,
1367
+ limited_variables: Sequence[ImplicitVariable] | None = None,
1351
1368
  external_module: str | None = None,
1352
1369
  ) -> Model:
1353
1370
  """
@@ -1370,7 +1387,7 @@ class Container(gt.Container):
1370
1387
  Objective variable to minimize or maximize or objective itself.
1371
1388
  matches : dict[Equation | Sequence[Equation], Variable | Sequence[Variable]], optional
1372
1389
  Equation - Variable matches for MCP models.
1373
- limited_variables : Sequence, optional
1390
+ limited_variables : Sequence[ImplicitVariable], optional
1374
1391
  Allows limiting the domain of variables used in a model.
1375
1392
  external_module: str, optional
1376
1393
  The name of the external module in which the external equations are implemented
@@ -1387,6 +1404,9 @@ class Container(gt.Container):
1387
1404
  >>> model = m.addModel("my_model", "LP", [e])
1388
1405
 
1389
1406
  """
1407
+ if name is None:
1408
+ name = self._get_symbol_name(prefix="m")
1409
+
1390
1410
  return gp.Model(
1391
1411
  self,
1392
1412
  name,
gamspy/_convert.py CHANGED
@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  import subprocess
6
6
  from collections.abc import Sequence
7
- from typing import TYPE_CHECKING
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
9
  import gamspy._symbols as syms
10
10
  import gamspy.utils as utils
@@ -12,6 +12,7 @@ from gamspy._options import EXECUTION_OPTIONS, MODEL_ATTR_OPTION_MAP, Options
12
12
  from gamspy.exceptions import LatexException, ValidationError
13
13
 
14
14
  if TYPE_CHECKING:
15
+ from pathlib import Path
15
16
  from typing import TypeAlias
16
17
 
17
18
  from gamspy import (
@@ -80,11 +81,11 @@ option js<js2; jd(js) = yes;
80
81
  jc(j) = yes;
81
82
  jc(jd) = no;
82
83
 
83
- xb.lo(jb) =xc.lo(jb); xb.up(jb) =xc.up(jb); xb.prior(jb) =xc.scale(jb);
84
- xi.lo(ji) =xc.lo(ji); xi.up(ji) =xc.up(ji); xi.prior(ji) =xc.scale(ji);
85
- xsc.lo(jsc) =xc.lo(jsc); xsc.up(jsc) =xc.up(jsc); xsc.prior(jsc) =xc.scale(jsc);
86
- xsi.lo(jsi) =xc.lo(jsi); xsi.up(jsi) =xc.up(jsi); xsi.prior(jsi) =xc.scale(jsi);
87
- xs1.lo(js1(s,j))=xc.lo(j); xs1.up(js1(s,j))=xc.up(j); xs1.prior(js1(s,j))=xc.scale(j);
84
+ xb.lo(jb) =xc.lo(jb); xb.up(jb) =xc.up(jb); xb.prior(jb) =xc.scale(jb);
85
+ xi.lo(ji) =xc.lo(ji); xi.up(ji) =xc.up(ji); xi.prior(ji) =xc.scale(ji);
86
+ xsc.lo(jsc) =xc.lo(jsc); xsc.up(jsc) =xc.up(jsc); xsc.prior(jsc) =xc.scale(jsc);
87
+ xsi.lo(jsi) =xc.lo(jsi); xsi.up(jsi) =xc.up(jsi); xsi.prior(jsi) =xc.scale(jsi);
88
+ xs1.lo(js1(s,j))=xc.lo(j); xs1.up(js1(s,j))=xc.up(j); xs1.prior(js1(s,j))=xc.scale(j);
88
89
  xs2.lo(js2(s,j))=xc.lo(j); xs2.up(js2(s,j))=xc.up(j); xs2.prior(js2(s,j))=xc.scale(j);
89
90
 
90
91
  option ij<A;
@@ -300,7 +301,7 @@ jac.solve(output=sys.stdout, options=options)
300
301
 
301
302
 
302
303
  def get_convert_solver_options(
303
- path: str,
304
+ path: Path,
304
305
  file_format: FileFormat | Sequence[FileFormat],
305
306
  options: ConvertOptions | None,
306
307
  ) -> dict[str, str]:
@@ -319,7 +320,7 @@ def get_convert_solver_options(
319
320
  if any(not isinstance(format, FileFormat) for format in file_format):
320
321
  raise ValidationError("`file_format` must be a FileFormat enum.")
321
322
 
322
- solver_options = {}
323
+ solver_options: dict[str, Any] = {}
323
324
  for format in file_format:
324
325
  name, value = format.name, format.value
325
326
  if name in FORMAT_RENAME_MAP:
@@ -335,13 +336,13 @@ def get_convert_solver_options(
335
336
  "$if not set jacfile $abort Please set --jacfile=<filename>.gdx"
336
337
  )
337
338
 
338
- with open(os.path.join(path, value), "w") as file:
339
+ with open(path / value, "w") as file:
339
340
  file.write(jacobian_gms)
340
341
  elif format == FileFormat.GAMSPyJacobian:
341
- with open(os.path.join(path, value), "w") as file:
342
+ with open(path / value, "w") as file:
342
343
  file.write(GAMSPY_JACOBIAN)
343
344
  else:
344
- solver_options[name] = os.path.join(path, value)
345
+ solver_options[name] = str((path / value).resolve())
345
346
 
346
347
  if options is not None:
347
348
  extra_options = options.model_dump(exclude_none=True)
@@ -375,7 +376,7 @@ class GamsConverter:
375
376
  def __init__(
376
377
  self,
377
378
  model: Model,
378
- path: str,
379
+ path: Path,
379
380
  options: Options | None,
380
381
  dump_gams_state: bool,
381
382
  ) -> None:
@@ -385,9 +386,9 @@ class GamsConverter:
385
386
  self.path = path
386
387
  self.options = options
387
388
  self.dump_gams_state = dump_gams_state
388
- self.gdx_path = os.path.join(path, model.name + "_data.gdx")
389
- self.gms_path = os.path.join(path, model.name + ".gms")
390
- self.g00_path = os.path.join(path, model.name + ".g00")
389
+ self.gdx_path = str((path / f"{model.name}_data.gdx").resolve())
390
+ self.gms_path = str((path / f"{model.name}.gms").resolve())
391
+ self.g00_path = str((path / f"{model.name}.g00").resolve())
391
392
 
392
393
  def get_definitions(self) -> list[str]:
393
394
  definitions = []
@@ -441,7 +442,7 @@ class GamsConverter:
441
442
  )
442
443
 
443
444
  # 2. Load the data from gdx
444
- load_str = f"$onMultiR\n$gdxLoadAll {os.path.abspath(self.gdx_path)}\n$offMulti"
445
+ load_str = f'$onMultiR\n$gdxLoadAll "{self.gdx_path}"\n$offMulti'
445
446
 
446
447
  # 3. Definitions
447
448
  definitions = self.get_definitions()
@@ -493,7 +494,7 @@ TABLE_FOOTER = "\\hline\n\\end{tabularx}"
493
494
 
494
495
 
495
496
  class LatexConverter:
496
- def __init__(self, model: Model, path: str) -> None:
497
+ def __init__(self, model: Model, path: Path) -> None:
497
498
  os.makedirs(path, exist_ok=True)
498
499
  self.model = model
499
500
  self.container = model.container
gamspy/_database.py CHANGED
@@ -193,7 +193,7 @@ class Database:
193
193
  """Communicates data between Python and GAMS"""
194
194
 
195
195
  def __init__(self, ws: Workspace):
196
- self.symbols: dict = dict()
196
+ self.symbols: dict = {}
197
197
  self.workspace = ws
198
198
  self.gmd = new_gmdHandle_tp()
199
199
 
gamspy/_miro.py CHANGED
@@ -303,7 +303,7 @@ class MiroJSONEncoder:
303
303
 
304
304
  symbol_dicts = self.prepare_symbols(non_scalars)
305
305
 
306
- non_scalars = [name for name in non_scalars]
306
+ non_scalars = list(non_scalars)
307
307
 
308
308
  keys = non_scalars
309
309
  values = symbol_dicts