gamspy 1.17.1__tar.gz → 1.17.2__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.
- {gamspy-1.17.1 → gamspy-1.17.2}/PKG-INFO +1 -1
- {gamspy-1.17.1 → gamspy-1.17.2}/pyproject.toml +1 -1
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_container.py +18 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_model.py +104 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/equation.py +7 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/variable.py +17 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_validation.py +0 -5
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/__init__.py +2 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/torch_sequential.py +80 -8
- gamspy-1.17.2/src/gamspy/formulations/result.py +119 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/__init__.py +2 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/activation.py +132 -6
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/utils.py +2 -1
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy.egg-info/PKG-INFO +1 -1
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy.egg-info/SOURCES.txt +1 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/tests/test_gamspy.py +1 -1
- {gamspy-1.17.1 → gamspy-1.17.2}/LICENSE +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/README.md +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/README_PYPI.md +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/setup.cfg +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/__main__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/condition.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/domain.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/expression.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/number.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/operable.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_algebra/operation.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_backend/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_backend/backend.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_backend/engine.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_backend/local.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_backend/neos.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/cli.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/gdx.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/install.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/list.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/probe.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/retrieve.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/run.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/show.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/uninstall.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_cli/util.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_config.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_convert.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_database.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_extrinsic.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_miro.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_model_instance.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_options.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_serialization.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/alias.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/implicits/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/implicits/implicit_equation.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/implicits/implicit_parameter.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/implicits/implicit_set.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/implicits/implicit_symbol.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/implicits/implicit_variable.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/parameter.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/set.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/symbol.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_symbols/universe_alias.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_types.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/_workspace.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/exceptions.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/ml/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/ml/decision_tree_struct.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/ml/gradient_boosting.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/ml/random_forest.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/ml/regression_tree.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/__init__.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/avgpool2d.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/conv1d.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/conv2d.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/linear.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/maxpool2d.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/minpool2d.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/nn/mpool2d.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/piecewise.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/shape.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/formulations/utils.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/log_power.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/matrix.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/misc.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/probability.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/math/trigonometric.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/py.typed +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy/version.py +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy.egg-info/dependency_links.txt +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy.egg-info/entry_points.txt +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy.egg-info/requires.txt +0 -0
- {gamspy-1.17.1 → gamspy-1.17.2}/src/gamspy.egg-info/top_level.txt +0 -0
|
@@ -1064,6 +1064,9 @@ class Container(gt.Container):
|
|
|
1064
1064
|
>>> a = m.addAlias("a", i)
|
|
1065
1065
|
|
|
1066
1066
|
"""
|
|
1067
|
+
if name is None:
|
|
1068
|
+
name = self._get_symbol_name(prefix="a")
|
|
1069
|
+
|
|
1067
1070
|
return gp.Alias(self, name, alias_with)
|
|
1068
1071
|
|
|
1069
1072
|
def addSet(
|
|
@@ -1121,6 +1124,9 @@ class Container(gt.Container):
|
|
|
1121
1124
|
>>> i = m.addSet("i")
|
|
1122
1125
|
|
|
1123
1126
|
"""
|
|
1127
|
+
if name is None:
|
|
1128
|
+
name = self._get_symbol_name(prefix="s")
|
|
1129
|
+
|
|
1124
1130
|
return gp.Set(
|
|
1125
1131
|
self,
|
|
1126
1132
|
name,
|
|
@@ -1189,6 +1195,9 @@ class Container(gt.Container):
|
|
|
1189
1195
|
>>> a = m.addParameter("a")
|
|
1190
1196
|
|
|
1191
1197
|
"""
|
|
1198
|
+
if name is None:
|
|
1199
|
+
name = self._get_symbol_name(prefix="p")
|
|
1200
|
+
|
|
1192
1201
|
return gp.Parameter(
|
|
1193
1202
|
self,
|
|
1194
1203
|
name,
|
|
@@ -1252,6 +1261,9 @@ class Container(gt.Container):
|
|
|
1252
1261
|
>>> v = m.addVariable("v")
|
|
1253
1262
|
|
|
1254
1263
|
"""
|
|
1264
|
+
if name is None:
|
|
1265
|
+
name = self._get_symbol_name(prefix="v")
|
|
1266
|
+
|
|
1255
1267
|
return gp.Variable(
|
|
1256
1268
|
self,
|
|
1257
1269
|
name,
|
|
@@ -1322,6 +1334,9 @@ class Container(gt.Container):
|
|
|
1322
1334
|
>>> i = m.addEquation("i")
|
|
1323
1335
|
|
|
1324
1336
|
"""
|
|
1337
|
+
if name is None:
|
|
1338
|
+
name = self._get_symbol_name(prefix="e")
|
|
1339
|
+
|
|
1325
1340
|
return gp.Equation(
|
|
1326
1341
|
self,
|
|
1327
1342
|
name,
|
|
@@ -1389,6 +1404,9 @@ class Container(gt.Container):
|
|
|
1389
1404
|
>>> model = m.addModel("my_model", "LP", [e])
|
|
1390
1405
|
|
|
1391
1406
|
"""
|
|
1407
|
+
if name is None:
|
|
1408
|
+
name = self._get_symbol_name(prefix="m")
|
|
1409
|
+
|
|
1392
1410
|
return gp.Model(
|
|
1393
1411
|
self,
|
|
1394
1412
|
name,
|
|
@@ -73,21 +73,52 @@ class Problem(Enum):
|
|
|
73
73
|
"""An enumeration for problem all problem types"""
|
|
74
74
|
|
|
75
75
|
LP = "LP"
|
|
76
|
+
"Linear Programming"
|
|
77
|
+
|
|
76
78
|
NLP = "NLP"
|
|
79
|
+
"""Non-Linear Programming"""
|
|
80
|
+
|
|
77
81
|
QCP = "QCP"
|
|
82
|
+
"""Quadratically Constrained Programs"""
|
|
83
|
+
|
|
78
84
|
DNLP = "DNLP"
|
|
85
|
+
"""Nonlinear Programming with Discontinuous Derivatives"""
|
|
86
|
+
|
|
79
87
|
MIP = "MIP"
|
|
88
|
+
"""Mixed Integer Programming"""
|
|
89
|
+
|
|
80
90
|
RMIP = "RMIP"
|
|
91
|
+
"""Relaxed Mixed Integer Program"""
|
|
92
|
+
|
|
81
93
|
MINLP = "MINLP"
|
|
94
|
+
"""Mixed Integer Nonlinear Program"""
|
|
95
|
+
|
|
82
96
|
RMINLP = "RMINLP"
|
|
97
|
+
"""Relaxed Mixed Integer Nonlinear Program"""
|
|
98
|
+
|
|
83
99
|
MIQCP = "MIQCP"
|
|
100
|
+
"""Mixed Integer Quadratically Constrained Program"""
|
|
101
|
+
|
|
84
102
|
RMIQCP = "RMIQCP"
|
|
103
|
+
"""Relaxed Mixed Integer Quadratically Constrained Program"""
|
|
104
|
+
|
|
85
105
|
MCP = "MCP"
|
|
106
|
+
"""Mixed Complementarity Problem"""
|
|
107
|
+
|
|
86
108
|
CNS = "CNS"
|
|
109
|
+
"""Constrained Nonlinear System"""
|
|
110
|
+
|
|
87
111
|
MPEC = "MPEC"
|
|
112
|
+
"""Mathematical Programs with Equilibrium Constraints"""
|
|
113
|
+
|
|
88
114
|
RMPEC = "RMPEC"
|
|
115
|
+
"""Relaxed Mathematical Program with Equilibrium Constraints"""
|
|
116
|
+
|
|
89
117
|
EMP = "EMP"
|
|
118
|
+
"""Extended Mathematical Program"""
|
|
119
|
+
|
|
90
120
|
MPSGE = "MPSGE"
|
|
121
|
+
"""General Equilibrium"""
|
|
91
122
|
|
|
92
123
|
@classmethod
|
|
93
124
|
def values(cls):
|
|
@@ -102,8 +133,13 @@ class Sense(Enum):
|
|
|
102
133
|
"""An enumeration for sense types"""
|
|
103
134
|
|
|
104
135
|
MIN = "MIN"
|
|
136
|
+
"""Minimize the objective."""
|
|
137
|
+
|
|
105
138
|
MAX = "MAX"
|
|
139
|
+
"""Maximize the objective."""
|
|
140
|
+
|
|
106
141
|
FEASIBILITY = "FEASIBILITY"
|
|
142
|
+
"""Assess feasibility."""
|
|
107
143
|
|
|
108
144
|
@classmethod
|
|
109
145
|
def values(cls):
|
|
@@ -118,24 +154,61 @@ class ModelStatus(Enum):
|
|
|
118
154
|
"""An enumeration for model status types"""
|
|
119
155
|
|
|
120
156
|
OptimalGlobal = 1
|
|
157
|
+
"""The solution is optimal, that is, it is feasible (within tolerances) and it has been proven that no other feasible solution with better objective value exists."""
|
|
158
|
+
|
|
121
159
|
OptimalLocal = 2
|
|
160
|
+
"""A local optimum for an NLP has been found. That is, a solution that is feasible (within tolerances) and it has been proven that there exists a neighborhood of this solution in which no other feasible solution with better objective value exists."""
|
|
161
|
+
|
|
122
162
|
Unbounded = 3
|
|
163
|
+
"""The solution is unbounded. This message is reliable if the problem is linear, but occasionally it appears for difficult nonlinear problems that are not truly unbounded, but that lack some strategically placed bounds to limit the variables to sensible values."""
|
|
164
|
+
|
|
123
165
|
InfeasibleGlobal = 4
|
|
166
|
+
"""The problem has been proven to be infeasible. If this was not intended, something is probably misspecified in the logic or the data."""
|
|
167
|
+
|
|
124
168
|
InfeasibleLocal = 5
|
|
169
|
+
"""No feasible point could be found for the NLP problem from the given starting point. It does not necessarily mean that no feasible point exists."""
|
|
170
|
+
|
|
125
171
|
InfeasibleIntermed = 6
|
|
172
|
+
"""The current solution is not feasible, but the solver stopped, either because of a limit (for example, iteration or resource) or because of some sort of difficulty. The solver status will give more information."""
|
|
173
|
+
|
|
126
174
|
Feasible = 7
|
|
175
|
+
"""A feasible solution to a problem without discrete variables has been found."""
|
|
176
|
+
|
|
127
177
|
Integer = 8
|
|
178
|
+
"""A feasible solution to a problem with discrete variables has been found."""
|
|
179
|
+
|
|
128
180
|
NonIntegerIntermed = 9
|
|
181
|
+
"""An incomplete solution to a problem with discrete variables. A feasible solution has not yet been found."""
|
|
182
|
+
|
|
129
183
|
IntegerInfeasible = 10
|
|
184
|
+
"""It has been proven that there is no feasible solution to a problem with discrete variables."""
|
|
185
|
+
|
|
130
186
|
LicenseError = 11
|
|
187
|
+
"""The solver cannot find the appropriate license key needed to use a specific subsolver."""
|
|
188
|
+
|
|
131
189
|
ErrorUnknown = 12
|
|
190
|
+
"""After a solver error the model status is unknown."""
|
|
191
|
+
|
|
132
192
|
ErrorNoSolution = 13
|
|
193
|
+
"""An error occurred and no solution has been returned. No solution will be returned to GAMS because of errors in the solution process."""
|
|
194
|
+
|
|
133
195
|
NoSolutionReturned = 14
|
|
196
|
+
"""A solution is not expected for this solve. For example, the CONVERT solver only reformats the model but does not give a solution."""
|
|
197
|
+
|
|
134
198
|
SolvedUnique = 15
|
|
199
|
+
"""Indicates the solution returned is unique, i.e. no other solution exists. Used for CNS models. Examples where this status could be returned include non-singular linear models, triangular models with constant non-zero elements on the diagonal, and triangular models where the functions are monotone in the variable on the diagonal."""
|
|
200
|
+
|
|
135
201
|
Solved = 16
|
|
202
|
+
"""Indicates the model has been solved: used for CNS models. The solution might or might not be unique. If the solver uses status SOLVED SINGULAR wherever possible then this status implies that the Jacobian is non-singular, i.e. that the solution is at least locally unique."""
|
|
203
|
+
|
|
136
204
|
SolvedSingular = 17
|
|
205
|
+
"""Indicates the CNS model has been solved, but the Jacobian is singular at the solution. This can indicate that other solutions exist, either along a line (for linear models) or a curve (for nonlinear models) including the solution returned."""
|
|
206
|
+
|
|
137
207
|
UnboundedNoSolution = 18
|
|
208
|
+
"""The model is unbounded and no solution can be provided."""
|
|
209
|
+
|
|
138
210
|
InfeasibleNoSolution = 19
|
|
211
|
+
"""The model is infeasible and no solution can be provided."""
|
|
139
212
|
|
|
140
213
|
|
|
141
214
|
class SolveStatus(Enum):
|
|
@@ -185,21 +258,52 @@ class FileFormat(Enum):
|
|
|
185
258
|
"""An enumeration for file format types"""
|
|
186
259
|
|
|
187
260
|
AMPL = "ampl.mod"
|
|
261
|
+
"""AMPL input format."""
|
|
262
|
+
|
|
188
263
|
AMPLNL = "ampl.nl"
|
|
264
|
+
"""AMPL nl format."""
|
|
265
|
+
|
|
189
266
|
CPLEXLP = "cplex.lp"
|
|
267
|
+
"""CPLEX LP format."""
|
|
268
|
+
|
|
190
269
|
CPLEXMPS = "cplex.mps"
|
|
270
|
+
"""CPLEX MPS format."""
|
|
271
|
+
|
|
191
272
|
GAMSDict = "dict.txt"
|
|
273
|
+
"""GAMS dictionary format."""
|
|
274
|
+
|
|
192
275
|
GAMSDictMap = "dictmap.gdx"
|
|
276
|
+
"""GAMS dictionary map format."""
|
|
277
|
+
|
|
193
278
|
GAMSJacobian = "jacobian.gms"
|
|
279
|
+
"""Jacobian in GAMS."""
|
|
280
|
+
|
|
194
281
|
GAMSPyJacobian = "jacobian.py"
|
|
282
|
+
"""Jacobian in GAMSPy."""
|
|
283
|
+
|
|
195
284
|
GDXJacobian = "jacobian.gdx"
|
|
285
|
+
"""GDX file with model data incl. Jacobian and Hessian evaluated at current point."""
|
|
286
|
+
|
|
196
287
|
FileList = "files.txt"
|
|
288
|
+
"""List of file formats generated."""
|
|
289
|
+
|
|
197
290
|
FixedMPS = "fixed.mps"
|
|
291
|
+
"""Fixed format mps file."""
|
|
292
|
+
|
|
198
293
|
GAMS = "gams.gms"
|
|
294
|
+
"""GAMS scalar model."""
|
|
295
|
+
|
|
199
296
|
JuMP = "jump.jl"
|
|
297
|
+
"""JuMP scalar model."""
|
|
298
|
+
|
|
200
299
|
LINGO = "lingo.lng"
|
|
300
|
+
"""Lingo format."""
|
|
301
|
+
|
|
201
302
|
OSiL = "osil.xml"
|
|
303
|
+
"""Optimization Services instance Language (OSiL) format."""
|
|
304
|
+
|
|
202
305
|
Pyomo = "pyomo.py"
|
|
306
|
+
"""Pyomo concrete scalar model."""
|
|
203
307
|
|
|
204
308
|
|
|
205
309
|
INTERRUPT_STATUS = [
|
|
@@ -45,9 +45,16 @@ IRREGULAR_EQ_MAP = {
|
|
|
45
45
|
|
|
46
46
|
class EquationType(Enum):
|
|
47
47
|
REGULAR = "regular"
|
|
48
|
+
"""Regular equations with =, >= and <= sign."""
|
|
49
|
+
|
|
48
50
|
NONBINDING = "nonbinding"
|
|
51
|
+
"""No relationship implied between left-hand side and right-hand side. This equation type is ideally suited for use in MCP models and in variational inequalities."""
|
|
52
|
+
|
|
49
53
|
EXTERNAL = "external"
|
|
54
|
+
"""Equation is defined by external programs."""
|
|
55
|
+
|
|
50
56
|
BOOLEAN = "boolean"
|
|
57
|
+
"""Boolean equations."""
|
|
51
58
|
|
|
52
59
|
@classmethod
|
|
53
60
|
def values(cls):
|
|
@@ -35,14 +35,31 @@ if TYPE_CHECKING:
|
|
|
35
35
|
|
|
36
36
|
class VariableType(Enum):
|
|
37
37
|
BINARY = "binary"
|
|
38
|
+
"""Discrete variable that can only take values of 0 or 1."""
|
|
39
|
+
|
|
38
40
|
INTEGER = "integer"
|
|
41
|
+
"""Discrete variable that can only take integer values between the bounds."""
|
|
42
|
+
|
|
39
43
|
POSITIVE = "positive"
|
|
44
|
+
"""No negative values are allowed for variable. The user may change both bounds from the default value."""
|
|
45
|
+
|
|
40
46
|
NEGATIVE = "negative"
|
|
47
|
+
"""No positive values are allowed for variables. The user may change both bounds from the default value."""
|
|
48
|
+
|
|
41
49
|
FREE = "free"
|
|
50
|
+
"""No bounds on variable. Both bounds may be changed from the default values by the user."""
|
|
51
|
+
|
|
42
52
|
SOS1 = "sos1"
|
|
53
|
+
"""A set of variables, such that at most one variable within a group may have a non-zero value."""
|
|
54
|
+
|
|
43
55
|
SOS2 = "sos2"
|
|
56
|
+
"""A set of variables, such that at most two variables within a group may have non-zero values and the two non-zero values are adjacent."""
|
|
57
|
+
|
|
44
58
|
SEMICONT = "semicont"
|
|
59
|
+
"""Semi-continuous, must be zero or above a given minimum level."""
|
|
60
|
+
|
|
45
61
|
SEMIINT = "semiint"
|
|
62
|
+
"""Semi-integer, must be zero or above a given minimum level and integer."""
|
|
46
63
|
|
|
47
64
|
@classmethod
|
|
48
65
|
def values(cls):
|
|
@@ -385,11 +385,6 @@ def validate_name(word: str) -> str:
|
|
|
385
385
|
f" words: {RESERVED_WORDS}"
|
|
386
386
|
)
|
|
387
387
|
|
|
388
|
-
if word.endswith("gpauto"):
|
|
389
|
-
raise ValidationError(
|
|
390
|
-
"Name cannot end with one of the reserved words. `gpauto` is a reserverd word."
|
|
391
|
-
)
|
|
392
|
-
|
|
393
388
|
if not re.match(NAME_MATCH_REGEX, word):
|
|
394
389
|
raise ValidationError(
|
|
395
390
|
f"`{word}` is an invalid GAMSPy symbol name. "
|
|
@@ -20,6 +20,7 @@ from gamspy.formulations.piecewise import (
|
|
|
20
20
|
pwl_convexity_formulation,
|
|
21
21
|
pwl_interval_formulation,
|
|
22
22
|
)
|
|
23
|
+
from gamspy.formulations.result import FormulationResult
|
|
23
24
|
from gamspy.formulations.shape import flatten_dims
|
|
24
25
|
|
|
25
26
|
__all__ = [
|
|
@@ -41,4 +42,5 @@ __all__ = [
|
|
|
41
42
|
"pwl_convexity_formulation",
|
|
42
43
|
"pwl_interval_formulation",
|
|
43
44
|
"utils",
|
|
45
|
+
"FormulationResult",
|
|
44
46
|
]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import typing
|
|
3
4
|
from functools import partial
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
6
|
|
|
@@ -196,11 +197,82 @@ class TorchSequential:
|
|
|
196
197
|
l = self._layer_converters[clz](container, layer)
|
|
197
198
|
return l
|
|
198
199
|
|
|
199
|
-
def
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
for
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
200
|
+
def _update_dict_layered(
|
|
201
|
+
self, large: dict[str, typing.Any], small: dict[str, typing.Any], layer_num: int
|
|
202
|
+
):
|
|
203
|
+
for key in small:
|
|
204
|
+
large[f"{layer_num}.{key}"] = small[key]
|
|
205
|
+
|
|
206
|
+
def __call__(self, input: gp.Variable) -> gp.formulations.FormulationResult:
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
This method returns a **`FormulationResult`** object, which includes symbols
|
|
210
|
+
and outputs created by its underlying layers.
|
|
211
|
+
|
|
212
|
+
The way to access these underlying symbols depends on what the sub-layer
|
|
213
|
+
returns:
|
|
214
|
+
|
|
215
|
+
1. **If a Sub-Layer Returns a `FormulationResult`**
|
|
216
|
+
|
|
217
|
+
All symbols created by that sub-layer can be accessed within the main
|
|
218
|
+
`FormulationResult`. Each symbol's name is **prefixed** with its layer
|
|
219
|
+
number, followed by a dot (`.`).
|
|
220
|
+
|
|
221
|
+
* **Access Format:** `<layer_num>.<symbol_name>`
|
|
222
|
+
* **Example:** If the first layer creates a parameter named `bias`, it is accessed as `0.bias` in `parameters_created`.
|
|
223
|
+
|
|
224
|
+
2. **If a Sub-Layer Returns the "Old Style" Output (Output Variable and List of Equations)**
|
|
225
|
+
|
|
226
|
+
For backward compatibility, if a sub-layer returns an output variable and
|
|
227
|
+
a list of equations instead of a `FormulationResult`, they are accessed
|
|
228
|
+
as follows:
|
|
229
|
+
|
|
230
|
+
* **Output Variable:** The main output variable is named:
|
|
231
|
+
* **Access Format:** `<layer_num>.output`
|
|
232
|
+
* **Equations:** Each returned equation is sequentially named:
|
|
233
|
+
* **Access Format:** `<layer_num>.eq_<eq_number>` (where `eq_number` starts at 0, 1, 2...)
|
|
234
|
+
* **Example:** The first equation from the third layer is accessed as `2.eq_0` in `equations_created`.
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
FormulationResult
|
|
240
|
+
|
|
241
|
+
"""
|
|
242
|
+
result = gp.formulations.FormulationResult()
|
|
243
|
+
|
|
244
|
+
out: gp.Variable | gp.Parameter | None = input
|
|
245
|
+
for layer_num, layer in enumerate(self.layers):
|
|
246
|
+
output = layer(out)
|
|
247
|
+
if isinstance(output, gp.formulations.FormulationResult):
|
|
248
|
+
self._update_dict_layered(
|
|
249
|
+
result.equations_created, output.equations_created, layer_num
|
|
250
|
+
)
|
|
251
|
+
self._update_dict_layered(
|
|
252
|
+
result.variables_created, output.variables_created, layer_num
|
|
253
|
+
)
|
|
254
|
+
self._update_dict_layered(
|
|
255
|
+
result.sets_created, output.sets_created, layer_num
|
|
256
|
+
)
|
|
257
|
+
self._update_dict_layered(
|
|
258
|
+
result.parameters_created, output.parameters_created, layer_num
|
|
259
|
+
)
|
|
260
|
+
self._update_dict_layered(result.other, output.other, layer_num)
|
|
261
|
+
|
|
262
|
+
# matches are not named
|
|
263
|
+
result.matches.update(output.matches)
|
|
264
|
+
out = output.result
|
|
265
|
+
else:
|
|
266
|
+
# old interface only provides output var and list of equations
|
|
267
|
+
out, layer_eqs = output
|
|
268
|
+
result.variables_created[f"{layer_num}.output"] = out
|
|
269
|
+
for eq_num, eq in enumerate(layer_eqs):
|
|
270
|
+
result.equations_created[f"{layer_num}.eq_{eq_num}"] = eq
|
|
271
|
+
|
|
272
|
+
result.result = out
|
|
273
|
+
|
|
274
|
+
# to prevent forgetting matches when unpacking
|
|
275
|
+
if result.matches:
|
|
276
|
+
result.extra_return = result.matches
|
|
277
|
+
|
|
278
|
+
return result
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, TypeAlias
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
|
|
8
|
+
import gamspy as gp
|
|
9
|
+
|
|
10
|
+
MatchesType: TypeAlias = dict[
|
|
11
|
+
gp.Equation | Sequence[gp.Equation],
|
|
12
|
+
gp.Variable | Sequence[gp.Variable],
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FormulationResult:
|
|
17
|
+
"""
|
|
18
|
+
FormulationResult class provides a common interface for returning results
|
|
19
|
+
when formulations are called. In the old convention, formulations returned
|
|
20
|
+
a tuple of result variable and list of equations. In some cases it was
|
|
21
|
+
possible to get extra output from the formulation. To provide backwards
|
|
22
|
+
compatibility, FormulationResult class can be unpacked into a result
|
|
23
|
+
variable and list of equations. Also it supports returning extra output in
|
|
24
|
+
unpacking.
|
|
25
|
+
|
|
26
|
+
With the FormulationResult you can have more access to underlying symbols
|
|
27
|
+
created such as equations, variables, parameters and sets. Since many
|
|
28
|
+
formulations created symbols with randomized names, it was tedious to find
|
|
29
|
+
intermediate symbols created. FormulationResult has dictionaries where keys
|
|
30
|
+
are expected to be documented in the formulation returning the
|
|
31
|
+
FormulationResult therefore you can access a symbol via its known key.
|
|
32
|
+
|
|
33
|
+
For example:
|
|
34
|
+
|
|
35
|
+
Examples
|
|
36
|
+
--------
|
|
37
|
+
>>> import gamspy as gp
|
|
38
|
+
>>> m = gp.Container()
|
|
39
|
+
>>> x = gp.Variable(m)
|
|
40
|
+
>>> res = gp.math.activation.relu_with_binary_var(x)
|
|
41
|
+
>>> aux_binary_var = res.variables_created["binary"]
|
|
42
|
+
|
|
43
|
+
Therefore, it is important for the formulation returning a
|
|
44
|
+
FormulationResult to properly list the keys to the symbols that are
|
|
45
|
+
created.
|
|
46
|
+
|
|
47
|
+
FormulationResult has the following attributes that might be useful:
|
|
48
|
+
- `result`
|
|
49
|
+
- `equations_created`
|
|
50
|
+
- `sets_created`
|
|
51
|
+
- `parameters_created`
|
|
52
|
+
- `matches`
|
|
53
|
+
- `other`
|
|
54
|
+
- `extra_return`
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
result: gp.Variable | gp.Parameter | None = None,
|
|
61
|
+
equations_created: dict[str, gp.Equation] | None = None,
|
|
62
|
+
extra_return: gp.Variable | MatchesType | None = None,
|
|
63
|
+
) -> None:
|
|
64
|
+
self.result = result
|
|
65
|
+
self.equations_created: dict[str, gp.Equation] = (
|
|
66
|
+
equations_created if equations_created is not None else {}
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
self.variables_created: dict[str, gp.Variable] = {}
|
|
70
|
+
self.sets_created: dict[str, gp.Set] = {}
|
|
71
|
+
self.parameters_created: dict[str, gp.Parameter] = {}
|
|
72
|
+
self.matches: MatchesType = {}
|
|
73
|
+
self.other: dict[str, Any] = {}
|
|
74
|
+
|
|
75
|
+
# Extra return is only here for backwards compat reasons
|
|
76
|
+
# try to use other when you can
|
|
77
|
+
self.extra_return = extra_return
|
|
78
|
+
|
|
79
|
+
def __len__(self):
|
|
80
|
+
# For backwards compat
|
|
81
|
+
return 2 + (self.extra_return is not None)
|
|
82
|
+
|
|
83
|
+
def __iter__(self):
|
|
84
|
+
# For backwards compat
|
|
85
|
+
if self.extra_return is None:
|
|
86
|
+
return [
|
|
87
|
+
self.result,
|
|
88
|
+
list(self.equations_created.values()),
|
|
89
|
+
].__iter__()
|
|
90
|
+
|
|
91
|
+
return [
|
|
92
|
+
self.result,
|
|
93
|
+
self.extra_return,
|
|
94
|
+
list(self.equations_created.values()),
|
|
95
|
+
].__iter__()
|
|
96
|
+
|
|
97
|
+
def __str__(self) -> str:
|
|
98
|
+
return (
|
|
99
|
+
"FormulationResult(\n"
|
|
100
|
+
+ " Equations: "
|
|
101
|
+
+ str(self.equations_created.keys())
|
|
102
|
+
+ "\n"
|
|
103
|
+
+ " Variables: "
|
|
104
|
+
+ str(self.variables_created.keys())
|
|
105
|
+
+ "\n"
|
|
106
|
+
+ " Sets: "
|
|
107
|
+
+ str(self.sets_created.keys())
|
|
108
|
+
+ "\n"
|
|
109
|
+
+ " Parameters: "
|
|
110
|
+
+ str(self.parameters_created.keys())
|
|
111
|
+
+ "\n"
|
|
112
|
+
+ " Num Matches: "
|
|
113
|
+
+ str(len(self.matches))
|
|
114
|
+
+ "\n"
|
|
115
|
+
+ " Other: "
|
|
116
|
+
+ str(self.other)
|
|
117
|
+
+ "\n"
|
|
118
|
+
+ ")"
|
|
119
|
+
)
|
|
@@ -5,6 +5,7 @@ from gamspy.math.activation import (
|
|
|
5
5
|
log_softmax,
|
|
6
6
|
relu_with_binary_var,
|
|
7
7
|
relu_with_complementarity_var,
|
|
8
|
+
relu_with_equilibrium,
|
|
8
9
|
relu_with_sos1_var,
|
|
9
10
|
softmax,
|
|
10
11
|
softplus,
|
|
@@ -184,6 +185,7 @@ __all__ = [
|
|
|
184
185
|
"rel_ne",
|
|
185
186
|
"relu_with_binary_var",
|
|
186
187
|
"relu_with_complementarity_var",
|
|
188
|
+
"relu_with_equilibrium",
|
|
187
189
|
"relu_with_sos1_var",
|
|
188
190
|
"rpower",
|
|
189
191
|
"same_as",
|
|
@@ -5,10 +5,12 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
import gamspy._symbols.implicits as implicits
|
|
6
6
|
import gamspy.math
|
|
7
7
|
import gamspy.utils as utils
|
|
8
|
+
from gamspy._algebra.number import Number
|
|
8
9
|
from gamspy._container import Container
|
|
9
10
|
from gamspy._symbols.equation import Equation
|
|
10
11
|
from gamspy._symbols.variable import Variable
|
|
11
12
|
from gamspy.exceptions import ValidationError
|
|
13
|
+
from gamspy.formulations.result import FormulationResult
|
|
12
14
|
from gamspy.math.matrix import next_alias
|
|
13
15
|
|
|
14
16
|
if TYPE_CHECKING:
|
|
@@ -272,7 +274,7 @@ def relu_with_binary_var(
|
|
|
272
274
|
default_lb: float = -(10**6),
|
|
273
275
|
default_ub: float = 10**6,
|
|
274
276
|
return_binary_var: bool = False,
|
|
275
|
-
):
|
|
277
|
+
) -> FormulationResult:
|
|
276
278
|
"""
|
|
277
279
|
Implements the ReLU activation function using binary variables. The ReLU
|
|
278
280
|
function is defined as ReLU(x) = max(x, 0). This implementation **generates**
|
|
@@ -292,6 +294,10 @@ def relu_with_binary_var(
|
|
|
292
294
|
|
|
293
295
|
Adapted from `OMLT <https://github.com/cog-imperial/OMLT/blob/e60563859a66ac5dd3348bf1763de57eec95171e/src/omlt/neuralnet/activations/relu.py>`_
|
|
294
296
|
|
|
297
|
+
FormulationResult:
|
|
298
|
+
- variables_created: ["output", "binary"]
|
|
299
|
+
- equations_created: ["y_gte_x", "y_lte_x_1", "y_lte_x_2"]
|
|
300
|
+
|
|
295
301
|
Parameters
|
|
296
302
|
----------
|
|
297
303
|
x : Parameter | Variable | implicits.ImplicitParameter | implicits.ImplicitVariable | Expression | Operation
|
|
@@ -301,7 +307,7 @@ def relu_with_binary_var(
|
|
|
301
307
|
|
|
302
308
|
Returns
|
|
303
309
|
-------
|
|
304
|
-
|
|
310
|
+
FormulationResult
|
|
305
311
|
|
|
306
312
|
Examples
|
|
307
313
|
--------
|
|
@@ -310,7 +316,7 @@ def relu_with_binary_var(
|
|
|
310
316
|
>>> m = Container()
|
|
311
317
|
>>> i = Set(m, "i", records=range(3))
|
|
312
318
|
>>> x = Variable(m, "x", domain=[i])
|
|
313
|
-
>>> y, eqs = relu_with_binary_var(x)
|
|
319
|
+
>>> y, eqs = relu_with_binary_var(x) # FormulationResult can be unpacked for backwards compat
|
|
314
320
|
>>> y.type
|
|
315
321
|
'positive'
|
|
316
322
|
>>> len(eqs)
|
|
@@ -322,6 +328,9 @@ def relu_with_binary_var(
|
|
|
322
328
|
[Set(name='i', domain=['*'])]
|
|
323
329
|
>>> b.domain # i many binary variables
|
|
324
330
|
[Set(name='i', domain=['*'])]
|
|
331
|
+
>>> output = relu_with_binary_var(x) # You can use FormulationResult too
|
|
332
|
+
>>> binary_var = output.variables_created["binary"]
|
|
333
|
+
>>> y = output.result
|
|
325
334
|
|
|
326
335
|
"""
|
|
327
336
|
assert isinstance(x.container, Container)
|
|
@@ -359,10 +368,127 @@ def relu_with_binary_var(
|
|
|
359
368
|
eq[2][...] = y <= sigma * default_ub
|
|
360
369
|
y.lo[...] = 0
|
|
361
370
|
|
|
362
|
-
|
|
363
|
-
|
|
371
|
+
result = FormulationResult(
|
|
372
|
+
y,
|
|
373
|
+
{
|
|
374
|
+
"y_gte_x": eq[0],
|
|
375
|
+
"y_lte_x_1": eq[1],
|
|
376
|
+
"y_lte_x_2": eq[2],
|
|
377
|
+
},
|
|
378
|
+
)
|
|
379
|
+
result.variables_created = {"binary": sigma, "output": y}
|
|
380
|
+
result.extra_return = sigma if return_binary_var else None
|
|
381
|
+
return result
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def relu_with_equilibrium(
|
|
385
|
+
x: (
|
|
386
|
+
Parameter
|
|
387
|
+
| Variable
|
|
388
|
+
| implicits.ImplicitParameter
|
|
389
|
+
| implicits.ImplicitVariable
|
|
390
|
+
| Expression
|
|
391
|
+
| Operation
|
|
392
|
+
),
|
|
393
|
+
) -> FormulationResult:
|
|
394
|
+
"""
|
|
395
|
+
Implements the ReLU activation function using Equilibrium Constraints.
|
|
396
|
+
This implementation is suitable for models of type Mathematical Program with
|
|
397
|
+
Equilibrium Constraints (MPEC) or Mixed Complementarity Problem (MCP).
|
|
398
|
+
One positive variable is **generated**, which serves as the activation
|
|
399
|
+
variable and no equations. The activation variable shares the same domain as
|
|
400
|
+
the input. Lower and upper bounds are not required for this formulation.
|
|
401
|
+
|
|
402
|
+
Returns FormulationResult which can be unpacked as activation variable,
|
|
403
|
+
matches dictionary and the equation list (empty).
|
|
404
|
+
|
|
405
|
+
FormulationResult:
|
|
406
|
+
- variables_created: ["output"]
|
|
407
|
+
- equations_created: []
|
|
408
|
+
- matches: {(output - x) : output}
|
|
409
|
+
- extra_return: yes (matches)
|
|
410
|
+
|
|
411
|
+
or if the provided input was not a Variable, this formulation assigns it to a
|
|
412
|
+
new variable and uses the new variable instead
|
|
413
|
+
|
|
414
|
+
FormulationResult:
|
|
415
|
+
- variables_created: ["output", "new_input"]
|
|
416
|
+
- equations_created: ["set_new_input"]
|
|
417
|
+
- matches: {(output - new_input) : output}
|
|
418
|
+
- extra_return: yes (matches)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
Parameters
|
|
422
|
+
----------
|
|
423
|
+
x : Variable
|
|
424
|
+
|
|
425
|
+
Returns
|
|
426
|
+
-------
|
|
427
|
+
FormulationResult
|
|
428
|
+
|
|
429
|
+
Examples
|
|
430
|
+
--------
|
|
431
|
+
>>> from gamspy import Container, Variable, Set
|
|
432
|
+
>>> from gamspy.math.activation import relu_with_equilibrium
|
|
433
|
+
>>> m = Container()
|
|
434
|
+
>>> i = Set(m, "i", records=range(3))
|
|
435
|
+
>>> x = Variable(m, "x", domain=[i])
|
|
436
|
+
>>> y, matches, eqs = relu_with_equilibrium(x)
|
|
437
|
+
>>> y.type
|
|
438
|
+
'positive'
|
|
439
|
+
>>> len(eqs)
|
|
440
|
+
0
|
|
441
|
+
>>> len(matches)
|
|
442
|
+
1
|
|
443
|
+
>>> result = relu_with_equilibrium(x)
|
|
444
|
+
>>> type(result)
|
|
445
|
+
<class 'gamspy.formulations.result.FormulationResult'>
|
|
446
|
+
>>> result = relu_with_equilibrium(x - 5)
|
|
447
|
+
>>> new_input = result.variables_created["new_input"]
|
|
448
|
+
|
|
449
|
+
"""
|
|
450
|
+
assert isinstance(x.container, Container)
|
|
451
|
+
domain = x.domain
|
|
452
|
+
|
|
453
|
+
y = x.container.addVariable(
|
|
454
|
+
type="positive",
|
|
455
|
+
domain=domain,
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
new_input = None
|
|
459
|
+
set_new_input = None
|
|
460
|
+
if not isinstance(x, Variable):
|
|
461
|
+
new_input = Variable._constructor_bypass(
|
|
462
|
+
x.container,
|
|
463
|
+
_get_random_name("new_input"),
|
|
464
|
+
domain=domain,
|
|
465
|
+
)
|
|
466
|
+
set_new_input = Equation._constructor_bypass(
|
|
467
|
+
x.container,
|
|
468
|
+
_get_random_name("set_new_input"),
|
|
469
|
+
domain=domain,
|
|
470
|
+
)
|
|
471
|
+
set_new_input[...] = new_input == x
|
|
364
472
|
else:
|
|
365
|
-
|
|
473
|
+
new_input = x
|
|
474
|
+
|
|
475
|
+
eq = Equation._constructor_bypass(
|
|
476
|
+
x.container,
|
|
477
|
+
_get_random_name("matches_eq"),
|
|
478
|
+
domain=domain,
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
eq[...] = y - new_input >= Number(0)
|
|
482
|
+
|
|
483
|
+
result = FormulationResult(y, {})
|
|
484
|
+
result.variables_created["output"] = y
|
|
485
|
+
if set_new_input is not None:
|
|
486
|
+
result.variables_created["new_input"] = new_input
|
|
487
|
+
result.equations_created["set_new_input"] = set_new_input
|
|
488
|
+
|
|
489
|
+
result.extra_return = {eq: y}
|
|
490
|
+
result.matches = {eq: y}
|
|
491
|
+
return result
|
|
366
492
|
|
|
367
493
|
|
|
368
494
|
def relu_with_complementarity_var(
|
|
@@ -385,7 +385,8 @@ def _get_name_from_stack() -> str:
|
|
|
385
385
|
# Current frame is this function (_get_name_from_stack)
|
|
386
386
|
# The first f_back takes us to _get_symbol_name
|
|
387
387
|
# The second f_back takes us to the __init__ function of
|
|
388
|
-
# the symbol
|
|
388
|
+
# the symbol or addX function of Container. The third f_back
|
|
389
|
+
# takes us to the user code.
|
|
389
390
|
frame = inspect.currentframe().f_back.f_back.f_back
|
|
390
391
|
assert frame is not None
|
|
391
392
|
|
|
@@ -66,6 +66,7 @@ src/gamspy/_symbols/implicits/implicit_symbol.py
|
|
|
66
66
|
src/gamspy/_symbols/implicits/implicit_variable.py
|
|
67
67
|
src/gamspy/formulations/__init__.py
|
|
68
68
|
src/gamspy/formulations/piecewise.py
|
|
69
|
+
src/gamspy/formulations/result.py
|
|
69
70
|
src/gamspy/formulations/shape.py
|
|
70
71
|
src/gamspy/formulations/utils.py
|
|
71
72
|
src/gamspy/formulations/ml/__init__.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|