Variable
Bases: BaseOperableBlock
A decision variable for an optimization model.
Tip
If lb or ub are a dimensioned object (e.g. an Expression), they will automatically be broadcasted to match the variable's dimensions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*indexing_sets
|
SetTypes | Iterable[SetTypes]
|
If no indexing_sets are provided, a single variable with no dimensions is created. Otherwise, a variable is created for each element in the Cartesian product of the indexing_sets (see Set for details on behaviour). |
()
|
vtype
|
VType | VTypeValue
|
The type of the variable. Can be either a VType enum or a string. Default is VType.CONTINUOUS. |
CONTINUOUS
|
lb
|
Operable | None
|
The lower bound for the variables. |
None
|
ub
|
Operable | None
|
The upper bound for the variables. |
None
|
equals
|
Operable | None
|
When specified, a variable is created for every label in |
None
|
Examples:
>>> import pandas as pd
>>> m = pf.Model()
>>> df = pd.DataFrame(
... {"dim1": [1, 1, 2, 2, 3, 3], "dim2": ["a", "b", "a", "b", "a", "b"]}
... )
>>> Variable(df)
<Variable 'unnamed' height=6>
┌──────┬──────┐
│ dim1 ┆ dim2 │
│ (3) ┆ (2) │
╞══════╪══════╡
│ 1 ┆ a │
│ 1 ┆ b │
│ 2 ┆ a │
│ 2 ┆ b │
│ 3 ┆ a │
│ 3 ┆ b │
└──────┴──────┘
Variables cannot be used until they're added to the model.
>>> m.constraint = Variable(df) <= 3
Traceback (most recent call last):
...
ValueError: Cannot use 'Variable' before it has been added to a model.
Instead, assign the variable to the model first:
>>> m.v
<Variable 'v' height=6>
┌──────┬──────┬──────────┐
│ dim1 ┆ dim2 ┆ variable │
│ (3) ┆ (2) ┆ │
╞══════╪══════╪══════════╡
│ 1 ┆ a ┆ v[1,a] │
│ 1 ┆ b ┆ v[1,b] │
│ 2 ┆ a ┆ v[2,a] │
│ 2 ┆ b ┆ v[2,b] │
│ 3 ┆ a ┆ v[3,a] │
│ 3 ┆ b ┆ v[3,b] │
└──────┴──────┴──────────┘
>>> m.v2 = Variable(df[["dim1"]])
Traceback (most recent call last):
...
ValueError: Duplicate rows found in input data.
>>> m.v3 = Variable(df[["dim1"]].drop_duplicates())
>>> m.v3
<Variable 'v3' height=3>
┌──────┬──────────┐
│ dim1 ┆ variable │
│ (3) ┆ │
╞══════╪══════════╡
│ 1 ┆ v3[1] │
│ 2 ┆ v3[2] │
│ 3 ┆ v3[3] │
└──────┴──────────┘
Methods:
| Name | Description |
|---|---|
get_solution |
Retrieves a variable's optimal value after the model has been solved. |
next |
Creates an expression where the variable at each label is the next variable in the specified dimension. |
to_expr |
Converts the Variable to an Expression. |
Attributes:
| Name | Type | Description |
|---|---|---|
attr |
Container
|
Allows reading and writing variable attributes similarly to Model.attr. |
solution |
DataFrame | float | int
|
Syntactic shortcut for |
vtype |
VType
|
|
Source code in pyoframe/_core.py
attr: Container
Allows reading and writing variable attributes similarly to Model.attr.
solution: pl.DataFrame | float | int
Syntactic shortcut for Variable.get_solution().
vtype: VType = VType(vtype)
get_solution(return_integers: bool = True) -> pl.DataFrame | float | int
Retrieves a variable's optimal value after the model has been solved.
Returns:
| Type | Description |
|---|---|
DataFrame | float | int
|
A DataFrame if the variable has dimensions and a |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the model has not been solved or the solver failed to find an optimal solution. |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_integers
|
bool
|
When |
True
|
Examples:
>>> m = pf.Model()
>>> m.var_continuous = pf.Variable({"dim1": [1, 2, 3]}, lb=5, ub=5)
>>> m.var_integer = pf.Variable(
... {"dim1": [1, 2, 3]}, lb=4.5, ub=5.5, vtype=pf.VType.INTEGER
... )
>>> m.var_dimensionless = pf.Variable(
... lb=4.5, ub=5.5, vtype=pf.VType.INTEGER
... )
>>> m.optimize()
>>> m.var_continuous.solution
shape: (3, 2)
┌──────┬──────────┐
│ dim1 ┆ solution │
│ --- ┆ --- │
│ i64 ┆ f64 │
╞══════╪══════════╡
│ 1 ┆ 5.0 │
│ 2 ┆ 5.0 │
│ 3 ┆ 5.0 │
└──────┴──────────┘
>>> m.var_integer.solution
shape: (3, 2)
┌──────┬──────────┐
│ dim1 ┆ solution │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞══════╪══════════╡
│ 1 ┆ 5 │
│ 2 ┆ 5 │
│ 3 ┆ 5 │
└──────┴──────────┘
>>> m.var_dimensionless.solution
5
Source code in pyoframe/_core.py
2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 | |
next(dim: str, wrap_around: bool = False) -> Expression
Creates an expression where the variable at each label is the next variable in the specified dimension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dim
|
str
|
The dimension over which to shift the variable. |
required |
wrap_around
|
bool
|
If |
False
|
Examples:
>>> time_dim = pl.DataFrame({"time": ["00:00", "06:00", "12:00", "18:00"]})
>>> space_dim = pl.DataFrame({"city": ["Toronto", "Berlin"]})
>>> m = pf.Model()
>>> m.bat_charge = pf.Variable(time_dim, space_dim)
>>> m.bat_flow = pf.Variable(time_dim, space_dim)
>>> # Fails because the dimensions are not the same
>>> m.bat_charge + m.bat_flow == m.bat_charge.next("time")
Traceback (most recent call last):
...
pyoframe._constants.PyoframeError: Cannot subtract the two expressions below because expression 1 has extra labels.
Expression 1: (bat_charge + bat_flow)
Expression 2: bat_charge.next(…)
Extra labels in expression 1:
┌───────┬─────────┐
│ time ┆ city │
╞═══════╪═════════╡
│ 18:00 ┆ Toronto │
│ 18:00 ┆ Berlin │
└───────┴─────────┘
Use .drop_extras() or .keep_extras() to indicate how the extra labels should be handled. Learn more at
https://bravos-power.github.io/pyoframe/latest/learn/concepts/addition
>>> (m.bat_charge + m.bat_flow).drop_extras() == m.bat_charge.next("time")
<Constraint 'unnamed' (linear) height=6 terms=18>
┌───────┬─────────┬────────────────────────────────────────────────────────────────────────────────┐
│ time ┆ city ┆ constraint │
│ (3) ┆ (2) ┆ │
╞═══════╪═════════╪════════════════════════════════════════════════════════════════════════════════╡
│ 00:00 ┆ Toronto ┆ bat_charge[00:00,Toronto] + bat_flow[00:00,Toronto] │
│ ┆ ┆ - bat_charge[06:00,Toronto] = 0 │
│ 00:00 ┆ Berlin ┆ bat_charge[00:00,Berlin] + bat_flow[00:00,Berlin] - bat_charge[06:00,Berlin] │
│ ┆ ┆ = 0 │
│ 06:00 ┆ Toronto ┆ bat_charge[06:00,Toronto] + bat_flow[06:00,Toronto] │
│ ┆ ┆ - bat_charge[12:00,Toronto] = 0 │
│ 06:00 ┆ Berlin ┆ bat_charge[06:00,Berlin] + bat_flow[06:00,Berlin] - bat_charge[12:00,Berlin] │
│ ┆ ┆ = 0 │
│ 12:00 ┆ Toronto ┆ bat_charge[12:00,Toronto] + bat_flow[12:00,Toronto] │
│ ┆ ┆ - bat_charge[18:00,Toronto] = 0 │
│ 12:00 ┆ Berlin ┆ bat_charge[12:00,Berlin] + bat_flow[12:00,Berlin] - bat_charge[18:00,Berlin] │
│ ┆ ┆ = 0 │
└───────┴─────────┴────────────────────────────────────────────────────────────────────────────────┘
>>> (m.bat_charge + m.bat_flow) == m.bat_charge.next(
... "time", wrap_around=True
... )
<Constraint 'unnamed' (linear) height=8 terms=24>
┌───────┬─────────┬────────────────────────────────────────────────────────────────────────────────┐
│ time ┆ city ┆ constraint │
│ (4) ┆ (2) ┆ │
╞═══════╪═════════╪════════════════════════════════════════════════════════════════════════════════╡
│ 00:00 ┆ Toronto ┆ bat_charge[00:00,Toronto] + bat_flow[00:00,Toronto] │
│ ┆ ┆ - bat_charge[06:00,Toronto] = 0 │
│ 00:00 ┆ Berlin ┆ bat_charge[00:00,Berlin] + bat_flow[00:00,Berlin] - bat_charge[06:00,Berlin] │
│ ┆ ┆ = 0 │
│ 06:00 ┆ Toronto ┆ bat_charge[06:00,Toronto] + bat_flow[06:00,Toronto] │
│ ┆ ┆ - bat_charge[12:00,Toronto] = 0 │
│ 06:00 ┆ Berlin ┆ bat_charge[06:00,Berlin] + bat_flow[06:00,Berlin] - bat_charge[12:00,Berlin] │
│ ┆ ┆ = 0 │
│ 12:00 ┆ Toronto ┆ bat_charge[12:00,Toronto] + bat_flow[12:00,Toronto] │
│ ┆ ┆ - bat_charge[18:00,Toronto] = 0 │
│ 12:00 ┆ Berlin ┆ bat_charge[12:00,Berlin] + bat_flow[12:00,Berlin] - bat_charge[18:00,Berlin] │
│ ┆ ┆ = 0 │
│ 18:00 ┆ Toronto ┆ bat_charge[18:00,Toronto] + bat_flow[18:00,Toronto] │
│ ┆ ┆ - bat_charge[00:00,Toronto] = 0 │
│ 18:00 ┆ Berlin ┆ bat_charge[18:00,Berlin] + bat_flow[18:00,Berlin] - bat_charge[00:00,Berlin] │
│ ┆ ┆ = 0 │
└───────┴─────────┴────────────────────────────────────────────────────────────────────────────────┘
Source code in pyoframe/_core.py
2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 | |
to_expr() -> Expression
Converts the Variable to an Expression.
Comments