gamspy 1.17.0__tar.gz → 1.17.1__tar.gz

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 (94) hide show
  1. {gamspy-1.17.0 → gamspy-1.17.1}/PKG-INFO +3 -2
  2. {gamspy-1.17.0 → gamspy-1.17.1}/pyproject.toml +7 -3
  3. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/__init__.py +1 -1
  4. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/expression.py +12 -14
  5. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/operation.py +3 -2
  6. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/install.py +4 -2
  7. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/show.py +4 -1
  8. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/uninstall.py +4 -2
  9. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_config.py +1 -1
  10. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_container.py +9 -7
  11. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_convert.py +18 -17
  12. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_database.py +1 -1
  13. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_miro.py +1 -1
  14. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_model.py +42 -13
  15. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_model_instance.py +3 -2
  16. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_options.py +6 -6
  17. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_serialization.py +8 -5
  18. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/alias.py +4 -3
  19. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/equation.py +3 -3
  20. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/implicits/implicit_parameter.py +4 -3
  21. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/implicits/implicit_set.py +3 -2
  22. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/implicits/implicit_symbol.py +7 -7
  23. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/implicits/implicit_variable.py +4 -3
  24. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/parameter.py +6 -5
  25. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/set.py +4 -3
  26. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/universe_alias.py +1 -1
  27. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/variable.py +6 -5
  28. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_types.py +0 -1
  29. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_validation.py +5 -5
  30. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/exceptions.py +1 -1
  31. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/maxpool2d.py +5 -1
  32. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/minpool2d.py +5 -1
  33. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/__init__.py +2 -0
  34. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/activation.py +63 -2
  35. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/matrix.py +2 -2
  36. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/misc.py +1 -1
  37. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/utils.py +59 -46
  38. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy.egg-info/PKG-INFO +3 -2
  39. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy.egg-info/requires.txt +2 -1
  40. {gamspy-1.17.0 → gamspy-1.17.1}/tests/test_gamspy.py +1 -1
  41. {gamspy-1.17.0 → gamspy-1.17.1}/LICENSE +0 -0
  42. {gamspy-1.17.0 → gamspy-1.17.1}/README.md +0 -0
  43. {gamspy-1.17.0 → gamspy-1.17.1}/README_PYPI.md +0 -0
  44. {gamspy-1.17.0 → gamspy-1.17.1}/setup.cfg +0 -0
  45. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/__main__.py +0 -0
  46. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/__init__.py +0 -0
  47. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/condition.py +0 -0
  48. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/domain.py +0 -0
  49. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/number.py +0 -0
  50. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_algebra/operable.py +0 -0
  51. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_backend/__init__.py +0 -0
  52. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_backend/backend.py +0 -0
  53. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_backend/engine.py +0 -0
  54. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_backend/local.py +0 -0
  55. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_backend/neos.py +0 -0
  56. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/__init__.py +0 -0
  57. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/cli.py +0 -0
  58. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/gdx.py +0 -0
  59. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/list.py +0 -0
  60. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/probe.py +0 -0
  61. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/retrieve.py +0 -0
  62. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/run.py +0 -0
  63. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_cli/util.py +0 -0
  64. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_extrinsic.py +0 -0
  65. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/__init__.py +0 -0
  66. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/implicits/__init__.py +0 -0
  67. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/implicits/implicit_equation.py +0 -0
  68. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_symbols/symbol.py +0 -0
  69. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/_workspace.py +0 -0
  70. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/__init__.py +0 -0
  71. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/ml/__init__.py +0 -0
  72. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/ml/decision_tree_struct.py +0 -0
  73. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/ml/gradient_boosting.py +0 -0
  74. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/ml/random_forest.py +0 -0
  75. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/ml/regression_tree.py +0 -0
  76. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/__init__.py +0 -0
  77. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/avgpool2d.py +0 -0
  78. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/conv1d.py +0 -0
  79. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/conv2d.py +0 -0
  80. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/linear.py +0 -0
  81. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/mpool2d.py +0 -0
  82. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/nn/torch_sequential.py +0 -0
  83. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/piecewise.py +0 -0
  84. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/shape.py +0 -0
  85. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/formulations/utils.py +0 -0
  86. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/log_power.py +0 -0
  87. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/probability.py +0 -0
  88. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/math/trigonometric.py +0 -0
  89. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/py.typed +0 -0
  90. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy/version.py +0 -0
  91. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy.egg-info/SOURCES.txt +0 -0
  92. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy.egg-info/dependency_links.txt +0 -0
  93. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy.egg-info/entry_points.txt +0 -0
  94. {gamspy-1.17.0 → gamspy-1.17.1}/src/gamspy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gamspy
