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,1029 @@
|
|
|
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 os
|
|
27
|
+
import copy
|
|
28
|
+
from typing import TYPE_CHECKING, Sequence, Any, Union, List
|
|
29
|
+
from warnings import warn
|
|
30
|
+
import pandas as pd
|
|
31
|
+
import numpy as np
|
|
32
|
+
from gams.core import gdx
|
|
33
|
+
import gams.transfer._abcs as abcs
|
|
34
|
+
from gams.transfer.syms import (
|
|
35
|
+
Set,
|
|
36
|
+
Parameter,
|
|
37
|
+
Variable,
|
|
38
|
+
Equation,
|
|
39
|
+
Alias,
|
|
40
|
+
UniverseAlias,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
from gams.transfer._internals import (
|
|
45
|
+
SpecialValues,
|
|
46
|
+
DomainStatus,
|
|
47
|
+
convert_to_categoricals_cat,
|
|
48
|
+
convert_to_categoricals_str,
|
|
49
|
+
generate_unique_labels,
|
|
50
|
+
get_keys_and_values,
|
|
51
|
+
GAMS_VARIABLE_SUBTYPES,
|
|
52
|
+
GAMS_EQUATION_SUBTYPES,
|
|
53
|
+
GAMS_DOMAIN_STATUS,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if TYPE_CHECKING:
|
|
57
|
+
from gams.transfer.containers import Container
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def isin(element: Any, container: Sequence) -> bool:
|
|
61
|
+
"""
|
|
62
|
+
Checks if an element is in a sequence.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
element: Any
|
|
67
|
+
The element to search for.
|
|
68
|
+
container: Sequence
|
|
69
|
+
The sequence where the element is to be searched in.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
bool
|
|
74
|
+
True if the element is in the container; False otherwise.
|
|
75
|
+
"""
|
|
76
|
+
for item in container:
|
|
77
|
+
if element is item:
|
|
78
|
+
return True
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def container_read(
|
|
83
|
+
container: "Container",
|
|
84
|
+
load_from: Union[str, os.PathLike],
|
|
85
|
+
symbols: Union[None, str, List[str]],
|
|
86
|
+
records: bool,
|
|
87
|
+
mode: str,
|
|
88
|
+
encoding: Union[None, str],
|
|
89
|
+
) -> None:
|
|
90
|
+
"""
|
|
91
|
+
Read symbols and associated data from a GDX file into a Container.
|
|
92
|
+
|
|
93
|
+
This function reads symbols and their associated data from a GDX (GAMS Data Exchange) file into a Container object.
|
|
94
|
+
You can specify the symbols to read, whether to read associated records, the reading mode, and encoding if required.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
container : Container
|
|
99
|
+
The target Container where symbols and data will be read into.
|
|
100
|
+
load_from : str | Path
|
|
101
|
+
The path to the GDX file from which to read symbols and data.
|
|
102
|
+
symbols : None | str | List[str]
|
|
103
|
+
A list of symbol names to read from the GDX file. If None, all symbols will be read.
|
|
104
|
+
records : bool
|
|
105
|
+
A flag indicating whether to read associated data records for symbols.
|
|
106
|
+
mode : str
|
|
107
|
+
The reading mode for the symbols. Use 'category' for categorical symbols or 'string' for string symbols.
|
|
108
|
+
encoding : None | str
|
|
109
|
+
The encoding to use when reading symbols from the GDX file. Default is None.
|
|
110
|
+
|
|
111
|
+
Raises
|
|
112
|
+
------
|
|
113
|
+
Exception
|
|
114
|
+
If there are issues with loading the GDX DLL or handling symbol metadata perhaps due to wrong path.
|
|
115
|
+
Exception
|
|
116
|
+
If the code tries to add an existing symbol.
|
|
117
|
+
Exception
|
|
118
|
+
Not being able to read a symbol in a specific mode.
|
|
119
|
+
ValueError
|
|
120
|
+
If an unrecognized reading mode is provided.
|
|
121
|
+
"""
|
|
122
|
+
if len(container) == 0:
|
|
123
|
+
initially_empty_container = True
|
|
124
|
+
else:
|
|
125
|
+
initially_empty_container = False
|
|
126
|
+
|
|
127
|
+
# test dll connection and create gdxhandle
|
|
128
|
+
try:
|
|
129
|
+
gdxHandle = gdx.new_gdxHandle_tp()
|
|
130
|
+
rc = gdx.gdxCreateD(gdxHandle, container.system_directory, gdx.GMS_SSSIZE)
|
|
131
|
+
assert rc[0], rc[1]
|
|
132
|
+
|
|
133
|
+
ret, fileVersion, producer = gdx.gdxFileVersion(gdxHandle)
|
|
134
|
+
|
|
135
|
+
except:
|
|
136
|
+
raise Exception("Could not properly load GDX DLL, check system_directory path")
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
|
|
140
|
+
# open file for reading
|
|
141
|
+
rc = gdx.gdxOpenRead(gdxHandle, load_from)
|
|
142
|
+
assert rc
|
|
143
|
+
ret, symCount, _ = gdx.gdxSystemInfo(gdxHandle)
|
|
144
|
+
|
|
145
|
+
# setting special values
|
|
146
|
+
specVals = gdx.doubleArray(gdx.GMS_SVIDX_MAX)
|
|
147
|
+
specVals[gdx.GMS_SVIDX_UNDEF] = SpecialValues.UNDEF
|
|
148
|
+
specVals[gdx.GMS_SVIDX_NA] = SpecialValues.NA
|
|
149
|
+
specVals[gdx.GMS_SVIDX_EPS] = SpecialValues.EPS
|
|
150
|
+
specVals[gdx.GMS_SVIDX_PINF] = SpecialValues.POSINF
|
|
151
|
+
specVals[gdx.GMS_SVIDX_MINF] = SpecialValues.NEGINF
|
|
152
|
+
|
|
153
|
+
rc = gdx.gdxSetSpecialValues(gdxHandle, specVals)
|
|
154
|
+
assert rc
|
|
155
|
+
|
|
156
|
+
# check for acronyms
|
|
157
|
+
n_acronyms = gdx.gdxAcronymCount(gdxHandle)
|
|
158
|
+
if n_acronyms > 0:
|
|
159
|
+
warn(
|
|
160
|
+
"GDX file contains acronyms. "
|
|
161
|
+
"Acronyms are not supported and are set to GAMS NA."
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
acronyms = []
|
|
165
|
+
for i in range(n_acronyms):
|
|
166
|
+
ret, acr_name, acr_text, acr_idx = gdx.gdxAcronymGetInfo(gdxHandle, i + 1)
|
|
167
|
+
acronyms.append(acr_idx)
|
|
168
|
+
|
|
169
|
+
# find symbol metadata if not reading in all
|
|
170
|
+
read_all_symbols = True
|
|
171
|
+
SYMBOL_METADATA = []
|
|
172
|
+
LINK_DOMAINS = []
|
|
173
|
+
SYMBOLS_W_RECORDS = []
|
|
174
|
+
|
|
175
|
+
if symbols is not None:
|
|
176
|
+
read_all_symbols = False
|
|
177
|
+
SYMBOL_METADATA = gdx_get_metadata_by_names(
|
|
178
|
+
container, gdxHandle, symbols, encoding
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# sort symbols by gdx number in order to read symbols in gdx order not user order
|
|
182
|
+
SYMBOL_METADATA = sorted(
|
|
183
|
+
SYMBOL_METADATA, key=lambda x: x["gdx_symbol_number"]
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# two paths to creating symbol objects
|
|
187
|
+
if read_all_symbols:
|
|
188
|
+
#
|
|
189
|
+
#
|
|
190
|
+
# fastpath if reading in all symbols (by number)
|
|
191
|
+
for i in range(1, symCount + 1):
|
|
192
|
+
md = gdx_get_metadata_by_number(container, gdxHandle, i, encoding)
|
|
193
|
+
|
|
194
|
+
# capture metadata
|
|
195
|
+
SYMBOL_METADATA.append(md)
|
|
196
|
+
|
|
197
|
+
# check if symbol already exists in container
|
|
198
|
+
if not initially_empty_container:
|
|
199
|
+
if md["name"] in container:
|
|
200
|
+
raise Exception(
|
|
201
|
+
f"Attempting to create a new symbol (through a read operation) named `{md['name']}` "
|
|
202
|
+
"but an object with this name already exists in the Container. "
|
|
203
|
+
"Symbol replacement is only possible if the existing symbol is "
|
|
204
|
+
"first removed from the Container with the `<container>.removeSymbols()` method."
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# figure out domain status
|
|
208
|
+
if GAMS_DOMAIN_STATUS.get(md["domain_type"], None) == "regular":
|
|
209
|
+
LINK_DOMAINS.append(md)
|
|
210
|
+
|
|
211
|
+
# capture symbols that have records (not aliases)
|
|
212
|
+
if md["number_records"] > 0 and md["type"] != gdx.GMS_DT_ALIAS:
|
|
213
|
+
SYMBOLS_W_RECORDS.append(md)
|
|
214
|
+
|
|
215
|
+
# create the symbol object in the container
|
|
216
|
+
create_symbol_from_metadata(container, md)
|
|
217
|
+
|
|
218
|
+
else:
|
|
219
|
+
#
|
|
220
|
+
#
|
|
221
|
+
# other
|
|
222
|
+
|
|
223
|
+
for md in SYMBOL_METADATA:
|
|
224
|
+
# check if symbol already exists in container
|
|
225
|
+
if not initially_empty_container:
|
|
226
|
+
if md["name"] in container:
|
|
227
|
+
raise Exception(
|
|
228
|
+
f"Attempting to create a new symbol (through a read operation) named `{md['name']}` "
|
|
229
|
+
"but an object with this name already exists in the Container. "
|
|
230
|
+
"Symbol replacement is only possible if the existing symbol is "
|
|
231
|
+
"first removed from the Container with the `<container>.removeSymbols()` method."
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if GAMS_DOMAIN_STATUS.get(md["domain_type"], None) == "regular":
|
|
235
|
+
LINK_DOMAINS.append(md)
|
|
236
|
+
|
|
237
|
+
# capture symbols that have records (not aliases)
|
|
238
|
+
if md["number_records"] > 0 and md["type"] != gdx.GMS_DT_ALIAS:
|
|
239
|
+
SYMBOLS_W_RECORDS.append(md)
|
|
240
|
+
|
|
241
|
+
# create the symbol object in the container
|
|
242
|
+
create_symbol_from_metadata(container, md)
|
|
243
|
+
|
|
244
|
+
#
|
|
245
|
+
#
|
|
246
|
+
# link domain objects
|
|
247
|
+
READ_SYMBOLS = [md["name"] for md in SYMBOL_METADATA]
|
|
248
|
+
for md in LINK_DOMAINS:
|
|
249
|
+
domain = md["domain"]
|
|
250
|
+
for n, i in enumerate(domain):
|
|
251
|
+
if i != "*" and i in READ_SYMBOLS:
|
|
252
|
+
domain[n] = container[i]
|
|
253
|
+
|
|
254
|
+
container[md["name"]]._domain = domain
|
|
255
|
+
|
|
256
|
+
#
|
|
257
|
+
#
|
|
258
|
+
# main records read
|
|
259
|
+
if records:
|
|
260
|
+
# get and store GDX_UELS
|
|
261
|
+
GDX_UELS = container._gams2np.gdxGetUelList(gdxHandle, encoding=encoding)
|
|
262
|
+
GDX_UELS[0] = "*"
|
|
263
|
+
|
|
264
|
+
for md in SYMBOLS_W_RECORDS:
|
|
265
|
+
# get symbol object
|
|
266
|
+
symobj = container[md["name"]]
|
|
267
|
+
|
|
268
|
+
# fastpath for scalar symbols
|
|
269
|
+
if md["dimension"] == 0 and md["number_records"] == 1:
|
|
270
|
+
ret, nrRecs = gdx.gdxDataReadRawStart(
|
|
271
|
+
gdxHandle, md["gdx_symbol_number"]
|
|
272
|
+
)
|
|
273
|
+
ret, keys, vals, a = gdx.gdxDataReadRaw(gdxHandle)
|
|
274
|
+
ret = gdx.gdxDataReadDone(gdxHandle)
|
|
275
|
+
|
|
276
|
+
symobj._records = pd.DataFrame(
|
|
277
|
+
[vals[: len(symobj._attributes)]],
|
|
278
|
+
columns=symobj._attributes,
|
|
279
|
+
dtype=float,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
else:
|
|
283
|
+
if mode.casefold() == "category":
|
|
284
|
+
try:
|
|
285
|
+
(
|
|
286
|
+
arrkeys,
|
|
287
|
+
arrvals,
|
|
288
|
+
unique_uels,
|
|
289
|
+
) = container._gams2np.gdxReadSymbolCat(
|
|
290
|
+
gdxHandle, md["name"], GDX_UELS, encoding=encoding
|
|
291
|
+
)
|
|
292
|
+
except:
|
|
293
|
+
raise Exception(
|
|
294
|
+
f"Could not properly read symbol {md['name']} from GDX file. "
|
|
295
|
+
"Try setting read argument mode='string'"
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# convert to categorical dataframe (return None if no data)
|
|
299
|
+
df = convert_to_categoricals_cat(arrkeys, arrvals, unique_uels)
|
|
300
|
+
|
|
301
|
+
elif mode.casefold() == "string":
|
|
302
|
+
try:
|
|
303
|
+
arrkeys, arrvals = container._gams2np.gdxReadSymbolStr(
|
|
304
|
+
gdxHandle, md["name"], GDX_UELS, encoding=encoding
|
|
305
|
+
)
|
|
306
|
+
except:
|
|
307
|
+
raise Exception(
|
|
308
|
+
f"Could not properly read symbol {md['name']} from GDX file."
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# convert to categorical dataframe (return None if no data)
|
|
312
|
+
df = convert_to_categoricals_str(arrkeys, arrvals, GDX_UELS[1:])
|
|
313
|
+
|
|
314
|
+
else:
|
|
315
|
+
raise ValueError("Unrecognized read `mode`")
|
|
316
|
+
|
|
317
|
+
# set records
|
|
318
|
+
symobj._records = df
|
|
319
|
+
|
|
320
|
+
# set column names
|
|
321
|
+
symobj._records.columns = (
|
|
322
|
+
generate_unique_labels(symobj.domain_names) + symobj._attributes
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# remap any acronyms to SpecialValues.NA
|
|
326
|
+
if len(acronyms) != 0:
|
|
327
|
+
if isinstance(
|
|
328
|
+
symobj, (abcs.ABCParameter, abcs.ABCVariable, abcs.ABCEquation)
|
|
329
|
+
):
|
|
330
|
+
for x in range(len(symobj._records.columns)):
|
|
331
|
+
if x >= symobj.dimension:
|
|
332
|
+
for a in acronyms:
|
|
333
|
+
idx = symobj._records.iloc[:, x][
|
|
334
|
+
symobj._records.iloc[:, x] == a * 1e301
|
|
335
|
+
].index
|
|
336
|
+
symobj._records.iloc[idx, x] = SpecialValues.NA
|
|
337
|
+
except Exception as err:
|
|
338
|
+
|
|
339
|
+
# close file
|
|
340
|
+
gdx.gdxClose(gdxHandle)
|
|
341
|
+
gdx.gdxFree(gdxHandle)
|
|
342
|
+
gdx.gdxLibraryUnload()
|
|
343
|
+
|
|
344
|
+
raise err
|
|
345
|
+
|
|
346
|
+
# close file
|
|
347
|
+
gdx.gdxClose(gdxHandle)
|
|
348
|
+
gdx.gdxFree(gdxHandle)
|
|
349
|
+
gdx.gdxLibraryUnload()
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def create_symbol_from_metadata(container: "Container", metadata: dict) -> None:
|
|
353
|
+
"""
|
|
354
|
+
Create a symbol object in the specified Container based on provided metadata.
|
|
355
|
+
|
|
356
|
+
This function creates a symbol object in the given Container based on the provided metadata.
|
|
357
|
+
The metadata includes information such as the symbol type, domain, description, and more.
|
|
358
|
+
|
|
359
|
+
Parameters
|
|
360
|
+
----------
|
|
361
|
+
container : Container
|
|
362
|
+
The Container where the symbol object will be created.
|
|
363
|
+
metadata : dict
|
|
364
|
+
Metadata containing information about the symbol to be created. It should include:
|
|
365
|
+
- 'name': The name of the symbol.
|
|
366
|
+
- 'type': The GAMS type of the symbol (e.g., gdx.GMS_DT_SET, gdx.GMS_DT_PAR, gdx.GMS_DT_VAR, gdx.GMS_DT_EQU, gdx.GMS_DT_ALIAS).
|
|
367
|
+
- 'userinfo': The GAMS userinfo of the symbol (subtype).
|
|
368
|
+
- 'domain': The domain associated with the symbol.
|
|
369
|
+
- 'description': The description or documentation for the symbol.
|
|
370
|
+
|
|
371
|
+
Raises
|
|
372
|
+
------
|
|
373
|
+
Exception
|
|
374
|
+
If the provided metadata indicates an unknown GDX symbol classification.
|
|
375
|
+
"""
|
|
376
|
+
if metadata["type"] == gdx.GMS_DT_ALIAS:
|
|
377
|
+
# test for universe alias
|
|
378
|
+
if metadata["userinfo"] != 0:
|
|
379
|
+
try:
|
|
380
|
+
Alias._from_gams(
|
|
381
|
+
container, metadata["name"], container.data[metadata["parent_set"]]
|
|
382
|
+
)
|
|
383
|
+
except Exception as err:
|
|
384
|
+
raise Exception(
|
|
385
|
+
(
|
|
386
|
+
f"Cannot create the Alias symbol `{metadata['name']}` "
|
|
387
|
+
f"because the parent set (`{metadata['parent_set']}`) is not "
|
|
388
|
+
"being read into the in the Container. "
|
|
389
|
+
"Alias symbols require the parent set object to exist in the Container. "
|
|
390
|
+
f"Add `{metadata['parent_set']}` to the list of symbols to read."
|
|
391
|
+
)
|
|
392
|
+
)
|
|
393
|
+
else:
|
|
394
|
+
UniverseAlias._from_gams(container, metadata["name"])
|
|
395
|
+
|
|
396
|
+
# regular set
|
|
397
|
+
elif metadata["type"] == gdx.GMS_DT_SET and metadata["userinfo"] == 0:
|
|
398
|
+
Set._from_gams(
|
|
399
|
+
container,
|
|
400
|
+
metadata["name"],
|
|
401
|
+
metadata["domain"],
|
|
402
|
+
is_singleton=False,
|
|
403
|
+
description=metadata["description"],
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
# singleton set
|
|
407
|
+
elif metadata["type"] == gdx.GMS_DT_SET and metadata["userinfo"] == 1:
|
|
408
|
+
Set._from_gams(
|
|
409
|
+
container,
|
|
410
|
+
metadata["name"],
|
|
411
|
+
metadata["domain"],
|
|
412
|
+
is_singleton=True,
|
|
413
|
+
description=metadata["description"],
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
# parameters
|
|
417
|
+
elif metadata["type"] == gdx.GMS_DT_PAR:
|
|
418
|
+
Parameter._from_gams(
|
|
419
|
+
container,
|
|
420
|
+
metadata["name"],
|
|
421
|
+
metadata["domain"],
|
|
422
|
+
description=metadata["description"],
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
# variables
|
|
426
|
+
elif metadata["type"] == gdx.GMS_DT_VAR:
|
|
427
|
+
Variable._from_gams(
|
|
428
|
+
container,
|
|
429
|
+
metadata["name"],
|
|
430
|
+
GAMS_VARIABLE_SUBTYPES.get(metadata["userinfo"], "free"),
|
|
431
|
+
metadata["domain"],
|
|
432
|
+
description=metadata["description"],
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# equations
|
|
436
|
+
elif metadata["type"] == gdx.GMS_DT_EQU:
|
|
437
|
+
Equation._from_gams(
|
|
438
|
+
container,
|
|
439
|
+
metadata["name"],
|
|
440
|
+
GAMS_EQUATION_SUBTYPES.get(metadata["userinfo"], "eq"),
|
|
441
|
+
metadata["domain"],
|
|
442
|
+
description=metadata["description"],
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# unknown symbols
|
|
446
|
+
else:
|
|
447
|
+
raise Exception(
|
|
448
|
+
f"Unknown GDX symbol classification (GAMS Type= {metadata['type']}, "
|
|
449
|
+
f"GAMS Subtype= {metadata['userinfo']}). ",
|
|
450
|
+
f"Cannot load symbol `{metadata['name']}`",
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def gdx_get_metadata_by_number(
|
|
455
|
+
container: "Container", gdxHandle, symbol_number: int, encoding: Union[None, str]
|
|
456
|
+
) -> dict:
|
|
457
|
+
"""
|
|
458
|
+
Retrieve metadata for a GDX symbol by its symbol number.
|
|
459
|
+
|
|
460
|
+
This function retrieves metadata for a GDX symbol in a Container by specifying its symbol number.
|
|
461
|
+
|
|
462
|
+
Parameters
|
|
463
|
+
----------
|
|
464
|
+
container : Container
|
|
465
|
+
The Container where the symbol is located.
|
|
466
|
+
|
|
467
|
+
gdxHandle : gdx.new_gdxHandle_tp()
|
|
468
|
+
The GDX handle or path to the GDX file where the symbol is stored.
|
|
469
|
+
|
|
470
|
+
symbol_number : int
|
|
471
|
+
The symbol number of the GDX symbol for which metadata is to be retrieved.
|
|
472
|
+
|
|
473
|
+
encoding : None | str
|
|
474
|
+
The encoding to use when reading symbols from the GDX file. Default is None.
|
|
475
|
+
|
|
476
|
+
Returns
|
|
477
|
+
-------
|
|
478
|
+
dict
|
|
479
|
+
A dictionary containing metadata for the GDX symbol.
|
|
480
|
+
"""
|
|
481
|
+
ret, syid, dimen, typ = gdx.gdxSymbolInfo(gdxHandle, symbol_number)
|
|
482
|
+
synr, nrecs, userinfo, _ = gdx.gdxSymbolInfoX(gdxHandle, symbol_number)
|
|
483
|
+
domain_type, domain = gdx.gdxSymbolGetDomainX(gdxHandle, symbol_number)
|
|
484
|
+
expltxt = container._gams2np._gdxGetSymbolExplTxt(
|
|
485
|
+
gdxHandle, symbol_number, encoding=encoding
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
# gdx specific adjustment for equations
|
|
489
|
+
if typ == gdx.GMS_DT_EQU:
|
|
490
|
+
userinfo = userinfo - gdx.GMS_EQU_USERINFO_BASE
|
|
491
|
+
|
|
492
|
+
if typ == gdx.GMS_DT_ALIAS:
|
|
493
|
+
_, parent_set, _, _ = gdx.gdxSymbolInfo(gdxHandle, userinfo)
|
|
494
|
+
else:
|
|
495
|
+
parent_set = None
|
|
496
|
+
|
|
497
|
+
# special handling of i(i) -- convert to relaxed domain_type
|
|
498
|
+
if dimen == 1:
|
|
499
|
+
if syid == domain[0]:
|
|
500
|
+
domain_type = 2
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
"name": syid,
|
|
504
|
+
"gdx_symbol_number": symbol_number,
|
|
505
|
+
"dimension": dimen,
|
|
506
|
+
"type": typ,
|
|
507
|
+
"userinfo": userinfo,
|
|
508
|
+
"number_records": nrecs,
|
|
509
|
+
"description": expltxt,
|
|
510
|
+
"domain_type": domain_type,
|
|
511
|
+
"domain": domain,
|
|
512
|
+
"parent_set": parent_set,
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def gdx_get_metadata_by_names(
|
|
517
|
+
container: "Container",
|
|
518
|
+
gdxHandle,
|
|
519
|
+
symbol_names: Union[str, List[str]],
|
|
520
|
+
encoding: Union[None, str],
|
|
521
|
+
) -> List[dict]:
|
|
522
|
+
"""
|
|
523
|
+
Retrieve metadata for GDX symbols by their names.
|
|
524
|
+
|
|
525
|
+
This function retrieves metadata for one or more GDX symbols in a Container based on their names.
|
|
526
|
+
|
|
527
|
+
Parameters
|
|
528
|
+
----------
|
|
529
|
+
container: Container
|
|
530
|
+
The Container where the symbols are located.
|
|
531
|
+
|
|
532
|
+
gdxHandle: gdx.new_gdxHandle_tp()
|
|
533
|
+
The GDX handle or path to the GDX file where the symbols are stored.
|
|
534
|
+
|
|
535
|
+
symbol_names: str | List[str]
|
|
536
|
+
The name or list of names of the GDX symbols for which metadata is to be retrieved.
|
|
537
|
+
|
|
538
|
+
encoding: None | str
|
|
539
|
+
The encoding used to decode the symbol descriptions. If None, default encoding is used.
|
|
540
|
+
|
|
541
|
+
Returns
|
|
542
|
+
-------
|
|
543
|
+
List[dict]
|
|
544
|
+
A list of dictionaries, each containing metadata for a GDX symbol.
|
|
545
|
+
|
|
546
|
+
Raises
|
|
547
|
+
------
|
|
548
|
+
ValueError
|
|
549
|
+
If symbol does not exist
|
|
550
|
+
|
|
551
|
+
Notes
|
|
552
|
+
-----
|
|
553
|
+
- This function is typically used during the process of reading symbols from a GDX file.
|
|
554
|
+
- It retrieves metadata for one or more GDX symbols identified by their names.
|
|
555
|
+
- The retrieved metadata provides information about the symbols' attributes and domains.
|
|
556
|
+
"""
|
|
557
|
+
if isinstance(symbol_names, str):
|
|
558
|
+
symbol_names = [symbol_names]
|
|
559
|
+
|
|
560
|
+
metadata = []
|
|
561
|
+
for sym in symbol_names:
|
|
562
|
+
ret, symnr = gdx.gdxFindSymbol(gdxHandle, sym)
|
|
563
|
+
if symnr == -1:
|
|
564
|
+
raise ValueError(
|
|
565
|
+
f"User specified to read symbol `{sym}`, "
|
|
566
|
+
"but it does not exist in the GDX file."
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
ret, syid, dimen, typ = gdx.gdxSymbolInfo(gdxHandle, symnr)
|
|
570
|
+
synr, nrecs, userinfo, _ = gdx.gdxSymbolInfoX(gdxHandle, symnr)
|
|
571
|
+
domain_type, domain = gdx.gdxSymbolGetDomainX(gdxHandle, symnr)
|
|
572
|
+
expltxt = container._gams2np._gdxGetSymbolExplTxt(
|
|
573
|
+
gdxHandle, symnr, encoding=encoding
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
# gdx specific adjustment for equations
|
|
577
|
+
if typ == gdx.GMS_DT_EQU:
|
|
578
|
+
userinfo = userinfo - gdx.GMS_EQU_USERINFO_BASE
|
|
579
|
+
|
|
580
|
+
if typ == gdx.GMS_DT_ALIAS:
|
|
581
|
+
_, parent_set, _, _ = gdx.gdxSymbolInfo(gdxHandle, userinfo)
|
|
582
|
+
else:
|
|
583
|
+
parent_set = None
|
|
584
|
+
|
|
585
|
+
# special handling of i(i) -- convert to relaxed domain_type
|
|
586
|
+
if dimen == 1:
|
|
587
|
+
if syid == domain[0]:
|
|
588
|
+
domain_type = 2
|
|
589
|
+
|
|
590
|
+
metadata.append(
|
|
591
|
+
{
|
|
592
|
+
"name": syid,
|
|
593
|
+
"gdx_symbol_number": symnr,
|
|
594
|
+
"dimension": dimen,
|
|
595
|
+
"type": typ,
|
|
596
|
+
"userinfo": userinfo,
|
|
597
|
+
"number_records": nrecs,
|
|
598
|
+
"description": expltxt,
|
|
599
|
+
"domain_type": domain_type,
|
|
600
|
+
"domain": domain,
|
|
601
|
+
"parent_set": parent_set,
|
|
602
|
+
}
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
return metadata
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def container_write(
|
|
609
|
+
container: "Container",
|
|
610
|
+
write_to: Union[str, os.PathLike],
|
|
611
|
+
symbols: Union[None, Sequence],
|
|
612
|
+
uel_priority: Union[None, Sequence],
|
|
613
|
+
compress: bool,
|
|
614
|
+
mode: str,
|
|
615
|
+
eps_to_zero: bool,
|
|
616
|
+
) -> None:
|
|
617
|
+
"""
|
|
618
|
+
Write data from a Container to a GDX (GAMS Data Exchange) file.
|
|
619
|
+
|
|
620
|
+
This function writes data from a Container to a GDX file. The GDX file can store symbols, sets, parameters,
|
|
621
|
+
variables, and equations. You can specify which symbols to write, set the UEL (Unique Element Label) priority,
|
|
622
|
+
enable compression, and choose the writing mode (category or string).
|
|
623
|
+
|
|
624
|
+
Parameters
|
|
625
|
+
----------
|
|
626
|
+
container: Container
|
|
627
|
+
The Container containing the data to be written.
|
|
628
|
+
|
|
629
|
+
write_to: str | Path
|
|
630
|
+
The path to the GDX file where the data will be written.
|
|
631
|
+
|
|
632
|
+
symbols: None | Sequence
|
|
633
|
+
A list of symbols to write to the GDX file. If None, all symbols in the container will be written.
|
|
634
|
+
|
|
635
|
+
uel_priority: None | Sequence
|
|
636
|
+
A list of UELs (Unique Element Labels) to be given priority during writing. These UELs will be written first.
|
|
637
|
+
|
|
638
|
+
compress: bool
|
|
639
|
+
If True, enable compression for the GDX file.
|
|
640
|
+
|
|
641
|
+
mode: str
|
|
642
|
+
The writing mode for symbols. Choose between "category" or "string" mode. In "category" mode, symbols are
|
|
643
|
+
written as categorical data, while in "string" mode, symbols are written as strings.
|
|
644
|
+
"""
|
|
645
|
+
if symbols is None:
|
|
646
|
+
write_all_symbols = True
|
|
647
|
+
else:
|
|
648
|
+
write_all_symbols = False
|
|
649
|
+
|
|
650
|
+
if write_all_symbols:
|
|
651
|
+
symbols = container.listSymbols()
|
|
652
|
+
|
|
653
|
+
# reorder symbols if necessary
|
|
654
|
+
if container._isValidSymbolOrder() == False:
|
|
655
|
+
container.reorderSymbols()
|
|
656
|
+
|
|
657
|
+
# get symbol objects to write
|
|
658
|
+
symobjs = container.getSymbols(symbols)
|
|
659
|
+
symnames = [sym.name for sym in symobjs]
|
|
660
|
+
|
|
661
|
+
# assert valid records
|
|
662
|
+
container._assert_valid_records(symbols=symbols)
|
|
663
|
+
|
|
664
|
+
# check symbols
|
|
665
|
+
for symobj in symobjs:
|
|
666
|
+
if not symobj.isValid():
|
|
667
|
+
raise Exception(
|
|
668
|
+
f"Cannot write to GDX because symbol `{symobj.name}` is invalid. "
|
|
669
|
+
"Use `<symbol>.isValid(verbose=True)` to debug."
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
# create gdxHandle
|
|
673
|
+
gdxHandle = gdx.new_gdxHandle_tp()
|
|
674
|
+
rc, msg = gdx.gdxCreateD(gdxHandle, container.system_directory, gdx.GMS_SSSIZE)
|
|
675
|
+
if not rc:
|
|
676
|
+
raise Exception(msg)
|
|
677
|
+
|
|
678
|
+
try:
|
|
679
|
+
was_relaxed = {}
|
|
680
|
+
# capture container modified state
|
|
681
|
+
orig_container_modified = container.modified
|
|
682
|
+
|
|
683
|
+
# open GDX for writing
|
|
684
|
+
if compress == False:
|
|
685
|
+
if not gdx.gdxOpenWrite(gdxHandle, write_to, "GAMS Transfer")[0]:
|
|
686
|
+
raise Exception(f"Error opening GDX `{write_to}` for writing")
|
|
687
|
+
else:
|
|
688
|
+
if not gdx.gdxOpenWriteEx(gdxHandle, write_to, "GAMS Transfer", 1)[0]:
|
|
689
|
+
raise Exception(
|
|
690
|
+
f"Error opening GDX (w/compression) `{write_to}` for writing"
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
# setting special values
|
|
694
|
+
specVals = gdx.doubleArray(gdx.GMS_SVIDX_MAX)
|
|
695
|
+
specVals[gdx.GMS_SVIDX_UNDEF] = SpecialValues.UNDEF
|
|
696
|
+
specVals[gdx.GMS_SVIDX_NA] = SpecialValues.NA
|
|
697
|
+
specVals[gdx.GMS_SVIDX_EPS] = (
|
|
698
|
+
SpecialValues.EPS if not eps_to_zero else gdx.GMS_SV_EPS
|
|
699
|
+
)
|
|
700
|
+
specVals[gdx.GMS_SVIDX_PINF] = SpecialValues.POSINF
|
|
701
|
+
specVals[gdx.GMS_SVIDX_MINF] = SpecialValues.NEGINF
|
|
702
|
+
|
|
703
|
+
rc = gdx.gdxSetSpecialValues(gdxHandle, specVals)
|
|
704
|
+
assert rc
|
|
705
|
+
|
|
706
|
+
#
|
|
707
|
+
# register the universe
|
|
708
|
+
# get UELS only once
|
|
709
|
+
if uel_priority is None:
|
|
710
|
+
uel_priority = []
|
|
711
|
+
|
|
712
|
+
UELS = uel_priority + container.getUELs(symbols=symnames)
|
|
713
|
+
|
|
714
|
+
# register UELs
|
|
715
|
+
try:
|
|
716
|
+
container._gams2np.gdxRegisterUels(gdxHandle, UELS)
|
|
717
|
+
except Exception as err:
|
|
718
|
+
raise err
|
|
719
|
+
|
|
720
|
+
# check if symbol domains are also being written -- if not, relax the domain for writing
|
|
721
|
+
# retain the string set label, do not relax to "*" domains
|
|
722
|
+
for symobj in symobjs:
|
|
723
|
+
if symobj.domain_type == "regular":
|
|
724
|
+
if any(not isin(domsymobj, symobjs) for domsymobj in symobj.domain):
|
|
725
|
+
was_relaxed[symobj.name] = {
|
|
726
|
+
"object": symobj,
|
|
727
|
+
"domain": symobj.domain,
|
|
728
|
+
"modified": symobj.modified,
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
# relax the domain
|
|
732
|
+
symobj.domain = [
|
|
733
|
+
dom.name if isinstance(dom, abcs.AnyContainerSymbol) else dom
|
|
734
|
+
for dom in symobj.domain
|
|
735
|
+
]
|
|
736
|
+
|
|
737
|
+
#
|
|
738
|
+
# main write
|
|
739
|
+
for symname, symobj in zip(symnames, symobjs):
|
|
740
|
+
if isinstance(symobj, abcs.AnyContainerAlias):
|
|
741
|
+
if isinstance(symobj, abcs.ABCUniverseAlias):
|
|
742
|
+
gdx.gdxAddAlias(gdxHandle, "*", symname)
|
|
743
|
+
else:
|
|
744
|
+
gdx.gdxAddAlias(gdxHandle, symobj.alias_with.name, symname)
|
|
745
|
+
|
|
746
|
+
else:
|
|
747
|
+
# adjust equation userinfo for GDX
|
|
748
|
+
if isinstance(symobj, abcs.ABCEquation):
|
|
749
|
+
symobj._gams_subtype = (
|
|
750
|
+
symobj._gams_subtype + gdx.GMS_EQU_USERINFO_BASE
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
if symobj.number_records == 0:
|
|
754
|
+
power_write_symbol_no_records(gdxHandle, symobj)
|
|
755
|
+
|
|
756
|
+
elif symobj.number_records == 1 and symobj.dimension == 0:
|
|
757
|
+
power_write_symbol_scalar_record(gdxHandle, symobj)
|
|
758
|
+
|
|
759
|
+
else:
|
|
760
|
+
# adjust write mode
|
|
761
|
+
if mode.casefold() == "category":
|
|
762
|
+
power_write_category(container, gdxHandle, symobj)
|
|
763
|
+
|
|
764
|
+
elif mode.casefold() == "string":
|
|
765
|
+
power_write_string(container, gdxHandle, symobj)
|
|
766
|
+
|
|
767
|
+
else:
|
|
768
|
+
raise Exception(f"Write mode not supported: {mode}")
|
|
769
|
+
|
|
770
|
+
current_error_count = gdx.gdxDataErrorCount(gdxHandle)
|
|
771
|
+
|
|
772
|
+
if current_error_count != 0:
|
|
773
|
+
raise Exception(
|
|
774
|
+
f"Encountered data errors with symbol `{symname}`. "
|
|
775
|
+
"Possible causes are from duplicate records and/or domain violations. \n\n"
|
|
776
|
+
"Use 'hasDuplicateRecords', 'findDuplicateRecords', 'dropDuplicateRecords', "
|
|
777
|
+
"and/or 'countDuplicateRecords' to find/resolve duplicate records. \n"
|
|
778
|
+
"Use 'hasDomainViolations', 'findDomainViolations', 'dropDomainViolations', "
|
|
779
|
+
"and/or 'countDomainViolations' to find/resolve domain violations. \n\n"
|
|
780
|
+
"GDX file was not created successfully."
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
except Exception as err:
|
|
784
|
+
# close file
|
|
785
|
+
gdx.gdxClose(gdxHandle)
|
|
786
|
+
gdx.gdxFree(gdxHandle)
|
|
787
|
+
gdx.gdxLibraryUnload()
|
|
788
|
+
|
|
789
|
+
# delete file
|
|
790
|
+
if os.path.exists(write_to):
|
|
791
|
+
os.remove(write_to)
|
|
792
|
+
|
|
793
|
+
# raise error
|
|
794
|
+
raise err
|
|
795
|
+
|
|
796
|
+
finally:
|
|
797
|
+
# restore domains in the Container
|
|
798
|
+
for _, properties in was_relaxed.items():
|
|
799
|
+
symobj = properties["object"]
|
|
800
|
+
symobj._domain = properties["domain"]
|
|
801
|
+
symobj._modified = properties["modified"]
|
|
802
|
+
|
|
803
|
+
# reset container modified flag
|
|
804
|
+
container._modified = orig_container_modified
|
|
805
|
+
|
|
806
|
+
# auto convert file and close
|
|
807
|
+
gdx.gdxAutoConvert(gdxHandle, 0)
|
|
808
|
+
gdx.gdxClose(gdxHandle)
|
|
809
|
+
gdx.gdxFree(gdxHandle)
|
|
810
|
+
gdx.gdxLibraryUnload()
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def power_write_symbol_no_records(
|
|
814
|
+
gdxHandle, symobj: Union["Set", "Parameter", "Variable", "Equation"]
|
|
815
|
+
) -> None:
|
|
816
|
+
"""
|
|
817
|
+
Write a GAMS symbol with no records to a GDX file.
|
|
818
|
+
|
|
819
|
+
This function is used to write a GAMS symbol (Set, Parameter, Variable, or Equation) to a GDX file when the symbol
|
|
820
|
+
has no records. It sets up the necessary information for the symbol, such as its name, description, dimension, type,
|
|
821
|
+
and subtype. The symbol's domain is also defined based on its domain status (regular or relaxed).
|
|
822
|
+
|
|
823
|
+
Parameters
|
|
824
|
+
----------
|
|
825
|
+
gdxHandle: gdx.new_gdxHandle_tp()
|
|
826
|
+
The GDX handle representing the GDX file where the symbol will be written.
|
|
827
|
+
|
|
828
|
+
symobj: Set | Parameter | Variable | Equation
|
|
829
|
+
The GAMS symbol (Set, Parameter, Variable, or Equation) to be written to the GDX file.
|
|
830
|
+
"""
|
|
831
|
+
gdx.gdxDataWriteStrStart(
|
|
832
|
+
gdxHandle,
|
|
833
|
+
symobj.name,
|
|
834
|
+
symobj.description,
|
|
835
|
+
symobj.dimension,
|
|
836
|
+
symobj._gams_type,
|
|
837
|
+
symobj._gams_subtype,
|
|
838
|
+
)
|
|
839
|
+
|
|
840
|
+
# define domain
|
|
841
|
+
if symobj._domain_status is DomainStatus.regular:
|
|
842
|
+
gdx.gdxSymbolSetDomain(gdxHandle, symobj.domain_names)
|
|
843
|
+
|
|
844
|
+
elif symobj._domain_status is DomainStatus.relaxed:
|
|
845
|
+
ret, synr = gdx.gdxFindSymbol(gdxHandle, symobj.name)
|
|
846
|
+
gdx.gdxSymbolSetDomainX(gdxHandle, synr, symobj.domain_names)
|
|
847
|
+
|
|
848
|
+
else:
|
|
849
|
+
...
|
|
850
|
+
|
|
851
|
+
gdx.gdxDataWriteDone(gdxHandle)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def power_write_symbol_scalar_record(
|
|
855
|
+
gdxHandle, symobj: Union["Set", "Parameter", "Variable", "Equation"]
|
|
856
|
+
) -> None:
|
|
857
|
+
"""
|
|
858
|
+
Write a GAMS symbol with a scalar record to a GDX file.
|
|
859
|
+
|
|
860
|
+
This function is used to write a GAMS symbol (Set, Parameter, Variable, or Equation) to a GDX file when the symbol
|
|
861
|
+
has a single scalar record. It sets up the necessary information for the symbol, such as its name, description,
|
|
862
|
+
dimension, type, and subtype, and writes the scalar record to the GDX file.
|
|
863
|
+
|
|
864
|
+
Parameters
|
|
865
|
+
----------
|
|
866
|
+
gdxHandle: gdx.new_gdxHandle_tp()
|
|
867
|
+
The GDX handle representing the GDX file where the symbol will be written.
|
|
868
|
+
|
|
869
|
+
symobj: Set | Parameter | Variable | Equation
|
|
870
|
+
The GAMS symbol (Set, Parameter, Variable, or Equation) with a scalar record to be written to the GDX file.
|
|
871
|
+
"""
|
|
872
|
+
gdx.gdxDataWriteStrStart(
|
|
873
|
+
gdxHandle,
|
|
874
|
+
symobj.name,
|
|
875
|
+
symobj.description,
|
|
876
|
+
symobj.dimension,
|
|
877
|
+
symobj._gams_type,
|
|
878
|
+
symobj._gams_subtype,
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
vals = symobj.records.to_numpy().reshape((-1,))
|
|
882
|
+
|
|
883
|
+
idx = np.arange(vals.size)
|
|
884
|
+
arr = np.zeros(gdx.GMS_VAL_MAX, dtype=np.float64)
|
|
885
|
+
arr[idx] = vals[idx]
|
|
886
|
+
|
|
887
|
+
values = gdx.doubleArray(gdx.GMS_VAL_MAX)
|
|
888
|
+
values[gdx.GMS_VAL_LEVEL] = arr[0]
|
|
889
|
+
values[gdx.GMS_VAL_MARGINAL] = arr[1]
|
|
890
|
+
values[gdx.GMS_VAL_LOWER] = arr[2]
|
|
891
|
+
values[gdx.GMS_VAL_UPPER] = arr[3]
|
|
892
|
+
values[gdx.GMS_VAL_SCALE] = arr[4]
|
|
893
|
+
|
|
894
|
+
gdx.gdxDataWriteStr(gdxHandle, [], values)
|
|
895
|
+
gdx.gdxDataWriteDone(gdxHandle)
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
def power_write_string(
|
|
899
|
+
container: "Container",
|
|
900
|
+
gdxHandle,
|
|
901
|
+
symobj: Union["Set", "Parameter", "Variable", "Equation"],
|
|
902
|
+
) -> None:
|
|
903
|
+
"""
|
|
904
|
+
Write a GAMS symbol to a GDX file with 'string' mode.
|
|
905
|
+
|
|
906
|
+
Parameters
|
|
907
|
+
----------
|
|
908
|
+
container: Container
|
|
909
|
+
The Container containing the symbol to be written to the GDX file.
|
|
910
|
+
|
|
911
|
+
gdxHandle: gdx.new_gdxHandle_tp()
|
|
912
|
+
The GDX handle representing the GDX file where the symbol will be written.
|
|
913
|
+
|
|
914
|
+
symobj: Set | Parameter | Variable | Equation
|
|
915
|
+
The GAMS symbol (Set, Parameter, Variable, or Equation) to be written to the GDX file.
|
|
916
|
+
"""
|
|
917
|
+
# get keys and values arrays
|
|
918
|
+
arrkeys, arrvals = get_keys_and_values(symobj, mode="string")
|
|
919
|
+
|
|
920
|
+
# final type checking
|
|
921
|
+
if not isinstance(symobj, abcs.ABCSet):
|
|
922
|
+
if not np.issubdtype(arrvals.dtype, np.floating):
|
|
923
|
+
arrvals = arrvals.astype(float)
|
|
924
|
+
|
|
925
|
+
# temporary adjustment to domain argument
|
|
926
|
+
if symobj._domain_status is DomainStatus.regular:
|
|
927
|
+
domain = symobj.domain_names
|
|
928
|
+
elif symobj._domain_status is DomainStatus.relaxed:
|
|
929
|
+
domain = ["*"] * symobj.dimension
|
|
930
|
+
elif symobj._domain_status is DomainStatus.none:
|
|
931
|
+
domain = None
|
|
932
|
+
|
|
933
|
+
# power write
|
|
934
|
+
try:
|
|
935
|
+
container._gams2np.gdxWriteSymbolStr(
|
|
936
|
+
gdxHandle,
|
|
937
|
+
symobj.name,
|
|
938
|
+
symobj.description,
|
|
939
|
+
symobj.dimension,
|
|
940
|
+
symobj._gams_type,
|
|
941
|
+
symobj._gams_subtype,
|
|
942
|
+
arrkeys,
|
|
943
|
+
arrvals,
|
|
944
|
+
domain,
|
|
945
|
+
)
|
|
946
|
+
except Exception as err:
|
|
947
|
+
raise Exception(
|
|
948
|
+
f"Error encountered when writing symbol `{symobj.name}`. "
|
|
949
|
+
f"GDX Error: '{err}'. \n\n"
|
|
950
|
+
"GDX file was not created successfully."
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
# assign actual relaxed domain labels
|
|
954
|
+
if symobj._domain_status is DomainStatus.relaxed:
|
|
955
|
+
ret, synr = gdx.gdxFindSymbol(gdxHandle, symobj.name)
|
|
956
|
+
gdx.gdxSymbolSetDomainX(gdxHandle, synr, symobj.domain_names)
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
def power_write_category(
|
|
960
|
+
container: "Container",
|
|
961
|
+
gdxHandle,
|
|
962
|
+
symobj: Union["Set", "Parameter", "Variable", "Equation"],
|
|
963
|
+
) -> None:
|
|
964
|
+
"""
|
|
965
|
+
Write a GAMS symbol to a GDX file with 'categorical' mode.
|
|
966
|
+
|
|
967
|
+
Parameters
|
|
968
|
+
----------
|
|
969
|
+
container: Container
|
|
970
|
+
The Container containing the symbol to be written to the GDX file.
|
|
971
|
+
|
|
972
|
+
gdxHandle: gdx.new_gdxHandle_tp()
|
|
973
|
+
The GDX handle representing the GDX file where the symbol will be written.
|
|
974
|
+
|
|
975
|
+
symobj: Set | Parameter | Variable | Equation
|
|
976
|
+
The GAMS symbol (Set, Parameter, Variable, or Equation) to be written to the GDX file.
|
|
977
|
+
"""
|
|
978
|
+
# initialize major list
|
|
979
|
+
majorList = [[]] * symobj.dimension
|
|
980
|
+
|
|
981
|
+
for i in range(symobj.dimension):
|
|
982
|
+
# create major list
|
|
983
|
+
majorList[i] = symobj.getUELs(i)
|
|
984
|
+
|
|
985
|
+
# get keys and values arrays
|
|
986
|
+
arrkeys, arrvals = get_keys_and_values(symobj, mode="category")
|
|
987
|
+
|
|
988
|
+
# final type checking
|
|
989
|
+
if not np.issubdtype(arrkeys.dtype, np.integer):
|
|
990
|
+
arrkeys = arrkeys.astype(int)
|
|
991
|
+
|
|
992
|
+
if not isinstance(symobj, abcs.ABCSet):
|
|
993
|
+
if not np.issubdtype(arrvals.dtype, np.floating):
|
|
994
|
+
arrvals = arrvals.astype(float)
|
|
995
|
+
|
|
996
|
+
# temporary adjustment to domain argument
|
|
997
|
+
if symobj._domain_status is DomainStatus.regular:
|
|
998
|
+
domain = symobj.domain_names
|
|
999
|
+
elif symobj._domain_status is DomainStatus.relaxed:
|
|
1000
|
+
domain = ["*"] * symobj.dimension
|
|
1001
|
+
elif symobj._domain_status is DomainStatus.none:
|
|
1002
|
+
domain = None
|
|
1003
|
+
|
|
1004
|
+
# power write
|
|
1005
|
+
try:
|
|
1006
|
+
container._gams2np.gdxWriteSymbolCat(
|
|
1007
|
+
gdxHandle,
|
|
1008
|
+
symobj.name,
|
|
1009
|
+
symobj.description,
|
|
1010
|
+
symobj.dimension,
|
|
1011
|
+
symobj._gams_type,
|
|
1012
|
+
symobj._gams_subtype,
|
|
1013
|
+
arrkeys,
|
|
1014
|
+
arrvals,
|
|
1015
|
+
majorList,
|
|
1016
|
+
domain,
|
|
1017
|
+
)
|
|
1018
|
+
|
|
1019
|
+
except Exception as err:
|
|
1020
|
+
raise Exception(
|
|
1021
|
+
f"Error encountered when writing symbol `{symobj.name}`. "
|
|
1022
|
+
f"GDX Error: '{err}'. \n\n"
|
|
1023
|
+
"GDX file was not created successfully."
|
|
1024
|
+
)
|
|
1025
|
+
|
|
1026
|
+
# assign actual relaxed domain labels
|
|
1027
|
+
if symobj._domain_status is DomainStatus.relaxed:
|
|
1028
|
+
ret, synr = gdx.gdxFindSymbol(gdxHandle, symobj.name)
|
|
1029
|
+
gdx.gdxSymbolSetDomainX(gdxHandle, synr, symobj.domain_names)
|