formulations#
- class gamspy.formulations.AvgPool2d(container: Container, kernel_size: int | tuple[int, int], stride: int | tuple[int, int] | None = None, padding: int = 0, name_prefix: str | None = None)[source]#
Bases:
objectFormulation generator for 2D Avg Pooling in GAMS.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- kernel_sizeint | tuple[int, int]
Filter size
- strideint | tuple[int, int] | None
Stride in the avg pooling, it is equal to kernel_size if not provided
- paddingint | tuple[int, int]
Amount of padding to be added to input, by default 0
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
Methods
__call__(input, *[, propagate_bounds])Forward pass your input, generate output and equations required for calculating the average pooling.
Examples
>>> import gamspy as gp >>> from gamspy.math import dim >>> m = gp.Container() >>> # 2x2 avg pooling >>> ap1 = gp.formulations.AvgPool2d(m, (2, 2)) >>> inp = gp.Variable(m, domain=dim((10, 1, 24, 24))) >>> out, eqs = ap1(inp) >>> type(out) <class 'gamspy._symbols.variable.Variable'> >>> [len(x) for x in out.domain] [10, 1, 12, 12]
- __call__(input: Parameter | Variable, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input, generate output and equations required for calculating the average pooling. Unlike the min or max pooling avg pooling does not require binary variables or the big-M formulation. if propagate_bounds is True, it will also set the bounds for the output variable based on the input. Returns the output variable and the list of equations required for the avg pooling formulation.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“set_output”]
variables_created: [“output”]
parameters_created: [“output_lb”, “output_ub”]
sets_creates: [“in_out_matching_1”, “in_out_matching_2”]
Note
For backward compatibility, this result object can be unpacked as a tuple: output, equations = conv2d(input).
output_lb and output_ub`are available as parameters if `propogate_bounds=True.
in_out_matching_1 is the subset used to map input indices to output indices based on stride and padding.
in_out_matching_2 is the subset used specifically for bound propagation.
It gets created only if propogate_bounds=True.
- Parameters:
- inputgp.Parameter | gp.Variable
input to the max pooling 2d layer, must be in shape (batch x in_channels x height x width)
- propagate_bounds: bool
If True, it will set the bounds for the output variable based on the input. Default value: True
- Returns:
- FormulationResult
- class gamspy.formulations.CVaR(tail: float, weight: float)[source]#
Bases:
objectConditional Value-at-Risk: a convex blend of expectation and CVaR.
At every stage the cost-to-go is aggregated as
(1 - weight) * E[cost + future] + weight * CVaR_tail[cost + future]that is, a blend of the expectation and the mean cost over the worst
tailfraction of outcomes. Withweight = 0this is the risk-neutral expectation; withweight = 1it is pure CVaR over the tail.- Parameters:
- tailfloat
Tail probability in
(0, 1]; the fraction of worst-case outcomes that CVaR averages over.- weightfloat
Risk weight in
[0, 1]; how much mass to place on the CVaR term relative to the expectation.
Methods
validate
- tail: float#
- weight: float#
- class gamspy.formulations.Conv1d(container: Container, in_channels: int, out_channels: int, kernel_size: int | tuple[int], stride: int | tuple[int] = 1, padding: int | tuple[int] | tuple[int, int] | Literal['same', 'valid'] = 0, name_prefix: str | None = None, *, bias: bool = True)[source]#
Bases:
objectFormulation generator for 1D Convolution symbol in GAMS. It can be used to embed convolutional layers of trained neural networks in your problem. It can also be used to embed convolutional layers when you need weights as variables.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- in_channelint
Number of channels in the input
- out_channelint
Number of channels in the output
- kernel_sizeint
Filter size
- strideint
Stride in the convolution, by default 1
- paddingint | Literal[“same”, “valid”]
Specifies the amount of padding to apply to the input, by default 0. If an integer is provided, that padding is applied to both the left and right. If a tuple of two integers is given, the first value determines the padding for the left, while the second value sets the padding for the right. It is also possible to provide string literals “same” and “valid”. “same” pads the input so the output has the shape as the input. “valid” is the same as no padding.
- biasbool
Is bias added after the convolution, by default True
- name_prefixstr | None
Prefix for names of the GAMS symbols generated, by default None which means random prefix. Using same name_prefix in different formulations causes name conflicts. Do not use same name_prefix again.
Methods
__call__(input, *[, propagate_bounds])Forward pass your input, generate output and equations required for calculating the convolution.
load_weights(weight[, bias])Mark Conv1d as parameter and load weights from NumPy arrays.
make_variable(*[, init_weights])Mark Conv1d as variable.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> w1 = np.random.rand(2, 1, 3) >>> b1 = np.random.rand(2) >>> m = gp.Container() >>> # in_channels=1, out_channels=2, kernel_size=3 >>> conv1 = gp.formulations.Conv1d(m, 1, 2, 3) >>> conv1.load_weights(w1, b1) >>> # 10 frequencies, 1 channel, 24 length >>> inp = gp.Variable(m, domain=dim((10, 1, 24))) >>> out, eqs = conv1(inp) >>> type(out) <class 'gamspy._symbols.variable.Variable'> >>> [len(x) for x in out.domain] [10, 2, 22]
- __call__(input: Parameter | Variable, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input, generate output and equations required for calculating the convolution. If propagate_bounds is True, the input is of type variable, and load_weights was called, then the bounds of the input are propagated to the output.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“set_output”]
variables_created: [“output”, “weight”, “bias”]
parameters_created: [“weight”, “bias”, “input_bounds”, “output_bounds”]
sets_creates: [“conv_subset”]
Note
For backward compatibility, this result object can be unpacked as a tuple: output, equations = linear(input).
weight and bias are available as variables if make_variable was called.
weight and bias are available as parameters if load_weights was called.
input_bounds and output_bounds`are available as parameters if `propogate_bounds=True.
The subset used to map input indices to output indices based on stride and padding.
- Parameters:
- inputgp.Parameter | gp.Variable
input to the conv layer, must be in shape (batch x in_channels x width)
- propagate_boundsbool = True
If True, propagate bounds of the input to the output. Otherwise, the output variable is unbounded.
- Returns:
- FormulationResult
- load_weights(weight: ndarray, bias: ndarray | None = None) None[source]#
Mark Conv1d as parameter and load weights from NumPy arrays. After this is called make_variable cannot be called. Use this when you already have the weights of your convolutional layer.
- Parameters:
- weightnp.ndarray
Conv1d layer weights in shape (out_channels x in_channels x kernel_size)
- biasnp.ndarray | None
Conv1d layer bias in shape (out_channels, ), only required when bias=True during initialization
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> w1 = np.random.rand(2, 1, 3) >>> b1 = np.random.rand(2) >>> m = gp.Container() >>> # in_channels=1, out_channels=2, kernel_size=3 >>> conv1 = gp.formulations.Conv1d(m, 1, 2, 3) >>> conv1.load_weights(w1, b1)
- make_variable(*, init_weights=False) None[source]#
Mark Conv1d as variable. After this is called load_weights cannot be called. Use this when you need to learn the weights of your convolutional layer in your optimization model.
- Parameters:
- init_weightsOptional[bool]
False by default. Whether to initialize weights. It is suggested you set this to True unless you want to initialize weights yourself. When init_weights is set to True, values are initialized from \(\mathcal{U}(-\sqrt{k},\sqrt{k})\), where \(k = 1/[C_{in} * kernel\_size]\).
- class gamspy.formulations.Conv2d(container: Container, in_channels: int, out_channels: int, kernel_size: int | tuple[int, int], stride: int | tuple[int, int] = 1, padding: int | tuple[int, int] | Literal['same', 'valid'] = 0, name_prefix: str | None = None, *, bias: bool = True)[source]#
Bases:
objectFormulation generator for 2D Convolution symbol in GAMS. It can be used to embed convolutional layers of trained neural networks in your problem. It can also be used to embed convolutional layers when you need weights as variables.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- in_channelint
Number of channels in the input
- out_channelint
Number of channels in the output
- kernel_sizeint | tuple[int, int]
Filter size
- strideint | tuple[int, int]
Stride in the convolution, by default 1
- paddingint | tuple[int, int] | Literal[“same”, “valid”]
Specifies the amount of padding to apply to the input, by default 0. If an integer is provided, that padding is applied to both the height and width. If a tuple of two integers is given, the first value determines the padding for the top and bottom, while the second value sets the padding for the left and right. It is also possible to provide string literals “same” and “valid”. “same” pads the input so the output has the shape as the input. “valid” is the same as no padding.
- biasbool
Is bias added after the convolution, by default True
- name_prefixstr | None
Prefix for names of the GAMS symbols generated, by default None which means random prefix. Using same name_prefix in different formulations causes name conflicts. Do not use same name_prefix again.
Methods
__call__(input, *[, propagate_bounds])Forward pass your input, generate output and equations required for calculating the convolution.
load_weights(weight[, bias])Mark Conv2d as parameter and load weights from NumPy arrays.
make_variable(*[, init_weights])Mark Conv2d as variable.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> w1 = np.random.rand(2, 1, 3, 3) >>> b1 = np.random.rand(2) >>> m = gp.Container() >>> # in_channels=1, out_channels=2, kernel_size=3x3 >>> conv1 = gp.formulations.Conv2d(m, 1, 2, 3) >>> conv1.load_weights(w1, b1) >>> # 10 images, 1 channel, 24 by 24 >>> inp = gp.Variable(m, domain=dim((10, 1, 24, 24))) >>> out, eqs = conv1(inp) >>> type(out) <class 'gamspy._symbols.variable.Variable'> >>> [len(x) for x in out.domain] [10, 2, 22, 22]
- __call__(input: Parameter | Variable, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input, generate output and equations required for calculating the convolution. If propagate_bounds is True, the input is of type variable, and load_weights was called, then the bounds of the input are propagated to the output.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“set_output”]
variables_created: [“output”, “weight”, “bias”]
parameters_created: [“weight”, “bias”, “input_bounds”, “output_bounds”]
sets_creates: [“conv_subset”]
Note
For backward compatibility, this result object can be unpacked as a tuple: output, equations = conv2d(input).
weight and bias are available as variables if make_variable was called.
weight and bias are available as parameters if load_weights was called.
input_bounds and output_bounds`are available as parameters if `propogate_bounds=True.
The subset used to map input indices to output indices based on stride and padding.
- Parameters:
- inputgp.Parameter | gp.Variable
input to the conv layer, must be in shape (batch x in_channels x height x width)
- propagate_boundsbool = True
If True, propagate bounds of the input to the output. Otherwise, the output variable is unbounded.
- Returns:
- FormulationResult
- load_weights(weight: ndarray, bias: ndarray | None = None) None[source]#
Mark Conv2d as parameter and load weights from NumPy arrays. After this is called make_variable cannot be called. Use this when you already have the weights of your convolutional layer.
- Parameters:
- weightnp.ndarray
Conv2d layer weights in shape (out_channels x in_channels x kernel_size[0] x kernel_size[1])
- biasnp.ndarray | None
Conv2d layer bias in shape (out_channels, ), only required when bias=True during initialization
- make_variable(*, init_weights=False) None[source]#
Mark Conv2d as variable. After this is called load_weights cannot be called. Use this when you need to learn the weights of your convolutional layer in your optimization model.
- Parameters:
- init_weightsOptional[bool]
False by default. Whether to initialize weights. It is suggested you set this to True unless you want to initialize weights yourself. When init_weights is set to True, values are initialized from \(\mathcal{U}(-\sqrt{k},\sqrt{k})\), where \(k = 1/[C_{in} * \prod_{i=0}^{1}{kernel\_size_n}]\).
- class gamspy.formulations.DecisionTreeStruct(children_left: ndarray | None = None, children_right: ndarray | None = None, feature: ndarray | None = None, threshold: ndarray | None = None, value: ndarray | None = None, capacity: int = 0, n_features: int = 0)[source]#
Bases:
objectRepresents the components of sklearn.tree.
This dataclass stores the core arrays (like children, features, thresholds, and values) that define the tree’s architecture and decision rules.
- Attributes:
- children_left: np.ndarray
An array where children_left[i] is the ID of the left child of node i. Leaf nodes have -1. Defaults to an empty numpy array.
- children_right: np.ndarray
An array where children_right[i] is the ID of the right child of node i. Leaf nodes have -1. Defaults to an empty numpy array.
- feature: np.ndarray
An array where feature[i] is the index of the feature used for splitting at node i. Leaf nodes have -2. Defaults to an empty numpy array.
- threshold: np.ndarray
An array where threshold[i] is the threshold value used for splitting at node i based on feature[i]. Leaf nodes have -2.0. Defaults to an empty numpy array.
- value: np.ndarray
An array (typically 2D for scikit-learn trees, squeezed to 1D for single-output regressors) where value[i] contains the prediction value(s) for node i. For leaf nodes, this is the final prediction. Defaults to an empty numpy array.
- capacityint
The total number of nodes allocated in the underlying tree structure arrays. Defaults to 0.
- n_featuresint
The number of features the decision tree was trained on or expects as input. Defaults to 0.
- capacity: int = 0#
- children_left: ndarray | None = None#
- children_right: ndarray | None = None#
- feature: ndarray | None = None#
- n_features: int = 0#
- threshold: ndarray | None = None#
- value: ndarray | None = None#
- class gamspy.formulations.FormulationResult(result: gp.Variable | gp.Parameter | None = None, equations_created: dict[str, gp.Equation] | None = None, extra_return: gp.Variable | MatchesType | None = None)[source]#
Bases:
objectFormulationResult class provides a common interface for returning results when formulations are called. In the old convention, formulations returned a tuple of result variable and list of equations. In some cases it was possible to get extra output from the formulation. To provide backwards compatibility, FormulationResult class can be unpacked into a result variable and list of equations. Also it supports returning extra output in unpacking.
With the FormulationResult you can have more access to underlying symbols created such as equations, variables, parameters and sets. Since many formulations created symbols with randomized names, it was tedious to find intermediate symbols created. FormulationResult has dictionaries where keys are expected to be documented in the formulation returning the FormulationResult therefore you can access a symbol via its known key.
For example:
Examples
>>> import gamspy as gp >>> m = gp.Container() >>> x = gp.Variable(m) >>> res = gp.math.activation.relu_with_binary_var(x) >>> aux_binary_var = res.variables_created["binary"]
Therefore, it is important for the formulation returning a FormulationResult to properly list the keys to the symbols that are created.
- FormulationResult has the following attributes that might be useful:
result
equations_created
variables_created
sets_created
parameters_created
matches
other
extra_return
- class gamspy.formulations.GRU(container: Container, input_size: int, hidden_size: int)[source]#
Bases:
objectFormulation generator for Gated Recurrent Units (GRU) in GAMSPy.It can be used to embed trained Gated Recurrent Units in your problem.
Note: It currently does NOT support Bidirectional RNNs and Dropout layers.
- Parameters:
- containerContainer
Container that will hold the new variables and equations.
- input_sizeint
The number of expected features in the input sequence.
- hidden_sizeint
The number of features in the hidden state.
Methods
__call__(input_seq[, h0])Forward pass your input sequence, generating the output hidden states and equations required for calculating the gated recurrent units steps over time.
load_weights(weight_ih, weight_hh[, ...])Mark GRU as parameter and load weights from NumPy arrays.
- __call__(input_seq: Parameter | Variable, h0: Parameter | None = None) FormulationResult[source]#
Forward pass your input sequence, generating the output hidden states and equations required for calculating the gated recurrent units steps over time.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“reset_gate”, “update_gate”, “new_gate”, “set_output”]
variables_created: [“r_gate”, “z_gate”, “n_gate”, “output”]
parameters_created: [“w_ih_r”, “w_ih_z”, “w_ih_n”, “w_hh_r”, “w_hh_z”, “w_hh_n”, “b_ih_r”, “b_ih_z”, “b_ih_n”, “b_hh_r”, “b_hh_z”, “b_hh_n”]
Note
The output variable will have the domain (batch, time_steps, hidden_size).
For backward compatibility, this result object can be unpacked as a tuple: output, equations = rnn_layer(input_seq).
- Parameters:
- input_seqgp.Parameter | gp.Variable
Input sequence to the GRU layer. It must be a 3D symbol of the following shape (batch_size, time_steps, input_features).
- h0gp.Parameter | None
Initial hidden state for the first time step. If None, the initial hidden state is assumed to be a vector of zeros. By default None. Shape: (batch, hidden_size)
- Returns:
- FormulationResult
- load_weights(weight_ih: ndarray, weight_hh: ndarray, bias_ih: ndarray | None = None, bias_hh: ndarray | None = None) None[source]#
Mark GRU as parameter and load weights from NumPy arrays. Follows the standard PyTorch packing layout: (3 * hidden_size, …), where the 3 chunks correspond to the reset (r), update (z), and new (n) gates.
- class gamspy.formulations.GradientBoosting(container: gp.Container, ensemble: GradientBoostingRegressor | list[DecisionTreeStruct], name_prefix: str | None = None, bias: float = 1, learning_rate: float = 0.1)[source]#
Bases:
objectFormulation generator for Gradient Boosted Trees in GAMSPy.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- ensemble: GradientBoostingRegressor | list[DecisionTreeStruct]
A fitted sklearn.ensemble.GradientBoostingRegressor instance,
If sklearn.ensemble.GradientBoostingRegressor is not utilized, the ensembled trees information can be supplied via a list of DecisionTreeStruct dataclasse instances, which represents the same components as those in sklearn.tree. See
DecisionTreeStructfor details on required attributes.
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
- bias: float | 1
Bias term used to consolidate the final output using the contribution of each tree. This is generally the average of the output data used for training and it is useful when ensemble is a list[DecisionTreeStruct]. Otherwise, this is deduced from ensemble itself.
- learning_rate: float | 0.1
Rate at which each tree’s contribution is reduced, by default is 0.1. This is useful when ensemble is a list[DecisionTreeStruct]. Otherwise, this is deduced from ensemble itself.
Methods
__call__(input[, M])Call self as a function.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> np.random.seed(42) >>> m = gp.Container() >>> in_data = np.random.randint(0, 10, size=(5, 2)) >>> out_data = np.random.randint(1, 3, size=(5, 1)) >>> tree1_attribute = { ... "capacity": 3, ... "children_left": np.array([1, -1, -1]), ... "children_right": np.array([2, -1, -1]), ... "feature": np.array([0, -2, -2]), ... "n_features": 2, ... "threshold": np.array([4.0, -2.0, -2.0]), ... "value": np.array([[-4.4408921e-17], [-8.0000000e-01], [2.0000000e-01]]), ... } >>> tree2_attribute = { ... "capacity": 3, ... "children_left": np.array([1, -1, -1]), ... "children_right": np.array([2, -1, -1]), ... "feature": np.array([0, -2, -2]), ... "n_features": 2, ... "threshold": np.array([4.0, -2.0, -2.0]), ... "value": np.array([[-8.8817842e-17], [-6.4000000e-01], [1.6000000e-01]]), ... } >>> gb_trees = [gp.formulations.DecisionTreeStruct(**tree1_attribute), gp.formulations.DecisionTreeStruct(**tree2_attribute)] >>> dt_model = gp.formulations.GradientBoosting(m, gb_trees) >>> x = gp.Variable(m, "x", domain=dim((5, 2)), type="positive") >>> x.up[:, :] = 10 >>> y, eqns = dt_model(x) >>> set_of_samples = y.domain[0] >>> set_of_samples.name 'DenseDim5_1'
- class gamspy.formulations.Linear(container: Container, in_features: int, out_features: int, name_prefix: str | None = None, *, bias: bool = True)[source]#
Bases:
objectFormulation generator for Linear layer in GAMS.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- in_featuresint
Input feature size
- out_featuresint
Output feature size
- biasbool = True
Should bias be added after linear transformation, by Default: True
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
Methods
__call__(input, *[, propagate_bounds])Forward pass your input, generate output and equations required for calculating the linear transformation.
load_weights(weight[, bias])Mark Linear as parameter and load weights from NumPy arrays.
make_variable(*[, init_weights])Mark Linear layer as variable.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> m = gp.Container() >>> l1 = gp.formulations.Linear(m, 128, 64) >>> w = np.random.rand(64, 128) >>> b = np.random.rand(64) >>> l1.load_weights(w, b) >>> x = gp.Variable(m, "x", domain=dim([10, 128])) >>> y, set_y = l1(x) >>> [d.name for d in y.domain] ['DenseDim10_1', 'DenseDim64_1']
- __call__(input: Parameter | Variable, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input, generate output and equations required for calculating the linear transformation. If propagate_bounds is True, the input is of type variable, and load_weights was called, then the bounds of the input are propagated to the output.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“set_output”]
variables_created: [“output”, “weight”, “bias”]
parameters_created: [“weight”, “bias”, “input_bounds”, “output_bounds”]
Note
For backward compatibility, this result object can be unpacked as a tuple: output, equations = linear(input).
weight and bias are available as variables if make_variable was called.
weight and bias are available as parameters if load_weights was called.
input_bounds and output_bounds`are available as parameters if `propogate_bounds=True.
- Parameters:
- inputgp.Parameter | gp.Variable
input to the linear layer, must be in shape (* x in_features)
- propagate_boundsbool = True
If True, propagate bounds of the input to the output. Otherwise, the output variable is unbounded.
- Returns:
- FormulationResult
- load_weights(weight: ndarray, bias: ndarray | None = None) None[source]#
Mark Linear as parameter and load weights from NumPy arrays. After this is called make_variable cannot be called. Use this when you already have the weights of your Linear layer.
- Parameters:
- weightnp.ndarray
Linear layer weights in shape (out_features x in_features)
- biasnp.ndarray | None
Linear layer bias in shape (out_features, ), only required when bias=True during initialization
- make_variable(*, init_weights=False) None[source]#
Mark Linear layer as variable. After this is called load_weights cannot be called. Use this when you need to learn the weights of your linear layer in your optimization model.
- Parameters:
- init_weightsOptional[bool]
False by default. Whether to initialize weights. It is suggested you set this to True unless you want to initialize weights yourself. When init_weights is set to True, values are initialized from \(\mathcal{U}(-\sqrt{k},\sqrt{k})\), where \(k = 1/in\_features\).
- class gamspy.formulations.MaxPool2d(container: gp.Container, kernel_size: int | tuple[int, int], stride: int | None = None, padding: int = 0, name_prefix: str | None = None)[source]#
Bases:
_MPool2dFormulation generator for 2D Max Pooling in GAMS.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- kernel_sizeint | tuple[int, int]
Filter size
- strideint | tuple[int, int] | None
Stride in the max pooling, it is equal to kernel_size if not provided
- paddingint | tuple[int, int]
Amount of padding to be added to input, by default 0
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
Methods
__call__(input[, big_m, propagate_bounds])Forward pass your input, generate output and equations required for calculating the max pooling.
Examples
>>> import gamspy as gp >>> from gamspy.math import dim >>> m = gp.Container() >>> # 2x2 max pooling >>> mp1 = gp.formulations.MaxPool2d(m, (2, 2)) >>> inp = gp.Variable(m, domain=dim((10, 1, 24, 24))) >>> out, eqs = mp1(inp) >>> type(out) <class 'gamspy._symbols.variable.Variable'> >>> [len(x) for x in out.domain] [10, 1, 12, 12]
- __call__(input: gp.Parameter | gp.Variable, big_m: int = 1000, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input, generate output and equations required for calculating the max pooling. Returns the output variable and the list of equations required for the max pooling formulation. if propagate_bounds is True, it will also set the bounds for the output variable based on the input. It will also compute the big M value required for the pooling operation using the bounds.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“lte”, “gte”, “pick_one”]
variables_created: [“output”, “aux_variable”]
parameters_created: [“bigM”, “output_lb”, “output_ub”]
sets_created: [“in_out_matching_1”, “in_out_matching_2”]
Note
For backward compatibility, this result object can be unpacked as a tuple: output, equations = maxpool(input).
aux_variable is the binary variable selecting the max element.
output_lb and output_ub are available as parameters if propagate_bounds=True.
`in_out_matching_1`is the subset used to map input indices to output indices based on stride and padding.
in_out_matching_2 is the subset used specifically for bound propagation.
It gets created only if propogate_bounds=True.
- Parameters:
- inputgp.Parameter | gp.Variable
input to the max pooling 2d layer, must be in shape (batch x in_channels x height x width)
- big_m: int
Big M value that is required for the pooling operation. Default value: 1000.
- propagate_bounds: bool
If True, it will set the bounds for the output variable based on the input. Default value: True
- Returns:
- FormulationResult
- class gamspy.formulations.MinPool2d(container: gp.Container, kernel_size: int | tuple[int, int], stride: int | None = None, padding: int = 0, name_prefix: str | None = None)[source]#
Bases:
_MPool2dFormulation generator for 2D Min Pooling in GAMS.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- kernel_sizeint | tuple[int, int]
Filter size
- strideint | tuple[int, int] | None
Stride in the min pooling, it is equal to kernel_size if not provided
- paddingint | tuple[int, int]
Amount of padding to be added to input, by default 0
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
Methods
__call__(input[, big_m, propagate_bounds])Forward pass your input, generate output and equations required for calculating the min pooling.
Examples
>>> import gamspy as gp >>> from gamspy.math import dim >>> m = gp.Container() >>> # 2x2 min pooling >>> mp1 = gp.formulations.MinPool2d(m, (2, 2)) >>> inp = gp.Variable(m, domain=dim((10, 1, 24, 24))) >>> out, eqs = mp1(inp) >>> type(out) <class 'gamspy._symbols.variable.Variable'> >>> [len(x) for x in out.domain] [10, 1, 12, 12]
- __call__(input: gp.Parameter | gp.Variable, big_m: int = 1000, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input, generate output and equations required for calculating the min pooling. Returns the output variable and the list of equations required for the min pooling formulation. if propagate_bounds is True, it will also set the bounds for the output variable based on the input. It will also compute the big M value required for the pooling operation using the bounds.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“lte”, “gte”, “pick_one”]
variables_created: [“output”, “aux_variable”]
parameters_created: [“bigM”, “output_lb”, “output_ub”]
sets_created: [“in_out_matching_1”, “in_out_matching_2”]
Note
For backward compatibility, this result object can be unpacked as a tuple: output, equations = minpool(input).
aux_variable is the binary variable selecting the min element.
output_lb and output_ub are available as parameters if propagate_bounds=True.
in_out_matching_1 is the subset used to map input indices to output indices based on stride and padding.
in_out_matching_2 is the subset used specifically for bound propagation.
It gets created only if propogate_bounds=True.
- Parameters:
- inputgp.Parameter | gp.Variable
input to the min pooling 2d layer, must be in shape (batch x in_channels x height x width)
- big_m: int
Big M value that is required for the pooling operation. Default value: 1000.
- propagate_bounds: bool
If True, it will set the bounds for the output variable based on the input. Default value: True
- Returns:
- FormulationResult
- class gamspy.formulations.PolicyResult(stage: str, incoming_state: float | dict[str, float], noise: float, approx_cost_to_go: float, decisions: dict[str, Any])[source]#
Bases:
objectThe trained policy’s decision at a single point.
Returned by SDDP.policy. Answers the operational question “I’m standing in `stage`, my state came in at `incoming_state`, the noise for this stage realised as `noise`. What should I do, and what does it cost me from here on?”
- Attributes:
- stagestr
The stage label that was queried (e.g.
"mar"or"w17").- incoming_statefloat | dict[str, float]
The state value entering the stage.
- noisefloat
The realised noise value injected for the stage.
- approx_cost_to_gofloat
acost.lfrom the point solve: the immediate stage cost plus the cut-approximated expected future cost.- decisionsdict[str, Any]
{variable_name: level}for each reported variable, evaluated at the stage’s last time step. The value shape depends on the variable’s domain:Variables with domain
[time_set]give afloat.Variables with domain
[time_set, other_dim]give adict[str, float]keyed by the non-time dimension’s label (e.g.{"Hydro": 100.0, "HardCoal": 200.0}).Variables with domain
[time_set, dim1, dim2, ...](3+-D) give adict[tuple[str, ...], float]keyed by a tuple of the non-time dim labels in declaration order.
- approx_cost_to_go: float#
- decisions: dict[str, Any]#
- incoming_state: float | dict[str, float]#
- noise: float#
- stage: str#
- class gamspy.formulations.RNN(container: Container, input_size: int, hidden_size: int, activation: Literal['tanh', 'relu', 'linear'] = 'tanh')[source]#
Bases:
objectFormulation generator for Recurrent Neural Networks in GAMSPy. It can be used to embed trained Recurrent neural networks in your problem.
Note: It currently does NOT support Bidirectional RNNs and Dropout layers.
- Parameters:
- containerContainer
Container that will hold the new variables and equations.
- input_sizeint
The number of expected features in the input sequence.
- hidden_sizeint
The number of features in the hidden state.
- activationLiteral[“tanh”, “relu”, “linear”]
The activation function applied to the hidden state update. By default “tanh”.
Methods
__call__(input_seq[, h0, propagate_bounds])Forward pass your input sequence, generating the output hidden states and equations required for calculating the recurrent neural network steps over time.
load_weights(weight_ih, weight_hh[, ...])Mark RNN as parameter and load weights from NumPy arrays.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> m = gp.Container() >>> # 2 input features, 4 hidden units >>> rnn = gp.formulations.RNN(m, input_size=2, hidden_size=4) >>> w_ih = np.random.rand(4, 2) >>> w_hh = np.random.rand(4, 4) >>> b_ih = np.random.rand(4) >>> b_hh = np.random.rand(4) >>> rnn.load_weights(w_ih, w_hh, b_ih, b_hh) >>> batch, time_step, features = [1, 3, 2] >>> input_domain = dim([batch, time_step, features]) >>> x = gp.Parameter(m, name="x_in", domain=input_domain, records=np.random.rand(1, 3, 2)) >>> out_var = rnn(x).result >>> type(out_var) <class 'gamspy._symbols.variable.Variable'> >>> [d.name for d in out_var.domain] ['DenseDim1_1', 'DenseDim3_1', 'DenseDim4_1']
- __call__(input_seq: Parameter | Variable, h0: Parameter | None = None, *, propagate_bounds: bool = True) FormulationResult[source]#
Forward pass your input sequence, generating the output hidden states and equations required for calculating the recurrent neural network steps over time. If propagate_bounds is True (default), the input_seq is of type variable, and load_weights was called, then the bounds of the input are propagated to the output.
Returns FormulationResult which can be unpacked as a output variable and list of equations.
- FormulationResult:
equations_created: [“set_output”, “set_pre_act”, “y_gte_x”, “y_lte_x_1”, “y_lte_x_2”]
variables_created: [“output”, “pre_act”, “binary”]
parameters_created: [“w_ih”, “w_hh”, “b_ih”, “b_hh”, “input_bounds”, “out_bounds”, “relu_bounds”]
Note
The output variable will have the domain (batch, time_steps, hidden_size).
Following equations are available only when activation=”relu”, [“set_pre_act”, “y_gte_x”, “y_lte_x_1”, “y_lte_x_2”].
Following variables are available only when activation=”relu”, [“pre_act”, “binary”].
Following parameters are available only when propagate_bounds=True, [“input_bounds”, “out_bounds”, “relu_bounds”]. Further, relu_bounds is only available when activation=”relu”.
For backward compatibility, this result object can be unpacked as a tuple: output, equations = rnn_layer(input_seq).
- Parameters:
- input_seqgp.Parameter | gp.Variable
Input sequence to the RNN layer. It must be a 3D symbol of the following shape (batch_size, time_steps, input_features).
- h0gp.Parameter | None
Initial hidden state for the first time step. If None, the initial hidden state is assumed to be a vector of zeros. By default None. Shape: (batch, hidden_size)
- propagate_boundsbool = True
If True, propagate bounds of the input to the output. Otherwise, the output variable is unbounded.
- Returns:
- FormulationResult
- load_weights(weight_ih: ndarray, weight_hh: ndarray, bias_ih: ndarray | None = None, bias_hh: ndarray | None = None) None[source]#
Mark RNN as parameter and load weights from NumPy arrays. Use this when you already have the weights of your hidden layers.
- Parameters:
- weight_ihnp.ndarray
The input-to-hidden layer weights. Shape: (hidden_size, input_size)
- weight_hhnp.ndarray
The hidden-to-hidden layer weights. Shape: (hidden_size, hidden_size)
- bias_ihnp.ndarray | None
The input-to-hidden layer bias. Shape: (hidden_size, )
- bias_hhnp.ndarray | None
The hidden-to-hidden layer bias. Shape: (hidden_size, )
- class gamspy.formulations.RandomForest(container: gp.Container, ensemble: RandomForestRegressor | list[DecisionTreeStruct], name_prefix: str | None = None)[source]#
Bases:
objectFormulation generator for Random Forests in GAMSPy.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- ensemble: RandomForestRegressor | None
A fitted sklearn.ensemble.RandomForestRegressor instance,
If sklearn.ensemble.RandomForestRegressor is not utilized, the ensembled trees information can be supplied via a list of DecisionTreeStruct dataclasse instances, which represents the same components as those in sklearn.tree. See
DecisionTreeStructfor details on required attributes.
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
Methods
__call__(input[, M])Call self as a function.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> np.random.seed(42) >>> m = gp.Container() >>> in_data = np.random.randint(0, 10, size=(5, 2)) >>> out_data = np.random.randint(1, 3, size=(5, 1)) >>> tree1_attribute = { ... "capacity": 7, ... "children_left": np.array([ 1, -1, 3, -1, 5, -1, -1]), ... "children_right": np.array([ 2, -1, 4, -1, 6, -1, -1]), ... "feature": np.array([ 1, -2, 0, -2, 1, -2, -2]), ... "n_features": 2, ... "threshold": np.array([ 2. , -2. , 5.5, -2. , 8.5, -2. , -2. ]), ... "value": np.array([[1.6 ],[1. ],[1.75],[2. ],[1.5 ],[1. ],[2. ]]) ... } >>> tree2_attribute = { ... "capacity": 3, ... "children_left": np.array([ 1, -1, -1]), ... "children_right": np.array([ 2, -1, -1]), ... "feature": np.array([ 0, -2, -2]), ... "n_features": 2, ... "threshold": np.array([ 1.5, -2. , -2. ]), ... "value": np.array([[1.4],[1. ],[2. ]]) ... } >>> forest = [gp.formulations.DecisionTreeStruct(**tree1_attribute), gp.formulations.DecisionTreeStruct(**tree2_attribute)] >>> dt_model = gp.formulations.RandomForest(m, forest) >>> x = gp.Variable(m, "x", domain=dim((5, 2)), type="positive") >>> x.up[:, :] = 10 >>> y, eqns = dt_model(x) >>> set_of_samples = y.domain[0] >>> set_of_samples.name 'DenseDim5_1'
- class gamspy.formulations.RegressionTree(container: gp.Container, regressor: DecisionTreeRegressor | DecisionTreeStruct, name_prefix: str | None = None)[source]#
Bases:
objectFormulation generator for Regression Trees in GAMSPy.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- regressor: DecisionTreeRegressor | DecisionTreeStruct
A fitted sklearn.tree.DecisionTreeRegressor instance.
If sklearn.tree.DecisionTreeRegressor is not utilized, the fitted tree information can be supplied via the DecisionTreeStruct dataclass, which represents the same components as those in sklearn.tree. See
DecisionTreeStructfor details on required attributes.
- name_prefixstr | None
Prefix for generated GAMSPy symbols, by default None which means random prefix. Using the same name_prefix in different formulations causes name conflicts. Do not use the same name_prefix again.
Methods
__call__(input[, M])Generate output variable and equations required for embedding the regression tree.
Examples
>>> import gamspy as gp >>> import numpy as np >>> from gamspy.math import dim >>> np.random.seed(42) >>> m = gp.Container() >>> in_data = np.random.randint(0, 10, size=(5, 2)) >>> out_data = np.random.randint(1, 3, size=(5, 1)) >>> tree_attribute = { ... "children_left": np.array([1, 2, -1, -1, -1]), ... "children_right": np.array([4, 3, -1, -1, -1]), ... "feature": np.array([0, 1, -2, -2, -2]), ... "threshold": np.array([5.5, 4.5, -2.0, -2.0, -2.0]), ... "value": np.array([[15.6], [11.25], [10.0], [15.0], [33.0]]), ... "capacity": 5, ... "n_features": 2, ... } >>> tree = gp.formulations.DecisionTreeStruct(**tree_attribute) >>> dt_model = gp.formulations.RegressionTree(m, tree) >>> x = gp.Variable(m, "x", domain=dim((5, 2)), type="positive") >>> x.up[:, :] = 10 >>> y, eqns = dt_model(x) >>> set_of_samples = y.domain[0] >>> set_of_samples.name 'DenseDim5_1'
- __call__(input: Parameter | Variable, M: float | None = None) tuple[Variable, list[Equation]][source]#
Generate output variable and equations required for embedding the regression tree.
- Parameters:
- inputgp.Parameter | gp.Variable
input for the regression tree, must be in shape (sample_size, number_of_features)
- Mfloat
value for the big_M. By default, infer the value using the available bounds for variables. If the variable is unbounded, then default to 1e10.
- class gamspy.formulations.SDDP(container: Container, stage_set: Set, time_set: Set | None = None, n_trials: int = 5, seed: int = 42, verbose: bool = True)[source]#
Bases:
objectStochastic Dual Dynamic Programming for multistage stochastic GAMSPy models.
SDDP trains a cost-to-go approximation for a multistage stochastic program by alternating forward simulation passes with backward Benders cut generation. Register the state variable(s) with
add_state, the stochastic noise withset_noise, inject the algorithm into the model withbuild, thentrainthe policy.- Parameters:
- containerContainer
The
gp.Containerholding every user-defined symbol.- stage_setSet
The full stage set; its length is the number of stages in the problem.
- time_setSet | None
Full time-domain set when the model has a finer-grained time inside each stage. By default None, which reuses
stage_set.- n_trialsint
Number of trial levels per state variable (must be >= 1). By default 5.
- seedint
Seed for the forward-pass scenario sampler. By default 42.
- verbosebool
Print one convergence row per iteration during training. By default True.
- Attributes:
active_stagesddp-owned active-stage singleton.
containerThe host
gp.Containerholding every symbol owned by this sddp instance.- n_stages
Methods
add_state(variable[, lower_bound, ...])Register a state variable.
build(stage_cost[, equations])Inject the SDDP algorithm into the user model.
load(path)Load an sddp instance.
policy(stage, state, noise[, report])Query the trained policy at a single situation.
save(path)Serialize this sddp instance to a single
.sddpfile.set_noise(parameter, scenario_data[, ...])Register the stochastic noise model.
simulate([n_paths, report, seed])Run the trained policy on fresh Monte Carlo paths.
train([n_iter, rel_tol, patience, risk, ...])Run the SDDP iteration loop and return convergence results.
Examples
>>> import numpy as np >>> import gamspy as gp >>> from gamspy.formulations import SDDP >>> m = gp.Container() >>> t = gp.Set(m, "t", records=["jan", "feb", "mar", "apr"]) >>> sddp = SDDP(m, stage_set=t, n_trials=2, seed=42, verbose=False) >>> stage = sddp.active_stage >>> precip = gp.Parameter(m, "precip") >>> level = gp.Variable(m, "L", type="positive", domain=t) >>> spill = gp.Variable(m, "F", type="positive", domain=t) >>> shortfall = gp.Variable(m, "Z", type="positive", domain=t) >>> release = gp.Variable(m, "R", type="positive", domain=t) >>> cost = gp.Variable(m, "COST") >>> release.up[t] = 200.0 >>> level.up[t] = 250.0 >>> balance = gp.Equation(m, "balance", domain=t) >>> obj = gp.Equation(m, "obj") >>> balance[t].where[stage[t]] = ( ... level[t] - level[t.lag(1, "circular")] ... + release[t] + spill[t] - shortfall[t] == precip ... ) >>> obj[...] = cost == gp.Sum(stage[t], 10.0 * spill[t] + 5.0 * shortfall[t]) >>> sddp.add_state(level, initial_state=100.0) >>> sddp.set_noise(precip, scenario_data=np.array([[50.0], [50.0], [-50.0], [-50.0]])) >>> sddp.build(stage_cost=cost) >>> sddp SDDP(stages=4, states=['L'], noise=precip, built=True)
- classmethod load(path: str) SDDP[source]#
Load an sddp instance.
The returned instance is read-only:
policy()andsimulate()work as expected, butadd_state()/set_noise()/build()/train()will raise. To add more iterations, retrain from scratch.- Parameters:
- pathstr
Path to a
.sddpfile produced bySDDP.save().
- Returns:
- SDDP
An sddp instance reattached to the deserialized Container.
- Raises:
- ValidationError
If
pathdoes not end with.sddp, the file is missing, malformed, references symbols absent from the Container, or carries a major version different from the current sddp module.
- add_state(variable: Variable, lower_bound: float | None = None, upper_bound: float | None = None, initial_state: float | None = None) None[source]#
Register a state variable.
- Parameters:
- variableVariable
GAMSPy Variable for the state (reservoir level, inventory, etc.), indexed over the time set.
- lower_boundfloat | None
Lower end of the feasible range used to seed the initial uniform trial grid and to clamp the adaptive trial update. By default None, which infers the bound (see Notes).
- upper_boundfloat | None
Upper end of the feasible range, resolved like
lower_bound. By default None.- initial_statefloat | None
Value the state takes before stage 1. By default None, which falls back to
lower_bound.
Notes
Each bound is resolved in the following order:
Use the value passed here.
If
None, read fromvariable.records["lower"]/variable.records["upper"].If the variable has no recorded bounds, fall back to the variable type’s default (
positivegives(0, +inf), etc.).
If a bound is passed explicitly while the variable also carries an explicit recorded bound that disagrees, a
UserWarningis raised and the passed value still wins.
- build(stage_cost: Variable, equations: list | None = None) None[source]#
Inject the SDDP algorithm into the user model.
- Parameters:
- stage_costVariable
GAMSPy Variable equal to the per-stage operational cost (WITHOUT the future-cost alpha term).
- equationslist | None
User physics equations to include in the LP. By default None, which makes the sddp module pull every equation currently declared in the container.
- policy(stage: str, state: float | dict[str, float], noise: float, report: list[Variable] | None = None) PolicyResult[source]#
Query the trained policy at a single situation.
Answers: “I’m in `stage`, my state arrived at `state`, this stage’s noise realised as `noise`. What is the optimal decision and what does it cost me from here on?”
- Parameters:
- stagestr
Stage label to stand in (must be one of the defined stages).
- statefloat | dict[str, float]
The state value(s) entering this stage. With a single registered state variable, pass a scalar (e.g.
180). With several states, pass adictkeyed by state-variable name, e.g.{"L_up": 120, "L_dn": 200}where its keys must match the registered states exactly. A scalar with multiple states raisesValidationError.- noisefloat
The realised noise value for this stage.
- reportlist[Variable] | None
Variables whose optimal level to return. By default None, which returns every state variable.
- Returns:
- PolicyResult
stage,incoming_state(scalar for one state,dictfor several),noise,approx_cost_to_goanddecisions({var_name: level}).
- save(path: str) None[source]#
Serialize this sddp instance to a single
.sddpfile.The saved artifact contains the host
Container(viagp.serialize) plus a small JSON sidecar mapping symbol names to sddp roles. The output is loadable in a different Python process / notebook withSDDP.load(path)and supportspolicy()/simulate()immediately; it does not support further training (seeSDDP.loadfor the rationale).- Parameters:
- pathstr
Output path. Must end with
.sddp.
- Raises:
- ValidationError
If the instance was not built, or
pathdoes not end with.sddp.
- set_noise(parameter: Parameter, scenario_data: ndarray, probabilities: ndarray | list[float] | None = None) None[source]#
Register the stochastic noise model.
- Parameters:
- parameterParameter
GAMSPy Parameter that is overwritten before each LP solve with the sampled inflow value for the current scenario.
- scenario_datanp.ndarray
2-D numpy array of shape
(n_stages, n_scenarios).- probabilitiesnp.ndarray | list[float] | None
Optional 1-D array of scenario probabilities, shape
(n_scenarios,). Must be non-negative and sum to 1.0. By default None, which makes the scenarios equally likely (probability1/n_scenarioseach).
- simulate(n_paths: int = 100, report: list[Variable] | None = None, seed: int | None = None) SimulationResult[source]#
Run the trained policy on fresh Monte Carlo paths.
- Parameters:
- n_pathsint
Number of independent simulation paths. By default 100.
- reportlist[Variable] | None
GAMSPy Variables to capture per (path, stage). By default None, which captures every state variable.
- seedint | None
Sampler seed. By default None, which sets it to
train_seed + 1.
- Returns:
- SimulationResult
Pivot-shaped DataFrames (paths x stages) for total cost, stage costs, realised noise, and each reported variable.
- train(n_iter: int = 20, rel_tol: float | None = None, patience: int = 5, risk: CVaR | None = None, gap_paths: int = 0) SDDPResult[source]#
Run the SDDP iteration loop and return convergence results.
- Parameters:
- n_iterint
Maximum number of SDDP iterations; training may stop earlier when
rel_tolis set. By default 20.- rel_tolfloat | None
Relative lower-bound improvement below which an iteration counts as a plateau step. By default None.
- patienceint
Number of consecutive sub-
rel_toliterations required before stopping early (must be >= 1). Ignored whenrel_tolisNone. By default 5.- riskCVaR | None
Risk measure to optimize. By default None, the risk-neutral expectation.
- gap_pathsint
If
>= 1, after training run an out-of-sample Monte-Carlo simulation of the trained policy with this many independent paths and report a statistically meaningful optimality gap (95% CI of the policy cost vs. the lower bound) on the result. By default 0.
Notes
Pressing CTRL+C during training stops gracefully: the current iteration is finalized (or, if its in-flight solve was aborted, discarded) and the policy trained so far is returned with
stop_reason == "interrupted". Press CTRL+C a second time to abort hard (raisesKeyboardInterrupt).
- property active_stage: Set#
sddp-owned active-stage singleton.
Reference this in your equations’
.where[stage[...]]clauses so each per-stage solve activates only the equations for the current stage.
- property container: Container#
The host
gp.Containerholding every symbol owned by this sddp instance.
- property n_stages: int#
!! processed by numpydoc !!
- class gamspy.formulations.SimulationResult(n_paths: int, total_cost: Series, stage_costs: DataFrame, noise: DataFrame, variables: dict[str, DataFrame], elapsed: float = 0.0)[source]#
Bases:
objectPer-path Monte Carlo evaluation of a trained SDDP policy.
All DataFrame attributes are indexed by
path(rows) andstage(columns) so the standard ClearLake-style pivot is the natural shape.- Attributes:
- n_pathsint
Number of independent simulation paths.
- total_costpd.Series
Total realised cost per path, indexed by
path.- stage_costspd.DataFrame
Per-stage cost, indexed by
pathwith one column perstage.- noisepd.DataFrame
Realised noise per (path, stage).
- variablesdict[str, pd.DataFrame]
{variable_name: per (path, stage) levels}for each reported variable.- elapsedfloat
Wall-clock simulation time in seconds. By default 0.0.
- elapsed: float = 0.0#
- n_paths: int#
- noise: DataFrame#
- stage_costs: DataFrame#
- property summary: Series#
Mean / std / percentiles of
total_costacross paths.
- total_cost: Series#
- variables: dict[str, DataFrame]#
- class gamspy.formulations.TorchSequential(container: gp.Container, network: torch.nn.Sequential, layer_converters: dict | None = None)[source]#
Bases:
objectFormulation generator for Sequential Layer from PyTorch. This is a convenience formulation that builds upon other formulations.
- Parameters:
- containerContainer
Container that will contain the new variable and equations.
- networktorch.nn.Sequential
Sequential network that will be translated to GAMSPy
- layer_convertersdict | None
You can change default layer converters or add support for not implemented layers through this dictionary. Key is the class name as string, and value expects a function that returns GAMSPy formulation given container and the PyTorch layer.
Methods
__call__(input)This method returns a `FormulationResult` object, which includes symbols and outputs created by its underlying layers.
Examples
>>> import gamspy as gp >>> from gamspy.math import dim >>> def embed(): ... try: ... import torch ... except ModuleNotFoundError as e: ... print("[10, 4, 30, 30]") ... return ... m = gp.Container() ... model = torch.nn.Sequential( ... torch.nn.Conv2d(3, 4, 3, bias=True), ... torch.nn.ReLU(), ... torch.nn.Conv2d(4, 4, 3, bias=False, padding=1), ... ) ... x = gp.Variable(m, domain=dim([10, 3, 32, 32])) ... seq_formulation = gp.formulations.TorchSequential(m, model) ... y, eqs = seq_formulation(x) ... print([len(d) for d in y.domain]) >>> embed() [10, 4, 30, 30]
- __call__(input: Variable) FormulationResult[source]#
This method returns a `FormulationResult` object, which includes symbols and outputs created by its underlying layers.
The way to access these underlying symbols depends on what the sub-layer returns:
If a Sub-Layer Returns a `FormulationResult`
All symbols created by that sub-layer can be accessed within the main FormulationResult. Each symbol’s name is prefixed with its layer number, followed by a dot (.).
Access Format: <layer_num>.<symbol_name>
Example: If the first layer creates a parameter named bias, it is accessed as 0.bias in parameters_created.
If a Sub-Layer Returns the “Old Style” Output (Output Variable and List of Equations)
For backward compatibility, if a sub-layer returns an output variable and a list of equations instead of a FormulationResult, they are accessed as follows:
- Output Variable: The main output variable is named:
Access Format: <layer_num>.output
- Equations: Each returned equation is sequentially named:
Access Format: <layer_num>.eq_<eq_number> (where eq_number starts at 0, 1, 2…)
Example: The first equation from the third layer is accessed as 2.eq_0 in equations_created.
- Returns:
- FormulationResult
- gamspy.formulations.flatten_dims(x: Variable | Parameter, dims: list[int], *, propagate_bounds: bool = True) tuple[Parameter | Variable, list[Equation]][source]#
Flatten domains indicated by dims into a single domain. If propagate_bounds is True, and x is of type variable, the bounds of the input variable are propagated to the output.
- Parameters:
- xgp.Variable | gp.Parameter
Input to be flattened
- dims: list[int]
List of integers indicating indices of the domains to be flattened. Must be consecutive indices.
- propagate_bounds: bool, optional
Propagate bounds from the input to the output variable. Default is True.
Examples
>>> import gamspy as gp >>> from gamspy.math import dim >>> m = gp.Container() >>> inp = gp.Variable(m, domain=dim((10, 1, 24, 24))) >>> out, eqs = gp.formulations.flatten_dims(inp, [2, 3]) >>> type(out) <class 'gamspy._symbols.variable.Variable'> >>> [len(x) for x in out.domain] [10, 1, 576]
- gamspy.formulations.pwl_convexity_formulation(input_x: Variable, x_points: Sequence[int | float], y_points: Sequence[int | float], using: Literal['binary', 'sos2'] = 'binary', *, bound_left: bool = True, bound_right: bool = True) tuple[Variable, list[Equation]][source]#
This function implements a piecewise linear function using the convexity formulation. Given an input (independent) variable input_x, along with the defining x_points and corresponding y_points of the piecewise function, it constructs the dependent variable y and formulates the equations necessary to define the function.
Here is the convexity formulation:
\[ \begin{align}\begin{aligned}x = \sum_{i}{x\_points_i * \lambda_i}\\y = \sum_{i}{y\_points_i * \lambda_i}\\\sum_{i}{\lambda_i} = 1\\\lambda_i \in SOS2\end{aligned}\end{align} \]By default, SOS2 variables are implemented using binary variables. See Modeling disjunctive constraints with a logarithmic number of binary variables and constraints . However, you can switch to SOS2 (Special Ordered Set Type 2) by setting the using parameter to “sos2”.
The implementation handles discontinuities in the function. To represent a discontinuity at a specific point x_i, include x_i twice in the x_points array with corresponding values in y_points. For example, if x_points = [1, 3, 3, 5] and y_points = [10, 30, 50, 70], the function allows y to take either 30 or 50 when x = 3. Note that discontinuities always introduce additional binary variables, regardless of the value of the using argument.
It is possible to disallow a specific range by including None in both x_points and the corresponding y_points. For example, with x_points = [1, 3, None, 5, 7] and y_points = [10, 35, None, -20, 40], the range between 3 and 5 is disallowed for input_x.
However, x_points cannot start or end with a None value, and a None value cannot be followed by another None. Additionally, if x_i is None, then y_i must also be None. Similar to the discontinuities, disallowed ranges always introduce additional binary variables, regardless of the value of the using argument.
The input variable input_x is restricted to the range defined by x_points unless bound_left or bound_right is set to False. Setting either to True, creates SOS1 type of variables. When input_x is not bound, you can assume as if the first and/or the last line segments are extended.
Returns the dependent variable y and the equations required to model the piecewise linear relationship.
- Parameters:
- xgp.Variable
Independent variable of the piecewise linear function
- x_points: typing.Sequence[int | float]
Break points of the piecewise linear function in the x-axis
- y_points: typing.Sequence[int| float]
Break points of the piecewise linear function in the y-axis
- using: str = “binary”
What type of variable is used during implementing piecewise function
- bound_left: bool = True
If input_x should be limited to start from x_points[0]
- bound_right: bool = True
If input_x should be limited to end at x_points[-1]
- Returns:
- tuple[gp.Variable, list[Equation]]
Examples
>>> from gamspy import Container, Variable, Set >>> from gamspy.formulations import pwl_convexity_formulation >>> m = Container() >>> x = Variable(m, "x") >>> y, eqs = pwl_convexity_formulation(x, [-1, 4, 10, 10, 20], [-2, 8, 15, 17, 37])
- gamspy.formulations.pwl_interval_formulation(input_x: Variable, x_points: Sequence[int | float], y_points: Sequence[int | float], *, bound_left: bool = True, bound_right: bool = True) tuple[Variable, list[Equation]][source]#
This function implements a piecewise linear function using the intervals formulation. Given an input (independent) variable input_x, along with the defining x_points and corresponding y_points of the piecewise function, it constructs the dependent variable y and formulates the equations necessary to define the function.
Here is the interval formulation:
\[ \begin{align}\begin{aligned}\lambda_i \geq b_i * LB_i \quad \forall{i}\\\lambda_i \leq b_i * UB_i \quad \forall{i}\\\sum_{i}{b_i} = 1\\x = \sum_{i}{\lambda_i}\\y = \sum_{i}{(\lambda_i * slope_i) + (b_i * offset_i) }\\b_i \in \{0, 1\} \quad \forall{i}\end{aligned}\end{align} \]The implementation handles discontinuities in the function. To represent a discontinuity at a specific point x_i, include x_i twice in the x_points array with corresponding values in y_points. For example, if x_points = [1, 3, 3, 5] and y_points = [10, 30, 50, 70], the function allows y to take either 30 or 50 when x = 3. Note that discontinuities introduce additional binary variables.
It is possible to disallow a specific range by including None in both x_points and the corresponding y_points. For example, with x_points = [1, 3, None, 5, 7] and y_points = [10, 35, None, -20, 40], the range between 3 and 5 is disallowed for input_x.
However, x_points cannot start or end with a None value, and a None value cannot be followed by another None. Additionally, if x_i is None, then y_i must also be None. Similar to the discontinuities, disallowed ranges always introduce additional binary variables.
The input variable input_x is restricted to the range defined by x_points unless bound_left or bound_right is set to False. Setting either to True, creates SOS1 type of variables. When input_x is not bound, you can assume as if the first and/or the last line segments are extended.
Returns the dependent variable y and the equations required to model the piecewise linear relationship.
- Parameters:
- xgp.Variable
Independent variable of the piecewise linear function
- x_points: typing.Sequence[int | float]
Break points of the piecewise linear function in the x-axis
- y_points: typing.Sequence[int | float]
Break points of the piecewise linear function in the y-axis
- bound_left: bool = True
If input_x should be limited to start from x_points[0]
- bound_right: bool = True
If input_x should be limited to end at x_points[-1]
- Returns:
- tuple[gp.Variable, list[Equation]]
Examples
>>> from gamspy import Container, Variable, Set >>> from gamspy.formulations import pwl_interval_formulation >>> m = Container() >>> x = Variable(m, "x") >>> y, eqs = pwl_interval_formulation(x, [-1, 4, 10, 10, 20], [-2, 8, 15, 17, 37])