3
- Version: 1.17.0
3
+ Version: 1.17.1
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,9 @@ 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[transfer]<52.0.0,>=51.1.0
34
+ Requires-Dist: gamsapi<52.0.0,>=51.1.0
35
35
  Requires-Dist: gamspy_base<52.0.0,>=51.1.0
36
+ Requires-Dist: pandas<2.4,>=2.2.2
36
37
  Requires-Dist: pydantic>=2.0
37
38
  Requires-Dist: requests>=2.28.0
38
39
  Requires-Dist: typer>=0.16.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gamspy"
7
- version = "1.17.0"
7
+ version = "1.17.1"
8
8
  authors = [
9
9
  { name = "GAMS Development Corporation", email = "support@gams.com" },
10
10
  ]
@@ -36,8 +36,9 @@ classifiers = [
36
36
  "Operating System :: Microsoft :: Windows",
37
37
  ]
38
38
  dependencies = [
39
- "gamsapi[transfer] >= 51.1.0, < 52.0.0",
39
+ "gamsapi >= 51.1.0, < 52.0.0",
40
40
  "gamspy_base >= 51.1.0, < 52.0.0",
41
+ "pandas >= 2.2.2, < 2.4",
41
42
  "pydantic >= 2.0",
42
43
  "requests >= 2.28.0",
43
44
  "typer >= 0.16.0",
@@ -222,7 +223,8 @@ target-version = "py310"
222
223
 
223
224
  [tool.ruff.lint]
224
225
  select = [
225
- "E", # pycodestyle
226
+ "E", # pycodestyle error
227
+ "W", # pycodestyle warning
226
228
  "F", # Pyflakes
227
229
  "UP", # pyupgrade
228
230
  "B", # flake8-bugbear
@@ -231,6 +233,8 @@ select = [
231
233
  "PIE", # flake8-pie
232
234
  "PLR1714", # Consider merging multiple comparisons
233
235
  "RUF", # Ruff-specific rules
236
+ "TC", # flake8-type-checking
237
+ "C4", # flake8-comprehensions
234
238
  ]
235
239
  ignore = ["E203", "E501", "E701", "E741", "E743", "W605", "SIM105", "SIM115", "B028", "B006", "RUF005", "RUF022"]
236
240
 
@@ -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
 
@@ -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.",
@@ -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.",
@@ -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.",
@@ -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:
@@ -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:
@@ -1347,7 +1349,7 @@ class Container(gt.Container):
1347
1349
  Variable | Sequence[Variable],
1348
1350
  ]
1349
1351
  | None = None,
1350
- limited_variables: Sequence[Variable] | None = None,
1352
+ limited_variables: Sequence[ImplicitVariable] | None = None,
1351
1353
  external_module: str | None = None,
1352
1354
  ) -> Model:
