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,626 @@
|
|
|
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 pandas as pd
|
|
27
|
+
import numpy as np
|
|
28
|
+
from gams.transfer._abcs import ABCAlias, AnyContainerSymbol
|
|
29
|
+
from gams.transfer._internals import SpecialValues
|
|
30
|
+
import typing
|
|
31
|
+
from typing import Union, Optional
|
|
32
|
+
|
|
33
|
+
if typing.TYPE_CHECKING:
|
|
34
|
+
from gams.transfer.syms.container_syms._set import Set
|
|
35
|
+
from gams.transfer.syms.container_syms._alias import Alias
|
|
36
|
+
from gams.transfer.syms.container_syms._parameter import Parameter
|
|
37
|
+
from gams.transfer.syms.container_syms._variable import Variable
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class EqualsBase:
|
|
41
|
+
@typing.no_type_check
|
|
42
|
+
def equals(self, other, check_uels, check_meta_data, verbose):
|
|
43
|
+
#
|
|
44
|
+
# ARG: self
|
|
45
|
+
if not self.isValid():
|
|
46
|
+
raise Exception(
|
|
47
|
+
f"Cannot compare objects because `{self.name}` is not a valid symbol object"
|
|
48
|
+
"Use `<symbol>.isValid(verbose=True)` to debug further."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
# ARG: other
|
|
53
|
+
if not isinstance(other, AnyContainerSymbol):
|
|
54
|
+
raise TypeError("Argument 'other' must be a GAMS Symbol object")
|
|
55
|
+
|
|
56
|
+
if not other.isValid():
|
|
57
|
+
raise Exception(
|
|
58
|
+
f"Cannot compare objects because `{other.name}` is not a valid symbol object"
|
|
59
|
+
"Use `<symbol>.isValid(verbose=True)` to debug further."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# adjustments
|
|
63
|
+
if isinstance(other, ABCAlias):
|
|
64
|
+
other = other.alias_with
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# ARG: self & other
|
|
68
|
+
if not isinstance(self, type(other)):
|
|
69
|
+
raise TypeError(
|
|
70
|
+
f"Symbol are not of the same type (`{type(self)}` != `{type(other)}`)"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# test for equal variable and equation types
|
|
74
|
+
if getattr(self, "type", None) != getattr(other, "type", None):
|
|
75
|
+
raise Exception(
|
|
76
|
+
f"Symbol types do not match (`{self.type}` != `{other.type}`)"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
#
|
|
80
|
+
# ARG: check_uels
|
|
81
|
+
if not isinstance(check_uels, bool):
|
|
82
|
+
raise TypeError("Argument 'check_uels' must be type bool")
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# ARG: check_meta_data
|
|
86
|
+
if not isinstance(check_meta_data, bool):
|
|
87
|
+
raise TypeError("Argument 'check_meta_data' must be type bool")
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# ARG: verbose
|
|
91
|
+
if not isinstance(verbose, bool):
|
|
92
|
+
raise TypeError("Argument 'verbose' must be type bool")
|
|
93
|
+
|
|
94
|
+
return other
|
|
95
|
+
|
|
96
|
+
def _assert_symbol_attributes(
|
|
97
|
+
self,
|
|
98
|
+
other,
|
|
99
|
+
check_uels,
|
|
100
|
+
check_meta_data,
|
|
101
|
+
):
|
|
102
|
+
#
|
|
103
|
+
# Mandatory checks
|
|
104
|
+
if self.dimension != other.dimension:
|
|
105
|
+
raise Exception(
|
|
106
|
+
f"Symbol dimensions do not match (`{self.dimension}` != `{other.dimension}`)"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if self.domain_type != other.domain_type:
|
|
110
|
+
raise Exception(
|
|
111
|
+
f"Symbol domain_types do not match (`{self.domain_type}` != `{other.domain_type}`)"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if self.records is not None and other.records is not None:
|
|
115
|
+
if self.number_records != other.number_records:
|
|
116
|
+
raise Exception(
|
|
117
|
+
"Symbols do not have the same number of records "
|
|
118
|
+
f"(`{self.number_records}` != `{other.number_records}`)"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if not isinstance(self.records, type(other.records)):
|
|
122
|
+
raise Exception(
|
|
123
|
+
f"Symbol records type do not match (`{type(self.records)}` != `{type(other.records)}`)"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# check domains even if symbols are in different containers
|
|
127
|
+
different_containers = True if self.container is not other.container else False
|
|
128
|
+
for n, (selfdom, otherdom) in enumerate(zip(self.domain, other.domain)):
|
|
129
|
+
if type(selfdom) is not type(otherdom):
|
|
130
|
+
raise Exception(
|
|
131
|
+
f"Domain symbols in dimension {n} (zero-indexed) are not the same type (i.e., '{selfdom.name}' "
|
|
132
|
+
f"is {type(selfdom)} does not match '{otherdom.name}' which is {type(otherdom)})"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if not different_containers:
|
|
136
|
+
if selfdom is not otherdom:
|
|
137
|
+
raise Exception(
|
|
138
|
+
f"Domain symbols in dimension {n} (zero-indexed) are not the same object (i.e., '{selfdom.name}' is not '{otherdom.name}')"
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
if not isinstance(selfdom, str):
|
|
142
|
+
if selfdom.name != otherdom.name:
|
|
143
|
+
raise Exception(
|
|
144
|
+
f"Domain symbols in dimension {n} (zero-indexed) do not have the same name (i.e., '{selfdom.name}' != '{otherdom.name}')"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
selfdom.equals(otherdom, verbose=True)
|
|
149
|
+
except Exception as err:
|
|
150
|
+
raise Exception(
|
|
151
|
+
f"Domain symbols '{selfdom.name}' are not equal . Reason: {err}"
|
|
152
|
+
) from err
|
|
153
|
+
|
|
154
|
+
#
|
|
155
|
+
# Check metadata (optional)
|
|
156
|
+
if check_meta_data:
|
|
157
|
+
if self.name != other.name:
|
|
158
|
+
raise Exception(
|
|
159
|
+
f"Symbol names do not match (`{self.name}` != `{other.name}`)"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if self.description != other.description:
|
|
163
|
+
raise Exception(
|
|
164
|
+
f"Symbol descriptions do not match (`{self.description}` != `{other.description}`)"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Check UELs (optional)
|
|
168
|
+
if check_uels:
|
|
169
|
+
if self.records is not None and other.records is not None:
|
|
170
|
+
left_uels = self.getUELs()
|
|
171
|
+
right_uels = other.getUELs()
|
|
172
|
+
|
|
173
|
+
if left_uels != right_uels:
|
|
174
|
+
raise Exception(
|
|
175
|
+
"Symbol UEL ordering does not match \n\n"
|
|
176
|
+
f"[self]: {left_uels} \n"
|
|
177
|
+
f"[other]: {right_uels} \n"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def _merge_records(self, other):
|
|
181
|
+
merged = pd.DataFrame()
|
|
182
|
+
if self.records is not None and other.records is not None:
|
|
183
|
+
if not self.records.empty and not other.records.empty:
|
|
184
|
+
merged = self.records.merge(
|
|
185
|
+
other.records,
|
|
186
|
+
how="outer",
|
|
187
|
+
left_on=self.domain_labels,
|
|
188
|
+
right_on=other.domain_labels,
|
|
189
|
+
indicator=True,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
return merged
|
|
193
|
+
|
|
194
|
+
def _assert_scalar_values(self, other, columns, rtol, atol):
|
|
195
|
+
for attr in columns:
|
|
196
|
+
for svlabel, SV in zip(
|
|
197
|
+
["EPS", "NA", "UNDEF"],
|
|
198
|
+
[
|
|
199
|
+
SpecialValues.isEps,
|
|
200
|
+
SpecialValues.isNA,
|
|
201
|
+
SpecialValues.isUndef,
|
|
202
|
+
],
|
|
203
|
+
):
|
|
204
|
+
self_is_special = SV(self.records[attr])
|
|
205
|
+
other_is_special = SV(other.records[attr])
|
|
206
|
+
|
|
207
|
+
if self_is_special != other_is_special:
|
|
208
|
+
raise Exception(
|
|
209
|
+
f"Symbol records with `{svlabel}` special values "
|
|
210
|
+
f"do not match in the `{attr}` column."
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
if self_is_special == False and other_is_special == False:
|
|
214
|
+
if not np.isclose(
|
|
215
|
+
self.records[attr],
|
|
216
|
+
other.records[attr],
|
|
217
|
+
rtol=rtol,
|
|
218
|
+
atol=atol,
|
|
219
|
+
):
|
|
220
|
+
raise Exception(
|
|
221
|
+
f"Symbol records contain numeric difference in the `{attr}` attribute "
|
|
222
|
+
f"that are outside the specified tolerances (rtol={rtol}, atol={atol})"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
@typing.no_type_check
|
|
226
|
+
def _assert_symbol_domains(self, merged):
|
|
227
|
+
if set(merged["_merge"]) != {"both"}:
|
|
228
|
+
self_only_recs = merged[merged["_merge"].isin({"left_only"})].head()
|
|
229
|
+
other_only_recs = merged[merged["_merge"].isin({"right_only"})].head()
|
|
230
|
+
|
|
231
|
+
if self_only_recs.empty:
|
|
232
|
+
self_only_recs = "All matched OK"
|
|
233
|
+
else:
|
|
234
|
+
self_only_recs = list(
|
|
235
|
+
self_only_recs[self_only_recs.columns[: self.dimension]].itertuples(
|
|
236
|
+
index=False, name=None
|
|
237
|
+
)
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
if other_only_recs.empty:
|
|
241
|
+
other_only_recs = "All matched OK"
|
|
242
|
+
else:
|
|
243
|
+
other_only_recs = list(
|
|
244
|
+
other_only_recs[
|
|
245
|
+
other_only_recs.columns[: other.dimension]
|
|
246
|
+
].itertuples(index=False, name=None)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
raise Exception(
|
|
250
|
+
"Symbol records do not match. First five unmatched domains: \n\n"
|
|
251
|
+
f"left_only : {self_only_recs} \n"
|
|
252
|
+
f"right_only: {other_only_recs} \n"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class EqualsSetMixin(EqualsBase):
|
|
257
|
+
@typing.no_type_check
|
|
258
|
+
def equals(
|
|
259
|
+
self,
|
|
260
|
+
other: Union["Set", "Alias"],
|
|
261
|
+
check_uels: bool = True,
|
|
262
|
+
check_element_text: bool = True,
|
|
263
|
+
check_meta_data: bool = True,
|
|
264
|
+
verbose: bool = False,
|
|
265
|
+
) -> bool:
|
|
266
|
+
"""
|
|
267
|
+
Used to compare the symbol to another symbol
|
|
268
|
+
|
|
269
|
+
Parameters
|
|
270
|
+
----------
|
|
271
|
+
other : Set | Alias
|
|
272
|
+
Other Symbol to compare with
|
|
273
|
+
check_uels : bool, optional
|
|
274
|
+
If True, check both used and unused UELs and confirm same order, otherwise only check used UELs in data and do not check UEL order, by default True
|
|
275
|
+
check_element_text : bool, optional
|
|
276
|
+
If True, check that all set elements have the same descriptive element text, otherwise skip, by default True
|
|
277
|
+
check_meta_data : bool, optional
|
|
278
|
+
If True, check that symbol name and description are the same, otherwise skip, by default True
|
|
279
|
+
verbose : bool, optional
|
|
280
|
+
If True, will return an exception from the asserter describing the nature of the difference, by default False
|
|
281
|
+
|
|
282
|
+
Returns
|
|
283
|
+
-------
|
|
284
|
+
bool
|
|
285
|
+
True if symbols are equal, False otherwise
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
# check & set
|
|
289
|
+
other = super().equals(other, check_uels, check_meta_data, verbose)
|
|
290
|
+
|
|
291
|
+
# check is_singleton
|
|
292
|
+
if self.is_singleton != other.is_singleton:
|
|
293
|
+
raise Exception("Symbols do not have matching 'is_singleton' state")
|
|
294
|
+
|
|
295
|
+
# extension to check check_element_text
|
|
296
|
+
# ARG: check_element_text
|
|
297
|
+
if not isinstance(check_element_text, bool):
|
|
298
|
+
raise TypeError("Argument 'check_element_text' must be type bool")
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
# check symbol attributes (not records)
|
|
302
|
+
super()._assert_symbol_attributes(other, check_uels, check_meta_data)
|
|
303
|
+
|
|
304
|
+
# merge records
|
|
305
|
+
merged = super()._merge_records(other)
|
|
306
|
+
|
|
307
|
+
# check symbol domain records
|
|
308
|
+
self._assert_symbol_domains(merged, check_element_text)
|
|
309
|
+
|
|
310
|
+
return True
|
|
311
|
+
except Exception as err:
|
|
312
|
+
if verbose:
|
|
313
|
+
raise err
|
|
314
|
+
else:
|
|
315
|
+
return False
|
|
316
|
+
|
|
317
|
+
@typing.no_type_check
|
|
318
|
+
def _assert_symbol_domains(self, merged, check_element_text):
|
|
319
|
+
if not merged.empty:
|
|
320
|
+
# check domains
|
|
321
|
+
super()._assert_symbol_domains(merged)
|
|
322
|
+
|
|
323
|
+
# extension to check element text
|
|
324
|
+
if check_element_text:
|
|
325
|
+
merged["_element_text"] = (
|
|
326
|
+
merged["element_text_x"] != merged["element_text_y"]
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
recs = merged[merged["_element_text"]].head()
|
|
330
|
+
|
|
331
|
+
if not recs.empty:
|
|
332
|
+
self_only_recs = list(
|
|
333
|
+
recs[
|
|
334
|
+
list(recs.columns[: self.dimension]) + ["element_text_x"]
|
|
335
|
+
].itertuples(index=False, name=None)
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
other_only_recs = list(
|
|
339
|
+
recs[
|
|
340
|
+
list(recs.columns[: self.dimension]) + ["element_text_y"]
|
|
341
|
+
].itertuples(index=False, name=None)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
raise Exception(
|
|
345
|
+
"Symbol element_text does not match. First five unmatched domains: \n\n"
|
|
346
|
+
f"left_only : {self_only_recs} \n"
|
|
347
|
+
f"right_only: {other_only_recs} \n"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
class EqualsParameterMixin(EqualsBase):
|
|
352
|
+
@typing.no_type_check
|
|
353
|
+
def equals(
|
|
354
|
+
self,
|
|
355
|
+
other: "Parameter",
|
|
356
|
+
check_uels: bool = True,
|
|
357
|
+
check_meta_data: bool = True,
|
|
358
|
+
rtol: Optional[Union[int, float]] = None,
|
|
359
|
+
atol: Optional[Union[int, float]] = None,
|
|
360
|
+
verbose: bool = False,
|
|
361
|
+
) -> bool:
|
|
362
|
+
"""
|
|
363
|
+
Used to compare the symbol to another symbol
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
other : Parameter
|
|
368
|
+
Other Symbol to compare with
|
|
369
|
+
check_uels : bool, optional
|
|
370
|
+
If True, check both used and unused UELs and confirm same order, otherwise only check used UELs in data and do not check UEL order. by default True
|
|
371
|
+
check_meta_data : bool, optional
|
|
372
|
+
If True, check that symbol name and description are the same, otherwise skip. by default True
|
|
373
|
+
rtol : int | float, optional
|
|
374
|
+
relative tolerance, by default None
|
|
375
|
+
atol : int | float, optional
|
|
376
|
+
absolute tolerance, by default None
|
|
377
|
+
verbose : bool, optional
|
|
378
|
+
If True, will return an exception from the asserter describing the nature of the difference. by default False
|
|
379
|
+
|
|
380
|
+
Returns
|
|
381
|
+
-------
|
|
382
|
+
bool
|
|
383
|
+
True if symbols are equal, False otherwise
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
# check & set
|
|
387
|
+
other = super().equals(other, check_uels, check_meta_data, verbose)
|
|
388
|
+
|
|
389
|
+
# set
|
|
390
|
+
columns = self._attributes
|
|
391
|
+
|
|
392
|
+
# extension to check rtol, atol
|
|
393
|
+
# ARG: rtol & atol
|
|
394
|
+
if not isinstance(rtol, (type(None), int, float)):
|
|
395
|
+
raise ValueError(
|
|
396
|
+
"Argument 'rtol' (relative tolerance) must be "
|
|
397
|
+
f"numeric (int, float) or None. User passed: {type(rtol)}."
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
if not isinstance(atol, (type(None), int, float)):
|
|
401
|
+
raise ValueError(
|
|
402
|
+
"Argument 'atol' (relative tolerance) must be "
|
|
403
|
+
f"numeric (int, float) or None. User passed: {type(rtol)}."
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
# set defaults
|
|
407
|
+
if rtol is None:
|
|
408
|
+
rtol = 0.0
|
|
409
|
+
|
|
410
|
+
if atol is None:
|
|
411
|
+
atol = 0.0
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
# check symbol attributes (not records)
|
|
415
|
+
super()._assert_symbol_attributes(other, check_uels, check_meta_data)
|
|
416
|
+
|
|
417
|
+
if self.dimension == 0:
|
|
418
|
+
super()._assert_scalar_values(other, columns, rtol, atol)
|
|
419
|
+
|
|
420
|
+
else:
|
|
421
|
+
# merge records
|
|
422
|
+
merged = super()._merge_records(other)
|
|
423
|
+
|
|
424
|
+
# check domains
|
|
425
|
+
super()._assert_symbol_domains(merged)
|
|
426
|
+
|
|
427
|
+
# check values
|
|
428
|
+
self._assert_symbol_values(merged, columns, rtol, atol)
|
|
429
|
+
|
|
430
|
+
return True
|
|
431
|
+
except Exception as err:
|
|
432
|
+
if verbose:
|
|
433
|
+
raise err
|
|
434
|
+
else:
|
|
435
|
+
return False
|
|
436
|
+
|
|
437
|
+
def _assert_symbol_values(self, merged, columns, rtol, atol):
|
|
438
|
+
if not merged.empty:
|
|
439
|
+
for attr in columns:
|
|
440
|
+
small_merged = merged[
|
|
441
|
+
list(merged.columns[: self.dimension]) + [f"{attr}_x", f"{attr}_y"]
|
|
442
|
+
].copy()
|
|
443
|
+
|
|
444
|
+
for svlabel, SV in zip(
|
|
445
|
+
["EPS", "NA", "UNDEF"],
|
|
446
|
+
[
|
|
447
|
+
SpecialValues.isEps,
|
|
448
|
+
SpecialValues.isNA,
|
|
449
|
+
SpecialValues.isUndef,
|
|
450
|
+
],
|
|
451
|
+
):
|
|
452
|
+
self_idx = SV(small_merged[f"{attr}_x"])
|
|
453
|
+
other_idx = SV(small_merged[f"{attr}_y"])
|
|
454
|
+
|
|
455
|
+
if any(self_idx != other_idx):
|
|
456
|
+
raise Exception(
|
|
457
|
+
f"Symbol records with `{svlabel}` special values "
|
|
458
|
+
f"do not match in the `{attr}` column."
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
#
|
|
462
|
+
# drop special values if all indices match
|
|
463
|
+
small_merged.drop(index=small_merged[self_idx].index, inplace=True)
|
|
464
|
+
|
|
465
|
+
#
|
|
466
|
+
# check attr values (subject to tolerances)
|
|
467
|
+
small_merged["isclose"] = np.isclose(
|
|
468
|
+
small_merged[f"{attr}_x"],
|
|
469
|
+
small_merged[f"{attr}_y"],
|
|
470
|
+
rtol=rtol,
|
|
471
|
+
atol=atol,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
if any(~small_merged["isclose"]):
|
|
475
|
+
raise Exception(
|
|
476
|
+
f"Symbol records contain numeric difference in the `{attr}` attribute "
|
|
477
|
+
f"that are outside the specified tolerances (rtol={rtol}, atol={atol})"
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
class EqualsVariableMixin(EqualsBase):
|
|
482
|
+
@typing.no_type_check
|
|
483
|
+
def equals(
|
|
484
|
+
self,
|
|
485
|
+
other: "Variable",
|
|
486
|
+
columns: str = None,
|
|
487
|
+
check_uels: bool = True,
|
|
488
|
+
check_meta_data: bool = True,
|
|
489
|
+
rtol: Optional[Union[int, float]] = None,
|
|
490
|
+
atol: Optional[Union[int, float]] = None,
|
|
491
|
+
verbose: bool = False,
|
|
492
|
+
) -> bool:
|
|
493
|
+
"""
|
|
494
|
+
Used to compare the symbol to another symbol
|
|
495
|
+
|
|
496
|
+
Parameters
|
|
497
|
+
----------
|
|
498
|
+
other : Variable
|
|
499
|
+
_description_
|
|
500
|
+
columns : str, optional
|
|
501
|
+
allows the user to numerically compare only specified variable attributes, by default None; compare all
|
|
502
|
+
check_uels : bool, optional
|
|
503
|
+
If True, check both used and unused UELs and confirm same order, otherwise only check used UELs in data and do not check UEL order. by default True
|
|
504
|
+
check_meta_data : bool, optional
|
|
505
|
+
If True, check that symbol name and description are the same, otherwise skip. by default True
|
|
506
|
+
rtol : int | float, optional
|
|
507
|
+
relative tolerance, by default None
|
|
508
|
+
atol : int | float, optional
|
|
509
|
+
absolute tolerance, by default None
|
|
510
|
+
verbose : bool, optional
|
|
511
|
+
If True, will return an exception from the asserter describing the nature of the difference. by default False
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
bool
|
|
516
|
+
True if symbols are equal, False otherwise
|
|
517
|
+
"""
|
|
518
|
+
# check & set
|
|
519
|
+
other = super().equals(other, check_uels, check_meta_data, verbose)
|
|
520
|
+
|
|
521
|
+
# extension to test columns
|
|
522
|
+
# ARG: columns
|
|
523
|
+
if not isinstance(columns, (str, list, type(None))):
|
|
524
|
+
raise TypeError(f"Argument 'columns' must be type str, list or NoneType")
|
|
525
|
+
|
|
526
|
+
if isinstance(columns, str):
|
|
527
|
+
columns = [columns]
|
|
528
|
+
|
|
529
|
+
if columns is None:
|
|
530
|
+
columns = self._attributes
|
|
531
|
+
|
|
532
|
+
if any(i not in self._attributes for i in columns):
|
|
533
|
+
raise ValueError(
|
|
534
|
+
f"Argument 'columns' can only contain the following symbol attributes: {self._attributes}"
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
# extension to check rtol, atol
|
|
538
|
+
# ARG: rtol & atol
|
|
539
|
+
if not isinstance(rtol, (type(None), int, float)):
|
|
540
|
+
raise ValueError(
|
|
541
|
+
"Argument 'rtol' (relative tolerance) must be "
|
|
542
|
+
f"numeric (int, float) or None. User passed: {type(rtol)}."
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
if not isinstance(atol, (type(None), int, float)):
|
|
546
|
+
raise ValueError(
|
|
547
|
+
"Argument 'atol' (relative tolerance) must be "
|
|
548
|
+
f"numeric (int, float) or None. User passed: {type(rtol)}."
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
# set defaults
|
|
552
|
+
if rtol is None:
|
|
553
|
+
rtol = 0.0
|
|
554
|
+
|
|
555
|
+
if atol is None:
|
|
556
|
+
atol = 0.0
|
|
557
|
+
|
|
558
|
+
try:
|
|
559
|
+
# check symbol attributes (not records)
|
|
560
|
+
super()._assert_symbol_attributes(other, check_uels, check_meta_data)
|
|
561
|
+
|
|
562
|
+
if self.dimension == 0:
|
|
563
|
+
super()._assert_scalar_values(other, columns, rtol, atol)
|
|
564
|
+
|
|
565
|
+
else:
|
|
566
|
+
# merge records
|
|
567
|
+
merged = super()._merge_records(other)
|
|
568
|
+
|
|
569
|
+
# check domains
|
|
570
|
+
super()._assert_symbol_domains(merged)
|
|
571
|
+
|
|
572
|
+
# check values
|
|
573
|
+
self._assert_symbol_values(merged, columns, rtol, atol)
|
|
574
|
+
|
|
575
|
+
return True
|
|
576
|
+
except Exception as err:
|
|
577
|
+
if verbose:
|
|
578
|
+
raise err
|
|
579
|
+
else:
|
|
580
|
+
return False
|
|
581
|
+
|
|
582
|
+
def _assert_symbol_values(self, merged, columns, rtol, atol):
|
|
583
|
+
if not merged.empty:
|
|
584
|
+
for attr in columns:
|
|
585
|
+
small_merged = merged[
|
|
586
|
+
list(merged.columns[: self.dimension]) + [f"{attr}_x", f"{attr}_y"]
|
|
587
|
+
].copy()
|
|
588
|
+
|
|
589
|
+
for svlabel, SV in zip(
|
|
590
|
+
["EPS", "NA", "UNDEF"],
|
|
591
|
+
[
|
|
592
|
+
SpecialValues.isEps,
|
|
593
|
+
SpecialValues.isNA,
|
|
594
|
+
SpecialValues.isUndef,
|
|
595
|
+
],
|
|
596
|
+
):
|
|
597
|
+
self_idx = SV(small_merged[f"{attr}_x"])
|
|
598
|
+
other_idx = SV(small_merged[f"{attr}_y"])
|
|
599
|
+
|
|
600
|
+
if any(self_idx != other_idx):
|
|
601
|
+
raise Exception(
|
|
602
|
+
f"Symbol records with `{svlabel}` special values "
|
|
603
|
+
f"do not match in the `{attr}` column."
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
#
|
|
607
|
+
# drop special values if all indices match
|
|
608
|
+
small_merged.drop(index=small_merged[self_idx].index, inplace=True)
|
|
609
|
+
|
|
610
|
+
#
|
|
611
|
+
# check attr values (subject to tolerances)
|
|
612
|
+
isclose = np.isclose(
|
|
613
|
+
small_merged[f"{attr}_x"],
|
|
614
|
+
small_merged[f"{attr}_y"],
|
|
615
|
+
rtol=rtol,
|
|
616
|
+
atol=atol,
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
if any(~isclose):
|
|
620
|
+
raise Exception(
|
|
621
|
+
f"Symbol records contain numeric difference in the `{attr}` attribute "
|
|
622
|
+
f"that are outside the specified tolerances (rtol={rtol}, atol={atol})"
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class EqualsEquationMixin(EqualsVariableMixin): ...
|