gamsapi 52.5.0__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gams/__init__.py +27 -0
- gams/_version.py +1 -0
- gams/connect/__init__.py +28 -0
- gams/connect/agents/__init__.py +24 -0
- gams/connect/agents/_excel/__init__.py +32 -0
- gams/connect/agents/_excel/excelagent.py +312 -0
- gams/connect/agents/_excel/workbook.py +155 -0
- gams/connect/agents/_sqlconnectors/__init__.py +42 -0
- gams/connect/agents/_sqlconnectors/_accesshandler.py +211 -0
- gams/connect/agents/_sqlconnectors/_databasehandler.py +250 -0
- gams/connect/agents/_sqlconnectors/_mysqlhandler.py +168 -0
- gams/connect/agents/_sqlconnectors/_postgreshandler.py +131 -0
- gams/connect/agents/_sqlconnectors/_pyodbchandler.py +112 -0
- gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +74 -0
- gams/connect/agents/_sqlconnectors/_sqlitehandler.py +262 -0
- gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +179 -0
- gams/connect/agents/concatenate.py +440 -0
- gams/connect/agents/connectagent.py +743 -0
- gams/connect/agents/csvreader.py +675 -0
- gams/connect/agents/csvwriter.py +151 -0
- gams/connect/agents/domainwriter.py +143 -0
- gams/connect/agents/excelreader.py +756 -0
- gams/connect/agents/excelwriter.py +467 -0
- gams/connect/agents/filter.py +223 -0
- gams/connect/agents/gamsreader.py +112 -0
- gams/connect/agents/gamswriter.py +239 -0
- gams/connect/agents/gdxreader.py +109 -0
- gams/connect/agents/gdxwriter.py +146 -0
- gams/connect/agents/labelmanipulator.py +303 -0
- gams/connect/agents/projection.py +539 -0
- gams/connect/agents/pythoncode.py +71 -0
- gams/connect/agents/rawcsvreader.py +248 -0
- gams/connect/agents/rawexcelreader.py +312 -0
- gams/connect/agents/schema/CSVReader.yaml +92 -0
- gams/connect/agents/schema/CSVWriter.yaml +44 -0
- gams/connect/agents/schema/Concatenate.yaml +52 -0
- gams/connect/agents/schema/DomainWriter.yaml +25 -0
- gams/connect/agents/schema/ExcelReader.yaml +121 -0
- gams/connect/agents/schema/ExcelWriter.yaml +78 -0
- gams/connect/agents/schema/Filter.yaml +74 -0
- gams/connect/agents/schema/GAMSReader.yaml +20 -0
- gams/connect/agents/schema/GAMSWriter.yaml +47 -0
- gams/connect/agents/schema/GDXReader.yaml +23 -0
- gams/connect/agents/schema/GDXWriter.yaml +32 -0
- gams/connect/agents/schema/LabelManipulator.yaml +99 -0
- gams/connect/agents/schema/Projection.yaml +24 -0
- gams/connect/agents/schema/PythonCode.yaml +6 -0
- gams/connect/agents/schema/RawCSVReader.yaml +34 -0
- gams/connect/agents/schema/RawExcelReader.yaml +42 -0
- gams/connect/agents/schema/SQLReader.yaml +75 -0
- gams/connect/agents/schema/SQLWriter.yaml +103 -0
- gams/connect/agents/sqlreader.py +301 -0
- gams/connect/agents/sqlwriter.py +276 -0
- gams/connect/connectdatabase.py +275 -0
- gams/connect/connectvalidator.py +93 -0
- gams/connect/errors.py +34 -0
- gams/control/__init__.py +136 -0
- gams/control/database.py +2231 -0
- gams/control/execution.py +1900 -0
- gams/control/options.py +2792 -0
- gams/control/workspace.py +1198 -0
- gams/core/__init__.py +24 -0
- gams/core/cfg/__init__.py +26 -0
- gams/core/cfg/_cfgmcc.cp312-win_amd64.pyd +0 -0
- gams/core/cfg/cfgmcc.py +519 -0
- gams/core/dct/__init__.py +26 -0
- gams/core/dct/_dctmcc.cp312-win_amd64.pyd +0 -0
- gams/core/dct/dctmcc.py +574 -0
- gams/core/embedded/__init__.py +26 -0
- gams/core/embedded/gamsemb.py +1024 -0
- gams/core/emp/__init__.py +24 -0
- gams/core/emp/emplexer.py +89 -0
- gams/core/emp/empyacc.py +281 -0
- gams/core/gdx/__init__.py +26 -0
- gams/core/gdx/_gdxcc.cp312-win_amd64.pyd +0 -0
- gams/core/gdx/gdxcc.py +866 -0
- gams/core/gev/__init__.py +26 -0
- gams/core/gev/_gevmcc.cp312-win_amd64.pyd +0 -0
- gams/core/gev/gevmcc.py +855 -0
- gams/core/gmd/__init__.py +26 -0
- gams/core/gmd/_gmdcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmd/gmdcc.py +917 -0
- gams/core/gmo/__init__.py +26 -0
- gams/core/gmo/_gmomcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmo/gmomcc.py +2046 -0
- gams/core/idx/__init__.py +26 -0
- gams/core/idx/_idxcc.cp312-win_amd64.pyd +0 -0
- gams/core/idx/idxcc.py +510 -0
- gams/core/numpy/__init__.py +29 -0
- gams/core/numpy/_gams2numpy.cp312-win_amd64.pyd +0 -0
- gams/core/numpy/gams2numpy.py +1048 -0
- gams/core/opt/__init__.py +26 -0
- gams/core/opt/_optcc.cp312-win_amd64.pyd +0 -0
- gams/core/opt/optcc.py +840 -0
- gams/engine/__init__.py +204 -0
- gams/engine/api/__init__.py +13 -0
- gams/engine/api/auth_api.py +7653 -0
- gams/engine/api/cleanup_api.py +751 -0
- gams/engine/api/default_api.py +887 -0
- gams/engine/api/hypercube_api.py +2629 -0
- gams/engine/api/jobs_api.py +5229 -0
- gams/engine/api/licenses_api.py +2220 -0
- gams/engine/api/namespaces_api.py +7783 -0
- gams/engine/api/usage_api.py +5627 -0
- gams/engine/api/users_api.py +5931 -0
- gams/engine/api_client.py +804 -0
- gams/engine/api_response.py +21 -0
- gams/engine/configuration.py +601 -0
- gams/engine/exceptions.py +216 -0
- gams/engine/models/__init__.py +86 -0
- gams/engine/models/bad_input.py +89 -0
- gams/engine/models/cleanable_job_result.py +104 -0
- gams/engine/models/cleanable_job_result_page.py +113 -0
- gams/engine/models/engine_license.py +107 -0
- gams/engine/models/files_not_found.py +93 -0
- gams/engine/models/forwarded_token_response.py +112 -0
- gams/engine/models/generic_key_value_pair.py +89 -0
- gams/engine/models/hypercube.py +160 -0
- gams/engine/models/hypercube_page.py +111 -0
- gams/engine/models/hypercube_summary.py +91 -0
- gams/engine/models/hypercube_token.py +97 -0
- gams/engine/models/identity_provider.py +107 -0
- gams/engine/models/identity_provider_ldap.py +121 -0
- gams/engine/models/identity_provider_oauth2.py +146 -0
- gams/engine/models/identity_provider_oauth2_scope.py +89 -0
- gams/engine/models/identity_provider_oauth2_with_secret.py +152 -0
- gams/engine/models/identity_provider_oidc.py +133 -0
- gams/engine/models/identity_provider_oidc_with_secret.py +143 -0
- gams/engine/models/inex.py +91 -0
- gams/engine/models/invitation.py +136 -0
- gams/engine/models/invitation_quota.py +106 -0
- gams/engine/models/invitation_token.py +87 -0
- gams/engine/models/job.py +165 -0
- gams/engine/models/job_no_text_entry.py +138 -0
- gams/engine/models/job_no_text_entry_page.py +111 -0
- gams/engine/models/license.py +91 -0
- gams/engine/models/log_piece.py +96 -0
- gams/engine/models/message.py +87 -0
- gams/engine/models/message_and_token.py +99 -0
- gams/engine/models/message_with_webhook_id.py +89 -0
- gams/engine/models/model_auth_token.py +87 -0
- gams/engine/models/model_configuration.py +125 -0
- gams/engine/models/model_default_instance.py +99 -0
- gams/engine/models/model_default_user_instance.py +98 -0
- gams/engine/models/model_hypercube_job.py +106 -0
- gams/engine/models/model_hypercube_usage.py +130 -0
- gams/engine/models/model_instance_info.py +116 -0
- gams/engine/models/model_instance_info_full.py +123 -0
- gams/engine/models/model_instance_pool_info.py +112 -0
- gams/engine/models/model_job_labels.py +179 -0
- gams/engine/models/model_job_usage.py +133 -0
- gams/engine/models/model_pool_usage.py +124 -0
- gams/engine/models/model_usage.py +115 -0
- gams/engine/models/model_user.py +96 -0
- gams/engine/models/model_userinstance_info.py +119 -0
- gams/engine/models/model_userinstancepool_info.py +95 -0
- gams/engine/models/model_version.py +91 -0
- gams/engine/models/models.py +120 -0
- gams/engine/models/namespace.py +104 -0
- gams/engine/models/namespace_quota.py +96 -0
- gams/engine/models/namespace_with_permission.py +96 -0
- gams/engine/models/not_found.py +91 -0
- gams/engine/models/password_policy.py +97 -0
- gams/engine/models/perm_and_username.py +89 -0
- gams/engine/models/quota.py +117 -0
- gams/engine/models/quota_exceeded.py +97 -0
- gams/engine/models/status_code_meaning.py +89 -0
- gams/engine/models/stream_entry.py +89 -0
- gams/engine/models/system_wide_license.py +92 -0
- gams/engine/models/text_entries.py +87 -0
- gams/engine/models/text_entry.py +101 -0
- gams/engine/models/time_span.py +95 -0
- gams/engine/models/time_span_pool_worker.py +99 -0
- gams/engine/models/token_forward_error.py +87 -0
- gams/engine/models/user.py +127 -0
- gams/engine/models/user_group_member.py +96 -0
- gams/engine/models/user_groups.py +108 -0
- gams/engine/models/vapid_info.py +87 -0
- gams/engine/models/webhook.py +138 -0
- gams/engine/models/webhook_parameterized_event.py +99 -0
- gams/engine/py.typed +0 -0
- gams/engine/rest.py +258 -0
- gams/magic/__init__.py +32 -0
- gams/magic/gams_magic.py +142 -0
- gams/magic/interactive.py +402 -0
- gams/tools/__init__.py +30 -0
- gams/tools/errors.py +34 -0
- gams/tools/toolcollection/__init__.py +24 -0
- gams/tools/toolcollection/alg/__init__.py +24 -0
- gams/tools/toolcollection/alg/rank.py +51 -0
- gams/tools/toolcollection/data/__init__.py +24 -0
- gams/tools/toolcollection/data/csvread.py +444 -0
- gams/tools/toolcollection/data/csvwrite.py +311 -0
- gams/tools/toolcollection/data/exceldump.py +47 -0
- gams/tools/toolcollection/data/sqlitewrite.py +276 -0
- gams/tools/toolcollection/gdxservice/__init__.py +24 -0
- gams/tools/toolcollection/gdxservice/gdxencoding.py +104 -0
- gams/tools/toolcollection/gdxservice/gdxrename.py +94 -0
- gams/tools/toolcollection/linalg/__init__.py +24 -0
- gams/tools/toolcollection/linalg/cholesky.py +57 -0
- gams/tools/toolcollection/linalg/eigenvalue.py +56 -0
- gams/tools/toolcollection/linalg/eigenvector.py +58 -0
- gams/tools/toolcollection/linalg/invert.py +55 -0
- gams/tools/toolcollection/linalg/ols.py +138 -0
- gams/tools/toolcollection/tooltemplate.py +321 -0
- gams/tools/toolcollection/win32/__init__.py +24 -0
- gams/tools/toolcollection/win32/excelmerge.py +93 -0
- gams/tools/toolcollection/win32/exceltalk.py +76 -0
- gams/tools/toolcollection/win32/msappavail.py +49 -0
- gams/tools/toolcollection/win32/shellexecute.py +54 -0
- gams/tools/tools.py +116 -0
- gams/transfer/__init__.py +35 -0
- gams/transfer/_abcs/__init__.py +37 -0
- gams/transfer/_abcs/container_abcs.py +433 -0
- gams/transfer/_internals/__init__.py +63 -0
- gams/transfer/_internals/algorithms.py +436 -0
- gams/transfer/_internals/casepreservingdict.py +124 -0
- gams/transfer/_internals/constants.py +270 -0
- gams/transfer/_internals/domainviolation.py +103 -0
- gams/transfer/_internals/specialvalues.py +172 -0
- gams/transfer/containers/__init__.py +26 -0
- gams/transfer/containers/_container.py +1794 -0
- gams/transfer/containers/_io/__init__.py +28 -0
- gams/transfer/containers/_io/containers.py +164 -0
- gams/transfer/containers/_io/gdx.py +1029 -0
- gams/transfer/containers/_io/gmd.py +872 -0
- gams/transfer/containers/_mixins/__init__.py +26 -0
- gams/transfer/containers/_mixins/ccc.py +1274 -0
- gams/transfer/syms/__init__.py +33 -0
- gams/transfer/syms/_methods/__init__.py +24 -0
- gams/transfer/syms/_methods/tables.py +120 -0
- gams/transfer/syms/_methods/toDict.py +115 -0
- gams/transfer/syms/_methods/toList.py +83 -0
- gams/transfer/syms/_methods/toValue.py +60 -0
- gams/transfer/syms/_mixins/__init__.py +32 -0
- gams/transfer/syms/_mixins/equals.py +626 -0
- gams/transfer/syms/_mixins/generateRecords.py +499 -0
- gams/transfer/syms/_mixins/pivot.py +313 -0
- gams/transfer/syms/_mixins/pve.py +627 -0
- gams/transfer/syms/_mixins/sa.py +27 -0
- gams/transfer/syms/_mixins/sapve.py +27 -0
- gams/transfer/syms/_mixins/saua.py +27 -0
- gams/transfer/syms/_mixins/sauapve.py +199 -0
- gams/transfer/syms/_mixins/spve.py +1528 -0
- gams/transfer/syms/_mixins/ve.py +936 -0
- gams/transfer/syms/container_syms/__init__.py +31 -0
- gams/transfer/syms/container_syms/_alias.py +984 -0
- gams/transfer/syms/container_syms/_equation.py +333 -0
- gams/transfer/syms/container_syms/_parameter.py +973 -0
- gams/transfer/syms/container_syms/_set.py +604 -0
- gams/transfer/syms/container_syms/_universe_alias.py +461 -0
- gams/transfer/syms/container_syms/_variable.py +321 -0
- gamsapi-52.5.0.dist-info/METADATA +150 -0
- gamsapi-52.5.0.dist-info/RECORD +257 -0
- gamsapi-52.5.0.dist-info/WHEEL +5 -0
- gamsapi-52.5.0.dist-info/licenses/LICENSE +22 -0
- gamsapi-52.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
import copy
|
|
27
|
+
import re
|
|
28
|
+
from gams.connect.agents.connectagent import ConnectAgent
|
|
29
|
+
import gams.transfer as gt
|
|
30
|
+
import pandas as pd
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Projection(ConnectAgent):
|
|
34
|
+
|
|
35
|
+
def __init__(self, cdb, inst, agent_index):
|
|
36
|
+
super().__init__(cdb, inst, agent_index)
|
|
37
|
+
self._parse_options(self._inst)
|
|
38
|
+
|
|
39
|
+
def _parse_options(self, inst):
|
|
40
|
+
self._aggregation_method = inst["aggregationMethod"]
|
|
41
|
+
self._as_set = inst["asSet"]
|
|
42
|
+
self._name = inst["name"]
|
|
43
|
+
self._new_name = inst["newName"]
|
|
44
|
+
self._text = inst["text"]
|
|
45
|
+
self._trace = inst["trace"]
|
|
46
|
+
|
|
47
|
+
def _generate_text(self, df, ssym, sdom, suffix_list, suffix_to_index):
|
|
48
|
+
"""Generates set element text."""
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
(isinstance(ssym, gt.Set) and not self._text in [None, ""])
|
|
52
|
+
or (
|
|
53
|
+
isinstance(ssym, (gt.Variable, gt.Equation))
|
|
54
|
+
and suffix_list
|
|
55
|
+
and not suffix_to_index
|
|
56
|
+
and not self._text in [None, ""]
|
|
57
|
+
)
|
|
58
|
+
or (isinstance(ssym, gt.Parameter) and not self._text in [None, ""])
|
|
59
|
+
):
|
|
60
|
+
df.columns = [*df.columns[:-1], "element_text"]
|
|
61
|
+
df["element_text"] = df["element_text"].astype(str)
|
|
62
|
+
sdom.append("element_text")
|
|
63
|
+
execcmd = 'df["element_text"] = ("' + self._text + '")'
|
|
64
|
+
for i, r in enumerate(sdom):
|
|
65
|
+
execcmd = execcmd.replace(
|
|
66
|
+
"{" + r + "}",
|
|
67
|
+
'" + df[df.columns[' + str(i) + ']].astype(str) + "',
|
|
68
|
+
)
|
|
69
|
+
exec(execcmd)
|
|
70
|
+
if self._trace > 2:
|
|
71
|
+
self._cdb.print_log(f"DataFrame after text adjustment:\n{df}")
|
|
72
|
+
|
|
73
|
+
return df
|
|
74
|
+
|
|
75
|
+
def _combine_scalars(self):
|
|
76
|
+
"""Aggregates a list of scalars of the same type into a 1-dimensional symbol (of the same type) that holds the symbol names as labels."""
|
|
77
|
+
|
|
78
|
+
symrecords_list = []
|
|
79
|
+
sym_types = []
|
|
80
|
+
for sym_name in self._name:
|
|
81
|
+
self._symbols_exist_cdb(sym_name, should_exist=True)
|
|
82
|
+
sym = self._cdb.container[sym_name]
|
|
83
|
+
if sym.dimension != 0:
|
|
84
|
+
self._connect_error(
|
|
85
|
+
f"Symbol '{sym_name}' needs to be a scalar when specified in <name> using a list."
|
|
86
|
+
)
|
|
87
|
+
sym_types.append(type(sym))
|
|
88
|
+
df = self._sym_records_no_none(sym).copy(deep=True)
|
|
89
|
+
symrecords_list.append(df)
|
|
90
|
+
if not all(t == sym_types[0] for t in sym_types):
|
|
91
|
+
self._connect_error(
|
|
92
|
+
"All symbols need to be of the same type when specified in <name> using a list."
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
df = pd.concat(symrecords_list, ignore_index=True)
|
|
96
|
+
df.insert(0, "uni_0", self._name)
|
|
97
|
+
sym0 = self._cdb.container[self._name[0]]
|
|
98
|
+
|
|
99
|
+
if isinstance(sym0, gt.Parameter):
|
|
100
|
+
gt.Parameter(
|
|
101
|
+
self._cdb.container,
|
|
102
|
+
self._new_name,
|
|
103
|
+
["*"],
|
|
104
|
+
records=df,
|
|
105
|
+
)
|
|
106
|
+
elif isinstance(sym0, gt.Equation):
|
|
107
|
+
gt.Equation(
|
|
108
|
+
self._cdb.container,
|
|
109
|
+
self._new_name,
|
|
110
|
+
sym0.type,
|
|
111
|
+
["*"],
|
|
112
|
+
records=df,
|
|
113
|
+
)
|
|
114
|
+
elif isinstance(sym0, gt.Variable):
|
|
115
|
+
gt.Variable(
|
|
116
|
+
self._cdb.container,
|
|
117
|
+
self._new_name,
|
|
118
|
+
sym0.type,
|
|
119
|
+
["*"],
|
|
120
|
+
records=df,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def _split_index(self, match, symname, allow_duplicates=False):
|
|
124
|
+
"""Splits provided index space into a list of indices. Return an empty list if no index space is provided."""
|
|
125
|
+
|
|
126
|
+
if match.group("index") is not None:
|
|
127
|
+
index = [d.strip() for d in match.group("index").split(",")]
|
|
128
|
+
if allow_duplicates:
|
|
129
|
+
return index
|
|
130
|
+
|
|
131
|
+
for i in index:
|
|
132
|
+
if index.count(i) > 1:
|
|
133
|
+
self._connect_error(
|
|
134
|
+
f"Multiple use of index >{i}< in index list of symbol >{symname}<."
|
|
135
|
+
)
|
|
136
|
+
return index
|
|
137
|
+
else:
|
|
138
|
+
return []
|
|
139
|
+
|
|
140
|
+
def _process_symbol_name(self):
|
|
141
|
+
"""Processes strings provided by the name/newName option. Splits name/newName into the symbol name, suffix and index list."""
|
|
142
|
+
|
|
143
|
+
regex = r"(?P<name>[a-zA-Z0-9_]+)(\.?(?P<suffix>([a-zA-Z]*)|(\[[a-zA-Z,\s]*\])))?(\((?P<index>[a-zA-Z0-9_,\s]*)\))?"
|
|
144
|
+
ms = re.fullmatch(regex, self._name)
|
|
145
|
+
if not ms:
|
|
146
|
+
self._connect_error(f"Invalid <name>: >{self._name}<.")
|
|
147
|
+
mt = re.fullmatch(regex, self._new_name)
|
|
148
|
+
if not mt:
|
|
149
|
+
self._connect_error(f"Invalid <newName>: >{self._new_name}<.")
|
|
150
|
+
|
|
151
|
+
# NAME
|
|
152
|
+
ssym_name = ms.group("name")
|
|
153
|
+
self._symbols_exist_cdb(ssym_name, should_exist=True)
|
|
154
|
+
ssym = self._cdb.container[ssym_name]
|
|
155
|
+
tsym_name = mt.group("name")
|
|
156
|
+
|
|
157
|
+
# INDEX
|
|
158
|
+
# Source symbol
|
|
159
|
+
sindex_list = self._split_index(ms, ssym_name)
|
|
160
|
+
|
|
161
|
+
# Target symbol
|
|
162
|
+
tindex_list = self._split_index(mt, tsym_name, allow_duplicates=True)
|
|
163
|
+
|
|
164
|
+
if len(sindex_list) != ssym.dimension:
|
|
165
|
+
self._connect_error(
|
|
166
|
+
f"Number of provided indices for symbol >{ssym_name}< <> dimension of the symbol ({len(sindex_list)}<>{ssym.dimension})."
|
|
167
|
+
)
|
|
168
|
+
if set(tindex_list) - set(sindex_list):
|
|
169
|
+
self._connect_error(
|
|
170
|
+
f"Unknown index >{(set(tindex_list) - set(sindex_list))}< in <newName>: >{self._new_name}<."
|
|
171
|
+
)
|
|
172
|
+
index_map = [sindex_list.index(d) for d in tindex_list]
|
|
173
|
+
tsym_domain = [ssym.domain[d] for d in index_map]
|
|
174
|
+
|
|
175
|
+
# SUFFIX
|
|
176
|
+
suffix_dict = {
|
|
177
|
+
"l": "level",
|
|
178
|
+
"m": "marginal",
|
|
179
|
+
"lo": "lower",
|
|
180
|
+
"up": "upper",
|
|
181
|
+
"scale": "scale",
|
|
182
|
+
"all": "all",
|
|
183
|
+
}
|
|
184
|
+
attribute_list = [a for a in suffix_dict.values() if a != "all"]
|
|
185
|
+
|
|
186
|
+
if mt.group("suffix"):
|
|
187
|
+
self._connect_error(f"No suffix allowed on <newName>: >{self._new_name}<.")
|
|
188
|
+
suffix = ms.group("suffix")
|
|
189
|
+
if suffix == "":
|
|
190
|
+
suffix_list = []
|
|
191
|
+
|
|
192
|
+
suffix_to_index = False
|
|
193
|
+
if suffix:
|
|
194
|
+
if not isinstance(ssym, (gt.Variable, gt.Equation)):
|
|
195
|
+
self._connect_error(
|
|
196
|
+
f"Suffix given but symbol >{ssym_name}< is not a variable or an equation."
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
if re.search(r"[\[\]]", suffix):
|
|
200
|
+
suffix_to_index = True
|
|
201
|
+
tsym_domain.append("attribute")
|
|
202
|
+
suffix = re.sub(r"[\[\]]", "", suffix)
|
|
203
|
+
if suffix == "":
|
|
204
|
+
self._connect_error("Suffix list is empty.")
|
|
205
|
+
else:
|
|
206
|
+
suffix_list = list(
|
|
207
|
+
dict.fromkeys(s.strip() for s in suffix.split(","))
|
|
208
|
+
)
|
|
209
|
+
else:
|
|
210
|
+
suffix_list = [suffix]
|
|
211
|
+
|
|
212
|
+
for s in suffix_list:
|
|
213
|
+
if s not in suffix_dict.keys():
|
|
214
|
+
self._connect_error(
|
|
215
|
+
f"Unknown suffix >{s}< (use {', '.join([s for s in suffix_dict.keys()])})."
|
|
216
|
+
)
|
|
217
|
+
# resolve v.all and v.[all]
|
|
218
|
+
if "all" in suffix_list:
|
|
219
|
+
suffix_list = attribute_list
|
|
220
|
+
if not suffix_to_index: # might have been added before already
|
|
221
|
+
suffix_to_index = True
|
|
222
|
+
tsym_domain.append("attribute")
|
|
223
|
+
else:
|
|
224
|
+
suffix_list = list(map(suffix_dict.get, suffix_list))
|
|
225
|
+
|
|
226
|
+
if self._trace > 1:
|
|
227
|
+
self._cdb.print_log(
|
|
228
|
+
"Processed <name>:"
|
|
229
|
+
f"\n name: >{ssym_name}<"
|
|
230
|
+
f"\n index: >{sindex_list}<"
|
|
231
|
+
f"\n suffix: >{suffix_list}<"
|
|
232
|
+
f"\n suffix to index: >{suffix_to_index}<"
|
|
233
|
+
"\n"
|
|
234
|
+
)
|
|
235
|
+
self._cdb.print_log(
|
|
236
|
+
"Processed <newName>:"
|
|
237
|
+
f"\n name: >{tsym_name}<"
|
|
238
|
+
f"\n index: >{tindex_list}<"
|
|
239
|
+
"\n"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
self._symbols_exist_cdb(tsym_name)
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
ssym,
|
|
246
|
+
ssym_name,
|
|
247
|
+
sindex_list,
|
|
248
|
+
suffix_list,
|
|
249
|
+
suffix_to_index,
|
|
250
|
+
tsym_name,
|
|
251
|
+
tindex_list,
|
|
252
|
+
index_map,
|
|
253
|
+
tsym_domain,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def _create_target_symbol(
|
|
257
|
+
self, ssym, ssym_name, tsym_name, tsym_domain, suffix_list
|
|
258
|
+
):
|
|
259
|
+
"""Create target symbol in Connect container."""
|
|
260
|
+
|
|
261
|
+
if self._as_set or isinstance(ssym, gt.Set):
|
|
262
|
+
tsym = gt.Set(self._cdb.container, tsym_name, tsym_domain)
|
|
263
|
+
elif suffix_list or isinstance(ssym, gt.Parameter):
|
|
264
|
+
tsym = gt.Parameter(self._cdb.container, tsym_name, tsym_domain)
|
|
265
|
+
elif isinstance(ssym, gt.Equation):
|
|
266
|
+
tsym = gt.Equation(self._cdb.container, tsym_name, ssym.type, tsym_domain)
|
|
267
|
+
elif isinstance(ssym, gt.Variable):
|
|
268
|
+
tsym = gt.Variable(self._cdb.container, tsym_name, ssym.type, tsym_domain)
|
|
269
|
+
else:
|
|
270
|
+
self._connect_error(
|
|
271
|
+
f"Projection can't handle symbol type >{type(ssym)}< of symbol >{ssym_name}<."
|
|
272
|
+
)
|
|
273
|
+
if self._trace > 1:
|
|
274
|
+
self._cdb.print_log(
|
|
275
|
+
f"Created >{tsym_name}< as {len(tsym_domain)}-dim {type(tsym)}.\n"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
return tsym
|
|
279
|
+
|
|
280
|
+
def _apply_aggregation_method(self, df, ssym_name, index_map):
|
|
281
|
+
"""Applies selected aggregation method."""
|
|
282
|
+
|
|
283
|
+
if len(index_map) > 0:
|
|
284
|
+
df = df.groupby(
|
|
285
|
+
[self._cdb.container[ssym_name].domain_labels[d] for d in index_map]
|
|
286
|
+
)
|
|
287
|
+
if not hasattr(df, self._aggregation_method):
|
|
288
|
+
self._connect_error(
|
|
289
|
+
f"Invalid aggregationMethod >{self._aggregation_method}<."
|
|
290
|
+
)
|
|
291
|
+
func = getattr(df, self._aggregation_method)
|
|
292
|
+
if not callable(func):
|
|
293
|
+
self._connect_error(
|
|
294
|
+
f"Invalid aggregationMethod >{self._aggregation_method}<. Not callable."
|
|
295
|
+
)
|
|
296
|
+
df = func()
|
|
297
|
+
if self._trace > 2:
|
|
298
|
+
self._cdb.print_log(f"DataFrame after aggregation:\n{df}")
|
|
299
|
+
return df
|
|
300
|
+
|
|
301
|
+
def _drop_text(self, df, ssym, suffix_list, suffix_to_index):
|
|
302
|
+
"""Drops set element text."""
|
|
303
|
+
|
|
304
|
+
if isinstance(ssym, gt.Set) and self._text == "":
|
|
305
|
+
df.drop(columns=df.columns[-1], inplace=True)
|
|
306
|
+
elif isinstance(ssym, (gt.Variable, gt.Equation)) and suffix_to_index:
|
|
307
|
+
df.drop(columns=df.columns[-1], inplace=True)
|
|
308
|
+
elif (
|
|
309
|
+
isinstance(ssym, (gt.Variable, gt.Equation))
|
|
310
|
+
and suffix_list
|
|
311
|
+
and self._text in [None, ""]
|
|
312
|
+
):
|
|
313
|
+
df.drop(columns=df.columns[-1], inplace=True)
|
|
314
|
+
elif isinstance(ssym, (gt.Variable, gt.Equation)) and not suffix_list:
|
|
315
|
+
df.drop(
|
|
316
|
+
columns=["level", "marginal", "lower", "upper", "scale"],
|
|
317
|
+
inplace=True,
|
|
318
|
+
)
|
|
319
|
+
elif isinstance(ssym, gt.Parameter) and self._text in [None, ""]:
|
|
320
|
+
df.drop(columns=df.columns[-1], inplace=True)
|
|
321
|
+
|
|
322
|
+
return df
|
|
323
|
+
|
|
324
|
+
def _apply_categories(self, ssym, tsym, suffix_to_index, suffix_list, index_map):
|
|
325
|
+
"""Applies categories from the source symbol to the domains of the target symbol."""
|
|
326
|
+
|
|
327
|
+
if tsym.dimension > 0:
|
|
328
|
+
for i in range(tsym.dimension):
|
|
329
|
+
if suffix_to_index and i == tsym.dimension - 1:
|
|
330
|
+
cats = suffix_list
|
|
331
|
+
else:
|
|
332
|
+
cats = ssym.records[
|
|
333
|
+
ssym.records.columns[index_map[i]]
|
|
334
|
+
].cat.categories
|
|
335
|
+
|
|
336
|
+
tsym.records.isetitem(
|
|
337
|
+
i,
|
|
338
|
+
tsym.records.iloc[:, i].astype(
|
|
339
|
+
pd.CategoricalDtype(
|
|
340
|
+
categories=cats,
|
|
341
|
+
ordered=True,
|
|
342
|
+
)
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
def execute(self):
|
|
347
|
+
if self._trace > 0:
|
|
348
|
+
self._log_instructions(self._inst, self._inst_raw)
|
|
349
|
+
self._describe_container(self._cdb.container, "Connect Container (before):")
|
|
350
|
+
|
|
351
|
+
# list of scalars into a 1-dim parameter/var/equ
|
|
352
|
+
if isinstance(self._name, list):
|
|
353
|
+
self._combine_scalars()
|
|
354
|
+
|
|
355
|
+
if self._trace > 2:
|
|
356
|
+
self._cdb.print_log(
|
|
357
|
+
f"Connect Container symbol={self._new_name}:\n {self._cdb.container[self._new_name].records}\n"
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
return
|
|
361
|
+
|
|
362
|
+
(
|
|
363
|
+
ssym,
|
|
364
|
+
ssym_name,
|
|
365
|
+
sindex_list,
|
|
366
|
+
suffix_list,
|
|
367
|
+
suffix_to_index,
|
|
368
|
+
tsym_name,
|
|
369
|
+
tindex_list,
|
|
370
|
+
index_map,
|
|
371
|
+
tsym_domain,
|
|
372
|
+
) = self._process_symbol_name()
|
|
373
|
+
|
|
374
|
+
# Get unique index, map lists
|
|
375
|
+
tindex_list_unq = list(dict.fromkeys(tindex_list)) # (i,j,i) -> (i,j)
|
|
376
|
+
index_map_unq = list(dict.fromkeys(index_map)) # (0,1,0) -> (0,1)
|
|
377
|
+
|
|
378
|
+
if tindex_list_unq != tindex_list: # duplicate index (e.g. newName: p(i,j,i))
|
|
379
|
+
if self._trace > 1:
|
|
380
|
+
self._cdb.print_log(
|
|
381
|
+
f"Duplicate indices found. Processing symbol without duplicate indices: {tsym_name}({','.join(tindex_list)}) -> {tsym_name}({','.join(tindex_list_unq)}).\n"
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
tsym = self._create_target_symbol(
|
|
385
|
+
ssym, ssym_name, tsym_name, tsym_domain, suffix_list
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
assert len(index_map) == tsym.dimension or (
|
|
389
|
+
len(index_map) + 1 == tsym.dimension and suffix_to_index
|
|
390
|
+
), "Number of domains for <newName> <> dimension of <newName>"
|
|
391
|
+
assert len(tsym_domain) == tsym.dimension or (
|
|
392
|
+
len(tsym_domain) + 1 == tsym.dimension and suffix_to_index
|
|
393
|
+
), "Number of domains for <newName> <> dimension of <newName>"
|
|
394
|
+
assert (
|
|
395
|
+
not suffix_list or isinstance(tsym, gt.Parameter) or self._as_set
|
|
396
|
+
), "Type of <newName> needs to be parameter or asSet needs to be True"
|
|
397
|
+
assert (
|
|
398
|
+
suffix_list
|
|
399
|
+
or suffix_to_index
|
|
400
|
+
or self._as_set
|
|
401
|
+
or isinstance(ssym, type(tsym))
|
|
402
|
+
), "No suffix, asSet: False but type of <name> <> type of <newName>"
|
|
403
|
+
|
|
404
|
+
df = copy.deepcopy(self._cdb.container[ssym_name].records)
|
|
405
|
+
# For symbols with None records or empty dataframe, an empty df is assigned then returned
|
|
406
|
+
if df is None or df.empty:
|
|
407
|
+
self._transform_sym_none_to_empty(tsym)
|
|
408
|
+
return
|
|
409
|
+
|
|
410
|
+
if suffix_list:
|
|
411
|
+
suffixes_to_drop = set(
|
|
412
|
+
["level", "marginal", "lower", "upper", "scale"]
|
|
413
|
+
) - set(suffix_list)
|
|
414
|
+
df.drop(columns=list(suffixes_to_drop), inplace=True)
|
|
415
|
+
if self._trace > 2:
|
|
416
|
+
self._cdb.print_log(f"DataFrame after dropping suffixes:\n{df}")
|
|
417
|
+
|
|
418
|
+
if isinstance(tsym, gt.Set):
|
|
419
|
+
df = self._generate_text(
|
|
420
|
+
df, ssym, sindex_list, suffix_list, suffix_to_index
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if self._aggregation_method is None: # no aggregation
|
|
424
|
+
permutation = index_map_unq != list(range(len(index_map_unq))) or len(
|
|
425
|
+
sindex_list
|
|
426
|
+
) > len(tindex_list_unq)
|
|
427
|
+
if permutation:
|
|
428
|
+
if self._trace > 1:
|
|
429
|
+
self._cdb.print_log("Permutation only.")
|
|
430
|
+
attributes = df.columns.tolist()[ssym.dimension :]
|
|
431
|
+
cols_permuted = [
|
|
432
|
+
df.columns.tolist()[i] for i in index_map_unq
|
|
433
|
+
] + attributes
|
|
434
|
+
if self._trace > 2:
|
|
435
|
+
self._cdb.print_log(f"DataFrame before permutation:\n{df}")
|
|
436
|
+
if self._trace > 1:
|
|
437
|
+
self._cdb.print_log(f"Column permutation:\n{cols_permuted}")
|
|
438
|
+
df = df.reindex(columns=cols_permuted)
|
|
439
|
+
if self._trace > 2:
|
|
440
|
+
self._cdb.print_log(f"DataFrame after permutation:\n{df}")
|
|
441
|
+
|
|
442
|
+
if suffix_to_index:
|
|
443
|
+
# stack suffix index
|
|
444
|
+
if ssym.dimension == 0:
|
|
445
|
+
# source and target symbols have 0 dimensions (scalar)
|
|
446
|
+
df = df.stack().droplevel(0)
|
|
447
|
+
df = list(dict(df).items())
|
|
448
|
+
else:
|
|
449
|
+
if len(index_map_unq) > 0:
|
|
450
|
+
new_index = [
|
|
451
|
+
df.columns.tolist()[i] for i in range(len(index_map_unq))
|
|
452
|
+
]
|
|
453
|
+
df.set_index(new_index, inplace=True)
|
|
454
|
+
df = df.stack().reset_index()
|
|
455
|
+
else:
|
|
456
|
+
df = df.stack().droplevel(0)
|
|
457
|
+
if self._trace > 2:
|
|
458
|
+
self._cdb.print_log(f"DataFrame after stacking suffix index:\n{df}")
|
|
459
|
+
|
|
460
|
+
else:
|
|
461
|
+
# TODO: Raise error if sets, variable or equations (without suffix) are not used with first/last aggregation
|
|
462
|
+
drop_cols = self._cdb.container[ssym_name].domain_labels[: ssym.dimension]
|
|
463
|
+
df[drop_cols] = df[drop_cols].astype(str)
|
|
464
|
+
|
|
465
|
+
if (
|
|
466
|
+
tsym.dimension == 0 or (tsym.dimension == 1 and suffix_to_index)
|
|
467
|
+
) and self._aggregation_method in [
|
|
468
|
+
"first",
|
|
469
|
+
"last",
|
|
470
|
+
]:
|
|
471
|
+
# target symbol has 0 dimensions (scalar) and aggregation first/last -> fast aggregation
|
|
472
|
+
|
|
473
|
+
df.drop(columns=drop_cols, inplace=True)
|
|
474
|
+
if self._trace > 2:
|
|
475
|
+
self._cdb.print_log(f"DataFrame after dropping columns:\n{df}")
|
|
476
|
+
if self._aggregation_method == "first":
|
|
477
|
+
df = df.iloc[0]
|
|
478
|
+
else:
|
|
479
|
+
df = df.iloc[-1]
|
|
480
|
+
if isinstance(tsym, (gt.Variable, gt.Equation)):
|
|
481
|
+
df = dict(df)
|
|
482
|
+
elif suffix_to_index:
|
|
483
|
+
df = list(dict(df).items())
|
|
484
|
+
if self._trace > 2:
|
|
485
|
+
self._cdb.print_log(
|
|
486
|
+
f"DataFrame after first/last aggregation:\n{df}"
|
|
487
|
+
)
|
|
488
|
+
else:
|
|
489
|
+
if ssym.dimension != 0:
|
|
490
|
+
multi_index = pd.MultiIndex.from_frame(
|
|
491
|
+
df[self._cdb.container[ssym_name].domain_labels]
|
|
492
|
+
)
|
|
493
|
+
df.set_index(multi_index, inplace=True)
|
|
494
|
+
if self._trace > 2:
|
|
495
|
+
self._cdb.print_log(f"DataFrame after .set_index():\n{df}")
|
|
496
|
+
|
|
497
|
+
df.drop(columns=drop_cols, inplace=True)
|
|
498
|
+
if self._trace > 2:
|
|
499
|
+
self._cdb.print_log(f"DataFrame after dropping columns:\n{df}")
|
|
500
|
+
|
|
501
|
+
df = self._apply_aggregation_method(df, ssym_name, index_map_unq)
|
|
502
|
+
|
|
503
|
+
if isinstance(df, pd.DataFrame):
|
|
504
|
+
if suffix_to_index:
|
|
505
|
+
df = df.stack()
|
|
506
|
+
if self._trace > 2:
|
|
507
|
+
self._cdb.print_log(
|
|
508
|
+
f"DataFrame after stacking suffix index:\n{df}"
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
df = df.reset_index(drop=False)
|
|
512
|
+
if self._trace > 2:
|
|
513
|
+
self._cdb.print_log(f"DataFrame after .reset_index():\n{df}")
|
|
514
|
+
|
|
515
|
+
if isinstance(df, pd.DataFrame) and isinstance(tsym, gt.Set):
|
|
516
|
+
df = self._drop_text(df, ssym, suffix_list, suffix_to_index)
|
|
517
|
+
|
|
518
|
+
if self._trace > 2:
|
|
519
|
+
self._cdb.print_log(f"DataFrame before .setRecords():\n{df}")
|
|
520
|
+
|
|
521
|
+
if tindex_list_unq != tindex_list: # duplicate index (e.g. newName: p(i,j,i))
|
|
522
|
+
if self._trace > 1:
|
|
523
|
+
self._cdb.print_log(
|
|
524
|
+
f"Restoring duplicate indices: {tsym_name}({','.join(tindex_list_unq)}) -> {tsym_name}({','.join(tindex_list)}).\n"
|
|
525
|
+
)
|
|
526
|
+
new_index = [tindex_list_unq.index(i) for i in tindex_list]
|
|
527
|
+
new_index = [df.columns.tolist()[x] for x in new_index]
|
|
528
|
+
new_cols = new_index + df.columns.tolist()[len(tindex_list_unq) :]
|
|
529
|
+
df = df[new_cols]
|
|
530
|
+
tsym.setRecords(df)
|
|
531
|
+
|
|
532
|
+
self._apply_categories(ssym, tsym, suffix_to_index, suffix_list, index_map)
|
|
533
|
+
|
|
534
|
+
if self._trace > 2:
|
|
535
|
+
self._cdb.print_log(
|
|
536
|
+
f"Connect Container symbol={tsym_name}:\n {tsym.records}\n"
|
|
537
|
+
)
|
|
538
|
+
if self._trace > 0:
|
|
539
|
+
self._describe_container(self._cdb.container, "Connect Container (after):")
|
|
@@ -0,0 +1,71 @@
|
|
|
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.connect.agents.connectagent import ConnectAgent
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PythonCode(ConnectAgent):
|
|
30
|
+
|
|
31
|
+
def __init__(self, cdb, inst, agent_index):
|
|
32
|
+
super().__init__(cdb, inst, agent_index)
|
|
33
|
+
self._parse_options(self._inst)
|
|
34
|
+
|
|
35
|
+
def _parse_options(self, inst):
|
|
36
|
+
self._code = inst["code"]
|
|
37
|
+
self._trace = inst["trace"]
|
|
38
|
+
|
|
39
|
+
def execute(self):
|
|
40
|
+
if self._trace > 0:
|
|
41
|
+
self._log_instructions(self._inst)
|
|
42
|
+
self._describe_container(self._cdb.container, "Connect Container (before):")
|
|
43
|
+
|
|
44
|
+
loc = dict(locals())
|
|
45
|
+
loc["instructions"] = []
|
|
46
|
+
loc["connect"] = self._cdb
|
|
47
|
+
loc["gams"] = self._cdb.ecdb
|
|
48
|
+
exec(self._inst["code"], loc)
|
|
49
|
+
|
|
50
|
+
if self._trace > 1:
|
|
51
|
+
self._cdb.print_log(
|
|
52
|
+
f"Number of generated instructions: {len(loc['instructions'])}"
|
|
53
|
+
)
|
|
54
|
+
if self._trace > 2:
|
|
55
|
+
self._cdb.print_log("List of generated instructions:")
|
|
56
|
+
for idx, gen_inst in enumerate(loc["instructions"]):
|
|
57
|
+
if isinstance(gen_inst, dict):
|
|
58
|
+
agent_name = list(gen_inst.keys())[0]
|
|
59
|
+
self._log_instructions(
|
|
60
|
+
gen_inst[agent_name], description=f"({idx + 1}) {agent_name}:"
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
self._cdb.print_log(
|
|
64
|
+
f"Warning: Could not log generated instructions since item {idx} was not of type 'dict' but '{type(gen_inst).__name__}'."
|
|
65
|
+
)
|
|
66
|
+
self._cdb.print_log("")
|
|
67
|
+
|
|
68
|
+
if self._trace > 0:
|
|
69
|
+
self._describe_container(self._cdb.container, "Connect Container (after):")
|
|
70
|
+
|
|
71
|
+
return loc["instructions"]
|