1353
1355
  """
@@ -1370,7 +1372,7 @@ class Container(gt.Container):
1370
1372
  Objective variable to minimize or maximize or objective itself.
1371
1373
  matches : dict[Equation | Sequence[Equation], Variable | Sequence[Variable]], optional
1372
1374
  Equation - Variable matches for MCP models.
1373
- limited_variables : Sequence, optional
1375
+ limited_variables : Sequence[ImplicitVariable], optional
1374
1376
  Allows limiting the domain of variables used in a model.
1375
1377
  external_module: str, optional
1376
1378
  The name of the external module in which the external equations are implemented
@@ -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
@@ -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
 
@@ -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
@@ -1,13 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- import io
5
4
  import logging
6
5
  import os
7
6
  import threading
8
7
  import warnings
9
8
  from collections.abc import Sequence
10
9
  from enum import Enum
10
+ from pathlib import Path
11
11
  from typing import TYPE_CHECKING, Any, ClassVar
12
12
 
13
13
  from gams.core.gdx import GMS_UEL_IDENT_SIZE
@@ -37,6 +37,7 @@ from gamspy._options import (
37
37
  from gamspy.exceptions import GamspyException, ValidationError
38
38
 
39
39
  if TYPE_CHECKING:
40
+ import io
40
41
  from typing import Literal
41
42
 
42
43
  import pandas as pd
@@ -141,18 +142,43 @@ class SolveStatus(Enum):
141
142
  """An enumeration for solve status types"""
142
143
 
143
144
  NormalCompletion = 1
145
+ """The solver terminated in a normal way."""
146
+
144
147
  IterationInterrupt = 2
148
+ """The solver was interrupted because it used too many iterations. The option `iteration_limit` may be used to increase the iteration limit if everything seems normal."""
149
+
145
150
  ResourceInterrupt = 3
151
+ """The solver was interrupted because it used too much time. The option `time_limit` may be used to increase the time limit if everything seems normal."""
152
+
146
153
  TerminatedBySolver = 4
154
+ """The solver encountered some difficulty and was unable to continue."""
155
+
147
156
  EvaluationInterrupt = 5
157
+ """Too many evaluations of nonlinear terms at undefined values. We recommend to use variable bounds to prevent forbidden operations, such as division by zero. The rows in which the errors occur are listed just before the solution."""
158
+
148
159
  CapabilityError = 6
160
+ """The solver does not have the capability required by the model. For example, some solvers do not support certain types of discrete variables or support a more limited set of functions than other solvers."""
161
+
149
162
  LicenseError = 7
163
+ """The solver cannot find the appropriate license key needed to use a specific subsolver."""
164
+
150
165
  UserInterrupt = 8
166
+ """The user has sent a signal to interrupt the solver."""
167
+
151
168
  SetupError = 9
169
+ """The solver encountered a fatal failure during problem set-up time."""
170
+
152
171
  SolverError = 10
172
+ """The solver encountered a fatal error."""
173
+
153
174
  InternalError = 11
175
+ """The solver encountered an internal fatal error."""
176
+
154
177
  Skipped = 12
178
+ """The entire solve step has been skipped."""
179
+
155
180
  SystemError = 13
181
+ """This indicates a completely unknown or unexpected error condition."""
156
182
 
157
183
 
158
184
  class FileFormat(Enum):
@@ -394,7 +420,7 @@ class Model:
394
420
 
395
421
  # matches
396
422
  if self._matches is not None:
397
- matches: dict = dict()
423
+ matches: dict = {}
398
424
  for key, value in self._matches.items():
399
425
  if isinstance(key, gp.Equation):
400
426
  if isinstance(value, gp.Variable):
@@ -924,19 +950,19 @@ class Model:
924
950
  return assignment
925
951
 
926
952
  def _generate_solve_string(self) -> str:
927
- solve_string = f"solve {self.name} using {self.problem}"
953
+ solve_statement = [f"solve {self.name} using {self.problem}"]
928
954
 
929
955
  if self.sense == gp.Sense.FEASIBILITY:
930
956
  # Set sense as min or max for feasibility
931
957
  self.sense = gp.Sense("MIN")
932
958
 
933
959
  if self.problem not in (Problem.MCP, Problem.CNS, Problem.EMP):
934
- solve_string += f" {self.sense}"
960
+ solve_statement.append(str(self.sense))
935
961
 
936
962
  if self._objective_variable is not None:
937
- solve_string += f" {self._objective_variable.gamsRepr()}"
963
+ solve_statement.append(self._objective_variable.gamsRepr())
938
964
 
939
- return solve_string
965
+ return " ".join(solve_statement)
940
966
 
941
967
  def _add_runtime_options(self, options: Options, backend: str = "local") -> None:
942
968
  for key, value in options.model_dump(exclude_none=True).items():
@@ -1058,7 +1084,7 @@ class Model:
1058
1084
 
1059
1085
  def convert(
1060
1086
  self,
1061
- path: str,
1087
+ path: str | Path,
1062
1088
  file_format: FileFormat | Sequence[FileFormat],
1063
1089
  options: ConvertOptions | None = None,
1064
1090
  ) -> None:
@@ -1067,7 +1093,7 @@ class Model:
1067
1093
 
1068
1094
  Parameters
1069
1095
  ----------
1070
- path : str
1096
+ path : str | Path
1071
1097
  Path to the directory where the converted model files will be saved.
1072
1098
  file_format : FileFormat | Sequence[FileFormat]
1073
1099
  File format(s) to convert the model to. Can be a single FileFormat or a list of FileFormats.
@@ -1090,6 +1116,7 @@ class Model:
1090
1116
  >>> my_model.convert("output_directory", [gp.FileFormat.GAMS, gp.FileFormat.AMPL])
1091
1117
 
1092
1118
  """
