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.
Files changed (257) hide show
  1. gams/__init__.py +27 -0
  2. gams/_version.py +1 -0
  3. gams/connect/__init__.py +28 -0
  4. gams/connect/agents/__init__.py +24 -0
  5. gams/connect/agents/_excel/__init__.py +32 -0
  6. gams/connect/agents/_excel/excelagent.py +312 -0
  7. gams/connect/agents/_excel/workbook.py +155 -0
  8. gams/connect/agents/_sqlconnectors/__init__.py +42 -0
  9. gams/connect/agents/_sqlconnectors/_accesshandler.py +211 -0
  10. gams/connect/agents/_sqlconnectors/_databasehandler.py +250 -0
  11. gams/connect/agents/_sqlconnectors/_mysqlhandler.py +168 -0
  12. gams/connect/agents/_sqlconnectors/_postgreshandler.py +131 -0
  13. gams/connect/agents/_sqlconnectors/_pyodbchandler.py +112 -0
  14. gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +74 -0
  15. gams/connect/agents/_sqlconnectors/_sqlitehandler.py +262 -0
  16. gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +179 -0
  17. gams/connect/agents/concatenate.py +440 -0
  18. gams/connect/agents/connectagent.py +743 -0
  19. gams/connect/agents/csvreader.py +675 -0
  20. gams/connect/agents/csvwriter.py +151 -0
  21. gams/connect/agents/domainwriter.py +143 -0
  22. gams/connect/agents/excelreader.py +756 -0
  23. gams/connect/agents/excelwriter.py +467 -0
  24. gams/connect/agents/filter.py +223 -0
  25. gams/connect/agents/gamsreader.py +112 -0
  26. gams/connect/agents/gamswriter.py +239 -0
  27. gams/connect/agents/gdxreader.py +109 -0
  28. gams/connect/agents/gdxwriter.py +146 -0
  29. gams/connect/agents/labelmanipulator.py +303 -0
  30. gams/connect/agents/projection.py +539 -0
  31. gams/connect/agents/pythoncode.py +71 -0
  32. gams/connect/agents/rawcsvreader.py +248 -0
  33. gams/connect/agents/rawexcelreader.py +312 -0
  34. gams/connect/agents/schema/CSVReader.yaml +92 -0
  35. gams/connect/agents/schema/CSVWriter.yaml +44 -0
  36. gams/connect/agents/schema/Concatenate.yaml +52 -0
  37. gams/connect/agents/schema/DomainWriter.yaml +25 -0
  38. gams/connect/agents/schema/ExcelReader.yaml +121 -0
  39. gams/connect/agents/schema/ExcelWriter.yaml +78 -0
  40. gams/connect/agents/schema/Filter.yaml +74 -0
  41. gams/connect/agents/schema/GAMSReader.yaml +20 -0
  42. gams/connect/agents/schema/GAMSWriter.yaml +47 -0
  43. gams/connect/agents/schema/GDXReader.yaml +23 -0
  44. gams/connect/agents/schema/GDXWriter.yaml +32 -0
  45. gams/connect/agents/schema/LabelManipulator.yaml +99 -0
  46. gams/connect/agents/schema/Projection.yaml +24 -0
  47. gams/connect/agents/schema/PythonCode.yaml +6 -0
  48. gams/connect/agents/schema/RawCSVReader.yaml +34 -0
  49. gams/connect/agents/schema/RawExcelReader.yaml +42 -0
  50. gams/connect/agents/schema/SQLReader.yaml +75 -0
  51. gams/connect/agents/schema/SQLWriter.yaml +103 -0
  52. gams/connect/agents/sqlreader.py +301 -0
  53. gams/connect/agents/sqlwriter.py +276 -0
  54. gams/connect/connectdatabase.py +275 -0
  55. gams/connect/connectvalidator.py +93 -0
  56. gams/connect/errors.py +34 -0
  57. gams/control/__init__.py +136 -0
  58. gams/control/database.py +2231 -0
  59. gams/control/execution.py +1900 -0
  60. gams/control/options.py +2792 -0
  61. gams/control/workspace.py +1198 -0
  62. gams/core/__init__.py +24 -0
  63. gams/core/cfg/__init__.py +26 -0
  64. gams/core/cfg/_cfgmcc.cp312-win_amd64.pyd +0 -0
  65. gams/core/cfg/cfgmcc.py +519 -0
  66. gams/core/dct/__init__.py +26 -0
  67. gams/core/dct/_dctmcc.cp312-win_amd64.pyd +0 -0
  68. gams/core/dct/dctmcc.py +574 -0
  69. gams/core/embedded/__init__.py +26 -0
  70. gams/core/embedded/gamsemb.py +1024 -0
  71. gams/core/emp/__init__.py +24 -0
  72. gams/core/emp/emplexer.py +89 -0
  73. gams/core/emp/empyacc.py +281 -0
  74. gams/core/gdx/__init__.py +26 -0
  75. gams/core/gdx/_gdxcc.cp312-win_amd64.pyd +0 -0
  76. gams/core/gdx/gdxcc.py +866 -0
  77. gams/core/gev/__init__.py +26 -0
  78. gams/core/gev/_gevmcc.cp312-win_amd64.pyd +0 -0
  79. gams/core/gev/gevmcc.py +855 -0
  80. gams/core/gmd/__init__.py +26 -0
  81. gams/core/gmd/_gmdcc.cp312-win_amd64.pyd +0 -0
  82. gams/core/gmd/gmdcc.py +917 -0
  83. gams/core/gmo/__init__.py +26 -0
  84. gams/core/gmo/_gmomcc.cp312-win_amd64.pyd +0 -0
  85. gams/core/gmo/gmomcc.py +2046 -0
  86. gams/core/idx/__init__.py +26 -0
  87. gams/core/idx/_idxcc.cp312-win_amd64.pyd +0 -0
  88. gams/core/idx/idxcc.py +510 -0
  89. gams/core/numpy/__init__.py +29 -0
  90. gams/core/numpy/_gams2numpy.cp312-win_amd64.pyd +0 -0
  91. gams/core/numpy/gams2numpy.py +1048 -0
  92. gams/core/opt/__init__.py +26 -0
  93. gams/core/opt/_optcc.cp312-win_amd64.pyd +0 -0
  94. gams/core/opt/optcc.py +840 -0
  95. gams/engine/__init__.py +204 -0
  96. gams/engine/api/__init__.py +13 -0
  97. gams/engine/api/auth_api.py +7653 -0
  98. gams/engine/api/cleanup_api.py +751 -0
  99. gams/engine/api/default_api.py +887 -0
  100. gams/engine/api/hypercube_api.py +2629 -0
  101. gams/engine/api/jobs_api.py +5229 -0
  102. gams/engine/api/licenses_api.py +2220 -0
  103. gams/engine/api/namespaces_api.py +7783 -0
  104. gams/engine/api/usage_api.py +5627 -0
  105. gams/engine/api/users_api.py +5931 -0
  106. gams/engine/api_client.py +804 -0
  107. gams/engine/api_response.py +21 -0
  108. gams/engine/configuration.py +601 -0
  109. gams/engine/exceptions.py +216 -0
  110. gams/engine/models/__init__.py +86 -0
  111. gams/engine/models/bad_input.py +89 -0
  112. gams/engine/models/cleanable_job_result.py +104 -0
  113. gams/engine/models/cleanable_job_result_page.py +113 -0
  114. gams/engine/models/engine_license.py +107 -0
  115. gams/engine/models/files_not_found.py +93 -0
  116. gams/engine/models/forwarded_token_response.py +112 -0
  117. gams/engine/models/generic_key_value_pair.py +89 -0
  118. gams/engine/models/hypercube.py +160 -0
  119. gams/engine/models/hypercube_page.py +111 -0
  120. gams/engine/models/hypercube_summary.py +91 -0
  121. gams/engine/models/hypercube_token.py +97 -0
  122. gams/engine/models/identity_provider.py +107 -0
  123. gams/engine/models/identity_provider_ldap.py +121 -0
  124. gams/engine/models/identity_provider_oauth2.py +146 -0
  125. gams/engine/models/identity_provider_oauth2_scope.py +89 -0
  126. gams/engine/models/identity_provider_oauth2_with_secret.py +152 -0
  127. gams/engine/models/identity_provider_oidc.py +133 -0
  128. gams/engine/models/identity_provider_oidc_with_secret.py +143 -0
  129. gams/engine/models/inex.py +91 -0
  130. gams/engine/models/invitation.py +136 -0
  131. gams/engine/models/invitation_quota.py +106 -0
  132. gams/engine/models/invitation_token.py +87 -0
  133. gams/engine/models/job.py +165 -0
  134. gams/engine/models/job_no_text_entry.py +138 -0
  135. gams/engine/models/job_no_text_entry_page.py +111 -0
  136. gams/engine/models/license.py +91 -0
  137. gams/engine/models/log_piece.py +96 -0
  138. gams/engine/models/message.py +87 -0
  139. gams/engine/models/message_and_token.py +99 -0
  140. gams/engine/models/message_with_webhook_id.py +89 -0
  141. gams/engine/models/model_auth_token.py +87 -0
  142. gams/engine/models/model_configuration.py +125 -0
  143. gams/engine/models/model_default_instance.py +99 -0
  144. gams/engine/models/model_default_user_instance.py +98 -0
  145. gams/engine/models/model_hypercube_job.py +106 -0
  146. gams/engine/models/model_hypercube_usage.py +130 -0
  147. gams/engine/models/model_instance_info.py +116 -0
  148. gams/engine/models/model_instance_info_full.py +123 -0
  149. gams/engine/models/model_instance_pool_info.py +112 -0
  150. gams/engine/models/model_job_labels.py +179 -0
  151. gams/engine/models/model_job_usage.py +133 -0
  152. gams/engine/models/model_pool_usage.py +124 -0
  153. gams/engine/models/model_usage.py +115 -0
  154. gams/engine/models/model_user.py +96 -0
  155. gams/engine/models/model_userinstance_info.py +119 -0
  156. gams/engine/models/model_userinstancepool_info.py +95 -0
  157. gams/engine/models/model_version.py +91 -0
  158. gams/engine/models/models.py +120 -0
  159. gams/engine/models/namespace.py +104 -0
  160. gams/engine/models/namespace_quota.py +96 -0
  161. gams/engine/models/namespace_with_permission.py +96 -0
  162. gams/engine/models/not_found.py +91 -0
  163. gams/engine/models/password_policy.py +97 -0
  164. gams/engine/models/perm_and_username.py +89 -0
  165. gams/engine/models/quota.py +117 -0
  166. gams/engine/models/quota_exceeded.py +97 -0
  167. gams/engine/models/status_code_meaning.py +89 -0
  168. gams/engine/models/stream_entry.py +89 -0
  169. gams/engine/models/system_wide_license.py +92 -0
  170. gams/engine/models/text_entries.py +87 -0
  171. gams/engine/models/text_entry.py +101 -0
  172. gams/engine/models/time_span.py +95 -0
  173. gams/engine/models/time_span_pool_worker.py +99 -0
  174. gams/engine/models/token_forward_error.py +87 -0
  175. gams/engine/models/user.py +127 -0
  176. gams/engine/models/user_group_member.py +96 -0
  177. gams/engine/models/user_groups.py +108 -0
  178. gams/engine/models/vapid_info.py +87 -0
  179. gams/engine/models/webhook.py +138 -0
  180. gams/engine/models/webhook_parameterized_event.py +99 -0
  181. gams/engine/py.typed +0 -0
  182. gams/engine/rest.py +258 -0
  183. gams/magic/__init__.py +32 -0
  184. gams/magic/gams_magic.py +142 -0
  185. gams/magic/interactive.py +402 -0
  186. gams/tools/__init__.py +30 -0
  187. gams/tools/errors.py +34 -0
  188. gams/tools/toolcollection/__init__.py +24 -0
  189. gams/tools/toolcollection/alg/__init__.py +24 -0
  190. gams/tools/toolcollection/alg/rank.py +51 -0
  191. gams/tools/toolcollection/data/__init__.py +24 -0
  192. gams/tools/toolcollection/data/csvread.py +444 -0
  193. gams/tools/toolcollection/data/csvwrite.py +311 -0
  194. gams/tools/toolcollection/data/exceldump.py +47 -0
  195. gams/tools/toolcollection/data/sqlitewrite.py +276 -0
  196. gams/tools/toolcollection/gdxservice/__init__.py +24 -0
  197. gams/tools/toolcollection/gdxservice/gdxencoding.py +104 -0
  198. gams/tools/toolcollection/gdxservice/gdxrename.py +94 -0
  199. gams/tools/toolcollection/linalg/__init__.py +24 -0
  200. gams/tools/toolcollection/linalg/cholesky.py +57 -0
  201. gams/tools/toolcollection/linalg/eigenvalue.py +56 -0
  202. gams/tools/toolcollection/linalg/eigenvector.py +58 -0
  203. gams/tools/toolcollection/linalg/invert.py +55 -0
  204. gams/tools/toolcollection/linalg/ols.py +138 -0
  205. gams/tools/toolcollection/tooltemplate.py +321 -0
  206. gams/tools/toolcollection/win32/__init__.py +24 -0
  207. gams/tools/toolcollection/win32/excelmerge.py +93 -0
  208. gams/tools/toolcollection/win32/exceltalk.py +76 -0
  209. gams/tools/toolcollection/win32/msappavail.py +49 -0
  210. gams/tools/toolcollection/win32/shellexecute.py +54 -0
  211. gams/tools/tools.py +116 -0
  212. gams/transfer/__init__.py +35 -0
  213. gams/transfer/_abcs/__init__.py +37 -0
  214. gams/transfer/_abcs/container_abcs.py +433 -0
  215. gams/transfer/_internals/__init__.py +63 -0
  216. gams/transfer/_internals/algorithms.py +436 -0
  217. gams/transfer/_internals/casepreservingdict.py +124 -0
  218. gams/transfer/_internals/constants.py +270 -0
  219. gams/transfer/_internals/domainviolation.py +103 -0
  220. gams/transfer/_internals/specialvalues.py +172 -0
  221. gams/transfer/containers/__init__.py +26 -0
  222. gams/transfer/containers/_container.py +1794 -0
  223. gams/transfer/containers/_io/__init__.py +28 -0
  224. gams/transfer/containers/_io/containers.py +164 -0
  225. gams/transfer/containers/_io/gdx.py +1029 -0
  226. gams/transfer/containers/_io/gmd.py +872 -0
  227. gams/transfer/containers/_mixins/__init__.py +26 -0
  228. gams/transfer/containers/_mixins/ccc.py +1274 -0
  229. gams/transfer/syms/__init__.py +33 -0
  230. gams/transfer/syms/_methods/__init__.py +24 -0
  231. gams/transfer/syms/_methods/tables.py +120 -0
  232. gams/transfer/syms/_methods/toDict.py +115 -0
  233. gams/transfer/syms/_methods/toList.py +83 -0
  234. gams/transfer/syms/_methods/toValue.py +60 -0
  235. gams/transfer/syms/_mixins/__init__.py +32 -0
  236. gams/transfer/syms/_mixins/equals.py +626 -0
  237. gams/transfer/syms/_mixins/generateRecords.py +499 -0
  238. gams/transfer/syms/_mixins/pivot.py +313 -0
  239. gams/transfer/syms/_mixins/pve.py +627 -0
  240. gams/transfer/syms/_mixins/sa.py +27 -0
  241. gams/transfer/syms/_mixins/sapve.py +27 -0
  242. gams/transfer/syms/_mixins/saua.py +27 -0
  243. gams/transfer/syms/_mixins/sauapve.py +199 -0
  244. gams/transfer/syms/_mixins/spve.py +1528 -0
  245. gams/transfer/syms/_mixins/ve.py +936 -0
  246. gams/transfer/syms/container_syms/__init__.py +31 -0
  247. gams/transfer/syms/container_syms/_alias.py +984 -0
  248. gams/transfer/syms/container_syms/_equation.py +333 -0
  249. gams/transfer/syms/container_syms/_parameter.py +973 -0
  250. gams/transfer/syms/container_syms/_set.py +604 -0
  251. gams/transfer/syms/container_syms/_universe_alias.py +461 -0
  252. gams/transfer/syms/container_syms/_variable.py +321 -0
  253. gamsapi-52.5.0.dist-info/METADATA +150 -0
  254. gamsapi-52.5.0.dist-info/RECORD +257 -0
  255. gamsapi-52.5.0.dist-info/WHEEL +5 -0
  256. gamsapi-52.5.0.dist-info/licenses/LICENSE +22 -0
  257. 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)