gamsapi 52.5.0__cp312-cp312-win_amd64.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.
- gams/__init__.py +27 -0
- gams/_version.py +1 -0
- gams/connect/__init__.py +28 -0
- gams/connect/agents/__init__.py +24 -0
- gams/connect/agents/_excel/__init__.py +32 -0
- gams/connect/agents/_excel/excelagent.py +312 -0
- gams/connect/agents/_excel/workbook.py +155 -0
- gams/connect/agents/_sqlconnectors/__init__.py +42 -0
- gams/connect/agents/_sqlconnectors/_accesshandler.py +211 -0
- gams/connect/agents/_sqlconnectors/_databasehandler.py +250 -0
- gams/connect/agents/_sqlconnectors/_mysqlhandler.py +168 -0
- gams/connect/agents/_sqlconnectors/_postgreshandler.py +131 -0
- gams/connect/agents/_sqlconnectors/_pyodbchandler.py +112 -0
- gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +74 -0
- gams/connect/agents/_sqlconnectors/_sqlitehandler.py +262 -0
- gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +179 -0
- gams/connect/agents/concatenate.py +440 -0
- gams/connect/agents/connectagent.py +743 -0
- gams/connect/agents/csvreader.py +675 -0
- gams/connect/agents/csvwriter.py +151 -0
- gams/connect/agents/domainwriter.py +143 -0
- gams/connect/agents/excelreader.py +756 -0
- gams/connect/agents/excelwriter.py +467 -0
- gams/connect/agents/filter.py +223 -0
- gams/connect/agents/gamsreader.py +112 -0
- gams/connect/agents/gamswriter.py +239 -0
- gams/connect/agents/gdxreader.py +109 -0
- gams/connect/agents/gdxwriter.py +146 -0
- gams/connect/agents/labelmanipulator.py +303 -0
- gams/connect/agents/projection.py +539 -0
- gams/connect/agents/pythoncode.py +71 -0
- gams/connect/agents/rawcsvreader.py +248 -0
- gams/connect/agents/rawexcelreader.py +312 -0
- gams/connect/agents/schema/CSVReader.yaml +92 -0
- gams/connect/agents/schema/CSVWriter.yaml +44 -0
- gams/connect/agents/schema/Concatenate.yaml +52 -0
- gams/connect/agents/schema/DomainWriter.yaml +25 -0
- gams/connect/agents/schema/ExcelReader.yaml +121 -0
- gams/connect/agents/schema/ExcelWriter.yaml +78 -0
- gams/connect/agents/schema/Filter.yaml +74 -0
- gams/connect/agents/schema/GAMSReader.yaml +20 -0
- gams/connect/agents/schema/GAMSWriter.yaml +47 -0
- gams/connect/agents/schema/GDXReader.yaml +23 -0
- gams/connect/agents/schema/GDXWriter.yaml +32 -0
- gams/connect/agents/schema/LabelManipulator.yaml +99 -0
- gams/connect/agents/schema/Projection.yaml +24 -0
- gams/connect/agents/schema/PythonCode.yaml +6 -0
- gams/connect/agents/schema/RawCSVReader.yaml +34 -0
- gams/connect/agents/schema/RawExcelReader.yaml +42 -0
- gams/connect/agents/schema/SQLReader.yaml +75 -0
- gams/connect/agents/schema/SQLWriter.yaml +103 -0
- gams/connect/agents/sqlreader.py +301 -0
- gams/connect/agents/sqlwriter.py +276 -0
- gams/connect/connectdatabase.py +275 -0
- gams/connect/connectvalidator.py +93 -0
- gams/connect/errors.py +34 -0
- gams/control/__init__.py +136 -0
- gams/control/database.py +2231 -0
- gams/control/execution.py +1900 -0
- gams/control/options.py +2792 -0
- gams/control/workspace.py +1198 -0
- gams/core/__init__.py +24 -0
- gams/core/cfg/__init__.py +26 -0
- gams/core/cfg/_cfgmcc.cp312-win_amd64.pyd +0 -0
- gams/core/cfg/cfgmcc.py +519 -0
- gams/core/dct/__init__.py +26 -0
- gams/core/dct/_dctmcc.cp312-win_amd64.pyd +0 -0
- gams/core/dct/dctmcc.py +574 -0
- gams/core/embedded/__init__.py +26 -0
- gams/core/embedded/gamsemb.py +1024 -0
- gams/core/emp/__init__.py +24 -0
- gams/core/emp/emplexer.py +89 -0
- gams/core/emp/empyacc.py +281 -0
- gams/core/gdx/__init__.py +26 -0
- gams/core/gdx/_gdxcc.cp312-win_amd64.pyd +0 -0
- gams/core/gdx/gdxcc.py +866 -0
- gams/core/gev/__init__.py +26 -0
- gams/core/gev/_gevmcc.cp312-win_amd64.pyd +0 -0
- gams/core/gev/gevmcc.py +855 -0
- gams/core/gmd/__init__.py +26 -0
- gams/core/gmd/_gmdcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmd/gmdcc.py +917 -0
- gams/core/gmo/__init__.py +26 -0
- gams/core/gmo/_gmomcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmo/gmomcc.py +2046 -0
- gams/core/idx/__init__.py +26 -0
- gams/core/idx/_idxcc.cp312-win_amd64.pyd +0 -0
- gams/core/idx/idxcc.py +510 -0
- gams/core/numpy/__init__.py +29 -0
- gams/core/numpy/_gams2numpy.cp312-win_amd64.pyd +0 -0
- gams/core/numpy/gams2numpy.py +1048 -0
- gams/core/opt/__init__.py +26 -0
- gams/core/opt/_optcc.cp312-win_amd64.pyd +0 -0
- gams/core/opt/optcc.py +840 -0
- gams/engine/__init__.py +204 -0
- gams/engine/api/__init__.py +13 -0
- gams/engine/api/auth_api.py +7653 -0
- gams/engine/api/cleanup_api.py +751 -0
- gams/engine/api/default_api.py +887 -0
- gams/engine/api/hypercube_api.py +2629 -0
- gams/engine/api/jobs_api.py +5229 -0
- gams/engine/api/licenses_api.py +2220 -0
- gams/engine/api/namespaces_api.py +7783 -0
- gams/engine/api/usage_api.py +5627 -0
- gams/engine/api/users_api.py +5931 -0
- gams/engine/api_client.py +804 -0
- gams/engine/api_response.py +21 -0
- gams/engine/configuration.py +601 -0
- gams/engine/exceptions.py +216 -0
- gams/engine/models/__init__.py +86 -0
- gams/engine/models/bad_input.py +89 -0
- gams/engine/models/cleanable_job_result.py +104 -0
- gams/engine/models/cleanable_job_result_page.py +113 -0
- gams/engine/models/engine_license.py +107 -0
- gams/engine/models/files_not_found.py +93 -0
- gams/engine/models/forwarded_token_response.py +112 -0
- gams/engine/models/generic_key_value_pair.py +89 -0
- gams/engine/models/hypercube.py +160 -0
- gams/engine/models/hypercube_page.py +111 -0
- gams/engine/models/hypercube_summary.py +91 -0
- gams/engine/models/hypercube_token.py +97 -0
- gams/engine/models/identity_provider.py +107 -0
- gams/engine/models/identity_provider_ldap.py +121 -0
- gams/engine/models/identity_provider_oauth2.py +146 -0
- gams/engine/models/identity_provider_oauth2_scope.py +89 -0
- gams/engine/models/identity_provider_oauth2_with_secret.py +152 -0
- gams/engine/models/identity_provider_oidc.py +133 -0
- gams/engine/models/identity_provider_oidc_with_secret.py +143 -0
- gams/engine/models/inex.py +91 -0
- gams/engine/models/invitation.py +136 -0
- gams/engine/models/invitation_quota.py +106 -0
- gams/engine/models/invitation_token.py +87 -0
- gams/engine/models/job.py +165 -0
- gams/engine/models/job_no_text_entry.py +138 -0
- gams/engine/models/job_no_text_entry_page.py +111 -0
- gams/engine/models/license.py +91 -0
- gams/engine/models/log_piece.py +96 -0
- gams/engine/models/message.py +87 -0
- gams/engine/models/message_and_token.py +99 -0
- gams/engine/models/message_with_webhook_id.py +89 -0
- gams/engine/models/model_auth_token.py +87 -0
- gams/engine/models/model_configuration.py +125 -0
- gams/engine/models/model_default_instance.py +99 -0
- gams/engine/models/model_default_user_instance.py +98 -0
- gams/engine/models/model_hypercube_job.py +106 -0
- gams/engine/models/model_hypercube_usage.py +130 -0
- gams/engine/models/model_instance_info.py +116 -0
- gams/engine/models/model_instance_info_full.py +123 -0
- gams/engine/models/model_instance_pool_info.py +112 -0
- gams/engine/models/model_job_labels.py +179 -0
- gams/engine/models/model_job_usage.py +133 -0
- gams/engine/models/model_pool_usage.py +124 -0
- gams/engine/models/model_usage.py +115 -0
- gams/engine/models/model_user.py +96 -0
- gams/engine/models/model_userinstance_info.py +119 -0
- gams/engine/models/model_userinstancepool_info.py +95 -0
- gams/engine/models/model_version.py +91 -0
- gams/engine/models/models.py +120 -0
- gams/engine/models/namespace.py +104 -0
- gams/engine/models/namespace_quota.py +96 -0
- gams/engine/models/namespace_with_permission.py +96 -0
- gams/engine/models/not_found.py +91 -0
- gams/engine/models/password_policy.py +97 -0
- gams/engine/models/perm_and_username.py +89 -0
- gams/engine/models/quota.py +117 -0
- gams/engine/models/quota_exceeded.py +97 -0
- gams/engine/models/status_code_meaning.py +89 -0
- gams/engine/models/stream_entry.py +89 -0
- gams/engine/models/system_wide_license.py +92 -0
- gams/engine/models/text_entries.py +87 -0
- gams/engine/models/text_entry.py +101 -0
- gams/engine/models/time_span.py +95 -0
- gams/engine/models/time_span_pool_worker.py +99 -0
- gams/engine/models/token_forward_error.py +87 -0
- gams/engine/models/user.py +127 -0
- gams/engine/models/user_group_member.py +96 -0
- gams/engine/models/user_groups.py +108 -0
- gams/engine/models/vapid_info.py +87 -0
- gams/engine/models/webhook.py +138 -0
- gams/engine/models/webhook_parameterized_event.py +99 -0
- gams/engine/py.typed +0 -0
- gams/engine/rest.py +258 -0
- gams/magic/__init__.py +32 -0
- gams/magic/gams_magic.py +142 -0
- gams/magic/interactive.py +402 -0
- gams/tools/__init__.py +30 -0
- gams/tools/errors.py +34 -0
- gams/tools/toolcollection/__init__.py +24 -0
- gams/tools/toolcollection/alg/__init__.py +24 -0
- gams/tools/toolcollection/alg/rank.py +51 -0
- gams/tools/toolcollection/data/__init__.py +24 -0
- gams/tools/toolcollection/data/csvread.py +444 -0
- gams/tools/toolcollection/data/csvwrite.py +311 -0
- gams/tools/toolcollection/data/exceldump.py +47 -0
- gams/tools/toolcollection/data/sqlitewrite.py +276 -0
- gams/tools/toolcollection/gdxservice/__init__.py +24 -0
- gams/tools/toolcollection/gdxservice/gdxencoding.py +104 -0
- gams/tools/toolcollection/gdxservice/gdxrename.py +94 -0
- gams/tools/toolcollection/linalg/__init__.py +24 -0
- gams/tools/toolcollection/linalg/cholesky.py +57 -0
- gams/tools/toolcollection/linalg/eigenvalue.py +56 -0
- gams/tools/toolcollection/linalg/eigenvector.py +58 -0
- gams/tools/toolcollection/linalg/invert.py +55 -0
- gams/tools/toolcollection/linalg/ols.py +138 -0
- gams/tools/toolcollection/tooltemplate.py +321 -0
- gams/tools/toolcollection/win32/__init__.py +24 -0
- gams/tools/toolcollection/win32/excelmerge.py +93 -0
- gams/tools/toolcollection/win32/exceltalk.py +76 -0
- gams/tools/toolcollection/win32/msappavail.py +49 -0
- gams/tools/toolcollection/win32/shellexecute.py +54 -0
- gams/tools/tools.py +116 -0
- gams/transfer/__init__.py +35 -0
- gams/transfer/_abcs/__init__.py +37 -0
- gams/transfer/_abcs/container_abcs.py +433 -0
- gams/transfer/_internals/__init__.py +63 -0
- gams/transfer/_internals/algorithms.py +436 -0
- gams/transfer/_internals/casepreservingdict.py +124 -0
- gams/transfer/_internals/constants.py +270 -0
- gams/transfer/_internals/domainviolation.py +103 -0
- gams/transfer/_internals/specialvalues.py +172 -0
- gams/transfer/containers/__init__.py +26 -0
- gams/transfer/containers/_container.py +1794 -0
- gams/transfer/containers/_io/__init__.py +28 -0
- gams/transfer/containers/_io/containers.py +164 -0
- gams/transfer/containers/_io/gdx.py +1029 -0
- gams/transfer/containers/_io/gmd.py +872 -0
- gams/transfer/containers/_mixins/__init__.py +26 -0
- gams/transfer/containers/_mixins/ccc.py +1274 -0
- gams/transfer/syms/__init__.py +33 -0
- gams/transfer/syms/_methods/__init__.py +24 -0
- gams/transfer/syms/_methods/tables.py +120 -0
- gams/transfer/syms/_methods/toDict.py +115 -0
- gams/transfer/syms/_methods/toList.py +83 -0
- gams/transfer/syms/_methods/toValue.py +60 -0
- gams/transfer/syms/_mixins/__init__.py +32 -0
- gams/transfer/syms/_mixins/equals.py +626 -0
- gams/transfer/syms/_mixins/generateRecords.py +499 -0
- gams/transfer/syms/_mixins/pivot.py +313 -0
- gams/transfer/syms/_mixins/pve.py +627 -0
- gams/transfer/syms/_mixins/sa.py +27 -0
- gams/transfer/syms/_mixins/sapve.py +27 -0
- gams/transfer/syms/_mixins/saua.py +27 -0
- gams/transfer/syms/_mixins/sauapve.py +199 -0
- gams/transfer/syms/_mixins/spve.py +1528 -0
- gams/transfer/syms/_mixins/ve.py +936 -0
- gams/transfer/syms/container_syms/__init__.py +31 -0
- gams/transfer/syms/container_syms/_alias.py +984 -0
- gams/transfer/syms/container_syms/_equation.py +333 -0
- gams/transfer/syms/container_syms/_parameter.py +973 -0
- gams/transfer/syms/container_syms/_set.py +604 -0
- gams/transfer/syms/container_syms/_universe_alias.py +461 -0
- gams/transfer/syms/container_syms/_variable.py +321 -0
- gamsapi-52.5.0.dist-info/METADATA +150 -0
- gamsapi-52.5.0.dist-info/RECORD +257 -0
- gamsapi-52.5.0.dist-info/WHEEL +5 -0
- gamsapi-52.5.0.dist-info/licenses/LICENSE +22 -0
- gamsapi-52.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
import itertools
|
|
27
|
+
import random
|
|
28
|
+
import numpy as np
|
|
29
|
+
import pandas as pd
|
|
30
|
+
import gams.transfer._abcs as abcs
|
|
31
|
+
from typing import Sequence, Tuple, Union, List, Optional, TYPE_CHECKING
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from gams.transfer.syms import Set, Parameter, Variable, Equation
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def check_all_same(iterable1: Sequence, iterable2: Sequence) -> bool:
|
|
38
|
+
"""
|
|
39
|
+
Check if two sequences have the same elements in the same order.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
iterable1 : Sequence
|
|
44
|
+
The first sequence to compare.
|
|
45
|
+
|
|
46
|
+
iterable2 : Sequence
|
|
47
|
+
The second sequence to compare.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
bool
|
|
52
|
+
Returns True if both sequences have the same elements in the same order; otherwise, False.
|
|
53
|
+
"""
|
|
54
|
+
if len(iterable1) != len(iterable2):
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
all_same = True
|
|
58
|
+
for elem1, elem2 in zip(iterable1, iterable2):
|
|
59
|
+
if elem1 is not elem2:
|
|
60
|
+
return False
|
|
61
|
+
return all_same
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_keys_and_values(
|
|
65
|
+
symobj: Union["Set", "Parameter", "Variable", "Equation"], mode: str
|
|
66
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
67
|
+
"""
|
|
68
|
+
Gets the keys and values of a specific symbol.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
symobj : Set | Parameter | Variable | Equation
|
|
73
|
+
The symbol to explore.
|
|
74
|
+
mode : str
|
|
75
|
+
The mode of keys and values; string or category.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
Tuple[ndarray, ndarray]
|
|
80
|
+
The tuple includes the symbol's keys and values.
|
|
81
|
+
|
|
82
|
+
Raises
|
|
83
|
+
------
|
|
84
|
+
ValueError
|
|
85
|
+
If the given mode is niether 'string' nor 'category'.
|
|
86
|
+
"""
|
|
87
|
+
if symobj.records is None:
|
|
88
|
+
if isinstance(symobj, abcs.ABCSet):
|
|
89
|
+
arrkeys = np.full(
|
|
90
|
+
(0, symobj.dimension), "", dtype=dtype_keys
|
|
91
|
+
) # dtype_keys is not defined
|
|
92
|
+
arrvals = np.full((0, 1), "", dtype=object)
|
|
93
|
+
return (arrkeys, arrvals)
|
|
94
|
+
if isinstance(symobj, abcs.ABCParameter):
|
|
95
|
+
arrkeys = np.full(
|
|
96
|
+
(0, symobj.dimension), "", dtype=dtype_keys
|
|
97
|
+
) # dtype_keys is not defined
|
|
98
|
+
arrvals = np.full((0, len(symobj._attributes)), "", dtype=np.float64)
|
|
99
|
+
return (arrkeys, arrvals)
|
|
100
|
+
if isinstance(symobj, (abcs.ABCVariable, abcs.ABCEquation)):
|
|
101
|
+
arrkeys = np.full(
|
|
102
|
+
(0, symobj.dimension), "", dtype=dtype_keys
|
|
103
|
+
) # dtype_keys is not defined
|
|
104
|
+
arrvals = np.full((0, len(symobj._attributes)), "", dtype=np.float64)
|
|
105
|
+
return (arrkeys, arrvals)
|
|
106
|
+
|
|
107
|
+
else:
|
|
108
|
+
#
|
|
109
|
+
#
|
|
110
|
+
# get keys array
|
|
111
|
+
if mode == "string":
|
|
112
|
+
nrecs = symobj.number_records
|
|
113
|
+
if symobj.dimension == 0:
|
|
114
|
+
arrkeys = np.array([[]], dtype=object)
|
|
115
|
+
elif symobj.dimension == 1:
|
|
116
|
+
arrkeys = np.empty(nrecs, dtype=object)
|
|
117
|
+
arrkeys[:nrecs] = symobj.records[symobj.records.columns[0]]
|
|
118
|
+
arrkeys = arrkeys.reshape((nrecs, 1), order="F")
|
|
119
|
+
else:
|
|
120
|
+
arrkeys = np.empty(symobj.dimension * nrecs, dtype=object)
|
|
121
|
+
for i in range(symobj.dimension):
|
|
122
|
+
idx_start = i * nrecs
|
|
123
|
+
idx_end = i * nrecs + nrecs
|
|
124
|
+
arrkeys[idx_start:idx_end] = symobj.records[
|
|
125
|
+
symobj.records.columns[i]
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
arrkeys = arrkeys.reshape((nrecs, symobj.dimension), order="F")
|
|
129
|
+
|
|
130
|
+
elif mode == "category":
|
|
131
|
+
nrecs = symobj.number_records
|
|
132
|
+
if symobj.dimension == 0:
|
|
133
|
+
arrkeys = np.array([[]], dtype=int)
|
|
134
|
+
elif symobj.dimension == 1:
|
|
135
|
+
arrkeys = np.empty(nrecs, dtype=int)
|
|
136
|
+
arrkeys[:nrecs] = symobj.records[symobj.records.columns[0]].cat.codes
|
|
137
|
+
arrkeys = arrkeys.reshape((nrecs, 1), order="F")
|
|
138
|
+
else:
|
|
139
|
+
arrkeys = np.empty(symobj.dimension * nrecs, dtype=int)
|
|
140
|
+
for i in range(symobj.dimension):
|
|
141
|
+
idx_start = i * nrecs
|
|
142
|
+
idx_end = i * nrecs + nrecs
|
|
143
|
+
arrkeys[idx_start:idx_end] = symobj.records[
|
|
144
|
+
symobj.records.columns[i]
|
|
145
|
+
].cat.codes
|
|
146
|
+
|
|
147
|
+
arrkeys = arrkeys.reshape((nrecs, symobj.dimension), order="F")
|
|
148
|
+
else:
|
|
149
|
+
raise ValueError("Unrecognized write 'mode'.")
|
|
150
|
+
#
|
|
151
|
+
#
|
|
152
|
+
# get values array
|
|
153
|
+
if symobj.dimension == 0:
|
|
154
|
+
arrvals = symobj.records.to_numpy()
|
|
155
|
+
else:
|
|
156
|
+
if isinstance(symobj, (abcs.ABCSet, abcs.ABCParameter)):
|
|
157
|
+
arrvals = (
|
|
158
|
+
symobj.records[symobj.records.columns[-1]]
|
|
159
|
+
.to_numpy()
|
|
160
|
+
.reshape((-1, 1))
|
|
161
|
+
)
|
|
162
|
+
else:
|
|
163
|
+
arrvals = np.empty(len(symobj._attributes) * nrecs, dtype=np.float64)
|
|
164
|
+
for i in range(len(symobj._attributes)):
|
|
165
|
+
idx_start = i * nrecs
|
|
166
|
+
idx_end = i * nrecs + nrecs
|
|
167
|
+
arrvals[idx_start:idx_end] = symobj.records[
|
|
168
|
+
symobj.records.columns[i + symobj.dimension]
|
|
169
|
+
].to_numpy()
|
|
170
|
+
|
|
171
|
+
arrvals = arrvals.reshape((nrecs, len(symobj._attributes)), order="F")
|
|
172
|
+
|
|
173
|
+
return (arrkeys, arrvals)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def convert_to_categoricals_str(
|
|
177
|
+
arrkeys: np.ndarray, arrvals: np.ndarray, all_uels: Sequence
|
|
178
|
+
) -> pd.DataFrame:
|
|
179
|
+
"""
|
|
180
|
+
This function takes two lists, `arrkeys` and `arrvals`, and converts them into a pandas
|
|
181
|
+
DataFrame.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
arrkeys : ndarray
|
|
186
|
+
An array of keys (e.g., labels or domain values).
|
|
187
|
+
|
|
188
|
+
arrvals : ndarray
|
|
189
|
+
An array of values corresponding to the keys.
|
|
190
|
+
|
|
191
|
+
all_uels : Sequence
|
|
192
|
+
A sequence of all unique elements (categories) that should be used to define
|
|
193
|
+
the categorical data.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
pd.DataFrame
|
|
198
|
+
A pandas DataFrame with categorical columns based on `arrkeys` and `arrvals`.
|
|
199
|
+
|
|
200
|
+
Notes
|
|
201
|
+
-----
|
|
202
|
+
- This function assumes that the lengths of `arrkeys` and `arrvals` are compatible.
|
|
203
|
+
"""
|
|
204
|
+
has_domains = arrkeys.size > 0
|
|
205
|
+
has_values = arrvals.size > 0
|
|
206
|
+
|
|
207
|
+
dfs = []
|
|
208
|
+
if has_domains:
|
|
209
|
+
dfs.append(pd.DataFrame(arrkeys))
|
|
210
|
+
|
|
211
|
+
if has_values:
|
|
212
|
+
dfs.append(pd.DataFrame(arrvals))
|
|
213
|
+
|
|
214
|
+
if has_domains and has_values:
|
|
215
|
+
df = pd.concat(dfs, axis=1, copy=False)
|
|
216
|
+
df.columns = pd.RangeIndex(start=0, stop=len(df.columns))
|
|
217
|
+
elif has_domains or has_values:
|
|
218
|
+
df = dfs[0]
|
|
219
|
+
df.columns = pd.RangeIndex(start=0, stop=len(df.columns))
|
|
220
|
+
else:
|
|
221
|
+
df = None
|
|
222
|
+
|
|
223
|
+
if has_domains:
|
|
224
|
+
rk, ck = arrkeys.shape
|
|
225
|
+
for i in range(ck):
|
|
226
|
+
dtype = pd.CategoricalDtype(categories=all_uels, ordered=True)
|
|
227
|
+
df.isetitem(
|
|
228
|
+
i, pd.Categorical(values=df[i], dtype=dtype).remove_unused_categories()
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return df
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def convert_to_categoricals_cat(
|
|
235
|
+
arrkeys: np.ndarray, arrvals: np.ndarray, unique_uels: Sequence
|
|
236
|
+
) -> pd.DataFrame:
|
|
237
|
+
has_domains = arrkeys.size > 0
|
|
238
|
+
has_values = arrvals.size > 0
|
|
239
|
+
|
|
240
|
+
dfs = []
|
|
241
|
+
if has_domains:
|
|
242
|
+
dfs.append(pd.DataFrame(arrkeys))
|
|
243
|
+
|
|
244
|
+
if has_values:
|
|
245
|
+
dfs.append(pd.DataFrame(arrvals))
|
|
246
|
+
|
|
247
|
+
if has_domains and has_values:
|
|
248
|
+
df = pd.concat(dfs, axis=1, copy=False)
|
|
249
|
+
df.columns = pd.RangeIndex(start=0, stop=len(df.columns))
|
|
250
|
+
elif has_domains or has_values:
|
|
251
|
+
df = dfs[0]
|
|
252
|
+
df.columns = pd.RangeIndex(start=0, stop=len(df.columns))
|
|
253
|
+
else:
|
|
254
|
+
df = None
|
|
255
|
+
|
|
256
|
+
if has_domains:
|
|
257
|
+
_, ck = arrkeys.shape
|
|
258
|
+
for i in range(ck):
|
|
259
|
+
dtype = pd.CategoricalDtype(categories=unique_uels[i], ordered=True)
|
|
260
|
+
df.isetitem(i, pd.Categorical.from_codes(codes=df[i], dtype=dtype))
|
|
261
|
+
|
|
262
|
+
return df
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def generate_unique_labels(labels: Union[list, str]) -> List[str]:
|
|
266
|
+
"""
|
|
267
|
+
Generate unique labels from a list of labels.
|
|
268
|
+
|
|
269
|
+
Parameters
|
|
270
|
+
----------
|
|
271
|
+
labels : list | str
|
|
272
|
+
A list of labels to be processed. This can be a single label or a list of labels.
|
|
273
|
+
|
|
274
|
+
Returns
|
|
275
|
+
-------
|
|
276
|
+
List[str]
|
|
277
|
+
A list of labels with uniqueness enforced. If the input list contains duplicates, this
|
|
278
|
+
function appends numeric suffixes to make the labels unique. If the input is not a list,
|
|
279
|
+
it is converted to a single-element list.
|
|
280
|
+
"""
|
|
281
|
+
if not isinstance(labels, list):
|
|
282
|
+
labels = [labels]
|
|
283
|
+
|
|
284
|
+
# default domain labels
|
|
285
|
+
labels = [i if i != "*" else "uni" for i in labels]
|
|
286
|
+
|
|
287
|
+
# make unique
|
|
288
|
+
is_unique = False
|
|
289
|
+
if len(labels) == len(set(labels)):
|
|
290
|
+
is_unique = True
|
|
291
|
+
|
|
292
|
+
if not is_unique:
|
|
293
|
+
labels = [f"{i}_{n}" for n, i in enumerate(labels)]
|
|
294
|
+
|
|
295
|
+
return labels
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def cartesian_product(*arrays: Tuple[np.ndarray]) -> np.ndarray:
|
|
299
|
+
"""
|
|
300
|
+
Calculate the Cartesian product of multiple input arrays.
|
|
301
|
+
|
|
302
|
+
Given multiple input arrays, this function computes the Cartesian product of these arrays.
|
|
303
|
+
The Cartesian product is an array containing all possible combinations of elements from
|
|
304
|
+
the input arrays, where each element in the result is a tuple representing one combination.
|
|
305
|
+
|
|
306
|
+
Parameters
|
|
307
|
+
----------
|
|
308
|
+
*arrays : Tuple[ndarray]
|
|
309
|
+
Multiple input arrays for which the Cartesian product is calculated.
|
|
310
|
+
|
|
311
|
+
Returns
|
|
312
|
+
-------
|
|
313
|
+
ndarray
|
|
314
|
+
A NumPy array containing the Cartesian product of the input arrays. Each row
|
|
315
|
+
represents a unique combination, and the columns represent the elements from the
|
|
316
|
+
input arrays.
|
|
317
|
+
|
|
318
|
+
Notes
|
|
319
|
+
-----
|
|
320
|
+
- The input arrays should be of compatible data types.
|
|
321
|
+
- The number of input arrays and their shapes may vary, and the function works for any
|
|
322
|
+
number of input arrays.
|
|
323
|
+
|
|
324
|
+
Examples
|
|
325
|
+
-------_
|
|
326
|
+
>>> import numpy as np
|
|
327
|
+
>>> arr1 = np.array([1, 2])
|
|
328
|
+
>>> arr2 = np.array(['A', 'B'])
|
|
329
|
+
>>> arr3 = np.array([0.1, 0.2])
|
|
330
|
+
>>> result = cartesian_product(arr1, arr2, arr3)
|
|
331
|
+
>>> print(result)
|
|
332
|
+
array([[1, 'A', 0.1],
|
|
333
|
+
[1, 'A', 0.2],
|
|
334
|
+
[1, 'B', 0.1],
|
|
335
|
+
[1, 'B', 0.2],
|
|
336
|
+
[2, 'A', 0.1],
|
|
337
|
+
[2, 'A', 0.2],
|
|
338
|
+
[2, 'B', 0.1],
|
|
339
|
+
[2, 'B', 0.2]], dtype=object)
|
|
340
|
+
|
|
341
|
+
"""
|
|
342
|
+
|
|
343
|
+
la = len(arrays)
|
|
344
|
+
dtype = np.result_type(*arrays)
|
|
345
|
+
arr = np.empty((la, *map(len, arrays)), dtype=dtype)
|
|
346
|
+
idx = slice(None), *itertools.repeat(None, la)
|
|
347
|
+
for i, a in enumerate(arrays):
|
|
348
|
+
arr[i, ...] = a[idx[: la - i]]
|
|
349
|
+
|
|
350
|
+
return arr.reshape(la, -1).T
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def choice_no_replace(
|
|
354
|
+
choose_from: int,
|
|
355
|
+
n_choose: int,
|
|
356
|
+
seed: Optional[int] = None,
|
|
357
|
+
) -> np.ndarray:
|
|
358
|
+
"""
|
|
359
|
+
Randomly select 'n_choose' unique items from a pool of 'choose_from' items without replacement.
|
|
360
|
+
|
|
361
|
+
This function allows you to randomly choose a specified number of unique items from a pool of items
|
|
362
|
+
defined by 'choose_from'. It ensures that the selected items are unique, meaning each item is chosen
|
|
363
|
+
only once.
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
choose_from : int
|
|
368
|
+
The total number of items to choose from.
|
|
369
|
+
|
|
370
|
+
n_choose : int
|
|
371
|
+
The number of items to select from the pool.
|
|
372
|
+
|
|
373
|
+
seed : int, optional
|
|
374
|
+
An optional seed for the random number generator. If provided, it should be an integer or None.
|
|
375
|
+
If 'seed' is None, the random selection will not be reproducible.
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
ndarray
|
|
380
|
+
An array containing the selected items. The array will have a length of 'n_choose', and the
|
|
381
|
+
items will be in random order.
|
|
382
|
+
|
|
383
|
+
Raises
|
|
384
|
+
------
|
|
385
|
+
TypeError
|
|
386
|
+
If 'seed' is not an integer or None.
|
|
387
|
+
|
|
388
|
+
Exception
|
|
389
|
+
If the 'density' of selection is out of bounds, which must be in the interval [0, 1].
|
|
390
|
+
|
|
391
|
+
Notes
|
|
392
|
+
-----
|
|
393
|
+
- For high-density selections (density > 0.08), NumPy is used for better performance.
|
|
394
|
+
- For low-density selections (density <= 0.08), the built-in 'random' module is used for speed.
|
|
395
|
+
|
|
396
|
+
Examples
|
|
397
|
+
--------
|
|
398
|
+
>>> choice_no_replace(100, 10, seed=42)
|
|
399
|
+
array([8, 9, 19, 41, 60, 68, 71, 82, 94, 96])
|
|
400
|
+
"""
|
|
401
|
+
|
|
402
|
+
if not isinstance(seed, (int, type(None))):
|
|
403
|
+
raise TypeError("Argument 'seed' must be type int or NoneType")
|
|
404
|
+
|
|
405
|
+
if not isinstance(choose_from, int):
|
|
406
|
+
choose_from = int(choose_from)
|
|
407
|
+
|
|
408
|
+
if not isinstance(n_choose, int):
|
|
409
|
+
n_choose = int(n_choose)
|
|
410
|
+
|
|
411
|
+
density = n_choose / choose_from
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
if density == 1:
|
|
415
|
+
return np.arange(choose_from, dtype=int)
|
|
416
|
+
|
|
417
|
+
# numpy is faster as density grows
|
|
418
|
+
if 0.08 < density < 1:
|
|
419
|
+
rng = np.random.default_rng(seed)
|
|
420
|
+
idx = rng.choice(
|
|
421
|
+
np.arange(choose_from, dtype=int), replace=False, size=(n_choose,)
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
# random.shuffle is much much faster at low density
|
|
425
|
+
elif density <= 0.08:
|
|
426
|
+
random.seed(seed)
|
|
427
|
+
idx = np.array(random.sample(range(choose_from), n_choose), dtype=int)
|
|
428
|
+
else:
|
|
429
|
+
raise Exception(
|
|
430
|
+
"Argument 'density' is out of bounds, must be on the interval [0,1]."
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
return np.sort(idx)
|
|
434
|
+
|
|
435
|
+
except Exception as err:
|
|
436
|
+
raise err
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
from collections import UserDict
|
|
27
|
+
from typing import Any, Optional, TYPE_CHECKING
|
|
28
|
+
from _collections_abc import dict_items, dict_keys, dict_values
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CasePreservingDict(UserDict):
|
|
32
|
+
def __init__(self, *args, **kwargs):
|
|
33
|
+
self._casefolded_key_map = {}
|
|
34
|
+
super().__init__(*args, **kwargs)
|
|
35
|
+
|
|
36
|
+
def __contains__(self, key):
|
|
37
|
+
return key.casefold() in self._casefolded_key_map
|
|
38
|
+
|
|
39
|
+
def __delitem__(self, key):
|
|
40
|
+
del self.data[self._casefolded_key_map[key.casefold()]]
|
|
41
|
+
del self._casefolded_key_map[key.casefold()]
|
|
42
|
+
|
|
43
|
+
def __setitem__(self, key, item):
|
|
44
|
+
try:
|
|
45
|
+
key_cf = key.casefold()
|
|
46
|
+
except:
|
|
47
|
+
raise TypeError("CasePreservingDict will only accept type str as keys")
|
|
48
|
+
|
|
49
|
+
if key_cf not in self._casefolded_key_map:
|
|
50
|
+
self.data[key] = item
|
|
51
|
+
self._casefolded_key_map[key_cf] = key
|
|
52
|
+
else:
|
|
53
|
+
self.data[self._casefolded_key_map[key_cf]] = item
|
|
54
|
+
|
|
55
|
+
def _repr_pretty_(self, p, cycle):
|
|
56
|
+
if cycle:
|
|
57
|
+
p.pretty(self.data)
|
|
58
|
+
else:
|
|
59
|
+
p.pretty(self.data)
|
|
60
|
+
|
|
61
|
+
def __getitem__(self, key):
|
|
62
|
+
return self.data[self._casefolded_key_map[key.casefold()]]
|
|
63
|
+
|
|
64
|
+
def pop(self, key: str) -> Any:
|
|
65
|
+
a = self.data.pop(self._casefolded_key_map[key.casefold()])
|
|
66
|
+
del self._casefolded_key_map[key.casefold()]
|
|
67
|
+
return a
|
|
68
|
+
|
|
69
|
+
def get(self, key: str, value: Optional[Any] = None) -> Any:
|
|
70
|
+
try:
|
|
71
|
+
return self.data.get(self._casefolded_key_map[key.casefold()])
|
|
72
|
+
except:
|
|
73
|
+
return value
|
|
74
|
+
|
|
75
|
+
def copy(self) -> "CasePreservingDict":
|
|
76
|
+
"""
|
|
77
|
+
Create a deep copy of the CasePreservingDict.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
CasePreservingDict
|
|
82
|
+
A deep copy of the CasePreservingDict.
|
|
83
|
+
"""
|
|
84
|
+
import copy
|
|
85
|
+
|
|
86
|
+
return copy.deepcopy(self)
|
|
87
|
+
|
|
88
|
+
def setdefault(self, key: str, default: Any) -> Any:
|
|
89
|
+
"""
|
|
90
|
+
Set the default value for a key if it does not exist (case-insensitive).
|
|
91
|
+
|
|
92
|
+
If the key already exists in the dictionary (case-insensitive), this function does not modify the existing value.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
key : str
|
|
97
|
+
The key to set the default value for.
|
|
98
|
+
|
|
99
|
+
default : Any
|
|
100
|
+
The default value to associate with the key if it does not exist.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
Any
|
|
105
|
+
The value associated with the key (case-insensitive) or the default value if the key was not found.
|
|
106
|
+
"""
|
|
107
|
+
key_cf = key.casefold()
|
|
108
|
+
if key_cf not in self._casefolded_key_map.keys():
|
|
109
|
+
self.__setitem__(key, default)
|
|
110
|
+
return default
|
|
111
|
+
else:
|
|
112
|
+
return self.data[self._casefolded_key_map[key_cf]]
|
|
113
|
+
|
|
114
|
+
def popitem(self) -> tuple:
|
|
115
|
+
return self.data.popitem()
|
|
116
|
+
|
|
117
|
+
def items(self) -> dict_items:
|
|
118
|
+
return self.data.items()
|
|
119
|
+
|
|
120
|
+
def keys(self) -> dict_keys:
|
|
121
|
+
return self.data.keys()
|
|
122
|
+
|
|
123
|
+
def values(self) -> dict_values:
|
|
124
|
+
return self.data.values()
|