1119
+ path = Path(path)
1093
1120
  os.makedirs(path, exist_ok=True)
1094
1121
  solver_options = get_convert_solver_options(path, file_format, options)
1095
1122
  self.solve(solver="convert", solver_options=solver_options)
@@ -1358,7 +1385,7 @@ class Model:
1358
1385
  if isinstance(key, gp.Equation):
1359
1386
  equations_in_matches.append(key)
1360
1387
  else:
1361
- equations_in_matches += [equation for equation in key]
1388
+ equations_in_matches += list(key)
1362
1389
 
1363
1390
  equations = []
1364
1391
  for equation in self.equations:
@@ -1413,7 +1440,7 @@ class Model:
1413
1440
 
1414
1441
  def toGams(
1415
1442
  self,
1416
- path: str,
1443
+ path: str | Path,
1417
1444
  options: Options | None = None,
1418
1445
  *,
1419
1446
  dump_gams_state: bool = False,
@@ -1423,7 +1450,7 @@ class Model:
1423
1450
 
1424
1451
  Parameters
1425
1452
  ----------
1426
- path : str
1453
+ path : str | Path
1427
1454
  Path to the directory which will contain the GAMS model.
1428
1455
  options : Options | None, optional
1429
1456
  GAMSPy options, by default None
@@ -1440,18 +1467,20 @@ class Model:
1440
1467
  f"`options` must be of type gp.Options of found {type(options)}"
1441
1468
  )
1442
1469
 
1470
+ path = Path(path)
1443
1471
  converter = GamsConverter(self, path, options, dump_gams_state)
1444
1472
  converter.convert()
1445
1473
 
1446
- def toLatex(self, path: str, generate_pdf: bool = False) -> None:
1474
+ def toLatex(self, path: str | Path, generate_pdf: bool = False) -> None:
1447
1475
  """
1448
1476
  Generates a latex file that contains the model definition under path/<model_name>.tex
1449
1477
 
1450
1478
  Parameters
1451
1479
  ----------
1452
- path : str
1480
+ path : str | Path
1453
1481
  Path to the directory which will contain the .tex file.
1454
1482
  """
1483
+ path = Path(path)
1455
1484
  converter = LatexConverter(self, path)
1456
1485
  converter.convert()
1457
1486
 
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import io
4
3
  import logging
5
4
  import os
6
5
  import sys
@@ -66,7 +65,6 @@ from gamspy._database import (
66
65
  GamsParameter,
67
66
  GamsVariable,
68
67
  )
69
- from gamspy._options import FreezeOptions, Options
70
68
  from gamspy.exceptions import (
71
69
  GamspyException,
72
70
  ValidationError,
@@ -74,7 +72,10 @@ from gamspy.exceptions import (
74
72
  )
75
73
 
76
74
  if TYPE_CHECKING:
75
+ import io
76
+
77
77
  from gamspy import Container, Model, Parameter
78
+ from gamspy._options import FreezeOptions, Options
78
79
  from gamspy._symbols.implicits import ImplicitParameter
79
80
 
80
81
  logger = logging.getLogger("FROZEN MODEL")