"""Module collecting all fundamental default settings of the package.
Defaults of the package are useful for simplifying renaming package labels,
defining templates for fundamental package objects (sets, data tables, variables, ...)
for validation purposes, defining fundamental numerical settings and template
text messages.
"""
from typing import Literal, TypeAlias, Union
import cvxpy as cp
import numpy as np
from cvxlab.support import util_constants, util_operators
[docs]
class Defaults:
"""Centralized repository for default settings of the package.
Defaults are grouped into meaningful categories (sub-classes) for clarity and
ease of access. Supports direct attribute access of default settings using '__getattr__' method.
Subgroups:
- ConfigFiles: Defaults related to configuration and file management.
- Labels: Standard headers and field names.
- DefaultStructures: Default structures for data validation.
- SymbolicDefinitions: Allowed constants and operators for symbolic problem definitions.
- NumericalSettings: Settings for numerical solvers and tolerances.
- TextNotes: Text notes and messages for user.
Usage::
# Attributes of sub-groups can be accessed directly
Defaults.ConfigFiles.SETUP_FILES
"""
_SUBGROUPS = []
class ConfigFiles:
"""Defaults related to configuration and file management.
- SETUP_INFO: Dictionary mapping setup information groups.
- SETUP_XLSX_FILE: Default name of the setup Excel file.
- SETS_FILE: Default name of the sets Excel file.
- AVAILABLE_SOURCES: List of possible formats for input data sources.
- INPUT_DATA_DIR: Default name for input data directory.
- INPUT_DATA_FILE: Default name for the input data file (for single input data file).
- DATA_FILES_EXTENSION: Default extension for data file/s.
- SQLITE_DATABASE_FILE: Default name for the SQLite database file.
- SQLITE_DATABASE_FILE_BKP: Default name for the SQLite database backup file.
- SQLITE_DATABASE_FILE_TEST: Default name for the SQLite database test file.
- INSTANCES_DIR: Default name for the directory containing saved Model instances.
"""
SETUP_INFO = {
0: 'structure_sets',
1: 'structure_variables',
2: 'problem'
}
SETUP_XLSX_FILE = 'model_settings.xlsx'
SETS_FILE = 'sets.xlsx'
AVAILABLE_SOURCES = ['yml', 'xlsx']
INPUT_DATA_DIR = 'input_data'
INPUT_DATA_FILE = 'input_data.xlsx'
DATA_FILES_EXTENSION = '.xlsx'
SQLITE_DATABASE_FILE = 'database.db'
SQLITE_DATABASE_FILE_BKP = 'database_bkp.db'
SQLITE_DATABASE_FILE_TEST = 'database_expected.db'
TEMPLATES_DIR_PATH = r'docs/templates'
INSTANCES_DIR = 'instances'
CUSTOM_OPERATORS_FILE_NAME = 'user_defined_operators.py'
CUSTOM_CONSTANTS_FILE_NAME = 'user_defined_constants.py'
class Labels:
"""Default labels and field names for dictionary keys and dataframes.
Dictionary keys default labels:
- NAME: key related to the name of the data table object.
- FILTERS: key related to set and data tables filters.
- SET: key related to the set key of the set table.
- DIM: key related to the dimension of the set.
- AGGREGATIONS: key related to set tables aggregations.
- CVXPY_VAR: key related to cvxpy variables.
- COORDINATES_KEY: key related to the coordinates of the data table.
- VARIABLES_INFO_KEY: key related to the variables information.
- VALUE_KEY: key related to the type for variable of type constants.
- BLANK_FILL_KEY: key related to the value used to fill blank.
- NONNEG_KEY: key related to the non-negativity sign of endogenous variables.
Dataframe columns default labels:
- SUB_PROBLEM_KEY: column representing sub-problem keys.
- FILTER_DICT_KEY: column representing filter dictionaries.
- PROBLEM: column representing problem names.
- SCENARIO_COORDINATES: column representing scenario coordinates.
- PROBLEM_STATUS: column representing problem status.
- OBJECTIVE: column representing the objective of the problem.
- EXPRESSIONS: column representing expressions in the problem.
- RMS_TABLES: column representing label for RMS reporting monitor for
integrated problems solving.
Default field types for SQLite data tables:
- GENERIC_FIELD_TYPE: default field type for text.
- VALUES_FIELD: default structure and type for numeric values.
- ID_FIELD: default structure and type for IDs.
Default suffixes and prefixes for SQLite tables:
- SET_TABLE_NAME_PREFIX: prefix for set table names.
- COLUMN_NAME_SUFFIX: suffix for column names.
- COLUMN_AGGREGATION_SUFFIX: suffix for aggregation columns.
"""
NAME = 'name'
FILTERS = 'filters'
SET = 'set'
DIM = 'dim'
AGGREGATIONS = 'aggregations'
CVXPY_VAR = 'variable'
COORDINATES_KEY = 'coordinates'
VARIABLES_INFO_KEY = 'variables_info'
VALUE_KEY = 'value'
BLANK_FILL_KEY = 'blank_fill'
NONNEG_KEY = 'nonneg'
SUB_PROBLEM_KEY = 'sub_problem_key'
FILTER_DICT_KEY = 'filter'
PROBLEM = 'problem'
SCENARIO_COORDINATES = 'info'
PROBLEM_STATUS = 'status'
OBJECTIVE = 'objective'
EXPRESSIONS = 'expressions'
RMS_TABLES = 'ALL TABLES RMS'
GENERIC_FIELD_TYPE = 'TEXT'
VALUES_FIELD = {'values': ['values', 'REAL']}
ID_FIELD = {'id': ['id', 'INTEGER PRIMARY KEY']}
SET_TABLE_NAME_PREFIX = '_set_'
COLUMN_NAME_SUFFIX = '_Name'
COLUMN_AGGREGATION_SUFFIX = '_agg_'
class DefaultStructures:
"""Default structures for data validation and for generating templates.
Changing these structures will change the way data is validated and
how templates are generated.
SET_STRUCTURE: Structure for defining sets with metadata and filters.
Sets are defined as the dimensions of the numerical problem.
Properties of a SET:
- set_key:
name of the set, used as name of the set in the SQLite data
table. Since SQLite tables names are case insensitive, the set_key
is case insensitive (e.g., 'e' and 'E' are the same set). This is
the sole set information that is required to define a set.
- description:
(Optional) information of the set provided by the modeler.
- split_problem:
(Optional) if the set items defines independent numerical
sub-problems. In case more sets are defined, the number of sub-problems
is equal to the linear combination of the items of the sets.
- copy_from:
(Optional) key of another set to copy the data from. If a set is
defined with this key, it will copy the data from the set with
the key defined in this field, and it is not necessary to provide the
related data in the sets file.
- filters:
(Optional) dictionary with keys as the filters name and values
as the list of filter values. Filters are used to define variables
as part of data tables.
- aggregations:
(Optional) list of set aggregations useful to aggregate data for
visualization. Not recalled in operating with numerical problem.
DATA_TABLE_STRUCTURE: Structure for defining data tables with variables
and their properties. Data tables correspond to SQLite tables and are
used to generate variables in the numerical problem.
Properties of a DATA TABLE:
- table_key:
name of the data table, used as name of the table in the SQLite data
table. Since SQLite tables names are case insensitive, the
table_key is case insensitive (e.g., 'e' and 'E' are the same table).
- description:
(Optional) information of the data table provided by the modeler.
- type:
type of the data table, can be one of VARIABLE_TYPES or a dictionary
with keys as problem name and corresponding values as allowed types.
- integer:
(Optional) if variables of the table are integers (default: False).
- coordinates:
list of table coordinates (set_key symbols) that define the dimensions
of the data table.
- variables_info:
definition of the variables based on the same data table. It is a
dictionary with keys as variables names and values as dict with
variable info. Variables are case sensitive.
- value:
(Optional) ALLOWED_CONSTANTS (only for constants!).
- blank_fill:
(Optional) numerical value that will be used to fill variables
in case of blank or nan values.
- nonneg:
(Optional) defines whether an endogenous variable is expected to
be non-negative. This will result in an implicit non-negativity
constraint defined in the model. In case of integrated models,
this constraint is useful to check if endogenous variables values
are exchanged with the correct sign, to avoid numerical inconsistencies.
- set_key:
(Optional) dictionary with keys as set_key symbols and values
defining the dimension and filters for the set.
- dim:
(Optional) DIMENSIONS (included in 'coordinates').
- filters:
(Optional) dictionary with keys as the filters key of the set
and values as the list of values to filter.
PROBLEM_STRUCTURE: Structure for defining problems with objectives and
expressions.
Properties of a PROBLEM:
- problem_key:
(Optional) name of the problem, used to define multiple problems
in the same model. If not defined, the problem is considered as the
main problem.
- objective:
(Optional) list of expressions defining the objective of the problem.
It can be a single expression or a list of expressions. The objective is
defined as a scalar that can be minimized or maximized. If not defined,
the problem is solved as a system of equations.
- expressions:
list of expressions defining the problem constraints. Each expression
can be an equality or inequality. The expressions are defined as a list of
cvxpy expressions. At least one expression is required to define a problem.
- description:
(Optional) list of strings with the problem description provided
by the modeler. It is used to provide additional information about the problem.
XLSX_PIVOT_KEYS and XLSX_TEMPLATE_COLUMNS: Keys and columns used to pivot
data for generating Excel template files for sets, variables, and problems.
ALLOWED_BOOL: Dictionary mapping common boolean representations to Python
boolean values. This is used to validate boolean values in the data files.
"""
OPTIONAL = object()
ANY = object()
SET_STRUCTURE = (
'set_key:',
{
'description': (OPTIONAL, str),
'split_problem': (OPTIONAL, bool),
'copy_from': (OPTIONAL, str),
'filters': (OPTIONAL, {ANY: list}),
'aggregations': (OPTIONAL, Union[int, str, list]),
}
)
DATA_TABLE_STRUCTURE = (
'table_key:',
{
'description': (OPTIONAL, str),
'type': (str, dict),
'integer': (OPTIONAL, bool),
'coordinates': (str, list),
'variables_info': {
ANY: {
'value': (OPTIONAL, str),
'blank_fill': (OPTIONAL, Union[int, float]),
'nonneg': (OPTIONAL, bool),
ANY: (OPTIONAL, {
'dim': (OPTIONAL, str),
'filters': (OPTIONAL, dict),
})
}
}
}
)
PROBLEM_STRUCTURE = (
'problem_key: # optional',
{
'objective': (OPTIONAL, list),
'expressions': list,
'description': (OPTIONAL, list),
}
)
XLSX_PIVOT_KEYS = {
'structure_sets': ('set_key', None),
'structure_variables': ('table_key', 'variables_info'),
'problem': ('problem_key', None),
}
XLSX_TEMPLATE_COLUMNS = {
'structure_sets': [
'set_key',
*SET_STRUCTURE[1].keys()
],
'structure_variables': [
'table_key',
*DATA_TABLE_STRUCTURE[1].keys(),
'value',
'blank_fill',
'set_keys ...'
],
'problem': [
'problem_key',
*PROBLEM_STRUCTURE[1].keys()
],
}
ALLOWED_BOOL = {
'true': True, 'True': True, 'TRUE': True,
'false': False, 'False': False, 'FALSE': False,
}
class SymbolicDefinitions:
"""Allowed constants and operators for symbolic problem definitions.
- TOKEN_PATTERNS:
Dictionary of regex patterns for token types (text,
numbers, operators, parentheses). Determines how the symbolic
expressions are parsed and validated.
- NONE_SYMBOLS:
List of symbols considered as None or empty.
- STD_TEXT_DATA_FILL:
Standard text used to fill blank text fields in SQLite sets or data tables.
- DIMENSIONS:
Dict of allowed dimensions of variables, where coordinates can be defined.
- VARIABLE_TYPES:
Dict of allowed variable types for data tables.
- ALLOWED_CONSTANTS:
Dictionary of user-defined constants. These are defined within the
dictionary values (complex constants are defined in util_constants module),
are used to define variables (see 'value' field in data tables).
Constants are be built with exogenous data only.
- ALLOWED_OPERATORS:
Dictionary of user-defined operators. Keys of operators can be directly
used in symbolic expressions. These are defined within the dictionary
values (complex operators are defined in util_operators module).
Operators are built with exogenous data only.
"""
TOKEN_PATTERNS = {
'text': r"\b[a-zA-Z_][a-zA-Z0-9_]*\b",
'numbers': r"\b(?:\d+\.\d*|\.\d+|\d+)(?:[eE][+-]?\d+)?\b",
'operators': [
r"==", r">=", r"<=",
r"\+", r"-", r"\*", r"/", r"@", f",",
],
'parentheses': [r"\(", r"\)"],
}
NONE_SYMBOLS = [None, 'nan', 'None', 'null', '', [], {}]
STD_TEXT_DATA_FILL = ''
DIMENSIONS = {
'ROWS': 'rows',
'COLS': 'cols',
'INTRA': 'intra',
'INTER': 'inter',
}
VARIABLE_TYPES = {
'CONSTANT': 'constant',
'EXOGENOUS': 'exogenous',
'ENDOGENOUS': 'endogenous',
}
ALLOWED_CONSTANTS = util_constants.CONSTANTS
ALLOWED_OPERATORS = util_operators.OPERATORS
class NumericalSettings:
"""Settings for numerical solvers and tolerances.
- STD_VALUES_TYPE:
Type of standard numerical values.
- ALLOWED_VALUES_TYPES:
Tuple of allowed numerical types for values. Useful to recognize and
homogenize numerical values provided by user in input data files.
- ALLOWED_TEXT_TYPE:
Type of allowed text values.
- ALLOWED_SOLVERS:
List of allowed solvers installed in the current CVXPY version.
- TOLERANCE_TESTS_RESULTS_CHECK:
Tolerance for checking results of tests. It is a relative difference
(0.02 means 2% of maximum allowed difference between the resulting
database and the test databases).
- ROUNDING_DIGITS_RELATIVE_DIFFERENCE_DB:
Number of digits to round the relative difference between the values
of the database and the test database. It is used to avoid numerical
issues in case of very small differences between the values of the
database and the test database.
- SPARSE_MATRIX_ZEROS_THRESHOLD:
Threshold for considering a matrix as sparse. (0.3 means 30% of zeros
in the matrix). If the percentage of zeros in the matrix is higher
than this threshold, the matrix is considered as sparse and stored
in a sparse format to save memory.
- SQL_BATCH_SIZE:
Batch size for SQL operations. It is used to limit the number of rows
processed in a single SQL operation to avoid memory issues and speed
up database operations.
- CVXPY_DEFAULT_SETTINGS:
Default settings for CVXPY solver. It includes the default solver,
canon backend, and whether to ignore DPP.
- MODEL_COUPLING_SETTINGS:
Settings for model coupling. It includes:
allowed norms for convergence (max_relative, max_absolute, l1, l2, linf),
numerical tolerance for convergence for each table (absolute value),
numerical tolerance for convergence for all tables (RMS, absolute value),
maximum number of iterations.
"""
STD_VALUES_TYPE = float
ALLOWED_VALUES_TYPES = (
int, float, np.dtype('float64'), np.dtype('int64'))
ALLOWED_TEXT_TYPE = str
ALLOWED_SOLVERS = cp.installed_solvers()
TOLERANCE_TESTS_RESULTS_CHECK = 0.02
ROUNDING_DIGITS_RELATIVE_DIFFERENCE_DB = 5
SPARSE_MATRIX_ZEROS_THRESHOLD = 0.3
SQL_BATCH_SIZE = 1000
CVXPY_DEFAULT_SETTINGS = {
'solver': 'SCIPY',
'canon_backend': cp.SCIPY_CANON_BACKEND,
'ignore_dpp': True,
}
MODEL_COUPLING_SETTINGS = {
'allowed_norms': ['max_relative', 'max_absolute', 'l1', 'l2', 'linf'],
# Per-table tolerance:
# - For l1, l2, linf, max_absolute: ABSOLUTE thresholds (same units as values)
# - For max_relative: RELATIVE threshold (fraction, e.g., 0.01 = 1%)
'numerical_tolerance_max': 0.1,
# Global RMS tolerance (ABSOLUTE; RMS of per-table errors in same units)
'numerical_tolerance_avg': 0.005,
'max_iterations': 20,
}
NormType: TypeAlias = Literal[
'max_relative', 'max_absolute', 'l1', 'l2', 'linf']
@staticmethod
def validate_norm_type(norm: str) -> str:
allowed_norms = Defaults.NumericalSettings.MODEL_COUPLING_SETTINGS['allowed_norms']
if norm not in allowed_norms:
raise ValueError(
f"Unsupported norm type '{norm}'. Allowed: {allowed_norms}.")
return norm
_SUBGROUPS = [
ConfigFiles,
Labels,
DefaultStructures,
SymbolicDefinitions,
NumericalSettings,
]
@classmethod
def __getattr__(cls, name):
"""Provide direct access to default settings by searching nested groups.
Args:
name (str): The name of the attribute to retrieve.
Returns:
Any: The requested constant or attribute.
Raises:
AttributeError: If the attribute is not found.
"""
for subgroup in cls._SUBGROUPS:
if hasattr(subgroup, name):
return getattr(subgroup, name)
raise AttributeError(
f"Constant '{name}' not found in {cls.__name__}.")