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,2231 @@
1
+ #
2
+ # GAMS - General Algebraic Modeling System Python API
3
+ #
4
+ # Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
5
+ # Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+ #
25
+
26
+ from gams.core.gdx import *
27
+ from gams.core.gmd import *
28
+ import gams.control.workspace
29
+ import os
30
+
31
+ SV_UNDEF = GMS_SV_UNDEF
32
+ SV_EPS = 4.94066e-324 # copied from value in C#
33
+
34
+ _spec_values = doubleArray(5)
35
+ _spec_values[0] = SV_UNDEF
36
+ _spec_values[1] = float("nan")
37
+ _spec_values[2] = float("inf")
38
+ _spec_values[3] = float("-inf")
39
+ _spec_values[4] = SV_EPS
40
+
41
+ _default_scale = 1.0
42
+ _default_level = 0.0
43
+ _default_marginal = 0.0
44
+ _par_level_default = 0.0
45
+
46
+ _var_lower_default = {}
47
+ _var_upper_default = {}
48
+
49
+ _equ_lower_default = {}
50
+ _equ_upper_default = {}
51
+
52
+ _var_lower_default[GMS_VARTYPE_UNKNOWN] = 0.0
53
+ _var_lower_default[GMS_VARTYPE_BINARY] = 0.0
54
+ _var_lower_default[GMS_VARTYPE_INTEGER] = 0.0
55
+ _var_lower_default[GMS_VARTYPE_POSITIVE] = 0.0
56
+ _var_lower_default[GMS_VARTYPE_NEGATIVE] = _spec_values[GMS_SVIDX_MINF]
57
+ _var_lower_default[GMS_VARTYPE_FREE] = _spec_values[GMS_SVIDX_MINF]
58
+ _var_lower_default[GMS_VARTYPE_SOS1] = 0.0
59
+ _var_lower_default[GMS_VARTYPE_SOS2] = 0.0
60
+ _var_lower_default[GMS_VARTYPE_SEMICONT] = 1.0
61
+ _var_lower_default[GMS_VARTYPE_SEMIINT] = 1.0
62
+
63
+ _var_upper_default[GMS_VARTYPE_UNKNOWN] = 0.0
64
+ _var_upper_default[GMS_VARTYPE_BINARY] = 1.0
65
+ _var_upper_default[GMS_VARTYPE_INTEGER] = 100.0
66
+ _var_upper_default[GMS_VARTYPE_POSITIVE] = _spec_values[GMS_SVIDX_PINF]
67
+ _var_upper_default[GMS_VARTYPE_NEGATIVE] = 0.0
68
+ _var_upper_default[GMS_VARTYPE_FREE] = _spec_values[GMS_SVIDX_PINF]
69
+ _var_upper_default[GMS_VARTYPE_SOS1] = _spec_values[GMS_SVIDX_PINF]
70
+ _var_upper_default[GMS_VARTYPE_SOS2] = _spec_values[GMS_SVIDX_PINF]
71
+ _var_upper_default[GMS_VARTYPE_SEMICONT] = _spec_values[GMS_SVIDX_PINF]
72
+ _var_upper_default[GMS_VARTYPE_SEMIINT] = 100.0
73
+
74
+ _equ_lower_default[GMS_EQUTYPE_E] = 0.0
75
+ _equ_lower_default[GMS_EQUTYPE_G] = 0.0
76
+ _equ_lower_default[GMS_EQUTYPE_L] = _spec_values[GMS_SVIDX_MINF]
77
+ _equ_lower_default[GMS_EQUTYPE_N] = _spec_values[GMS_SVIDX_MINF]
78
+ _equ_lower_default[GMS_EQUTYPE_X] = 0.0
79
+ _equ_lower_default[GMS_EQUTYPE_C] = 0.0
80
+
81
+ _equ_upper_default[GMS_EQUTYPE_E] = 0.0
82
+ _equ_upper_default[GMS_EQUTYPE_G] = _spec_values[GMS_SVIDX_PINF]
83
+ _equ_upper_default[GMS_EQUTYPE_L] = 0.0
84
+ _equ_upper_default[GMS_EQUTYPE_N] = _spec_values[GMS_SVIDX_PINF]
85
+ _equ_upper_default[GMS_EQUTYPE_X] = 0.0
86
+ _equ_upper_default[GMS_EQUTYPE_C] = _spec_values[GMS_SVIDX_PINF]
87
+
88
+
89
+ def _int_value_and_free(intP):
90
+ intp_val = intp_value(intP)
91
+ delete_intp(intP)
92
+ return intp_val
93
+
94
+
95
+ class _GamsSymbolRecord(object):
96
+ """
97
+ @brief This is the representation of a single record of a GamsSymbol.
98
+ @details Derived classes are GamsEquationRecord, GamsParameterRecord, GamsSetRecord and GamsVariableRecord
99
+ """
100
+
101
+ def __eq__(self, other):
102
+ if isinstance(other, self.__class__):
103
+ return bool(
104
+ gmdSameRecord(
105
+ self._symbol._database._gmd, self._sym_iter_ptr, other._sym_iter_ptr
106
+ )
107
+ )
108
+ else:
109
+ return False
110
+
111
+ def __ne__(self, other):
112
+ return not self.__eq__(other)
113
+
114
+ def get_keys(self):
115
+ rc, keys = gmdGetKeys(
116
+ self._symbol._database._gmd, self._sym_iter_ptr, self._symbol._dim
117
+ )
118
+ self._symbol._database._check_for_gmd_error(rc)
119
+ return keys
120
+
121
+ ## @brief Retrieve keys of GamsSymbolRecord
122
+ keys = property(get_keys)
123
+
124
+ def key(self, index):
125
+ """
126
+ @brief Retrieve key of GamsSymbolRecord on position index
127
+ @param index Index position of key to be returned
128
+ @return Key at position index
129
+ """
130
+ rc, key = gmdGetKey(self._symbol._database._gmd, self._sym_iter_ptr, index)
131
+ self._symbol._database._check_for_gmd_error(rc)
132
+ return key
133
+
134
+ def get_symbol(self):
135
+ return self._symbol
136
+
137
+ ## @brief Retrieve the GamsSymbol that contains this record
138
+ symbol = property(get_symbol)
139
+
140
+ def __init__(self, symbol, sym_iter_ptr):
141
+ # get already existing record from GMD
142
+ symbol._database._workspace._debug_out(
143
+ "---- Entering _GamsSymbolRecord constructor ----", 0
144
+ )
145
+ self._symbol = symbol
146
+ self._sym_iter_ptr = sym_iter_ptr
147
+
148
+ def move_next(self):
149
+ """
150
+ @brief Iterate to next GamsSymbolRecord of GamsSymbol
151
+ @return True if everything worked, False otherwise
152
+ """
153
+ rc = gmdRecordMoveNext(self._symbol._database._gmd, self._sym_iter_ptr)
154
+ return bool(rc)
155
+
156
+ def move_previous(self):
157
+ """
158
+ @brief Iterate to previous GamsSymbolRecord of GamsSymbol
159
+ @return True if everything worked, False otherwise
160
+ """
161
+ rc = gmdRecordMovePrev(self._symbol._database._gmd, self._sym_iter_ptr)
162
+ return bool(rc)
163
+
164
+ def _keys_representation(self):
165
+ s = self._symbol.name
166
+
167
+ if self._symbol._dim > 0:
168
+ s += "("
169
+
170
+ sep = False
171
+ for k in self.keys:
172
+ if sep:
173
+ s += ", "
174
+ s += k
175
+ sep = True
176
+
177
+ if self._symbol._dim > 0:
178
+ s += ")"
179
+ s += ":"
180
+ return s
181
+
182
+ def __del__(self):
183
+ self._symbol._database._workspace._debug_out(
184
+ "---- Entering _GamsSymbolRecord destructor ----", 0
185
+ )
186
+ if self._sym_iter_ptr:
187
+ rc = gmdFreeSymbolIterator(self._symbol._database._gmd, self._sym_iter_ptr)
188
+ self._symbol._database._check_for_gmd_error(rc)
189
+ self._sym_iter_ptr = None
190
+
191
+
192
+ class GamsEquationRecord(_GamsSymbolRecord):
193
+ """
194
+ @brief This is the representation of a single record of a GamsEquation.
195
+ """
196
+
197
+ def get_level(self):
198
+ rc, v = gmdGetLevel(self._symbol._database._gmd, self._sym_iter_ptr)
199
+ if rc:
200
+ return v
201
+ else:
202
+ return float("nan")
203
+
204
+ def set_level(self, value):
205
+ rc = gmdSetLevel(self._symbol._database._gmd, self._sym_iter_ptr, value)
206
+ self._symbol._database._check_for_gmd_error(rc)
207
+
208
+ ## @brief Get or set the level of this record
209
+ level = property(get_level, set_level)
210
+
211
+ def get_marginal(self):
212
+ rc, v = gmdGetMarginal(self._symbol._database._gmd, self._sym_iter_ptr)
213
+ if rc:
214
+ return v
215
+ else:
216
+ return float("nan")
217
+
218
+ def set_marginal(self, value):
219
+ rc = gmdSetMarginal(self._symbol._database._gmd, self._sym_iter_ptr, value)
220
+ self._symbol._database._check_for_gmd_error(rc)
221
+
222
+ ## @brief Get or set the marginal of this record
223
+ marginal = property(get_marginal, set_marginal)
224
+
225
+ def get_upper(self):
226
+ rc, v = gmdGetUpper(self._symbol._database._gmd, self._sym_iter_ptr)
227
+ if rc:
228
+ return v
229
+ else:
230
+ return float("nan")
231
+
232
+ def set_upper(self, value):
233
+ rc = gmdSetUpper(self._symbol._database._gmd, self._sym_iter_ptr, value)
234
+ self._symbol._database._check_for_gmd_error(rc)
235
+
236
+ ## @brief Get or set the upper bound of this record
237
+ upper = property(get_upper, set_upper)
238
+
239
+ def get_lower(self):
240
+ rc, v = gmdGetLower(self._symbol._database._gmd, self._sym_iter_ptr)
241
+ if rc:
242
+ return v
243
+ else:
244
+ return float("nan")
245
+
246
+ def set_lower(self, value):
247
+ rc = gmdSetLower(self._symbol._database._gmd, self._sym_iter_ptr, value)
248
+ self._symbol._database._check_for_gmd_error(rc)
249
+
250
+ ## @brief Get or set the lower bound of this record
251
+ lower = property(get_lower, set_lower)
252
+
253
+ def get_scale(self):
254
+ rc, v = gmdGetScale(self._symbol._database._gmd, self._sym_iter_ptr)
255
+ if rc:
256
+ return v
257
+ else:
258
+ return float("nan")
259
+
260
+ def set_scale(self, value):
261
+ rc = gmdSetScale(self._symbol._database._gmd, self._sym_iter_ptr, value)
262
+ self._symbol._database._check_for_gmd_error(rc)
263
+
264
+ ## @brief Get or set the scale of this record
265
+ scale = property(get_scale, set_scale)
266
+
267
+ def __init__(self, equation, sym_iter_ptr):
268
+ super(GamsEquationRecord, self).__init__(equation, sym_iter_ptr)
269
+
270
+ ## @brief Retrieve a string representation of this record
271
+ def __str__(self):
272
+ s = self._keys_representation()
273
+
274
+ level = self.level
275
+ marginal = self.marginal
276
+ lower = self.lower
277
+ upper = self.upper
278
+ scale = self.scale
279
+
280
+ if level != _default_level:
281
+ s += " level=" + str(level)
282
+ if marginal != _default_marginal:
283
+ s += " marginal=" + str(marginal)
284
+ if lower != _equ_lower_default[self._symbol._equtype]:
285
+ s += " lower=" + str(lower)
286
+ if upper != _equ_upper_default[self._symbol._equtype]:
287
+ s += " upper=" + str(upper)
288
+ if scale != _default_scale:
289
+ s += " scale=" + str(scale)
290
+
291
+ return s
292
+
293
+
294
+ class GamsParameterRecord(_GamsSymbolRecord):
295
+ """
296
+ @brief This is the representation of a single record of a GamsParameter.
297
+ """
298
+
299
+ def get_value(self):
300
+ rc, v = gmdGetLevel(self._symbol._database._gmd, self._sym_iter_ptr)
301
+ if rc:
302
+ return v
303
+ else:
304
+ return float("nan")
305
+
306
+ def set_value(self, value):
307
+ rc = gmdSetLevel(self._symbol._database._gmd, self._sym_iter_ptr, value)
308
+ self._symbol._database._check_for_gmd_error(rc)
309
+
310
+ ## @brief Get or set the value of this record
311
+ value = property(get_value, set_value)
312
+
313
+ def __init__(self, set, sym_iter_ptr):
314
+ super(GamsParameterRecord, self).__init__(set, sym_iter_ptr)
315
+
316
+ ## @brief Retrieve a string representation of this record
317
+ def __str__(self):
318
+ s = self._keys_representation()
319
+
320
+ value = self.value
321
+
322
+ if value != _par_level_default:
323
+ s += " value=" + str(value)
324
+
325
+ return s
326
+
327
+
328
+ class GamsSetRecord(_GamsSymbolRecord):
329
+ """
330
+ @brief This is the representation of a single record of a GamsSet.
331
+ """
332
+
333
+ def get_text(self):
334
+ text = ""
335
+ rc, text = gmdGetElemText(self._symbol._database._gmd, self._sym_iter_ptr)
336
+ self._symbol._database._check_for_gmd_error(rc)
337
+ return text
338
+
339
+ def set_text(self, value):
340
+ rc = gmdSetElemText(self._symbol._database._gmd, self._sym_iter_ptr, value)
341
+ self._symbol._database._check_for_gmd_error(rc)
342
+
343
+ ## @brief Get or set the explanatory text of this record
344
+ text = property(get_text, set_text)
345
+
346
+ def __init__(self, set, sym_iter_ptr):
347
+ super(GamsSetRecord, self).__init__(set, sym_iter_ptr)
348
+
349
+ ## @brief Retrieve a string representation of this record
350
+ def __str__(self):
351
+ s = self._keys_representation()
352
+
353
+ text = self.text
354
+ if text != "" and text != " ":
355
+ s += " " + text
356
+ else:
357
+ s += " yes"
358
+
359
+ return s
360
+
361
+
362
+ class GamsVariableRecord(_GamsSymbolRecord):
363
+ """
364
+ @brief This is the representation of a single record of a GamsVariable.
365
+ """
366
+
367
+ # TODO: additional get_variable call beside get_symbol call in GamsSymbolRecord?
368
+
369
+ def get_level(self):
370
+ rc, v = gmdGetLevel(self._symbol._database._gmd, self._sym_iter_ptr)
371
+ if rc:
372
+ return v
373
+ else:
374
+ return float("nan")
375
+
376
+ def set_level(self, value):
377
+ rc = gmdSetLevel(self._symbol._database._gmd, self._sym_iter_ptr, value)
378
+ self._symbol._database._check_for_gmd_error(rc)
379
+
380
+ ## @brief Get or set the level of this record
381
+ level = property(get_level, set_level)
382
+
383
+ def get_marginal(self):
384
+ rc, v = gmdGetMarginal(self._symbol._database._gmd, self._sym_iter_ptr)
385
+ if rc:
386
+ return v
387
+ else:
388
+ return float("nan")
389
+
390
+ def set_marginal(self, value):
391
+ rc = gmdSetMarginal(self._symbol._database._gmd, self._sym_iter_ptr, value)
392
+ self._symbol._database._check_for_gmd_error(rc)
393
+
394
+ ## @brief Get or set the marginal of this record
395
+ marginal = property(get_marginal, set_marginal)
396
+
397
+ def get_upper(self):
398
+ rc, v = gmdGetUpper(self._symbol._database._gmd, self._sym_iter_ptr)
399
+ if rc:
400
+ return v
401
+ else:
402
+ return float("nan")
403
+
404
+ def set_upper(self, value):
405
+ rc = gmdSetUpper(self._symbol._database._gmd, self._sym_iter_ptr, value)
406
+ self._symbol._database._check_for_gmd_error(rc)
407
+
408
+ ## @brief Get or set the upper bound of this record
409
+ upper = property(get_upper, set_upper)
410
+
411
+ def get_lower(self):
412
+ rc, v = gmdGetLower(self._symbol._database._gmd, self._sym_iter_ptr)
413
+ if rc:
414
+ return v
415
+ else:
416
+ return float("nan")
417
+
418
+ def set_lower(self, value):
419
+ rc = gmdSetLower(self._symbol._database._gmd, self._sym_iter_ptr, value)
420
+ self._symbol._database._check_for_gmd_error(rc)
421
+
422
+ ## @brief Get or set the lower bound of this record
423
+ lower = property(get_lower, set_lower)
424
+
425
+ def get_scale(self):
426
+ rc, v = gmdGetScale(self._symbol._database._gmd, self._sym_iter_ptr)
427
+ if rc:
428
+ return v
429
+ else:
430
+ return float("nan")
431
+
432
+ def set_scale(self, value):
433
+ rc = gmdSetScale(self._symbol._database._gmd, self._sym_iter_ptr, value)
434
+ self._symbol._database._check_for_gmd_error(rc)
435
+
436
+ ## @brief Get or set the scale of this record
437
+ scale = property(get_scale, set_scale)
438
+
439
+ def __init__(self, variable, sym_iter_ptr):
440
+ super(GamsVariableRecord, self).__init__(variable, sym_iter_ptr)
441
+
442
+ ## @brief Retrieve a string representation of this record
443
+ def __str__(self):
444
+ s = self._keys_representation()
445
+
446
+ level = self.level
447
+ marginal = self.marginal
448
+ lower = self.lower
449
+ upper = self.upper
450
+ scale = self.scale
451
+
452
+ if level != _default_level:
453
+ s += " level=" + str(level)
454
+ if marginal != _default_marginal:
455
+ s += " marginal=" + str(marginal)
456
+ if lower != _var_lower_default[self._symbol._vartype]:
457
+ s += " lower=" + str(lower)
458
+ if upper != _var_upper_default[self._symbol._vartype]:
459
+ s += " upper=" + str(upper)
460
+ if scale != _default_scale:
461
+ s += " scale=" + str(scale)
462
+
463
+ return s
464
+
465
+
466
+ class _GamsSymbol(object):
467
+ """
468
+ @brief This is the representation of a symbol in GAMS.
469
+ @details It exists in a GamsDatabase and contains GamsSymbolRecords which one can iterate through.
470
+ Derived classes are GamsEquation, GamsParameter, GamsSet and GamsVariable.
471
+ """
472
+
473
+ def __eq__(self, other):
474
+ if isinstance(other, self.__class__):
475
+ return self._sym_ptr == other._sym_ptr
476
+ else:
477
+ return False
478
+
479
+ def __ne__(self, other):
480
+ return not self.__eq__(other)
481
+
482
+ def get_domains(self):
483
+ if self._domains == None:
484
+ self._domains = []
485
+ if self._dim == 0:
486
+ return self._domains
487
+ retDom = gmdGetDomain(self._database._gmd, self._sym_ptr, self._dim)
488
+ self._database._check_for_gmd_error(retDom[0])
489
+ domains = retDom[1]
490
+ for i in range(self._dim):
491
+ if domains[i] != None:
492
+ retSym = gmdSymbolInfo(self._database._gmd, domains[i], GMD_NAME)
493
+ self._database._check_for_gmd_error(retSym[0])
494
+ name = retSym[3]
495
+ if name == "*":
496
+ self._domains.append("*")
497
+ else:
498
+ self._domains.append(
499
+ GamsSet(self._database, sym_ptr=domains[i])
500
+ )
501
+ else:
502
+ self._domains.append(retDom[2][i])
503
+ return self._domains
504
+
505
+ ## @brief Domains of Symbol, each element is either a GamsSet (real domain) or a string (relaxed domain)
506
+ domains = property(get_domains)
507
+
508
+ def get_domains_as_strings(self):
509
+ if self._domains_as_strings == None:
510
+ self._domains_as_strings = []
511
+ if self._dim == 0:
512
+ return self._domains_as_strings
513
+ ret = gmdGetDomain(self._database._gmd, self._sym_ptr, self._dim)
514
+ self._database._check_for_gmd_error(ret[0])
515
+
516
+ for i in range(self._dim):
517
+ self._domains_as_strings.append(ret[2][i])
518
+ return self._domains_as_strings
519
+
520
+ ## @brief Domains of Symbol, each element is a string. Note: If the domains is as alias in GAMS, this call will return the name of the alias, not the name of the aliased set
521
+ domains_as_strings = property(get_domains_as_strings)
522
+
523
+ def get_dimension(self):
524
+ return self._dim
525
+
526
+ ## @brief Get GamsSymbol dimension
527
+ dimension = property(get_dimension)
528
+
529
+ def get_text(self):
530
+ return self._text
531
+
532
+ ## @brief Get explanatory text of GamsSymbol
533
+ text = property(get_text)
534
+
535
+ def get_name(self):
536
+ return self._name
537
+
538
+ ## Get GamsSymbol name
539
+ name = property(get_name)
540
+
541
+ def get_database(self):
542
+ return self._database
543
+
544
+ ## @brief Get GamsDatabase containing GamsSymbol
545
+ database = property(get_database)
546
+
547
+ def get_number_records(self):
548
+ ret = gmdSymbolInfo(self._database._gmd, self._sym_ptr, GMD_NRRECORDS)
549
+ self._database._check_for_gmd_error(ret[0])
550
+ return ret[1]
551
+
552
+ ## @brief Retrieve the number of records of the GamsSymbol
553
+ # @note This is the same as calling len(symbol)
554
+ number_records = property(get_number_records)
555
+
556
+ ## @brief Retrieve the number of records of the GamsSymbol
557
+ def __len__(self):
558
+ return self.get_number_records()
559
+
560
+ def __init__(
561
+ self,
562
+ database,
563
+ identifier=None,
564
+ dimension=None,
565
+ explanatory_text="",
566
+ sym_ptr=None,
567
+ ):
568
+ database._workspace._debug_out("---- Entering _GamsSymbol constructor ----", 0)
569
+ self._sym_iter_ptr = None
570
+ self._database = database
571
+ self._domains = None
572
+ self._domains_as_strings = None
573
+
574
+ # receive an already existing symbol from GMD
575
+ if not (identifier or dimension or explanatory_text) and sym_ptr:
576
+ if sym_ptr == None:
577
+ raise gams.control.workspace.GamsException("Symbol does not exist")
578
+
579
+ self._sym_ptr = sym_ptr
580
+
581
+ rc, type = gmdSymbolType(self._database._gmd, self._sym_ptr)
582
+ self._database._check_for_gmd_error(rc)
583
+
584
+ rc, ival, dval, self._name = gmdSymbolInfo(
585
+ self._database._gmd, self._sym_ptr, GMD_NAME
586
+ )
587
+ self._database._check_for_gmd_error(rc)
588
+
589
+ rc, self._dim, dval, sval = gmdSymbolInfo(
590
+ self._database._gmd, self._sym_ptr, GMD_DIM
591
+ )
592
+ self._database._check_for_gmd_error(rc)
593
+
594
+ rc, ival, dval, self._text = gmdSymbolInfo(
595
+ self._database._gmd, self._sym_ptr, GMD_EXPLTEXT
596
+ )
597
+ self._database._check_for_gmd_error(rc)
598
+
599
+ # create a new symbol in GMD
600
+ elif not sym_ptr and identifier and dimension != None:
601
+ if dimension < 0 or dimension > GMS_MAX_INDEX_DIM:
602
+ raise gams.control.workspace.GamsException(
603
+ "Invalid dimension specified "
604
+ + str(dimension)
605
+ + " is not in [0,"
606
+ + str(GMS_MAX_INDEX_DIM)
607
+ + "]"
608
+ )
609
+ self._name = identifier
610
+ self._dim = dimension
611
+ self._text = explanatory_text
612
+
613
+ else:
614
+ raise gams.control.workspace.GamsException(
615
+ "Invalid combination of parameters"
616
+ )
617
+
618
+ def __del__(self):
619
+ self._database._workspace._debug_out(
620
+ "---- Entering _GamsSymbol destructor ----", 0
621
+ )
622
+ if self._sym_iter_ptr:
623
+ rc = gmdFreeSymbolIterator(self._database._gmd, self._sym_iter_ptr)
624
+ self._database._check_for_gmd_error(rc)
625
+ self._sym_iter_ptr = None
626
+
627
+ def copy_symbol(self, target):
628
+ """
629
+ @brief Copys all records from the GamsSymbol to the target GamsSymbol (if target had records, they will be deleted)
630
+ @param target Target GamsSymbol
631
+ @returns True if everything worked, else false
632
+ """
633
+ if target._database._record_lock:
634
+ raise gams.control.workspace.GamsException(
635
+ "Cannot add data records to record-locked database"
636
+ )
637
+ rc = gmdCopySymbol(self._database._gmd, target._sym_ptr, self._sym_ptr)
638
+ self._database._check_for_gmd_error(rc)
639
+ return True
640
+
641
+ def _check_keys(self, keys):
642
+ if len(keys) != self._dim:
643
+ raise gams.control.workspace.GamsException(
644
+ "Different dimensions: " + str(len(keys)) + " vs. " + str(self._dim)
645
+ )
646
+ for i in range(self._dim):
647
+ if keys[i] == None:
648
+ raise gams.control.workspace.GamsException(
649
+ "'Key' not allowed to be None (found at dimension "
650
+ + str(i + 1)
651
+ + ")"
652
+ )
653
+
654
+ def delete_record(self, keys=None):
655
+ """
656
+ @brief Delete GamsSymbol record
657
+ @param keys List of keys
658
+ @return True if everything worked, else False
659
+ """
660
+ if self._database._record_lock:
661
+ raise gams.control.workspace.GamsException(
662
+ "Cannot remove data records to record-locked database"
663
+ )
664
+ if not (
665
+ isinstance(keys, str)
666
+ or isinstance(keys, list)
667
+ or isinstance(keys, tuple)
668
+ or keys == None
669
+ ):
670
+ raise gams.control.workspace.GamsException(
671
+ "Wrong type of keys argument in delete_record. Valid types are 'str', 'list', 'tuple' and their subclasses"
672
+ )
673
+ if isinstance(keys, str):
674
+ keys = [keys]
675
+ elif isinstance(keys, tuple):
676
+ keys = list(keys)
677
+ elif not keys:
678
+ keys = []
679
+ self._check_keys(keys)
680
+ rc = new_intp()
681
+ sym_iter_ptr = gmdFindRecordPy(self._database._gmd, self._sym_ptr, keys, rc)
682
+ if not _int_value_and_free(rc):
683
+ return False
684
+ rc = gmdDeleteRecord(self._database._gmd, sym_iter_ptr)
685
+ self._database._check_for_gmd_error(rc)
686
+ rc = gmdFreeSymbolIterator(self._database._gmd, sym_iter_ptr)
687
+ self._database._check_for_gmd_error(rc)
688
+ sym_iter_ptr = None
689
+ return True
690
+
691
+ def clear(self):
692
+ """
693
+ @brief Clear symbol
694
+ @returns True if everything worked, else False
695
+ """
696
+ if self._database._record_lock:
697
+ raise gams.control.workspace.GamsException(
698
+ "Cannot remove data records to record-locked database"
699
+ )
700
+ return bool(gmdClearSymbol(self._database._gmd, self._sym_ptr))
701
+
702
+ def __iter__(self):
703
+ self._sym_iter_ptr = None
704
+ return self
705
+
706
+ def _concat_keys(self, keys):
707
+ if not keys or len(keys) == 0:
708
+ return ""
709
+ else:
710
+ ret = ""
711
+ for i in range(len(keys) - 1):
712
+ ret += keys[i] + ","
713
+ ret += keys[len(keys) - 1]
714
+ return ret
715
+
716
+ def _check_and_return_record(self, sym_iter_ptr, cb_msg):
717
+ if sym_iter_ptr == None:
718
+ raise gams.control.workspace.GamsException(cb_msg())
719
+ if self._sym_ptr == None:
720
+ raise gams.control.workspace.GamsException("Invalid Pointer")
721
+ if isinstance(self, GamsVariable):
722
+ return GamsVariableRecord(self, sym_iter_ptr)
723
+ if isinstance(self, GamsEquation):
724
+ return GamsEquationRecord(self, sym_iter_ptr)
725
+ if isinstance(self, GamsParameter):
726
+ return GamsParameterRecord(self, sym_iter_ptr)
727
+ if isinstance(self, GamsSet):
728
+ return GamsSetRecord(self, sym_iter_ptr)
729
+ else:
730
+ raise gams.control.workspace.GamsException("Invalid symbol type")
731
+
732
+ def next(self):
733
+
734
+ if self._sym_iter_ptr == None:
735
+ rc = new_intp()
736
+ self._sym_iter_ptr = gmdFindFirstRecordPy(
737
+ self._database._gmd, self._sym_ptr, rc
738
+ )
739
+ delete_intp(rc)
740
+ if self._sym_iter_ptr == None:
741
+ raise StopIteration
742
+ else:
743
+ if not gmdRecordMoveNext(self._database._gmd, self._sym_iter_ptr):
744
+ raise StopIteration
745
+ if self._sym_iter_ptr == None:
746
+ raise StopIteration
747
+ else:
748
+ cb_msg = lambda: "No next record available in symbol '" + self._name + "'"
749
+ rc = new_intp()
750
+ rec = gmdCopySymbolIteratorPy(self._database._gmd, self._sym_iter_ptr, rc)
751
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
752
+ return self._check_and_return_record(rec, cb_msg)
753
+
754
+ def __next__(self):
755
+ return self.next()
756
+
757
+ def find_record(self, keys=None):
758
+ """
759
+ @brief Find record in GamsSymbol
760
+ @param keys List of keys
761
+ @return Reference to found record
762
+ """
763
+ if not (
764
+ isinstance(keys, str)
765
+ or isinstance(keys, list)
766
+ or isinstance(keys, tuple)
767
+ or keys == None
768
+ ):
769
+ raise gams.control.workspace.GamsException(
770
+ "Wrong type of keys argument in find_record. Valid types are 'str', 'list', 'tuple' and their subclasses"
771
+ )
772
+ if not keys:
773
+ keys = []
774
+ if isinstance(keys, str):
775
+ keys = [keys]
776
+ elif isinstance(keys, tuple):
777
+ keys = list(keys)
778
+ self._check_keys(keys)
779
+ rc = new_intp()
780
+ sym_iter_ptr = gmdFindRecordPy(self._database._gmd, self._sym_ptr, keys, rc)
781
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
782
+ cb_msg = (
783
+ lambda: "Cannot find record '"
784
+ + self._concat_keys(keys)
785
+ + "' in symbol '"
786
+ + self._name
787
+ + "'"
788
+ )
789
+ return self._check_and_return_record(sym_iter_ptr, cb_msg)
790
+
791
+ def __getitem__(self, keys=None):
792
+ return self.find_record(keys)
793
+
794
+ def add_record(self, keys=None):
795
+ """
796
+ @brief Add record to GamsSymbol
797
+ @param keys List of keys
798
+ @return Reference to added record
799
+ """
800
+ if self._database._record_lock:
801
+ raise gams.control.workspace.GamsException(
802
+ "Cannot add data records to record-locked database"
803
+ )
804
+ if not (
805
+ isinstance(keys, str)
806
+ or isinstance(keys, list)
807
+ or isinstance(keys, tuple)
808
+ or keys == None
809
+ ):
810
+ raise gams.control.workspace.GamsException(
811
+ "Wrong type of keys argument in add_record. Valid types are 'str', 'list', 'tuple' and their subclasses"
812
+ )
813
+ if isinstance(keys, str):
814
+ keys = [keys]
815
+ elif isinstance(keys, tuple):
816
+ keys = list(keys)
817
+ elif not keys:
818
+ keys = []
819
+ self._check_keys(keys)
820
+ rc = new_intp()
821
+ sym_iter_ptr = gmdAddRecordPy(self._database._gmd, self._sym_ptr, keys, rc)
822
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
823
+ cb_msg = (
824
+ lambda: "Record '"
825
+ + self._concat_keys(keys)
826
+ + "' aleady exists in symbol '"
827
+ + self._name
828
+ + "'"
829
+ )
830
+ return self._check_and_return_record(sym_iter_ptr, cb_msg)
831
+
832
+ def merge_record(self, keys=None):
833
+ """
834
+ @brief Finds record in GamsSymbol if it exists, adds it if not
835
+ @param keys List of keys
836
+ @return Reference to found or added record
837
+ """
838
+ if not (
839
+ isinstance(keys, str)
840
+ or isinstance(keys, list)
841
+ or isinstance(keys, tuple)
842
+ or keys == None
843
+ ):
844
+ raise gams.control.workspace.GamsException(
845
+ "Wrong type of keys argument in merge_record. Valid types are 'str', 'list', 'tuple' and their subclasses"
846
+ )
847
+ if not keys:
848
+ keys = []
849
+ if isinstance(keys, str):
850
+ keys = [keys]
851
+ elif isinstance(keys, tuple):
852
+ keys = list(keys)
853
+ self._check_keys(keys)
854
+ rc = new_intp()
855
+ sym_iter_ptr = gmdFindRecordPy(self._database._gmd, self._sym_ptr, keys, rc)
856
+ delete_intp(rc)
857
+ # self._database._check_for_gmd_error(intp_value(rc))
858
+ if sym_iter_ptr != None:
859
+ cb_msg = (
860
+ lambda: "Cannot find record '"
861
+ + self._concat_keys(keys)
862
+ + "' in symbol '"
863
+ + self._name
864
+ + "'"
865
+ )
866
+ return self._check_and_return_record(sym_iter_ptr, cb_msg)
867
+ else:
868
+ if self._database._record_lock:
869
+ raise gams.control.workspace.GamsException(
870
+ "Cannot add data records to record-locked database"
871
+ )
872
+ rc = new_intp()
873
+ sym_iter_ptr = gmdAddRecordPy(self._database._gmd, self._sym_ptr, keys, rc)
874
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
875
+ cb_msg = (
876
+ lambda: "Record '"
877
+ + self._concat_keys(keys)
878
+ + "' could neither be found in nor added to symbol '"
879
+ + self._name
880
+ + "'"
881
+ )
882
+ return self._check_and_return_record(sym_iter_ptr, cb_msg)
883
+
884
+ def first_record(self, slice=None):
885
+ """
886
+ @brief Retrieve first record in GamsSymbol
887
+ @param slice Define filter for elements whose record should be retrieved
888
+ @code{.py}
889
+ print("Transportation costs from Seattle")
890
+ record = job.out_db.get_parameter("c").first_record(["seattle", " "])
891
+ @endcode
892
+ @return Reference to record
893
+ """
894
+ if not slice:
895
+ rc = new_intp()
896
+ sym_iter_ptr = gmdFindFirstRecordPy(self._database._gmd, self._sym_ptr, rc)
897
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
898
+ cb_msg = lambda: "Symbol '" + self._name + "' is empty"
899
+ else:
900
+ if not (
901
+ isinstance(slice, str)
902
+ or isinstance(slice, list)
903
+ or isinstance(slice, tuple)
904
+ or keys == None
905
+ ):
906
+ raise gams.control.workspace.GamsException(
907
+ "Wrong type of slice argument in first_record. Valid types are 'str', 'list', 'tuple' and their subclasses"
908
+ )
909
+ if isinstance(slice, str):
910
+ slice = [slice]
911
+ elif isinstance(slice, tuple):
912
+ slice = list(slice)
913
+ if len(slice) != self._dim:
914
+ raise gams.control.workspace.GamsException(
915
+ "Different dimensions: "
916
+ + str(len(slice))
917
+ + " vs. "
918
+ + str(self._dim)
919
+ )
920
+ rc = new_intp()
921
+ sym_iter_ptr = gmdFindFirstRecordSlicePy(
922
+ self._database._gmd, self._sym_ptr, slice, rc
923
+ )
924
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
925
+ cb_msg = (
926
+ lambda: "No record with slice '"
927
+ + self._concat_keys(slice)
928
+ + "' found in symbol '"
929
+ + self._name
930
+ + "'"
931
+ )
932
+ return self._check_and_return_record(sym_iter_ptr, cb_msg)
933
+
934
+ def last_record(self, slice=None):
935
+ if not slice:
936
+ rc = new_intp()
937
+ sym_iter_ptr = gmdFindLastRecordPy(self._database._gmd, self._sym_ptr, rc)
938
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
939
+ cb_msg = lambda: "Symbol '" + self._name + "' is empty"
940
+ else:
941
+ if not (
942
+ isinstance(slice, str)
943
+ or isinstance(slice, list)
944
+ or isinstance(slice, tuple)
945
+ or keys == None
946
+ ):
947
+ raise gams.control.workspace.GamsException(
948
+ "Wrong type of slice argument in last_record. Valid types are 'str', 'list', 'tuple' and their subclasses"
949
+ )
950
+ if isinstance(slice, str):
951
+ slice = [slice]
952
+ elif isinstance(slice, tuple):
953
+ slice = list(slice)
954
+ if len(slice) != self._dim:
955
+ raise gams.control.workspace.GamsException(
956
+ "Different dimensions: "
957
+ + str(len(slice))
958
+ + " vs. "
959
+ + str(self._dim)
960
+ )
961
+ rc = new_intp()
962
+ sym_iter_ptr = gmdFindLastRecordSlicePy(
963
+ self._database._gmd, self._sym_ptr, slice, rc
964
+ )
965
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
966
+ cb_msg = (
967
+ lambda: "No record with slice '"
968
+ + self._concat_keys(slice)
969
+ + "' found in symbol '"
970
+ + self._name
971
+ + "'"
972
+ )
973
+ return self._check_and_return_record(sym_iter_ptr, cb_msg)
974
+
975
+ def check_domains(self):
976
+ """
977
+ @brief Check if all records are within the specified domain of the symbol
978
+ @return True: Everything is correct, False: There is a domain violation
979
+ """
980
+ has_violation = new_intp()
981
+ rc = gmdCheckSymbolDV(self._database._gmd, self._sym_ptr, has_violation)
982
+ self._database._check_for_gmd_error(rc)
983
+ if _int_value_and_free(has_violation) == 1:
984
+ return False
985
+ else:
986
+ return True
987
+
988
+ def get_symbol_dvs(self, max_viol=0):
989
+ """
990
+ @brief return all GamsSymbolDomainViolations
991
+ @param max_viol The maximum number of domain violations which should be stored (0 for no limit)
992
+ @return List containing GamsSymbolDomainViolation objects
993
+ """
994
+
995
+ ret_list = []
996
+ rc = new_intp()
997
+ dv_handle = gmdGetFirstDVInSymbolPy(self._database._gmd, self._sym_ptr, rc)
998
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
999
+ has_next = False
1000
+ if dv_handle != None:
1001
+ has_next = True
1002
+
1003
+ while has_next and (len(ret_list) < max_viol or max_viol == 0):
1004
+ rc = new_intp()
1005
+ rec = gmdGetDVSymbolRecordPy(self._database._gmd, dv_handle, rc)
1006
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1007
+
1008
+ violation_idx = intArray(self._dim)
1009
+ rc = gmdGetDVIndicator(self._database._gmd, dv_handle, violation_idx)
1010
+ self._database._check_for_gmd_error(rc)
1011
+
1012
+ violation_idx_list = []
1013
+ for i in range(self._dim):
1014
+ violation_idx_list.append(bool(violation_idx[i]))
1015
+
1016
+ rc, type = gmdSymbolType(self._database._gmd, self._sym_ptr)
1017
+ self._database._check_for_gmd_error(rc)
1018
+ symbol_record = None
1019
+
1020
+ if type == dt_equ:
1021
+ symbol_record = GamsEquationRecord(self, rec)
1022
+ elif type == dt_var:
1023
+ symbol_record = GamsVariableRecord(self, rec)
1024
+ elif type == dt_par:
1025
+ symbol_record = GamsParameterRecord(self, rec)
1026
+ elif type == dt_set:
1027
+ symbol_record = GamsSetRecord(self, rec)
1028
+
1029
+ ret_list.append(
1030
+ GamsSymbolDomainViolation(violation_idx_list, symbol_record)
1031
+ )
1032
+
1033
+ has_next = new_intp()
1034
+ rc = gmdMoveNextDVInSymbol(self._database._gmd, dv_handle, has_next)
1035
+ self._database._check_for_gmd_error(rc)
1036
+ has_next = bool(_int_value_and_free(has_next))
1037
+
1038
+ rc = gmdDomainCheckDone(self._database._gmd)
1039
+ self._database._check_for_gmd_error(rc)
1040
+ rc = gmdFreeDVHandle(self._database._gmd, dv_handle)
1041
+ self._database._check_for_gmd_error(rc)
1042
+ return ret_list
1043
+
1044
+
1045
+ class GamsVariable(_GamsSymbol):
1046
+ """
1047
+ @brief This is the representation of a variable symbol in GAMS.
1048
+ @details It exists in a GamsDatabase and contains GamsVariableRecords which one can iterate through.
1049
+ """
1050
+
1051
+ def get_vartype(self):
1052
+ return self._vartype
1053
+
1054
+ ## @brief Retrieve subtype of variable (VarType.Binary, VarType.Integer, VarType.Positive, VarType.Negative, VarType.Free, VarType.SOS1, VarType.SOS2, VarType.SemiCont, VarType.SemiInt)
1055
+ vartype = property(get_vartype)
1056
+
1057
+ def __init__(
1058
+ self,
1059
+ database,
1060
+ identifier=None,
1061
+ dimension=None,
1062
+ vartype=None,
1063
+ explanatory_text="",
1064
+ sym_ptr=None,
1065
+ domains=None,
1066
+ ):
1067
+ if identifier and (vartype != None) and (domains != None) and not dimension:
1068
+ super(GamsVariable, self).__init__(
1069
+ database, identifier, len(domains), explanatory_text, sym_ptr
1070
+ )
1071
+ else:
1072
+ super(GamsVariable, self).__init__(
1073
+ database, identifier, dimension, explanatory_text, sym_ptr
1074
+ )
1075
+
1076
+ # receive an already existing symbol from GMD
1077
+ if not (identifier or dimension or vartype or explanatory_text) and sym_ptr:
1078
+ rc, subtype, dval, sval = gmdSymbolInfo(
1079
+ self._database._gmd, self._sym_ptr, GMD_USERINFO
1080
+ )
1081
+ self._database._check_for_gmd_error(rc)
1082
+ self._vartype = subtype
1083
+
1084
+ # create new variable in GMD
1085
+ elif not sym_ptr and identifier and dimension != None and vartype != None:
1086
+ self._vartype = vartype
1087
+ rc = new_intp()
1088
+ self._sym_ptr = gmdAddSymbolPy(
1089
+ self._database._gmd,
1090
+ self._name,
1091
+ self._dim,
1092
+ dt_var,
1093
+ self._vartype,
1094
+ self._text,
1095
+ rc,
1096
+ )
1097
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1098
+
1099
+ # create new variable with domain information
1100
+ elif identifier and (vartype != None) and (domains != None) and not dimension:
1101
+ if not isinstance(domains, (list, tuple)):
1102
+ raise gams.control.workspace.GamsException(
1103
+ "Parameter domains has to be a list or a tuple"
1104
+ )
1105
+
1106
+ self._vartype = vartype
1107
+ if len(domains) == 0:
1108
+ rc = new_intp()
1109
+ self._sym_ptr = gmdAddSymbolPy(
1110
+ self._database._gmd,
1111
+ self._name,
1112
+ self._dim,
1113
+ dt_var,
1114
+ self._vartype,
1115
+ self._text,
1116
+ rc,
1117
+ )
1118
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1119
+ else:
1120
+ dom_ptr = [None] * self._dim
1121
+ rel_dom = [""] * self._dim
1122
+
1123
+ for i in range(self._dim):
1124
+ if isinstance(domains[i], GamsSet):
1125
+ dom_ptr[i] = domains[i]._sym_ptr
1126
+ elif isinstance(domains[i], str):
1127
+ rel_dom[i] = domains[i]
1128
+ else:
1129
+ raise gams.control.workspace.GamsException(
1130
+ "Domain must be GamsSet or string but saw "
1131
+ + str(type(domains[i]))
1132
+ + " on index "
1133
+ + str(i)
1134
+ )
1135
+ rc = new_intp()
1136
+ self._sym_ptr = gmdAddSymbolXPy(
1137
+ self._database._gmd,
1138
+ self._name,
1139
+ self._dim,
1140
+ dt_var,
1141
+ self._vartype,
1142
+ self._text,
1143
+ dom_ptr,
1144
+ rel_dom,
1145
+ rc,
1146
+ )
1147
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1148
+ else:
1149
+ raise gams.control.workspace.GamsException(
1150
+ "Invalid combination of parameters"
1151
+ )
1152
+
1153
+
1154
+ class GamsParameter(_GamsSymbol):
1155
+ """
1156
+ @brief This is the representation of a parameter symbol in GAMS.
1157
+ @details It exists in a GamsDatabase and contains GamsParameterRecords which one can iterate through.
1158
+ """
1159
+
1160
+ def __init__(
1161
+ self,
1162
+ database,
1163
+ identifier=None,
1164
+ dimension=None,
1165
+ explanatory_text="",
1166
+ sym_ptr=None,
1167
+ domains=None,
1168
+ ):
1169
+ if identifier and (domains != None) and not dimension:
1170
+ super(GamsParameter, self).__init__(
1171
+ database, identifier, len(domains), explanatory_text, sym_ptr
1172
+ )
1173
+ else:
1174
+ super(GamsParameter, self).__init__(
1175
+ database, identifier, dimension, explanatory_text, sym_ptr
1176
+ )
1177
+
1178
+ # receive an already existing symbol from GMD - nothing to do
1179
+ if not (identifier or dimension or explanatory_text) and sym_ptr:
1180
+ pass
1181
+
1182
+ # create new parameter in GMD
1183
+ elif not sym_ptr and identifier and dimension != None:
1184
+ rc = new_intp()
1185
+ self._sym_ptr = gmdAddSymbolPy(
1186
+ self._database._gmd, self._name, self._dim, dt_par, 0, self._text, rc
1187
+ )
1188
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1189
+ if self._sym_ptr == None:
1190
+ raise gams.control.workspace.GamsException(
1191
+ "Cannot create parameter " + self._name
1192
+ )
1193
+
1194
+ # create new parameter with domain information
1195
+ elif identifier and (domains != None) and not dimension:
1196
+ if not isinstance(domains, (list, tuple)):
1197
+ raise gams.control.workspace.GamsException(
1198
+ "Parameter domains has to be a list or a tuple"
1199
+ )
1200
+
1201
+ if len(domains) == 0:
1202
+ rc = new_intp()
1203
+ self._sym_ptr = gmdAddSymbolPy(
1204
+ self._database._gmd,
1205
+ self._name,
1206
+ self._dim,
1207
+ dt_par,
1208
+ 0,
1209
+ self._text,
1210
+ rc,
1211
+ )
1212
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1213
+ else:
1214
+ dom_ptr = [None] * self._dim
1215
+ rel_dom = [""] * self._dim
1216
+
1217
+ for i in range(self._dim):
1218
+ if isinstance(domains[i], GamsSet):
1219
+ dom_ptr[i] = domains[i]._sym_ptr
1220
+ elif isinstance(domains[i], str):
1221
+ rel_dom[i] = domains[i]
1222
+ else:
1223
+ raise gams.control.workspace.GamsException(
1224
+ "Domain must be GamsSet or string but saw "
1225
+ + str(type(domains[i]))
1226
+ + " on index "
1227
+ + str(i)
1228
+ )
1229
+ rc = new_intp()
1230
+ self._sym_ptr = gmdAddSymbolXPy(
1231
+ self._database._gmd,
1232
+ self._name,
1233
+ self._dim,
1234
+ dt_par,
1235
+ 0,
1236
+ self._text,
1237
+ dom_ptr,
1238
+ rel_dom,
1239
+ rc,
1240
+ )
1241
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1242
+
1243
+ else:
1244
+ raise gams.control.workspace.GamsException(
1245
+ "Invalid combination of parameters"
1246
+ )
1247
+
1248
+
1249
+ class GamsSet(_GamsSymbol):
1250
+ """
1251
+ @brief This is the representation of a set symbol in GAMS.
1252
+ @details It exists in a GamsDatabase and contains GamsSetRecords which one can iterate through.
1253
+ """
1254
+
1255
+ def get_settype(self):
1256
+ return self._settype
1257
+
1258
+ ## @brief Retrieve subtype of set (SetType.Multi, SetType.Singleton)
1259
+ settype = property(get_settype)
1260
+
1261
+ def __init__(
1262
+ self,
1263
+ database,
1264
+ identifier=None,
1265
+ dimension=None,
1266
+ explanatory_text="",
1267
+ sym_ptr=None,
1268
+ domains=None,
1269
+ settype=0,
1270
+ ):
1271
+ if identifier and (domains != None) and not dimension:
1272
+ super(GamsSet, self).__init__(
1273
+ database, identifier, len(domains), explanatory_text, sym_ptr
1274
+ )
1275
+ else:
1276
+ super(GamsSet, self).__init__(
1277
+ database, identifier, dimension, explanatory_text, sym_ptr
1278
+ )
1279
+
1280
+ # receive an already existing symbol from GMD
1281
+ if not (identifier or dimension or explanatory_text) and sym_ptr:
1282
+ rc, subtype, dval, sval = gmdSymbolInfo(
1283
+ self._database._gmd, self._sym_ptr, GMD_USERINFO
1284
+ )
1285
+ self._database._check_for_gmd_error(rc)
1286
+ self._settype = subtype
1287
+
1288
+ # create new set in GMD
1289
+ elif not sym_ptr and identifier and dimension != None:
1290
+ self._settype = settype
1291
+ rc = new_intp()
1292
+ self._sym_ptr = gmdAddSymbolPy(
1293
+ self._database._gmd,
1294
+ self._name,
1295
+ self._dim,
1296
+ dt_set,
1297
+ self._settype,
1298
+ self._text,
1299
+ rc,
1300
+ )
1301
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1302
+
1303
+ # create new set with domain information
1304
+ elif identifier and (domains != None) and not dimension:
1305
+ if not isinstance(domains, (list, tuple)):
1306
+ raise gams.control.workspace.GamsException(
1307
+ "Parameter domains has to be a list or a tuple"
1308
+ )
1309
+
1310
+ self._settype = settype
1311
+ if len(domains) == 0:
1312
+ rc = new_intp()
1313
+ self._sym_ptr = gmdAddSymbolPy(
1314
+ self._database._gmd,
1315
+ self._name,
1316
+ self._dim,
1317
+ dt_set,
1318
+ self._settype,
1319
+ self._text,
1320
+ rc,
1321
+ )
1322
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1323
+ else:
1324
+ dom_ptr = [None] * self._dim
1325
+ rel_dom = [""] * self._dim
1326
+
1327
+ for i in range(self._dim):
1328
+ if isinstance(domains[i], GamsSet):
1329
+ dom_ptr[i] = domains[i]._sym_ptr
1330
+ elif isinstance(domains[i], str):
1331
+ rel_dom[i] = domains[i]
1332
+ else:
1333
+ raise gams.control.workspace.GamsException(
1334
+ "Domain must be GamsSet or string but saw "
1335
+ + str(type(domains[i]))
1336
+ + " on index "
1337
+ + str(i)
1338
+ )
1339
+ rc = new_intp()
1340
+ self._sym_ptr = gmdAddSymbolXPy(
1341
+ self._database._gmd,
1342
+ self._name,
1343
+ self._dim,
1344
+ dt_set,
1345
+ self._settype,
1346
+ self._text,
1347
+ dom_ptr,
1348
+ rel_dom,
1349
+ rc,
1350
+ )
1351
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1352
+
1353
+ else:
1354
+ raise gams.control.workspace.GamsException(
1355
+ "Invalid combination of parameters"
1356
+ )
1357
+
1358
+
1359
+ class GamsEquation(_GamsSymbol):
1360
+ """
1361
+ @brief This is the representation of an equation symbol in GAMS.
1362
+ @details It exists in a GamsDatabase and contains GamsEquationRecords which one can iterate through.
1363
+ """
1364
+
1365
+ def get_equtype(self):
1366
+ return self._equtype
1367
+
1368
+ ## @brief Retrieve subtype of Equation (EquType.E: Equal, EquType.G: Greater, EquType.L: Less, EquType.N: No specification, EquType.X: External defined, EquType.C: Conic)
1369
+ equtype = property(get_equtype)
1370
+
1371
+ def __init__(
1372
+ self,
1373
+ database,
1374
+ identifier=None,
1375
+ dimension=None,
1376
+ equtype=None,
1377
+ explanatory_text="",
1378
+ sym_ptr=None,
1379
+ domains=None,
1380
+ ):
1381
+ if identifier and (equtype != None) and (domains != None) and not dimension:
1382
+ super(GamsEquation, self).__init__(
1383
+ database, identifier, len(domains), explanatory_text, sym_ptr
1384
+ )
1385
+ else:
1386
+ super(GamsEquation, self).__init__(
1387
+ database, identifier, dimension, explanatory_text, sym_ptr
1388
+ )
1389
+
1390
+ # receive an already existing symbol from GMD
1391
+ if not (identifier or dimension or equtype or explanatory_text) and sym_ptr:
1392
+ rc, subtype, dval, sval = gmdSymbolInfo(
1393
+ self._database._gmd, self._sym_ptr, GMD_USERINFO
1394
+ )
1395
+ self._database._check_for_gmd_error(rc)
1396
+ self._equtype = subtype
1397
+
1398
+ # create new equation in GMD
1399
+ elif not sym_ptr and identifier and dimension != None and equtype != None:
1400
+ self._equtype = equtype
1401
+ rc = new_intp()
1402
+ self._sym_ptr = gmdAddSymbolPy(
1403
+ self._database._gmd,
1404
+ self._name,
1405
+ self._dim,
1406
+ dt_equ,
1407
+ self._equtype,
1408
+ self._text,
1409
+ rc,
1410
+ )
1411
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1412
+
1413
+ # create new equation with domain information
1414
+ elif identifier and (equtype != None) and (domains != None) and not dimension:
1415
+ if not isinstance(domains, (list, tuple)):
1416
+ raise gams.control.workspace.GamsException(
1417
+ "Parameter domains has to be a list or a tuple"
1418
+ )
1419
+
1420
+ self._equtype = equtype
1421
+ if len(domains) == 0:
1422
+ rc = new_intp()
1423
+ self._sym_ptr = gmdAddSymbolPy(
1424
+ self._database._gmd,
1425
+ self._name,
1426
+ self._dim,
1427
+ dt_equ,
1428
+ self._equtype,
1429
+ self._text,
1430
+ rc,
1431
+ )
1432
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1433
+ else:
1434
+ dom_ptr = [None] * self._dim
1435
+ rel_dom = [""] * self._dim
1436
+
1437
+ for i in range(self._dim):
1438
+ if isinstance(domains[i], GamsSet):
1439
+ dom_ptr[i] = domains[i]._sym_ptr
1440
+ elif isinstance(domains[i], str):
1441
+ rel_dom[i] = domains[i]
1442
+ else:
1443
+ raise gams.control.workspace.GamsException(
1444
+ "Domain must be GamsSet or string but saw "
1445
+ + str(type(domains[i]))
1446
+ + " on index "
1447
+ + str(i)
1448
+ )
1449
+ rc = new_intp()
1450
+ self._sym_ptr = gmdAddSymbolXPy(
1451
+ self._database._gmd,
1452
+ self._name,
1453
+ self._dim,
1454
+ dt_equ,
1455
+ self._equtype,
1456
+ self._text,
1457
+ dom_ptr,
1458
+ rel_dom,
1459
+ rc,
1460
+ )
1461
+ self._database._check_for_gmd_error(_int_value_and_free(rc))
1462
+
1463
+ else:
1464
+ raise gams.control.workspace.GamsException(
1465
+ "Invalid combination of parameters"
1466
+ )
1467
+
1468
+
1469
+ class GamsDatabaseDomainViolation(object):
1470
+ """
1471
+ @brief This class describes a domain violation of a GamsDatabase.
1472
+ """
1473
+
1474
+ def __init__(self, symbol, dvs):
1475
+ self._symbol = symbol
1476
+ self._symbol_dvs = dvs
1477
+
1478
+ def _get_symbol(self):
1479
+ return self._symbol
1480
+
1481
+ ## @brief GamsSymbol that has a domain violation
1482
+ symbol = property(_get_symbol)
1483
+
1484
+ def _get_symbol_dvs(self):
1485
+ return self._symbol_dvs
1486
+
1487
+ ## @brief List of domain violations represented by objects of type GamsSymbolDomainViolation
1488
+ symbol_dvs = property(_get_symbol_dvs)
1489
+
1490
+
1491
+ class GamsSymbolDomainViolation(object):
1492
+ """
1493
+ This class describes a domain violation of a GamsSymbol.
1494
+ """
1495
+
1496
+ def __init__(self, violation_idx, symbol_record):
1497
+ self._violation_idx = violation_idx
1498
+ self._symbol_record = symbol_record
1499
+
1500
+ def _get_violation_idx(self):
1501
+ return self._violation_idx
1502
+
1503
+ ## @brief Array indicating which positions of a record has a domain violation
1504
+ violation_idx = property(_get_violation_idx)
1505
+
1506
+ def _get_symbol_record(self):
1507
+ return self._symbol_record
1508
+
1509
+ ## @brief GamsSymbolRecord that has a domain violation
1510
+ symbol_record = property(_get_symbol_record)
1511
+
1512
+
1513
+ class GamsDatabase(object):
1514
+ r"""
1515
+ @brief An instance of GamsDatabase communicates data between the Python world and the
1516
+ GAMS world.
1517
+ @details <p>A GamsDatabase consists of a collection of symbols (GamsDatabase
1518
+ implements \__iter__() and next() to allow iterating conveniently
1519
+ through the symbols in a GamsDatabase). The symbol types available for a
1520
+ GamsDatabase correspond to the symbol types known from the GAMS language: Set,
1521
+ Parameter, Variable, and Equation are represented in Python by a derived class
1522
+ (e.g. GamsSet, GamsParameter, etc). Besides the type, a GamsSymbol has a name
1523
+ (this has to match the name inside the GAMS model), a dimension (currently up to
1524
+ 20 or GMS_MAX_INDEX_DIM) and some explanatory text.</p>
1525
+ <p>Variables and equations also have a subtype: e.g. VarType.Binary, VarType.Positive, etc. for
1526
+ variables and e.g. EquType.E, EquType.G etc. for equations</p>
1527
+ <p>GamsDatabases can be created empty, or initialized from existing GDX files or
1528
+ from another GamsDatabase (copy). Symbols can be added at any time (e.g.
1529
+ GamsDatabase.add_parameter), but once a symbol is part of a GamsDatabase, it
1530
+ cannot be removed. Only its associated data (GamsSymbolRecord) can be purged
1531
+ (see GamsSymbol.clear()) or individually removed (GamsSymbol.delete_record).
1532
+ Individual data elements are accessed record by record. A record is identified
1533
+ by the keys (a vector of strings). The record data varies by symbol type. For
1534
+ example, a parameter record has a value property, a variable has the properties
1535
+ level, lower, upper, marginal, and scale. Adding a record with keys that already
1536
+ exist results in an exception. Similar, the unsuccessful search for a record
1537
+ also results in an exception.</p>
1538
+ <p>GamsSymbol implements \__iter__() and next() to conveniently iterate through
1539
+ the records of a symbol. There are also sliced access methods to symbol records
1540
+ that allow to iterate through all records with a fixed index at some positions.
1541
+ GamsDatabases can be exported as GDX files for permanent storage.</p>
1542
+ <p>GamsJob.out_db and GamsModelInstance.sync_db provide instances of GamsDatabase
1543
+ to communicate results from a GAMS run or a solve. These databases should only
1544
+ be used in the context of the base object (GamsJob or GamsModelInstance). If a
1545
+ copy of such a database is required GamsWorkspace.add_database can be used to
1546
+ initialize a GamsDatabase from another database by specifying the optional parameter
1547
+ source_database (e.g. newdb = workspace.add_database(GamsJob.out_db)).</p>
1548
+ <p>GamsDatabases often provide the input data for a GamsJob. Such GamsDatabases are
1549
+ listed in the GamsJob.run method. Inside the GAMS model source the GamsDatabase
1550
+ is accessible through a GDX file. The GAMS model source requires a particular
1551
+ file name to connect to the proper GDX file (e.g. $GDXIN filename). A
1552
+ GamsDatabase can be created with a given name which can be then used inside the
1553
+ model (e.g. db = workspace.add_database(database_name="SupplyData"))
1554
+ and then inside the GAMS model source: $GDXIN SupplyData) or an automatically
1555
+ generated name can be used. This name can be passed down to the GAMS model by
1556
+ using the defines dictionary of a GamsOptions instance:</p>
1557
+ @code{.py}
1558
+ db = workspace.add_database()
1559
+ opt = workspace.add_options()
1560
+ opt.defines["SupplyDataFileName"] = db.name
1561
+ ...
1562
+ gamsjob.run(gams_options=opt, databases=db)
1563
+ @endcode
1564
+ <p>Inside the GAMS model source the name is accessed as follows:</p>
1565
+ @code{.gms}
1566
+ $GDXIN %SupplyDataFileName%
1567
+ @endcode
1568
+ <p>One has to act with some caution when it comes to ordered sets which e.g.
1569
+ allow lag and lead. By not enforcing the "domain checking" for the GamsDatabase
1570
+ class we have aggravated the potential problems for ordered sets.
1571
+ For GAMS, the labels of set elements are just strings, so the order of a set is
1572
+ determined by the appearance of its elements. For example, if one has 'set k
1573
+ / 2,3,4,1,5 /', the order of k is exactly given by this sequence. So the lag (k-1)
1574
+ of k=4 is 3 and the lead (k+1) of k=4 is 1.</p>
1575
+ <p>GAMS performs arithmetic with an extended number range. GAMS has special values
1576
+ for infinity (+INF, -INF), epsilon (EPS), not available (NA), and undefined (UNDEF).
1577
+ When GAMS evaluates expressions with these special values, the calculating engine
1578
+ ensures the correctness of the result (e.g. 5*eps=eps or 5+eps=5). The GAMS model
1579
+ CRAZY in the GAMS Model Library documents the results of the arithmetic operations
1580
+ with respect to special values.</p>
1581
+ <p>In the GAMS Python API we map the IEEE standard values for +/-infinity (float('inf')/float('-inf')) and NA (float('nan'))
1582
+ to the corresponding GAMS values. The
1583
+ special value for UNDEF gets unfiltered through the GAMS Python API. The internal
1584
+ double value of UNDEF is 1.0E300 (or better use the constant SV_UNDEF).</p>
1585
+ <p>Special attention needs to be given to the value of 0. Since GAMS is a sparse system
1586
+ it does not store (parameter) records with a true 0. If a record with numerical value of
1587
+ 0 is needed, EPS(SV_EPS) can help. For example:</p>
1588
+ @code{.gms}
1589
+ set j /1*10 /; parameter b(j); b(j) = 1; b('5') = 0;
1590
+ scalar s,c; s = sum(j, b(j)); c = card(b); display s,c;
1591
+ @endcode
1592
+ <p>will result in</p>
1593
+ @code{.gms}
1594
+ ---- 3 PARAMETER s = 9.000
1595
+ PARAMETER c = 9.000
1596
+ @endcode
1597
+ <p>but</p>
1598
+ @code{.gms}
1599
+ b(j) = 1; b('5') = EPS;
1600
+ @endcode
1601
+ <p>will result in</p>
1602
+ @code{.gms}
1603
+ ---- 3 PARAMETER s = 9.000
1604
+ PARAMETER c = 10.000
1605
+ @endcode
1606
+ <p>What are the consequences for the GAMS Python API? If we read parameter b in case of b('5')=0,
1607
+ the GAMSDatabase will not have a record for b('5'). In case of b('5')=EPS, the GamsDatabase will
1608
+ have a record with value EPS. Unlike the IEEE values (e.g. float("inf")),
1609
+ arithmetic operations in Python will modify EPS (e.g. 5*float("inf")==float("inf")
1610
+ but 5*EPS!=EPS). The same rules apply for preparing input data for GAMS
1611
+ in a GamsDatabase. If a value of EPS is written, GAMS will see the special value EPS.
1612
+ All other small values (including 0) will be communicated unfiltered to GAMS. As mentioned before,
1613
+ zeros will not be entered as data records in GAMS. The compiler control $on/offEPS can help to
1614
+ automatically map zeros to EPS.</p>
1615
+ <p>There is one oddity concerning values smaller than 1e-250 on GAMS input. Consider the following example:</p>
1616
+ @code{.py}
1617
+ b = db.add_parameter("b",1)
1618
+ for i in range(1,11):
1619
+ b.add_record(str(i)).value = 1
1620
+ b.find_record("5").value = 1E-251
1621
+ job.run(db)
1622
+ @endcode
1623
+ @code{.gms}
1624
+ $load j b
1625
+ scalar card_b; card_b = card(b); display card_b;
1626
+ b(j) = 2*b(j); card_b = card(b); display card_b;
1627
+ @endcode
1628
+ <p>A record with values smaller than 1e-250 exists on input in GAMS, but as soon as the record gets
1629
+ updated by GAMS and is still smaller than 1e-250, the record gets removed.</p>
1630
+ <p>The ordering of a set in GAMS can be non-intuitive: Consider "set i /5/, j /1*5/;".
1631
+ Elements '5' gets internal number 1, '1' get 2, '2' gets 3 and so on. The last element
1632
+ of j '5' has already the internal number 1. The sequence of internal numbers in j is
1633
+ not ascending and hence GAMS considers set j as not sorted, i.e. one can't use the
1634
+ ord() function nor the lag or lead (-,--,+,++) operators. If 'j' would have been defined
1635
+ before 'i' in this example, the "set not ordered" problem would have been avoided.</p>
1636
+ <p>Please note that the GamsDatabase actually does not implement a relational model for
1637
+ database management. It should be seen as a data storage or data container.</p>
1638
+ """
1639
+
1640
+ # properties
1641
+
1642
+ def get_nr_symbols(self):
1643
+ ret = gmdInfo(self._gmd, GMD_NRSYMBOLS)
1644
+ self._check_for_gmd_error(ret[0])
1645
+ return ret[1]
1646
+
1647
+ ## @brief Retrieve the number of symbols in the GamsDatabase
1648
+ # @note This is the same as calling len(database)
1649
+ number_symbols = property(get_nr_symbols)
1650
+
1651
+ def get_workspace(self):
1652
+ return self._workspace
1653
+
1654
+ ## @brief Get GamsWorkspace containing GamsDatabase
1655
+ workspace = property(get_workspace)
1656
+
1657
+ def get_name(self):
1658
+ return self._database_name
1659
+
1660
+ ## @brief Get GamsDatabase name
1661
+ name = property(get_name)
1662
+
1663
+ def get_suppress_auto_domain_checking(self):
1664
+ return self._suppress_auto_domain_checking
1665
+
1666
+ def set_suppress_auto_domain_checking(self, value):
1667
+ self._suppress_auto_domain_checking = value
1668
+
1669
+ ## @brief Controls whether domain checking is called in GamsDatabase export
1670
+ suppress_auto_domain_checking = property(
1671
+ get_suppress_auto_domain_checking, set_suppress_auto_domain_checking
1672
+ )
1673
+
1674
+ ## @brief Retrieve the number of symbols in the GamsDatabase
1675
+ def __len__(self):
1676
+ return self.get_nr_symbols()
1677
+
1678
+ def _check_for_gmd_error(self, rc, workspace=None):
1679
+ if not rc:
1680
+ msg = gmdGetLastError(self._gmd)[1]
1681
+ raise gams.control.workspace.GamsException(msg, workspace)
1682
+
1683
+ def __init__(
1684
+ self,
1685
+ ws,
1686
+ database_name=None,
1687
+ gdx_file_name=None,
1688
+ source_database=None,
1689
+ in_model_name=None,
1690
+ force_name=False,
1691
+ gmd_handle=None,
1692
+ ):
1693
+
1694
+ ws._debug_out("---- Entering GamsDatabase constructor ----", 0)
1695
+ self._workspace = ws
1696
+ self._database_name = None
1697
+ if gmd_handle:
1698
+ self._gmd = gmd_handle
1699
+ self._from_gmd = True
1700
+ else:
1701
+ self._gmd = new_gmdHandle_tp()
1702
+ self._from_gmd = False
1703
+ self._record_lock = False
1704
+ self._symbol_lock = False
1705
+ self._suppress_auto_domain_checking = False
1706
+ self._in_model_name = in_model_name
1707
+
1708
+ if not database_name:
1709
+ self._database_name = self._workspace._database_add()
1710
+ else:
1711
+ self._database_name = os.path.splitext(database_name)[0]
1712
+ if (
1713
+ not self._workspace._database_add(self._database_name)
1714
+ and not force_name
1715
+ ):
1716
+ raise gams.control.workspace.GamsException(
1717
+ "Database with name " + self._database_name + " already exists"
1718
+ )
1719
+ if not self._from_gmd:
1720
+ ret = gmdCreateD(self._gmd, self._workspace._system_directory, GMS_SSSIZE)
1721
+ if not ret[0]:
1722
+ raise gams.control.workspace.GamsException(ret[1])
1723
+ # we need to add the gmd handle to ws in order to free it from the workspace
1724
+ ws._gmdHandles.append(self._gmd)
1725
+ # set debug mode
1726
+ if self._workspace._debug == gams.control.workspace.DebugLevel.Verbose:
1727
+ rc = gmdSetDebug(self._gmd, 10)
1728
+ self._check_for_gmd_error(rc)
1729
+
1730
+ # we have to register our special values first
1731
+ if not self._from_gmd:
1732
+ if self._workspace._eps != None:
1733
+ tmp_spec_values = doubleArray(5)
1734
+ tmp_spec_values[0] = _spec_values[0]
1735
+ tmp_spec_values[1] = _spec_values[1]
1736
+ tmp_spec_values[2] = _spec_values[2]
1737
+ tmp_spec_values[3] = _spec_values[3]
1738
+ tmp_spec_values[4] = self._workspace._eps
1739
+ rc = gmdSetSpecialValues(self._gmd, tmp_spec_values)
1740
+ else:
1741
+ rc = gmdSetSpecialValues(self._gmd, _spec_values)
1742
+ self._check_for_gmd_error(rc)
1743
+
1744
+ # in C# this is separated and is located in another constructor
1745
+ if gdx_file_name:
1746
+ if (
1747
+ str.lower(self._database_name)
1748
+ == str.lower(os.path.splitext(gdx_file_name)[0])
1749
+ and not force_name
1750
+ ):
1751
+ raise gams.control.workspace.GamsException(
1752
+ "GAMSDatabase name and gdx file name for initialization must be different (saw "
1753
+ + self._database_name
1754
+ + " for both)"
1755
+ )
1756
+
1757
+ if os.path.isabs(gdx_file_name):
1758
+ rc = gmdInitFromGDX(self._gmd, gdx_file_name)
1759
+ self._check_for_gmd_error(rc)
1760
+ else:
1761
+ rc = gmdInitFromGDX(
1762
+ self._gmd,
1763
+ os.path.join(self._workspace._working_directory, gdx_file_name),
1764
+ )
1765
+ self._check_for_gmd_error(rc)
1766
+
1767
+ # in C# this is separated and is located in another constructor
1768
+ if source_database:
1769
+ rc = gmdInitFromDB(self._gmd, gmdHandleToPtr(source_database._gmd))
1770
+ self._check_for_gmd_error(rc)
1771
+
1772
+ ## @brief Use this to explicitly free unmanaged resources associated with this GamsDatabase
1773
+ def __del__(self):
1774
+ self._workspace._debug_out("---- Entering GamsDatabase destructor ----", 0)
1775
+ if not self._from_gmd:
1776
+ try:
1777
+ if self._gmd != None:
1778
+ if gmdHandleToPtr(self._gmd) != None:
1779
+ gmdFree(self._gmd)
1780
+ except:
1781
+ pass
1782
+
1783
+ def __getitem__(self, symbol_identifier):
1784
+ return self.get_symbol(symbol_identifier)
1785
+
1786
+ def __iter__(self):
1787
+ self._position = -1
1788
+ return self
1789
+
1790
+ def next(self):
1791
+ self._position += 1
1792
+ rc, nr_symbols, dval, sval = gmdInfo(self._gmd, GMD_NRSYMBOLS)
1793
+ if not rc:
1794
+ raise StopIteration
1795
+ if self._position >= nr_symbols:
1796
+ raise StopIteration
1797
+
1798
+ rc = new_intp()
1799
+ sym_ptr = gmdGetSymbolByIndexPy(self._gmd, self._position + 1, rc)
1800
+ self._check_for_gmd_error(_int_value_and_free(rc))
1801
+ rc, type = gmdSymbolType(self._gmd, sym_ptr)
1802
+ self._check_for_gmd_error(rc)
1803
+
1804
+ if type < 0:
1805
+ raise gams.control.workspace.GamsException("Cannot retrieve type of symbol")
1806
+ if dt_var == type:
1807
+ return GamsVariable(self, sym_ptr=sym_ptr)
1808
+ if dt_equ == type:
1809
+ return GamsEquation(self, sym_ptr=sym_ptr)
1810
+ if dt_par == type:
1811
+ return GamsParameter(self, sym_ptr=sym_ptr)
1812
+ if dt_set == type or dt_alias == type:
1813
+ return GamsSet(self, sym_ptr=sym_ptr)
1814
+ raise gams.control.workspace.GamsException("Unknown symbol type " + str(type))
1815
+
1816
+ def __next__(self):
1817
+ return self.next()
1818
+
1819
+ def get_symbol(self, symbol_identifier):
1820
+ """
1821
+ @brief Get GamsSymbol by name
1822
+ @details
1823
+ @code{.py}
1824
+ symbol = database.get_symbol("a")
1825
+ if isinstance(symbol, GamsParameter):
1826
+ print("symbol is a GamsParameter")
1827
+ if isinstance(symbol, GamsSet):
1828
+ print("symbol is a GamsSet")
1829
+ if isinstance(symbol, GamsVariable):
1830
+ print("symbol is a GamsVariable")
1831
+ if isinstance(symbol, GamsEquation):
1832
+ print("symbol is a GamsEquation")
1833
+ @endcode
1834
+ @param symbol_identifier Name of the symbol to retrieve
1835
+ @return Instance of _GamsSymbol
1836
+ @see get_parameter(), get_set(). get_variable(), get_equation()
1837
+ """
1838
+ rc = new_intp()
1839
+ sym_ptr = gmdFindSymbolPy(self._gmd, symbol_identifier, rc)
1840
+ self._check_for_gmd_error(_int_value_and_free(rc))
1841
+ rc, type = gmdSymbolType(self._gmd, sym_ptr)
1842
+ self._check_for_gmd_error(rc)
1843
+
1844
+ # implement this as a dictionary to provide switch-like behavior like in C#
1845
+ if type == dt_equ:
1846
+ return self.get_equation(symbol_identifier)
1847
+ elif type == dt_var:
1848
+ return self.get_variable(symbol_identifier)
1849
+ elif type == dt_par:
1850
+ return self.get_parameter(symbol_identifier)
1851
+ elif type == dt_set:
1852
+ return self.get_set(symbol_identifier)
1853
+ elif type == dt_alias:
1854
+ return self.get_set(symbol_identifier)
1855
+ else:
1856
+ raise gams.control.workspace.GamsException(
1857
+ "Unknown symbol type " + str(type)
1858
+ )
1859
+
1860
+ def get_equation(self, equation_identifier):
1861
+ """
1862
+ @brief Get GamsEquation by name
1863
+ @param equation_identifier Name of the equation to retrieve
1864
+ @return Instance of GamsEquation
1865
+ @see get_symbol(), get_parameter(), get_set(), get_variable()
1866
+ """
1867
+ rc = new_intp()
1868
+ sym_ptr = gmdFindSymbolPy(self._gmd, equation_identifier, rc)
1869
+ self._check_for_gmd_error(_int_value_and_free(rc))
1870
+ rc, type = gmdSymbolType(self._gmd, sym_ptr)
1871
+ self._check_for_gmd_error(rc)
1872
+ if type != dt_equ:
1873
+ raise gams.control.workspace.GamsException(
1874
+ "GamsDatabase: Symbol " + equation_identifier + " is not an equation"
1875
+ )
1876
+ return GamsEquation(self, sym_ptr=sym_ptr)
1877
+
1878
+ def get_parameter(self, parameter_identifier):
1879
+ """
1880
+ @brief Get GamsParameter by name
1881
+ @param parameter_identifier Name of the parameter to retrieve
1882
+ @return Instance of GamsParameter
1883
+ @see get_symbol(), get_set(), get_variable(), get_equation()
1884
+ """
1885
+ rc = new_intp()
1886
+ sym_ptr = gmdFindSymbolPy(self._gmd, parameter_identifier, rc)
1887
+ self._check_for_gmd_error(_int_value_and_free(rc))
1888
+ rc, type = gmdSymbolType(self._gmd, sym_ptr)
1889
+ self._check_for_gmd_error(rc)
1890
+ if type != dt_par:
1891
+ raise gams.control.workspace.GamsException(
1892
+ "GamsDatabase: Symbol " + parameter_identifier + " is not a parameter"
1893
+ )
1894
+ return GamsParameter(self, sym_ptr=sym_ptr)
1895
+
1896
+ def get_variable(self, variable_identifier):
1897
+ """
1898
+ @brief Get GamsVariable by name
1899
+ @param variable_identifier Name of the variable to retrieve
1900
+ @return Instance of GamsVariable
1901
+ @see get_symbol(), get_parameter(), get_set(), get_equation()
1902
+ """
1903
+ rc = new_intp()
1904
+ sym_ptr = gmdFindSymbolPy(self._gmd, variable_identifier, rc)
1905
+ self._check_for_gmd_error(_int_value_and_free(rc))
1906
+ rc, type = gmdSymbolType(self._gmd, sym_ptr)
1907
+ self._check_for_gmd_error(rc)
1908
+ if type != dt_var:
1909
+ raise gams.control.workspace.GamsException(
1910
+ "GamsDatabase: Symbol " + variable_identifier + " is not a variable"
1911
+ )
1912
+ return GamsVariable(self, sym_ptr=sym_ptr)
1913
+
1914
+ def get_set(self, set_identifier):
1915
+ """
1916
+ @brief Get GamsSet by name
1917
+ @param set_identifier Name of the set to retrieve
1918
+ @return Instance of GamsSet
1919
+ @see get_symbol(), get_parameter(), get_variable(), get_equation()
1920
+ """
1921
+ rc = new_intp()
1922
+ sym_ptr = gmdFindSymbolPy(self._gmd, set_identifier, rc)
1923
+ self._check_for_gmd_error(_int_value_and_free(rc))
1924
+ rc, type = gmdSymbolType(self._gmd, sym_ptr)
1925
+ if type != dt_set and type != dt_alias:
1926
+ raise gams.control.workspace.GamsException(
1927
+ "GamsDatabase: Symbol " + set_identifier + " is not a set"
1928
+ )
1929
+ return GamsSet(self, sym_ptr=sym_ptr)
1930
+
1931
+ def add_equation(self, identifier, dimension, equtype, explanatory_text=""):
1932
+ """
1933
+ @brief Add equation symbol to database
1934
+ @param identifier Equation name
1935
+ @param dimension Equation dimension
1936
+ @param equtype Equation subtype (EquType.E: Equal, EquType.G: Greater, EquType.L: Less, EquType.N: No specification, EquType.X: External defined, EquType.C: Conic)
1937
+ @param explanatory_text Explanatory text of equation
1938
+ @return Instance of GamsEquation
1939
+ @see add_parameter(), add_set(), add_variable()
1940
+ """
1941
+ if self._symbol_lock:
1942
+ raise gams.control.workspace.GamsException(
1943
+ "Cannot add symbols to symbol-locked database"
1944
+ )
1945
+ return GamsEquation(self, identifier, dimension, equtype, explanatory_text)
1946
+
1947
+ def add_equation_dc(self, identifier, equtype, domains, explanatory_text=""):
1948
+ """
1949
+ @brief Add equation symbol to database using domain information
1950
+ @param identifier Equation name
1951
+ @param equtype Equation subtype (EquType.E: Equal, EquType.G: Greater, EquType.L: Less, EquType.N: No specification, EquType.X: External defined, EquType.C: Conic)
1952
+ @param domains A list containing GamsSet objects and strings for domain information. The length of the list specifies the dimension.
1953
+ @param explanatory_text Explanatory text of equation
1954
+ @return Instance of GamsEquation
1955
+ @see add_parameter_dc(), add_set_dc(), add_variable_dc()
1956
+ """
1957
+ if self._symbol_lock:
1958
+ raise gams.control.workspace.GamsException(
1959
+ "Cannot add symbols to symbol-locked database"
1960
+ )
1961
+ if domains == None:
1962
+ domains = []
1963
+ return GamsEquation(
1964
+ self, identifier, None, equtype, explanatory_text, domains=domains
1965
+ )
1966
+
1967
+ def add_variable(self, identifier, dimension, vartype, explanatory_text=""):
1968
+ """
1969
+ @brief Add variable symbol to database
1970
+ @param identifier Variable name
1971
+ @param dimension Variable dimension
1972
+ @param vartype Variable subtype (VarType.Binary, VarType.Integer, VarType.Positive, VarType.Negative, VarType.Free, VarType.SOS1, VarType.SOS2, VarType.SemiCont, VarType.SemiInt)
1973
+ @param explanatory_text Explanatory text to variable
1974
+ @return Instance of GamsVariable
1975
+ @see add_equation(), add_parameter(), add_set()
1976
+ """
1977
+ if self._symbol_lock:
1978
+ raise gams.control.workspace.GamsException(
1979
+ "Cannot add symbols to symbol-locked database"
1980
+ )
1981
+ return GamsVariable(self, identifier, dimension, vartype, explanatory_text)
1982
+
1983
+ def add_variable_dc(self, identifier, vartype, domains, explanatory_text=""):
1984
+ """
1985
+ @brief Add variable symbol to database using domain information
1986
+ @param identifier Variable name
1987
+ @param vartype Variable subtype (VarType.Binary, VarType.Integer, VarType.Positive, VarType.Negative, VarType.Free, VarType.SOS1, VarType.SOS2, VarType.SemiCont, VarType.SemiInt)
1988
+ @param domains A list containing GamsSet objects and strings for domain information. The length of the list specifies the dimension.
1989
+ @param explanatory_text Explanatory text to variable
1990
+ @return Instance of GamsVariable
1991
+ @see add_equation_dc(), add_parameter_dc(), add_set_dc()
1992
+ """
1993
+ if self._symbol_lock:
1994
+ raise gams.control.workspace.GamsException(
1995
+ "Cannot add symbols to symbol-locked database"
1996
+ )
1997
+ if domains == None:
1998
+ domains = []
1999
+ return GamsVariable(
2000
+ self, identifier, None, vartype, explanatory_text, domains=domains
2001
+ )
2002
+
2003
+ def add_set(self, identifier, dimension, explanatory_text="", settype=0):
2004
+ """
2005
+ @brief Add set symbol to database
2006
+ @param identifier Set name
2007
+ @param dimension Set dimension
2008
+ @param explanatory_text Explanatory text of set
2009
+ @param settype Set subtype (SetType.Multi, SetType.Singleton)
2010
+ @return Instance of GamsSet
2011
+ @see add_equation(), add_parameter(), add_variable()
2012
+ """
2013
+ if self._symbol_lock:
2014
+ raise gams.control.workspace.GamsException(
2015
+ "Cannot add symbols to symbol-locked database"
2016
+ )
2017
+ return GamsSet(self, identifier, dimension, explanatory_text, settype=settype)
2018
+
2019
+ def add_set_dc(self, identifier, domains, explanatory_text="", settype=0):
2020
+ """
2021
+ @brief Add set symbol to database using domain information
2022
+ @param identifier Set name
2023
+ @param domains A list containing GamsSet objects and strings for domain information. The length of the list specifies the dimension.
2024
+ @param explanatory_text Explanatory text of set
2025
+ @param settype Set subtype (SetType.Multi, SetType.Singleton)
2026
+ @return Instance of GamsSet
2027
+ @see add_equation_dc(), add_parameter_dc(), add_variable_dc()
2028
+ """
2029
+ if self._symbol_lock:
2030
+ raise gams.control.workspace.GamsException(
2031
+ "Cannot add symbols to symbol-locked database"
2032
+ )
2033
+ if domains == None or len(domains) == 0:
2034
+ domains = ["*"]
2035
+ return GamsSet(
2036
+ self, identifier, None, explanatory_text, domains=domains, settype=settype
2037
+ )
2038
+
2039
+ def add_parameter(self, identifier, dimension, explanatory_text=""):
2040
+ """
2041
+ @brief Add parameter symbol to database
2042
+ @param identifier Parameter name
2043
+ @param dimension Parameter dimension
2044
+ @param explanatory_text Explanatory text of parameter
2045
+ @return Instance of GamsParameter
2046
+ @see add_equation(), add_set(), add_variable()
2047
+ """
2048
+ if self._symbol_lock:
2049
+ raise gams.control.workspace.GamsException(
2050
+ "Cannot add symbols to symbol-locked database"
2051
+ )
2052
+ return GamsParameter(self, identifier, dimension, explanatory_text)
2053
+
2054
+ def add_parameter_dc(self, identifier, domains, explanatory_text=""):
2055
+ """
2056
+ @brief Add parameter symbol to database using domain information
2057
+ @param identifier Parameter name
2058
+ @param domains A list containing GamsSet objects and strings for domain information. The length of the list specifies the dimension.
2059
+ @param explanatory_text Explanatory text of parameter
2060
+ @return Instance of GamsParameter
2061
+ @see add_equation_dc(), add_set_dc(), add_variable_dc()
2062
+ """
2063
+ if self._symbol_lock:
2064
+ raise gams.control.workspace.GamsException(
2065
+ "Cannot add symbols to symbol-locked database"
2066
+ )
2067
+ if domains == None:
2068
+ domains = []
2069
+ return GamsParameter(self, identifier, None, explanatory_text, domains=domains)
2070
+
2071
+ def export(self, file_path=None):
2072
+ """
2073
+ @brief Write database into a GDX file
2074
+ @param file_path The path used to write the GDX file.
2075
+ A relative path is relative to the GAMS working directory.
2076
+ If not present, the file is written to the working directory using the name of the database.
2077
+ """
2078
+ if not self._suppress_auto_domain_checking:
2079
+ if not self.check_domains():
2080
+ raise gams.control.workspace.GamsException(
2081
+ "Domain violations in GamsDatabase " + self._database_name
2082
+ )
2083
+
2084
+ if not file_path:
2085
+ rc = gmdWriteGDX(
2086
+ self._gmd,
2087
+ os.path.join(
2088
+ self._workspace._working_directory, self._database_name + ".gdx"
2089
+ ),
2090
+ self._suppress_auto_domain_checking,
2091
+ )
2092
+ self._check_for_gmd_error(rc)
2093
+ else:
2094
+ file_path = os.path.splitext(file_path)[0] + ".gdx"
2095
+ if os.path.isabs(file_path):
2096
+ rc = gmdWriteGDX(
2097
+ self._gmd, file_path, self._suppress_auto_domain_checking
2098
+ )
2099
+ else:
2100
+ rc = gmdWriteGDX(
2101
+ self._gmd,
2102
+ os.path.join(self._workspace._working_directory, file_path),
2103
+ self._suppress_auto_domain_checking,
2104
+ )
2105
+ self._check_for_gmd_error(rc)
2106
+
2107
+ def clear(self):
2108
+ """
2109
+ @brief Clear all symbols in GamsDatabase
2110
+ """
2111
+ for symbol in self:
2112
+ if not symbol.clear():
2113
+ raise gams.control.workspace.GamsException(
2114
+ "Cannot clear symbol " + symbol._name
2115
+ )
2116
+
2117
+ def compact(self):
2118
+ """
2119
+ @brief This function is obsolete and has no effect anymore. It will be removed in the future
2120
+ """
2121
+ # gmdFreeAllSymbolIterators(self._gmd)
2122
+
2123
+ def check_domains(self):
2124
+ """
2125
+ @brief Check for all symbols if all records are within the specified domain of the symbol
2126
+ @return True: Everything is correct, False: There is a domain violation
2127
+ """
2128
+ has_violation = new_intp()
2129
+ rc = gmdCheckDBDV(self._gmd, has_violation)
2130
+ self._check_for_gmd_error(rc)
2131
+ if _int_value_and_free(has_violation) == 1:
2132
+ return False
2133
+ else:
2134
+ return True
2135
+
2136
+ def get_database_dvs(self, max_viol=0, max_viol_per_symbol=0):
2137
+ """
2138
+ @brief return all GamsDatabaseDomainViolations
2139
+ @param max_viol The maximum number of domain violations which should be stored (0 for no limit)
2140
+ @param max_viol_per_symbol The maximum number of domain violations which should be stored per Symbol (0 for no limit)
2141
+ @return List containing GamsDatabaseDomainViolation objects
2142
+ """
2143
+ rc = new_intp()
2144
+ ret_list = []
2145
+ nr_viols = 0
2146
+ dv_handle = gmdGetFirstDBDVPy(self._gmd, rc)
2147
+ self._check_for_gmd_error(_int_value_and_free(rc))
2148
+
2149
+ has_next_db = False
2150
+ if dv_handle != None:
2151
+ has_next = True
2152
+ has_next_db = True
2153
+
2154
+ while has_next_db and (nr_viols < max_viol or max_viol == 0):
2155
+ current_symbol_dvs = []
2156
+ rc = new_intp()
2157
+ current_symbol_ptr = gmdGetDVSymbolPy(self._gmd, dv_handle, rc)
2158
+ self._check_for_gmd_error(_int_value_and_free(rc))
2159
+
2160
+ ret = gmdSymbolInfo(self._gmd, current_symbol_ptr, GMD_DIM)
2161
+ self._check_for_gmd_error(ret[0])
2162
+ dim = ret[1]
2163
+ rc, type = gmdSymbolType(self._gmd, current_symbol_ptr)
2164
+ self._check_for_gmd_error(rc)
2165
+ current_symbol = None
2166
+ if type == dt_equ:
2167
+ current_symbol = GamsEquation(self, sym_ptr=current_symbol_ptr)
2168
+ elif type == dt_var:
2169
+ current_symbol = GamsVariable(self, sym_ptr=current_symbol_ptr)
2170
+ elif type == dt_par:
2171
+ current_symbol = GamsParameter(self, sym_ptr=current_symbol_ptr)
2172
+ elif type == dt_set:
2173
+ current_symbol = GamsSet(self, sym_ptr=current_symbol_ptr)
2174
+
2175
+ while (
2176
+ has_next
2177
+ and (
2178
+ len(current_symbol_dvs) < max_viol_per_symbol
2179
+ or max_viol_per_symbol == 0
2180
+ )
2181
+ and (nr_viols < max_viol or max_viol == 0)
2182
+ ):
2183
+ rc = new_intp()
2184
+ rec = gmdGetDVSymbolRecordPy(self._gmd, dv_handle, rc)
2185
+ self._check_for_gmd_error(_int_value_and_free(rc))
2186
+
2187
+ violation_idx = intArray(dim)
2188
+ rc = gmdGetDVIndicator(self._gmd, dv_handle, violation_idx)
2189
+ self._check_for_gmd_error(rc)
2190
+
2191
+ violation_idx_list = []
2192
+ for i in range(dim):
2193
+ violation_idx_list.append(bool(violation_idx[i]))
2194
+
2195
+ rc, type = gmdSymbolType(self._gmd, current_symbol_ptr)
2196
+ self._check_for_gmd_error(rc)
2197
+ symbol_record = None
2198
+ if type == dt_equ:
2199
+ symbol_record = GamsEquationRecord(current_symbol, rec)
2200
+ elif type == dt_var:
2201
+ symbol_record = GamsVariableRecord(current_symbol, rec)
2202
+ elif type == dt_par:
2203
+ symbol_record = GamsParameterRecord(current_symbol, rec)
2204
+ elif type == dt_set:
2205
+ symbol_record = GamsSetRecord(current_symbol, rec)
2206
+
2207
+ current_symbol_dvs.append(
2208
+ GamsSymbolDomainViolation(violation_idx_list, symbol_record)
2209
+ )
2210
+ nr_viols += 1
2211
+ has_next = new_intp()
2212
+ rc = gmdMoveNextDVInSymbol(self._gmd, dv_handle, has_next)
2213
+ self._check_for_gmd_error(rc)
2214
+ has_next = bool(_int_value_and_free(has_next))
2215
+
2216
+ has_next_db = new_intp()
2217
+ rc = gmdGetFirstDVInNextSymbol(self._gmd, dv_handle, has_next_db)
2218
+ self._check_for_gmd_error(rc)
2219
+ has_next_db = bool(_int_value_and_free(has_next_db))
2220
+ has_next = has_next_db
2221
+
2222
+ ret_list.append(
2223
+ GamsDatabaseDomainViolation(current_symbol, current_symbol_dvs)
2224
+ )
2225
+
2226
+ rc = gmdDomainCheckDone(self._gmd)
2227
+ self._check_for_gmd_error(rc)
2228
+ rc = gmdFreeDVHandle(self._gmd, dv_handle)
2229
+ self._check_for_gmd_error(rc)
2230
+
2231
+ return ret_list