diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..f8a1345 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,32 @@ +name: CI +on: + push: + branches: + - master + tags: '*' + pull_request: +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + version: + - '1.6' + os: + - ubuntu-latest + - macOS-latest + - windows-latest + arch: + - x64 + steps: + - uses: actions/checkout@v1 + - uses: julia-actions/setup-julia@latest + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/julia-runtest@latest + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v3 + with: + file: lcov.info \ No newline at end of file diff --git a/Project.toml b/Project.toml index b8304ac..3007a7d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DisjunctiveProgramming" uuid = "0d27d021-0159-4c7d-b4a7-9ccb5d9366cf" authors = ["hdavid16 "] -version = "0.4.0" +version = "0.4.1" [deps] JuMP = "4076af6c-e467-56ae-b986-b466b2749572" diff --git a/README.md b/README.md index 55bca53..8237cc3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ Generalized Disjunctive Programming (GDP) extension to JuMP, based on the GDP mo ![](logo.png) +[![codecov](https://codecov.io/gh/hdavid16/DisjunctiveProgramming.jl/graph/badge.svg?token=3FRPGMWF0J)](https://codecov.io/gh/hdavid16/DisjunctiveProgramming.jl) +[![Docs](https://img.shields.io/badge/docs-stable-blue.svg)](https://hdavid16.github.io/DisjunctiveProgramming.jl/stable/) +[![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://hdavid16.github.io/DisjunctiveProgramming.jl/dev/) + ## Installation ```julia @@ -45,10 +49,10 @@ data = gdp_data(model) ## Logical Variables -Logical variables are JuMP `AbstractVariable`s with two fields: `fix_value` and `start_value`. These can be optionally specified at variable creation. Logical variables are created with the `@variable` JuMP macro by adding the tag `LogicalVariable` as the last keyword argument. As with the regular `@variable` macro, variables can be named and indexed: +Logical variables are JuMP `AbstractVariable`s with two fields: `fix_value` and `start_value`. These can be optionally specified at variable creation. Logical variables are created with the `@variable` JuMP macro by adding the tag `Logical` as the last keyword argument. As with the regular `@variable` macro, variables can be named and indexed: ```julia -@variable(model, Y[1:3], LogicalVariable) +@variable(model, Y[1:3], Logical) ``` ## Logical Constraints @@ -81,12 +85,12 @@ Two types of logical constraints are supported: ## Disjunctions -Disjunctions are built by first defining the constraints associated with each disjunct. This is done via the `@constraint` JuMP macro with the extra `DisjunctConstraint` tag specifying the Logical variable associated with the constraint: +Disjunctions are built by first defining the constraints associated with each disjunct. This is done via the `@constraint` JuMP macro with the extra `Disjunct` tag specifying the Logical variable associated with the constraint: ```julia @variable(model, x) -@constraint(model, x ≤ 100, DisjunctConstraint(Y[1])) -@constraint(model, x ≥ 200, DisjunctConstraint(Y[2])) +@constraint(model, x ≤ 100, Disjunct(Y[1])) +@constraint(model, x ≥ 200, Disjunct(Y[2])) ``` After all disjunct constraints associated with a disjunction have been defined, the disjunction is created with the `@disjunction` macro, where the disjunction is defined as a `Vector` of Logical variables associated with each disjunct: @@ -95,10 +99,10 @@ After all disjunct constraints associated with a disjunction have been defined, @disjunction(model, [Y[1], Y[2]]) ``` -Disjunctions can be nested by passing an additional `DisjunctConstraint` tag. The Logical variable in the `DisjunctConstraint` tag specifies which disjunct, the nested disjunction belongs to: +Disjunctions can be nested by passing an additional `Disjunct` tag. The Logical variable in the `Disjunct` tag specifies which disjunct, the nested disjunction belongs to: ```julia -@disjunction(model, Y[1:2], DisjunctConstraint(Y[3])) +@disjunction(model, Y[1:2], Disjunct(Y[3])) ``` Empty disjuncts are supported in GDP models. When used, the only constraints enforced on the model when the empty disjunct is selected are the global constraints and any other disjunction constraints defined. @@ -129,21 +133,29 @@ Prior to `v0.4.0`, the package did not leverage the JuMP extension capabilities The example below is from the [Cornell University Computational Optimization Open Textbook](https://optimization.cbe.cornell.edu/index.php?title=Disjunctive_inequalities#Big-M_Reformulation[1][2]). ```julia -using JuMP using DisjunctiveProgramming +using HiGHS -m = GDPModel() +m = GDPModel(HiGHS.Optimizer) @variable(m, 0 ≤ x[1:2] ≤ 20) -@variable(m, Y[1:2], LogicalVariable) -@constraint(m, [i = 1:2], [2,5][i] ≤ x[i] ≤ [6,9][i], DisjunctConstraint(Y[1])) -@constraint(m, [i = 1:2], [8,10][i] ≤ x[i] ≤ [11,15][i], DisjunctConstraint(Y[2])) +@variable(m, Y[1:2], Logical) +@constraint(m, [i = 1:2], [2,5][i] ≤ x[i] ≤ [6,9][i], Disjunct(Y[1])) +@constraint(m, [i = 1:2], [8,10][i] ≤ x[i] ≤ [11,15][i], Disjunct(Y[2])) @disjunction(m, Y) @constraint(m, Y in Exactly(1)) #logical constraint +@objective(m, Max, sum(x)) +print(m) +# Max x[1] + x[2] +# Subject to +# x[1] ≥ 0 +# x[2] ≥ 0 +# x[1] ≤ 20 +# x[2] ≤ 20 -## Big-M -reformulate_model(m, BigM(100, false)) #specify M value and disable M-tightening +## +optimize!(m, method = BigM(100, false)) #specify M value and disable M-tightening print(m) -# Feasibility +# Max x[1] + x[2] # Subject to # Y[1] + Y[2] = 1 # x[1] - 100 Y[1] ≥ -98 @@ -161,10 +173,10 @@ print(m) # Y[1] binary # Y[2] binary -## Hull -reformulate_model(m, Hull()) +## +optimize!(m, method = Hull()) print(m) -# Feasibility +# Max x[1] + x[2] # Subject to # -x[2] + x[2]_Y[1] + x[2]_Y[2] = 0 # -x[1] + x[1]_Y[1] + x[1]_Y[2] = 0 @@ -199,21 +211,8 @@ print(m) # x[1]_Y[2] ≤ 20 # Y[1] binary # Y[2] binary - -## Indicator -reformulate_model(m, Indicator()) -print(m) -# Feasibility -# Subject to -# Y[1] + Y[2] = 1 -# x[1] ≥ 0 -# x[2] ≥ 0 -# x[1] ≤ 20 -# x[2] ≤ 20 -# Y[1] binary -# Y[2] binary -# Y[1] => {x[1] ∈ [2, 6]} -# Y[1] => {x[2] ∈ [5, 9]} -# Y[2] => {x[1] ∈ [8, 11]} -# Y[2] => {x[2] ∈ [10, 15]} ``` + +## Contributing +`DisjunctiveProgramming` is being actively developed and suggestions or other forms of contribution are encouraged. +There are many ways to contribute to this package. Feel free to create an issue to address questions or provide feedback. diff --git a/docs/Project.toml b/docs/Project.toml index dfa65cd..ef99e1a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,2 +1,3 @@ [deps] +DisjunctiveProgramming = "0d27d021-0159-4c7d-b4a7-9ccb5d9366cf" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" diff --git a/docs/make.jl b/docs/make.jl index 6823b31..b5b960a 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,12 +1,14 @@ -push!(LOAD_PATH,"../src/") using DisjunctiveProgramming using Documenter makedocs( - sitename = "DisjunctiveProgramming.jl", - modules = [DisjunctiveProgramming], - pages=[ - "Home" => "index.md" - ]) + sitename = "DisjunctiveProgramming.jl", + modules = [DisjunctiveProgramming], + pages=[ + "Home" => "index.md", + "API" => "api.md" + ], + checkdocs = :none +) deploydocs(; repo="github.com/hdavid16/DisjunctiveProgramming.jl", ) diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..d243fc9 --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,6 @@ +# API + +```@autodocs +Modules = [DisjunctiveProgramming] +Order = [:type, :function] +``` \ No newline at end of file diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png new file mode 100644 index 0000000..5e2b3b3 Binary files /dev/null and b/docs/src/assets/logo.png differ diff --git a/docs/src/index.md b/docs/src/index.md index bfed8d5..22d382e 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,2 +1,218 @@ -# Overview -DisjunctiveProgramming.jl +# DisjunctiveProgramming.jl +Generalized Disjunctive Programming (GDP) extension to JuMP, based on the GDP modeling paradigm described in [Perez and Grossmann, 2023](https://arxiv.org/abs/2303.04375). + +![](assets/logo.png) + +[![codecov](https://codecov.io/gh/hdavid16/DisjunctiveProgramming.jl/graph/badge.svg?token=3FRPGMWF0J)](https://codecov.io/gh/hdavid16/DisjunctiveProgramming.jl) +[![Docs](https://img.shields.io/badge/docs-stable-blue.svg)](https://hdavid16.github.io/InventoryManagement.jl/stable/) +[![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://hdavid16.github.io/InventoryManagement.jl/dev/) + +## Installation + +```julia +using Pkg +Pkg.add("DisjunctiveProgramming") +``` + +## Model + +A generalized disjunctive programming (GDP) model is created using `GDPModel()`, where the optimizer can be passed at model creation, along with other keyword arguments supported by JuMP Models. + +```julia +using DisjunctiveProgramming +using HiGHS + +model = GDPModel(HiGHS.Optimizer) +``` + +A `GDPModel` is a `JuMP Model` with a `GDPData` field in the model's `.ext` dictionary, which stores the following: + +- `Logical Variables`: Indicator variables used for the various disjuncts involved in the model's disjunctions. +- `Logical Constraints`: Selector (cardinality) or proposition (Boolean) constraints describing the relationships between the logical variables. +- `Disjunct Constraints`: Constraints associated with each disjunct in the model. +- `Disjunctions`: Disjunction constraints. +- `Solution Method`: The reformulation technique or solution method. Currently supported methods include Big-M, Hull, and Indicator Constraints. +- `Reformulation Variables`: List of JuMP variables created when reformulating a GDP model into a MIP model. +- `Reformulation Constraints`: List of constraints created when reformulating a GDP model into a MIP model. +- `Ready to Optimize`: Flag indicating if the model can be optimized. + +Additionally, the following mapping dictionaries are stored in `GDPData`: + +- `Indicator to Binary`: Maps the Logical variables to their respective reformulated Binary variables. +- `Indicator to Constraints`: Maps the Logical variables to the disjunct constraints associated with them. + +A GDP Model's `GDPData` can be accessed via: + +```julia +data = gdp_data(model) +``` + +## Logical Variables + +Logical variables are JuMP `AbstractVariable`s with two fields: `fix_value` and `start_value`. These can be optionally specified at variable creation. Logical variables are created with the `@variable` JuMP macro by adding the tag `Logical` as the last keyword argument. As with the regular `@variable` macro, variables can be named and indexed: + +```julia +@variable(model, Y[1:3], Logical) +``` + +## Logical Constraints + +Two types of logical constraints are supported: + +1. `Selector` or cardinality constraints: A subset of Logical variables is passed and `Exactly`, `AtMost`, or `AtLeast` `n` of these is allowed to be `True`. These constraints are specified with the `func` $\in$ `set` notation in `MathOptInterface` in a `@constraint` JuMP macro. It is not assumed that disjunctions have an `Exactly(1)` constraint enforced on their disjuncts upon creation. This constraint must be explicitly specified. + + ```julia + @constraint(model, [Y[1], Y[2]] in Exactly(1)) + ``` + +2. `Proposition` or Boolean constraints: These describe the relationships between Logical variables via Boolean algebra. Supported logical operators include: + + - `∨` or `logical_or` (OR, typed with `\vee + tab`). + - `∧` or `logical_and` (AND, typed with `\wedge + tab`). + - `¬` or `logical_not` (NOT, typed with `\neg + tab`). + - `⟹` of `implies` (Implication, typed with `\Longrightarrow + tab`). + - `⇔` or `iff` (double implication or equivalence, typed with `\Leftrightarrow + tab`). + + The `@constraint` JuMP macro is used to create these constraints with the `IsTrue` set: + + ```julia + @constraint(model, (Y[1] ⟹ Y[2]) in IsTrue()) + ``` + + _Note_: The parenthesis in the example above around the implication clause are only required when the parent logical operator is `⟹` or `⇔` to avoid parsing errors. + + Logical propositions can be reformulated to IP constraints by automatic reformulation to [Conjunctive Normal Form](https://en.wikipedia.org/wiki/Conjunctive_normal_form). + +## Disjunctions + +Disjunctions are built by first defining the constraints associated with each disjunct. This is done via the `@constraint` JuMP macro with the extra `Disjunct` tag specifying the Logical variable associated with the constraint: + +```julia +@variable(model, x) +@constraint(model, x ≤ 100, Disjunct(Y[1])) +@constraint(model, x ≥ 200, Disjunct(Y[2])) +``` + +After all disjunct constraints associated with a disjunction have been defined, the disjunction is created with the `@disjunction` macro, where the disjunction is defined as a `Vector` of Logical variables associated with each disjunct: + +```julia +@disjunction(model, [Y[1], Y[2]]) +``` + +Disjunctions can be nested by passing an additional `Disjunct` tag. The Logical variable in the `Disjunct` tag specifies which disjunct, the nested disjunction belongs to: + +```julia +@disjunction(model, Y[1:2], Disjunct(Y[3])) +``` + +Empty disjuncts are supported in GDP models. When used, the only constraints enforced on the model when the empty disjunct is selected are the global constraints and any other disjunction constraints defined. + +## MIP Reformulations + +The following reformulation methods are currently supported: + +1. [Big-M](https://optimization.cbe.cornell.edu/index.php?title=Disjunctive_inequalities#Big-M_Reformulation[1][2]): The `BigM` struct is created with the following optional arguments: + + - `value`: Big-M value to use. Default: `1e9`. Big-M values are currently global to the model. Constraint specific Big-M values can be supported in future releases. + - `tighten`: Boolean indicating if tightening the Big-M value should be attempted (currently supported only for linear disjunct constraints when variable bounds have been set or specified in the `variable_bounds` field). Default: `true`. + - `variable_bounds`: Dictionary specifying the lower and upper bounds for each `VariableRef` (e.g., `Dict(x => (lb, ub))`). Default: populate when calling the reformulation method. + +2. [Hull](https://optimization.cbe.cornell.edu/index.php?title=Disjunctive_inequalities#Convex-Hull_Reformulation[1][2]): The `Hull` struct is created with the following optional arguments: + + - `value`: `ϵ` value to use when reformulating quadratic or nonlinear constraints via the perspective function proposed by [Furman, et al. [2020]](https://link.springer.com/article/10.1007/s10589-020-00176-0). Default: `1e-6`. `ϵ` values are currently global to the model. Constraint specific tolerances can be supported in future releases. + - `variable_bounds`: Dictionary specifying the lower and upper bounds for each `VariableRef` (e.g., `Dict(x => (lb, ub))`). Default: populate when calling the reformulation method. + +3. [Indicator](https://jump.dev/JuMP.jl/stable/manual/constraints/#Indicator-constraints): This method reformulates each disjunct constraint into an indicator constraint with the Boolean reformulation counterpart of the Logical variable used to define the disjunct constraint. + +## Release Notes + +Prior to `v0.4.0`, the package did not leverage the JuMP extension capabilities and was not as robust. For these earlier releases, refer to [Perez, Joshi, and Grossmann, 2023](https://arxiv.org/abs/2304.10492v1) and the following [JuliaCon 2022 Talk](https://www.youtube.com/watch?v=AMIrgTTfUkI). + +## Example + +The example below is from the [Cornell University Computational Optimization Open Textbook](https://optimization.cbe.cornell.edu/index.php?title=Disjunctive_inequalities#Big-M_Reformulation[1][2]). + +```julia +using DisjunctiveProgramming +using HiGHS + +m = GDPModel(HiGHS.Optimizer) +@variable(m, 0 ≤ x[1:2] ≤ 20) +@variable(m, Y[1:2], Logical) +@constraint(m, [i = 1:2], [2,5][i] ≤ x[i] ≤ [6,9][i], Disjunct(Y[1])) +@constraint(m, [i = 1:2], [8,10][i] ≤ x[i] ≤ [11,15][i], Disjunct(Y[2])) +@disjunction(m, Y) +@constraint(m, Y in Exactly(1)) #logical constraint +@objective(m, Max, sum(x)) +print(m) +# Max x[1] + x[2] +# Subject to +# x[1] ≥ 0 +# x[2] ≥ 0 +# x[1] ≤ 20 +# x[2] ≤ 20 + +## +optimize!(m, method = BigM(100, false)) #specify M value and disable M-tightening +print(m) +# Max x[1] + x[2] +# Subject to +# Y[1] + Y[2] = 1 +# x[1] - 100 Y[1] ≥ -98 +# x[2] - 100 Y[1] ≥ -95 +# x[1] - 100 Y[2] ≥ -92 +# x[2] - 100 Y[2] ≥ -90 +# x[1] + 100 Y[1] ≤ 106 +# x[2] + 100 Y[1] ≤ 109 +# x[1] + 100 Y[2] ≤ 111 +# x[2] + 100 Y[2] ≤ 115 +# x[1] ≥ 0 +# x[2] ≥ 0 +# x[1] ≤ 20 +# x[2] ≤ 20 +# Y[1] binary +# Y[2] binary + +## +optimize!(m, method = Hull()) +print(m) +# Max x[1] + x[2] +# Subject to +# -x[2] + x[2]_Y[1] + x[2]_Y[2] = 0 +# -x[1] + x[1]_Y[1] + x[1]_Y[2] = 0 +# Y[1] + Y[2] = 1 +# -2 Y[1] + x[1]_Y[1] ≥ 0 +# -5 Y[1] + x[2]_Y[1] ≥ 0 +# -8 Y[2] + x[1]_Y[2] ≥ 0 +# -10 Y[2] + x[2]_Y[2] ≥ 0 +# x[2]_Y[1]_lower_bound : -x[2]_Y[1] ≤ 0 +# x[2]_Y[1]_upper_bound : -20 Y[1] + x[2]_Y[1] ≤ 0 +# x[1]_Y[1]_lower_bound : -x[1]_Y[1] ≤ 0 +# x[1]_Y[1]_upper_bound : -20 Y[1] + x[1]_Y[1] ≤ 0 +# x[2]_Y[2]_lower_bound : -x[2]_Y[2] ≤ 0 +# x[2]_Y[2]_upper_bound : -20 Y[2] + x[2]_Y[2] ≤ 0 +# x[1]_Y[2]_lower_bound : -x[1]_Y[2] ≤ 0 +# x[1]_Y[2]_upper_bound : -20 Y[2] + x[1]_Y[2] ≤ 0 +# -6 Y[1] + x[1]_Y[1] ≤ 0 +# -9 Y[1] + x[2]_Y[1] ≤ 0 +# -11 Y[2] + x[1]_Y[2] ≤ 0 +# -15 Y[2] + x[2]_Y[2] ≤ 0 +# x[1] ≥ 0 +# x[2] ≥ 0 +# x[2]_Y[1] ≥ 0 +# x[1]_Y[1] ≥ 0 +# x[2]_Y[2] ≥ 0 +# x[1]_Y[2] ≥ 0 +# x[1] ≤ 20 +# x[2] ≤ 20 +# x[2]_Y[1] ≤ 20 +# x[1]_Y[1] ≤ 20 +# x[2]_Y[2] ≤ 20 +# x[1]_Y[2] ≤ 20 +# Y[1] binary +# Y[2] binary +``` + +## Contributing +`DisjunctiveProgramming` is being actively developed and suggestions or other forms of contribution are encouraged. +There are many ways to contribute to this package. Feel free to create an issue to address questions or provide feedback. \ No newline at end of file diff --git a/examples/ex1.jl b/examples/ex1.jl index b6810d7..938b739 100644 --- a/examples/ex1.jl +++ b/examples/ex1.jl @@ -1,4 +1,3 @@ -using JuMP using DisjunctiveProgramming using HiGHS @@ -7,10 +6,10 @@ using HiGHS # Disjunction Method 1: Assign Logical Variables Explicitly m = GDPModel() @variable(m, -5 ≤ x ≤ 10) -@variable(m, Y[1:2], LogicalVariable) -@constraint(m, 0 ≤ x ≤ 3, DisjunctConstraint(Y[1])) -@constraint(m, 5 ≤ x, DisjunctConstraint(Y[2])) -@constraint(m, x ≤ 9, DisjunctConstraint(Y[2])) +@variable(m, Y[1:2], Logical) +@constraint(m, 0 ≤ x ≤ 3, Disjunct(Y[1])) +@constraint(m, 5 ≤ x, Disjunct(Y[2])) +@constraint(m, x ≤ 9, Disjunct(Y[2])) @disjunction(m, [Y[1], Y[2]]) @constraint(m, Y in Exactly(1)) @objective(m, Max, x) diff --git a/examples/ex2.jl b/examples/ex2.jl index d23a540..eb4876e 100644 --- a/examples/ex2.jl +++ b/examples/ex2.jl @@ -1,13 +1,12 @@ # https://optimization.cbe.cornell.edu/index.php?title=Disjunctive_inequalities#Big-M_Reformulation[1][2] -using JuMP using DisjunctiveProgramming using HiGHS m = GDPModel(HiGHS.Optimizer) @variable(m, 0 ≤ x[1:2] ≤ 20) -@variable(m, Y[1:2], LogicalVariable) -@constraint(m, [i = 1:2], [2,5][i] ≤ x[i] ≤ [6,9][i], DisjunctConstraint(Y[1])) -@constraint(m, [i = 1:2], [8,10][i] ≤ x[i] ≤ [11,15][i], DisjunctConstraint(Y[2])) +@variable(m, Y[1:2], Logical) +@constraint(m, [i = 1:2], [2,5][i] ≤ x[i] ≤ [6,9][i], Disjunct(Y[1])) +@constraint(m, [i = 1:2], [8,10][i] ≤ x[i] ≤ [11,15][i], Disjunct(Y[2])) @disjunction(m, Y) @constraint(m, Y in Exactly(1)) #logical constraint @objective(m, Max, sum(x)) diff --git a/examples/ex3.jl b/examples/ex3.jl index 39481be..6bf5d3f 100644 --- a/examples/ex3.jl +++ b/examples/ex3.jl @@ -1,13 +1,12 @@ -using JuMP using DisjunctiveProgramming m = GDPModel() @variable(m, -5 ≤ x ≤ 10) -@variable(m, Y[1:2], LogicalVariable) -@constraint(m, exp(x) <= 2, DisjunctConstraint(Y[1])) -@constraint(m, x >= -3, DisjunctConstraint(Y[1])) -@constraint(m, exp(x) >= 3, DisjunctConstraint(Y[2])) -@constraint(m, x >= 5, DisjunctConstraint(Y[2])) +@variable(m, Y[1:2], Logical) +@constraint(m, exp(x) <= 2, Disjunct(Y[1])) +@constraint(m, x >= -3, Disjunct(Y[1])) +@constraint(m, exp(x) >= 3, Disjunct(Y[2])) +@constraint(m, x >= 5, Disjunct(Y[2])) @disjunction(m, Y) @constraint(m, Y in Exactly(1)) #logical constraint @objective(m, Max, x) diff --git a/examples/ex4.jl b/examples/ex4.jl index 77ec314..ab0641d 100644 --- a/examples/ex4.jl +++ b/examples/ex4.jl @@ -1,4 +1,3 @@ -using JuMP using DisjunctiveProgramming # Example with proposition reformulation @@ -6,7 +5,7 @@ using DisjunctiveProgramming # ¬((Y[1] ∧ ¬Y[2]) ⇔ (Y[3] ∨ Y[4])) m = GDPModel() -@variable(m, Y[1:4], LogicalVariable) +@variable(m, Y[1:4], Logical) @constraint(m, ¬((Y[1] ∧ ¬Y[2]) ⇔ (Y[3] ∨ Y[4])) ∈ IsTrue()) reformulate_model(m, BigM()) print(m) diff --git a/examples/ex5.jl b/examples/ex5.jl index 20b5549..2202f79 100644 --- a/examples/ex5.jl +++ b/examples/ex5.jl @@ -1,19 +1,17 @@ -# https://arxiv.org/pdf/2303.04375.pdf - -using JuMP +# Nested GDP: https://arxiv.org/pdf/2303.04375.pdf using DisjunctiveProgramming ## m = GDPModel() @variable(m, 1 ≤ x[1:2] ≤ 9) -@variable(m, Y[1:2], LogicalVariable) -@variable(m, W[1:2], LogicalVariable) +@variable(m, Y[1:2], Logical) +@variable(m, W[1:2], Logical) @objective(m, Max, sum(x)) -@constraint(m, y1[i=1:2], [1,4][i] ≤ x[i] ≤ [3,6][i], DisjunctConstraint(Y[1])) -@constraint(m, w1[i=1:2], [1,5][i] ≤ x[i] ≤ [2,6][i], DisjunctConstraint(W[1])) -@constraint(m, w2[i=1:2], [2,4][i] ≤ x[i] ≤ [3,5][i], DisjunctConstraint(W[2])) -@constraint(m, y2[i=1:2], [8,1][i] ≤ x[i] ≤ [9,2][i], DisjunctConstraint(Y[2])) -@disjunction(m, inner, [W[1], W[2]], DisjunctConstraint(Y[1])) +@constraint(m, y1[i=1:2], [1,4][i] ≤ x[i] ≤ [3,6][i], Disjunct(Y[1])) +@constraint(m, w1[i=1:2], [1,5][i] ≤ x[i] ≤ [2,6][i], Disjunct(W[1])) +@constraint(m, w2[i=1:2], [2,4][i] ≤ x[i] ≤ [3,5][i], Disjunct(W[2])) +@constraint(m, y2[i=1:2], [8,1][i] ≤ x[i] ≤ [9,2][i], Disjunct(Y[2])) +@disjunction(m, inner, [W[1], W[2]], Disjunct(Y[1])) @disjunction(m, outer, [Y[1], Y[2]]) @constraint(m, Y in Exactly(1)) @constraint(m, W in Exactly(Y[1])) diff --git a/examples/ex6.jl b/examples/ex6.jl index 0fb3ea2..f86e73f 100644 --- a/examples/ex6.jl +++ b/examples/ex6.jl @@ -1,29 +1,28 @@ -using JuMP using DisjunctiveProgramming -## +## Multi-level Nested GDP m = GDPModel() @variable(m, -5 <= x[1:3] <= 5) -@variable(m, y[1:2], LogicalVariable) -@constraint(m, x[1] <= -2, DisjunctConstraint(y[1])) -@constraint(m, x[1] >= 2, DisjunctConstraint(y[2])) -@constraint(m, x[2] == -1, DisjunctConstraint(y[2])) -@constraint(m, x[3] == 1, DisjunctConstraint(y[2])) +@variable(m, y[1:2], Logical) +@constraint(m, x[1] <= -2, Disjunct(y[1])) +@constraint(m, x[1] >= 2, Disjunct(y[2])) +@constraint(m, x[2] == -1, Disjunct(y[2])) +@constraint(m, x[3] == 1, Disjunct(y[2])) @disjunction(m, y) @constraint(m, y in Exactly(1)) -@variable(m, w[1:2], LogicalVariable) -@constraint(m, x[2] <= -3, DisjunctConstraint(w[1])) -@constraint(m, x[2] >= 3, DisjunctConstraint(w[2])) -@constraint(m, x[3] == 0, DisjunctConstraint(w[2])) -@disjunction(m, w, DisjunctConstraint(y[1])) +@variable(m, w[1:2], Logical) +@constraint(m, x[2] <= -3, Disjunct(w[1])) +@constraint(m, x[2] >= 3, Disjunct(w[2])) +@constraint(m, x[3] == 0, Disjunct(w[2])) +@disjunction(m, w, Disjunct(y[1])) @constraint(m, w in Exactly(y[1])) -@variable(m, z[1:2], LogicalVariable) -@constraint(m, x[3] <= -4, DisjunctConstraint(z[1])) -@constraint(m, x[3] >= 4, DisjunctConstraint(z[2])) -@disjunction(m, z, DisjunctConstraint(w[1])) +@variable(m, z[1:2], Logical) +@constraint(m, x[3] <= -4, Disjunct(z[1])) +@constraint(m, x[3] >= 4, Disjunct(z[2])) +@disjunction(m, z, Disjunct(w[1])) @constraint(m, z in Exactly(w[1])) ## diff --git a/paper/paper.aux b/paper/paper.aux new file mode 100644 index 0000000..4bf28f6 --- /dev/null +++ b/paper/paper.aux @@ -0,0 +1,139 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} +\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined +\global\let\oldcontentsline\contentsline +\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} +\global\let\oldnewlabel\newlabel +\gdef\newlabel#1#2{\newlabelxx{#1}#2} +\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} +\AtEndDocument{\ifx\hyper@anchor\@undefined +\let\contentsline\oldcontentsline +\let\newlabel\oldnewlabel +\fi} +\fi} +\global\let\hyper@last\relax +\gdef\HyperFirstAtBeginDocument#1{#1} +\providecommand\HyField@AuxAddToFields[1]{} +\providecommand\HyField@AuxAddToCoFields[2]{} +\citation{chen_grossmann_2019} +\citation{grossmann_trespalacios_2013} +\citation{balas_2018} +\citation{chen_grossmann_2019} +\citation{MATOVU2022107856} +\citation{ZHOU202269} +\citation{CHO2022841} +\citation{CHEN2022107616} +\citation{chen2022pyomo} +\citation{vecchietti1999logmip} +\citation{dunning_huchette_lubin_2017} +\citation{dunning_huchette_lubin_2017} +\citation{nemhauser_1999} +\citation{TRESPALACIOS201598} +\citation{LEE20002125} +\citation{grossmann_lee_2003} +\citation{chen_grossmann_2019} +\newlabel{@firstpg}{{}{1}{}{Doc-Start}{}} +\@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{1}{section.1}} +\@writefile{toc}{\contentsline {section}{\numberline {2}Generalized Disjunctive Programming}{1}{section.2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Model}{1}{subsection.2.1}} +\newlabel{eq:general_gdp}{{1}{1}{Model}{equation.2.1}{}} +\newlabel{eq:general_gdp1}{{6}{1}{Model}{equation.2.6}{}} +\citation{TRESPALACIOS201598} +\citation{grossmann_trespalacios_2013} +\newlabel{eq:lgdp}{{7}{2}{Model}{equation.2.7}{}} +\newlabel{eq:lgdp2}{{11}{2}{Model}{equation.2.11}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Solution Technique: Reformulation to Mixed-Integer Program}{2}{subsection.2.2}} +\newlabel{eq:ex}{{12}{2}{Solution Technique: Reformulation to Mixed-Integer Program}{equation.2.12}{}} +\newlabel{eq:x}{{13}{2}{Solution Technique: Reformulation to Mixed-Integer Program}{equation.2.13}{}} +\newlabel{eq:simple_xor}{{14}{2}{Solution Technique: Reformulation to Mixed-Integer Program}{equation.2.14}{}} +\newlabel{eq:y}{{15}{2}{Solution Technique: Reformulation to Mixed-Integer Program}{equation.2.15}{}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.2.1}Big-M Reformulation}{2}{subsubsection.2.2.1}} +\newlabel{eq:ex_bigm1}{{16}{2}{Big-M Reformulation}{equation.2.16}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Feasible solution space for example disjunction}}{2}{figure.1}} +\newlabel{fig:reform_figure}{{1}{2}{Feasible solution space for example disjunction}{figure.1}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Relaxed solution space using Big-M Reformulation}}{2}{figure.2}} +\newlabel{fig:bigm}{{2}{2}{Relaxed solution space using Big-M Reformulation}{figure.2}{}} +\newlabel{eq:ex_bigm2}{{17}{2}{Big-M Reformulation}{equation.2.17}{}} +\newlabel{eq:ex_bigm3}{{18}{2}{Big-M Reformulation}{equation.2.18}{}} +\newlabel{eq:ex_bigm4}{{19}{2}{Big-M Reformulation}{equation.2.19}{}} +\newlabel{eq:ex_bigm5}{{20}{2}{Big-M Reformulation}{equation.2.20}{}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.2.2}Hull Reformulation}{2}{subsubsection.2.2.2}} +\citation{jackson_sheridan_2005} +\citation{grossmann_lee_2003} +\citation{E.Grossmann2009} +\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Relaxed solution space using Hull Reformulation}}{3}{figure.3}} +\newlabel{fig:chr}{{3}{3}{Relaxed solution space using Hull Reformulation}{figure.3}{}} +\newlabel{eq:ex_hull0}{{21}{3}{Hull Reformulation}{equation.2.21}{}} +\newlabel{eq:ex_hull1}{{22}{3}{Hull Reformulation}{equation.2.22}{}} +\newlabel{eq:ex_hull2}{{23}{3}{Hull Reformulation}{equation.2.23}{}} +\newlabel{eq:ex_hull4}{{24}{3}{Hull Reformulation}{equation.2.24}{}} +\newlabel{eq:ex_hull5}{{25}{3}{Hull Reformulation}{equation.2.25}{}} +\newlabel{eq:ex_hull3}{{26}{3}{Hull Reformulation}{equation.2.26}{}} +\newlabel{eq:ex_hull6}{{27}{3}{Hull Reformulation}{equation.2.27}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Logic constraint reformulation}{3}{subsection.2.3}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.3.1}Propositional Logic}{3}{subsubsection.2.3.1}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.3.2}Constraint Programming}{3}{subsubsection.2.3.2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.4}Other Solution Techniques}{3}{subsection.2.4}} +\newlabel{other_techniques}{{2.4}{3}{Other Solution Techniques}{subsection.2.4}{}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.4.1}Disjunctive branch and bound}{3}{subsubsection.2.4.1}} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.4.2}Logic-based outer approximation}{3}{subsubsection.2.4.2}} +\citation{trespalacios_grossmann_2016} +\citation{agarwal2010automating} +\citation{furman_sawaya_grossmann_2020} +\citation{10.1145/3511528.3511535} +\citation{huangfu2018parallelizing} +\@writefile{toc}{\contentsline {subsubsection}{\numberline {\itshape 2.4.3}Hybrid cutting planes}{4}{subsubsection.2.4.3}} +\@writefile{toc}{\contentsline {section}{\numberline {3}DisjunctiveProgramming.jl}{4}{section.3}} +\@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Features}{4}{subsection.3.1}} +\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Example}{4}{subsection.3.2}} +\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces Illustrative superstructure optimization problem}}{4}{figure.4}} +\newlabel{fig:superstruct_opt_diagram}{{4}{4}{Illustrative superstructure optimization problem}{figure.4}{}} +\newlabel{eq:example_obj}{{28}{4}{Example}{equation.3.28}{}} +\newlabel{eq:example_gdp}{{29}{4}{Example}{equation.3.29}{}} +\newlabel{eq:example_global}{{30}{4}{Example}{equation.3.30}{}} +\newlabel{eq:example_global1}{{31}{4}{Example}{equation.3.31}{}} +\newlabel{eq:example_var1}{{32}{4}{Example}{equation.3.32}{}} +\newlabel{eq:example_var2}{{33}{4}{Example}{equation.3.33}{}} +\newlabel{eq:example_var3}{{34}{4}{Example}{equation.3.34}{}} +\citation{kronqvist2022p} +\citation{agarwal2015novel} +\citation{bynum2021pyomo} +\citation{hart2011pyomo} +\citation{chen2022pyomo} +\citation{Bussieck2004} +\citation{vecchietti1999logmip} +\citation{NAVARROAMOROS201413} +\bibstyle{juliacon} +\bibdata{ref.bib} +\bibcite{agarwal2015novel}{1} +\bibcite{agarwal2010automating}{2} +\bibcite{balas_2018}{3} +\bibcite{Bussieck2004}{4} +\bibcite{bynum2021pyomo}{5} +\bibcite{chen_grossmann_2019}{6} +\bibcite{chen2022pyomo}{7} +\@writefile{toc}{\contentsline {section}{\numberline {4}Future Work}{5}{section.4}} +\@writefile{toc}{\contentsline {section}{\numberline {5}Related Work}{5}{section.5}} +\@writefile{toc}{\contentsline {section}{\numberline {6}Conclusion}{5}{section.6}} +\@writefile{toc}{\contentsline {section}{\numberline {7}References}{5}{section.7}} +\bibcite{CHEN2022107616}{8} +\bibcite{CHO2022841}{9} +\bibcite{dunning_huchette_lubin_2017}{10} +\bibcite{E.Grossmann2009}{11} +\bibcite{furman_sawaya_grossmann_2020}{12} +\bibcite{10.1145/3511528.3511535}{13} +\bibcite{grossmann_lee_2003}{14} +\bibcite{grossmann_trespalacios_2013}{15} +\bibcite{hart2011pyomo}{16} +\bibcite{huangfu2018parallelizing}{17} +\bibcite{jackson_sheridan_2005}{18} +\bibcite{kronqvist2022p}{19} +\bibcite{LEE20002125}{20} +\bibcite{MATOVU2022107856}{21} +\bibcite{NAVARROAMOROS201413}{22} +\bibcite{nemhauser_1999}{23} +\bibcite{TRESPALACIOS201598}{24} +\bibcite{trespalacios_grossmann_2016}{25} +\bibcite{vecchietti1999logmip}{26} +\bibcite{ZHOU202269}{27} diff --git a/paper/paper.bbl b/paper/paper.bbl new file mode 100644 index 0000000..3b34be3 --- /dev/null +++ b/paper/paper.bbl @@ -0,0 +1,182 @@ +\begin{thebibliography}{10} + +\bibitem{agarwal2015novel} +Anshul Agarwal. +A novel minlp reformulation for nonlinear generalized disjunctive programming + (gdp) problems. +{\em arXiv preprint arXiv:1510.01791}, 2015. +\href{http://dx.doi.org/10.48550/arXiv.1510.01791}{doi:10.48550/arXiv.1510.01791}. + +\bibitem{agarwal2010automating} +Ashish Agarwal, Sooraj Bhat, Alexander Gray, and Ignacio~E Grossmann. +Automating mathematical program transformations. +In {\em International Symposium on Practical Aspects of Declarative Languages}, + pages 134--148. Springer, 2010. +\href{http://dx.doi.org/10.1007/978-3-642-11503-5\_12}{doi:10.1007/978-3-642-11503-5\_12}. + +\bibitem{balas_2018} +Egon Balas. +{\em Disjunctive programming}. +Springer, 2018. +\href{http://dx.doi.org/10.1007/978-3-030-00148-3}{doi:10.1007/978-3-030-00148-3}. + +\bibitem{Bussieck2004} +Michael~R. Bussieck and Alex Meeraus. +{\em General Algebraic Modeling System (GAMS)}, pages 137--157. +Springer US, Boston, MA, 2004. +\href{http://dx.doi.org/10.1007/978-1-4613-0215-5\_8}{doi:10.1007/978-1-4613-0215-5\_8}. + +\bibitem{bynum2021pyomo} +Michael~L. Bynum, Gabriel~A. Hackebeil, William~E. Hart, Carl~D. Laird, + Bethany~L. Nicholson, John~D. Siirola, Jean-Paul Watson, and David~L. + Woodruff. +{\em Pyomo--optimization modeling in python}, volume~67. +Springer Science \& Business Media, third edition, 2021. +\href{http://dx.doi.org/10.1007/978-3-030-68928-5}{doi:10.1007/978-3-030-68928-5}. + +\bibitem{chen_grossmann_2019} +Qi~Chen and Ignacio Grossmann. +Modern modeling paradigms using generalized disjunctive programming. +{\em Processes}, 7(11), 2019. +\href{http://dx.doi.org/10.3390/pr7110839}{doi:10.3390/pr7110839}. + +\bibitem{chen2022pyomo} +Qi~Chen, Emma~S Johnson, David~E Bernal, Romeo Valentin, Sunjeev Kale, Johnny + Bates, John~D Siirola, and Ignacio~E Grossmann. +Pyomo. gdp: an ecosystem for logic based modeling and optimization development. +{\em Optimization and Engineering}, 23(1):607--642, 2022. +\href{http://dx.doi.org/10.1007/978-3-030-00148-3}{doi:10.1007/978-3-030-00148-3}. + +\bibitem{CHEN2022107616} +Ying Chen, Yixin Ye, Zhihong Yuan, Ignacio~E. Grossmann, and Bingzhen Chen. +Integrating stochastic programming and reliability in the optimal synthesis of + chemical processes. +{\em Computers \& Chemical Engineering}, 157:107616, 2022. +\href{http://dx.doi.org/10.1016/j.compchemeng.2021.107616}{doi:10.1016/j.compchemeng.2021.107616}. + +\bibitem{CHO2022841} +Seolhee Cho and Ignacio~E. Grossmann. +An optimization model for expansion planning of reliable power generation + systems. +In Ludovic Montastruc and Stephane Negny, editors, {\em 32nd European Symposium + on Computer Aided Process Engineering}, volume~51 of {\em Computer Aided + Chemical Engineering}, pages 841--846. Elsevier, 2022. +\href{http://dx.doi.org/10.1016/B978-0-323-95879-0.50141-7}{doi:10.1016/B978-0-323-95879-0.50141-7}. + +\bibitem{dunning_huchette_lubin_2017} +Iain Dunning, Joey Huchette, and Miles Lubin. +Jump: A modeling language for mathematical optimization. +{\em SIAM Review}, 59(2):295–320, 2017. +\href{http://dx.doi.org/10.1137/15M1020575}{doi:10.1137/15M1020575}. + +\bibitem{E.Grossmann2009} +Ignacio E.~Grossmann. +{\em Logic-based outer approximation}, pages 1928--1931. +Springer US, Boston, MA, 2009. +\href{http://dx.doi.org/10.1007/978-0-387-74759-0\_348}{doi:10.1007/978-0-387-74759-0\_348}. + +\bibitem{furman_sawaya_grossmann_2020} +Kevin~C. Furman, Nicolas~W. Sawaya, and Ignacio~E. Grossmann. +A computationally useful algebraic representation of nonlinear disjunctive + convex sets using the perspective function. +{\em Computational Optimization and Applications}, 76(2):589–614, 2020. +\href{http://dx.doi.org/10.1007/s10589-020-00176-0}{doi:10.1007/s10589-020-00176-0}. + +\bibitem{10.1145/3511528.3511535} +Shashi Gowda, Yingbo Ma, Alessandro Cheli, Maja Gw\'{o}\'{z}zd\'{z}, Viral~B. + Shah, Alan Edelman, and Christopher Rackauckas. +High-performance symbolic-numerics via multiple dispatch. +{\em ACM Commun. Comput. Algebra}, 55(3):92–96, jan 2022. +\href{http://dx.doi.org/10.1145/3511528.3511535}{doi:10.1145/3511528.3511535}. + +\bibitem{grossmann_lee_2003} +Ignacio~E. Grossmann and Sangbum Lee. +Generalized convex disjunctive programming: Nonlinear convex hull relaxation. +{\em Computational Optimization and Applications}, 26(1):83–100, 2003. +\href{http://dx.doi.org/10.1023/a:1025154322278}{doi:10.1023/a:1025154322278}. + +\bibitem{grossmann_trespalacios_2013} +Ignacio~E. Grossmann and Francisco Trespalacios. +Systematic modeling of discrete-continuous optimization models through + generalized disjunctive programming. +{\em AIChE Journal}, 59(9):3276--3295, 2013. +\href{http://dx.doi.org/10.1002/aic.14088}{doi:10.1002/aic.14088}. + +\bibitem{hart2011pyomo} +William~E Hart, Jean-Paul Watson, and David~L Woodruff. +Pyomo: modeling and solving mathematical programs in python. +{\em Mathematical Programming Computation}, 3(3):219--260, 2011. +\href{http://dx.doi.org/10.1007/s12532-011-0026-8}{doi:10.1007/s12532-011-0026-8}. + +\bibitem{huangfu2018parallelizing} +Qi~Huangfu and JA~Julian Hall. +Parallelizing the dual revised simplex method. +{\em Mathematical Programming Computation}, 10(1):119--142, 2018. +\href{http://dx.doi.org/10.1007/s12532-017-0130-5}{doi:10.1007/s12532-017-0130-5}. + +\bibitem{jackson_sheridan_2005} +Paul Jackson and Daniel Sheridan. +Clause form conversions for boolean circuits. +{\em Theory and Applications of Satisfiability Testing}, page 183–198, 2005. +\href{http://dx.doi.org/10.1007/11527695\_15}{doi:10.1007/11527695\_15}. + +\bibitem{kronqvist2022p} +Jan Kronqvist, Ruth Misener, and Calvin Tsay. +P-split formulations: A class of intermediate formulations between big-m and + convex hull for disjunctive constraints. +{\em arXiv preprint arXiv:2202.05198}, 2022. +\href{http://dx.doi.org/10.48550/arXiv.2202.05198}{doi:10.48550/arXiv.2202.05198}. + +\bibitem{LEE20002125} +Sangbum Lee and Ignacio~E. Grossmann. +New algorithms for nonlinear generalized disjunctive programming. +{\em Computers \& Chemical Engineering}, 24(9):2125--2141, 2000. +\href{http://dx.doi.org/10.1016/S0098-1354(00)00581-0}{doi:10.1016/S0098-1354(00)00581-0}. + +\bibitem{MATOVU2022107856} +Fahad Matovu, Shuhaimi Mahadzir, Rasel Ahmed, and Nor Erniza~Mohammad Rozali. +Synthesis and optimization of multilevel refrigeration systems using + generalized disjunctive programming. +{\em Computers \& Chemical Engineering}, 163:107856, 2022. +\href{http://dx.doi.org/10.1016/j.compchemeng.2022.107856}{doi:10.1016/j.compchemeng.2022.107856}. + +\bibitem{NAVARROAMOROS201413} +Miguel~A. Navarro-Amorós, Rubén Ruiz-Femenia, and José~A. Caballero. +Integration of modular process simulators under the generalized disjunctive + programming framework for the structural flowsheet optimization. +{\em Computers \& Chemical Engineering}, 67:13--25, 2014. +\href{http://dx.doi.org/10.1016/j.compchemeng.2014.03.014}{doi:10.1016/j.compchemeng.2014.03.014}. + +\bibitem{nemhauser_1999} +George~L. Nemhauser. +{\em Integer and combinatorial optimization}. +John Wiley and Sons, 1999. +\href{http://dx.doi.org/10.1002/9781118627372}{doi:10.1002/9781118627372}. + +\bibitem{TRESPALACIOS201598} +Francisco Trespalacios and Ignacio~E. Grossmann. +Improved big-m reformulation for generalized disjunctive programs. +{\em Computers \& Chemical Engineering}, 76:98--103, 2015. +\href{http://dx.doi.org/10.1016/j.compchemeng.2015.02.013}{doi:10.1016/j.compchemeng.2015.02.013}. + +\bibitem{trespalacios_grossmann_2016} +Francisco Trespalacios and Ignacio~E. Grossmann. +Cutting plane algorithm for convex generalized disjunctive programs. +{\em INFORMS Journal on Computing}, 28(2):209–222, 2016. +\href{http://dx.doi.org/10.1287/ijoc.2015.0669}{doi:10.1287/ijoc.2015.0669}. + +\bibitem{vecchietti1999logmip} +Aldo Vecchietti and Ignacio~E Grossmann. +Logmip: a disjunctive 0--1 non-linear optimizer for process system models. +{\em Computers \& chemical engineering}, 23(4-5):555--565, 1999. +\href{http://dx.doi.org/10.1016/s0098-1354(98)00293-2}{doi:10.1016/s0098-1354(98)00293-2}. + +\bibitem{ZHOU202269} +Wenjin Zhou, Kashif Iqbal, Xiaogang Sun, Dinghui Gan, Chun Deng, José~María + Ponce-Ortega, and Chunmao Chen. +Disjunctive programming model for the synthesis of property-based water supply + network with multiple resources. +{\em Chemical Engineering Research and Design}, 187:69--83, 2022. +\href{http://dx.doi.org/10.1016/j.cherd.2022.08.027}{doi:10.1016/j.cherd.2022.08.027}. + +\end{thebibliography} diff --git a/paper/paper.blg b/paper/paper.blg new file mode 100644 index 0000000..6db484c --- /dev/null +++ b/paper/paper.blg @@ -0,0 +1,46 @@ +This is BibTeX, Version 0.99d (TeX Live 2018/W32TeX) +Capacity: max_strings=100000, hash_size=100000, hash_prime=85009 +The top-level auxiliary file: paper.aux +The style file: juliacon.bst +Database file #1: ref.bib +You've used 27 entries, + 2314 wiz_defined-function locations, + 723 strings with 10063 characters, +and the built_in function-call counts, 10799 in all, are: += -- 1074 +> -- 505 +< -- 7 ++ -- 200 +- -- 170 +* -- 844 +:= -- 1761 +add.period$ -- 110 +call.type$ -- 27 +change.case$ -- 161 +chr.to.int$ -- 0 +cite$ -- 27 +duplicate$ -- 417 +empty$ -- 844 +format.name$ -- 170 +if$ -- 2296 +int.to.chr$ -- 0 +int.to.str$ -- 27 +missing$ -- 32 +newline$ -- 165 +num.names$ -- 56 +pop$ -- 179 +preamble$ -- 1 +purify$ -- 138 +quote$ -- 0 +skip$ -- 272 +stack$ -- 0 +substring$ -- 652 +swap$ -- 88 +text.length$ -- 7 +text.prefix$ -- 0 +top$ -- 0 +type$ -- 98 +warning$ -- 0 +while$ -- 87 +width$ -- 29 +write$ -- 355 diff --git a/paper/paper.fdb_latexmk b/paper/paper.fdb_latexmk new file mode 100644 index 0000000..f399f47 --- /dev/null +++ b/paper/paper.fdb_latexmk @@ -0,0 +1,163 @@ +# Fdb version 3 +["bibtex paper"] 1697252440 "paper.aux" "paper.bbl" "paper" 1697252664 + "./juliacon.bst" 1683852295 22186 2eaa317b2b3889daf19a84ad3db6071a "" + "paper.aux" 1697252663 7715 822ea37fa57aa053d638df6ec355f458 "" + "ref.bib" 1697252439 27978 dce8ad984b85ef4eb1e3d1e6c104f8d5 "" + (generated) + "paper.blg" + "paper.bbl" +["pdflatex"] 1697252662 "c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.tex" "c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.pdf" "paper" 1697252664 + "bib.tex" 1683852295 115 fb8dcbd9d4481bde59a06a28ec8a83ca "" + "bigm.png" 1683852295 16157 24bd6e3bc27d995ac037e601c6fb5268 "" + "c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux" 1697252663 7715 822ea37fa57aa053d638df6ec355f458 "" + "c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.tex" 1697252661 26527 fd78089a63a54012af545feb9ae77edf "" + "c:/texlive/2018/texmf-dist/fonts/enc/dvips/base/8r.enc" 1532704159 4850 80dc9bab7f31fb78a000ccfed0e27cab "" + "c:/texlive/2018/texmf-dist/fonts/enc/dvips/cm-super/cm-super-t1.enc" 1532703951 2971 def0b6c1f0b107b3b936def894055589 "" + "c:/texlive/2018/texmf-dist/fonts/map/fontname/texfonts.map" 1532704303 3332 103109f5612ad95229751940c61aada0 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmb8r.tfm" 1532705452 4524 6bce29db5bc272ba5f332261583fee9c "" + "c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmb8t.tfm" 1532705452 6880 f19b8995b61c334d78fc734065f6b4d4 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8r.tfm" 1532705452 4408 25b74d011a4c66b7f212c0cc3c90061b "" + "c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm" 1532705452 6672 e3ab9e37e925f3045c9005e6d1473d56 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmri8r.tfm" 1532705452 4640 532ca3305aad10cc01d769f3f91f1029 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmri8t.tfm" 1532705452 6944 94c55ad86e6ea2826f78ba2240d50df9 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ecrm0900.tfm" 1532704170 3584 d3d8ac8b25ca19c0a40b86a5db1e8ccc "" + "c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ecrm1000.tfm" 1532704170 3584 adb004a0c8e7c46ee66cad73671f37b4 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ectt0800.tfm" 1532704170 1536 0b0b8ca286de6a006b681926403f35cd "" + "c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ectt0900.tfm" 1532704170 1536 ae7aab2f8a4bc9edfce2899f53ba88c3 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1532703666 1004 54797486969f23fa377b128694d548df "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm" 1532703666 988 bdf658c3bfc2d96d3c8b02cfc1c94c20 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex9.tfm" 1532703666 996 a18840b13b499c08ac2de96a99eda4bc "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib5.tfm" 1532703666 1496 c79f6914c6d39ffb3759967363d1be79 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib6.tfm" 1532703666 1516 a3bf6a5e7ec4401b1f52092dfaaed242 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib7.tfm" 1532703666 1508 6e807ff901c35a5f1fde0ca275533df8 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib8.tfm" 1532703666 1528 dab402b9d3774ca98baa037071cee7ae "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib9.tfm" 1532703666 1528 159d57adcba064aab4277245c826577d "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm" 1532703666 916 f87d7c45f9c908e672703b83b72241a3 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam5.tfm" 1532703666 924 9904cf1d39e9767e7a3622f2a125a565 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam7.tfm" 1532703666 928 2dc8d444221b7a635bb58038579b861a "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm" 1532703666 908 2921f8a10601f252058503cc6570e581 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm5.tfm" 1532703666 940 75ac932a52f80982a9f8ea75d03a34cf "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm" 1532703666 940 228d6584342e91276bf566bcf9716b83 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm" 1532703935 1116 4e6ba9d7914baa6482fd69f67d126380 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx10.tfm" 1532703935 1328 c834bbb027764024c09d3d2bf908b5f0 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm" 1532703935 1324 c910af8c371558dc20f2d7822f66fe64 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx5.tfm" 1532703935 1332 f817c21a1ba54560425663374f1b651a "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx6.tfm" 1532703935 1344 8a0be4fe4d376203000810ad4dc81558 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx7.tfm" 1532703935 1336 3125ccb448c1a09074e3aa4a9832f130 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx8.tfm" 1532703935 1332 1fde11373e221473104d6cc5993f046e "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx9.tfm" 1532703935 1328 5442e22a7072966dbaf88ca900acf3f0 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmex10.tfm" 1532703935 992 662f679a0b3d2d53c1b94050fdaa3f50 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi12.tfm" 1532703935 1524 4414a8315f39513458b80dfc63bff03a "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi6.tfm" 1532703935 1512 f21f83efb36853c0b70002322c1ab3ad "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi8.tfm" 1532703935 1520 eccf95517727cb11801f4f1aee3a21b4 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi9.tfm" 1532703935 1524 d89e2d087a9828407a196f428428ef4a "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmib10.tfm" 1532703935 1524 554068197b70979a55370e6c6495f441 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr12.tfm" 1532703935 1288 655e228510b4c2a1abe905c368440826 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr17.tfm" 1532703935 1292 296a67155bdbfc32aa9c636f21e91433 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr6.tfm" 1532703935 1300 b62933e007d01cfd073f79b963c01526 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr8.tfm" 1532703935 1292 21c1c5bfeaebccffdb478fd231a0997d "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr9.tfm" 1532703935 1292 6b21b9c2c7bebb38aa2273f7ca0fb3af "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm" 1532703935 1124 6c73e740cf17375f03eec0ee63599741 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy10.tfm" 1532704561 520 82a3d37183f34b6eb363a161dfc002c2 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy5.tfm" 1532704561 520 d082ac03a1087bc1ec2a06e24a9f68c0 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy6.tfm" 1532704561 520 4889cce2180234b97cad636b6039c722 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy7.tfm" 1532704561 520 a74c6ed8cb48679fdc3ea874d9d34a7e "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy8.tfm" 1532704561 520 7bb3abb160b19e0ed6ac404bb59052b7 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy9.tfm" 1532704561 520 1cc7cc05f4d7bae5c23bf7516f88fa52 "" + "c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasyb10.tfm" 1532704561 520 4bf1455197d190cb95c579bde4c2f0ba "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb" 1532703666 37912 07513ec114ac737ab54cea0152f4424b "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi6.pfb" 1532703666 37166 8ab3487cbe3ab49ebce74c29ea2418db "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb" 1532703666 36281 c355509802a035cadc5f15869451dcee "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi9.pfb" 1532703666 36094 798f80770b3b148ceedd006d487db67c "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb" 1532703666 31809 8670ca339bf94e56da1fc21c80635e2a "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmr6.pfb" 1532703666 32734 69e00a6b65cedb993666e42eedb3d48f "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmr9.pfb" 1532703666 33993 9b89b85fd2d9df0482bd47194d1d3bf3 "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb" 1532703666 32569 5e5ddc8df908dea60932f3c484a54c0d "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cmextra/cmex9.pfb" 1532703666 30212 f7062d6da71d1ec66ffb8906891648f7 "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/latxfont/lcircle1.pfb" 1532703666 10594 310261a6407d360eda1ed257d05cd4df "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/symbols/msbm10.pfb" 1532703666 34694 870c211f62cb72718a00e353f14f254d "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/cm-super/sftt0800.pfb" 1532703952 175641 e37e2df5b70b76a1b78bfb3b804197c7 "" + "c:/texlive/2018/texmf-dist/fonts/type1/public/cm-super/sftt0900.pfb" 1532703952 170827 b1cb46f82d978af2aeb6bf26777fa82d "" + "c:/texlive/2018/texmf-dist/fonts/type1/urw/times/utmb8a.pfb" 1532705452 44729 fea0975e20ec51c992338362f05f1146 "" + "c:/texlive/2018/texmf-dist/fonts/type1/urw/times/utmr8a.pfb" 1532705452 46026 687528a208fbfc1f00832bb96cccebbb "" + "c:/texlive/2018/texmf-dist/fonts/type1/urw/times/utmri8a.pfb" 1532705452 45458 504e2b06fa82109d168c7a0afb09e145 "" + "c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmb8t.vf" 1532705452 2340 df9c920cc5688ebbf16a93f45ce7bdd3 "" + "c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmr8t.vf" 1532705452 2348 91706c542228501c410c266421fbe30c "" + "c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmri8t.vf" 1532705452 2328 6cd7df782b09b29cfc4d93e55b6b9a59 "" + "c:/texlive/2018/texmf-dist/tex/context/base/mkii/supp-pdf.mkii" 1532704803 71627 94eb9990bed73c364d7f53f960cc8c5b "" + "c:/texlive/2018/texmf-dist/tex/generic/ifxetex/ifxetex.sty" 1532704456 1458 43ab4710dc82f3edeabecd0d099626b2 "" + "c:/texlive/2018/texmf-dist/tex/generic/oberdiek/gettitlestring.sty" 1532704885 8237 3b62ef1f7e2c23a328c814b3893bc11f "" + "c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty" 1532704885 185313 3e16abd014cb2c328020e45d63ed7f45 "" + "c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty" 1532704885 70864 bcd5b216757bd619ae692a151d90085d "" + "c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amsfonts.sty" 1532703666 5949 3f3fd50a8cc94c3d4cbf4fc66cd3df1c "" + "c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amssymb.sty" 1532703666 13829 94730e64147574077f8ecfea9bb69af4 "" + "c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsa.fd" 1532703667 961 6518c6525a34feb5e8250ffa91731cff "" + "c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsb.fd" 1532703667 961 d02606146ba5601b5645f987c92e6193 "" + "c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsbsy.sty" 1532703669 2211 ca7ce284ab93c8eecdc6029dc5ccbd73 "" + "c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsgen.sty" 1532703669 4161 7f6eb9092061a11f87d08ed13515b48d "" + "c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsmath.sty" 1532703669 84354 7292177bb735c466b78634ee4efd537e "" + "c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsopn.sty" 1532703669 4116 32e6abd27229755a83a8b7f18e583890 "" + "c:/texlive/2018/texmf-dist/tex/latex/amsmath/amstext.sty" 1532703669 2432 8ff93b1137020e8f21930562a874ae66 "" + "c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty" 1532704554 4573 ae83473dfe6aea3508ab88d22c4457b2 "" + "c:/texlive/2018/texmf-dist/tex/latex/base/inputenc.sty" 1532704554 5052 f2525dfd6e503dc383e90b568c6c9f02 "" + "c:/texlive/2018/texmf-dist/tex/latex/base/latexsym.sty" 1532704554 2856 7730103c7f3589c6c9d963ace57a7c18 "" + "c:/texlive/2018/texmf-dist/tex/latex/base/t1cmtt.fd" 1532704554 2446 898e9a1961d873c4471b5d9a683366d0 "" + "c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def" 1532704554 10008 3208fbcdd7b3f5dd0dda02e6507bf38c "" + "c:/texlive/2018/texmf-dist/tex/latex/base/textcomp.sty" 1532704554 16156 c88fab7ab9716ccedc3dc1fa0f1f22da "" + "c:/texlive/2018/texmf-dist/tex/latex/base/ts1cmr.fd" 1532704554 2433 cdefd2509a12ba58001f2024f63aae9a "" + "c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.def" 1532704554 7769 97b639552068544f7c98d557abb19f41 "" + "c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.dfu" 1532704554 4973 a0ebe45f171b33c2df4e84416140511f "" + "c:/texlive/2018/texmf-dist/tex/latex/base/ulasy.fd" 1532704554 2236 d19fc9d1775d819862989c760289e5a5 "" + "c:/texlive/2018/texmf-dist/tex/latex/eurosym/eurosym.sty" 1532704231 3028 8faeef64adee9b964b5e7f5e45921024 "" + "c:/texlive/2018/texmf-dist/tex/latex/float/float.sty" 1532704290 6749 16d2656a1984957e674b149555f1ea1d "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/color.cfg" 1532704382 1213 620bba36b25224fa9b7e1ccb4ecb76fd "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/graphics.cfg" 1532704382 1224 978390e9c2234eab29404bc21b268d1e "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics-def/pdftex.def" 1532704382 17334 520b9b85ad8a2a48eda3f643e27a5179 "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics/graphics.sty" 1532704381 15272 5a97061616e0c8b2aa79c6615ff769f4 "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics/graphicx.sty" 1532704381 9063 d0a305975932762117cd1f06a582f896 "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics/keyval.sty" 1532704381 2591 6404d0c7d28505fb38ce0d86c2e28ae7 "" + "c:/texlive/2018/texmf-dist/tex/latex/graphics/trig.sty" 1532704381 3977 cb9221976ed8a183afad65b59aa8629a "" + "c:/texlive/2018/texmf-dist/tex/latex/hyperref/hpdftex.def" 1532704428 51699 9069fc983fff0db91d59a15af144ad62 "" + "c:/texlive/2018/texmf-dist/tex/latex/hyperref/hyperref.sty" 1532704428 234088 2c849389d62d41c593d9f5176c4116ab "" + "c:/texlive/2018/texmf-dist/tex/latex/hyperref/nameref.sty" 1532704428 12949 81e4e808884a8f0e276b69410e234656 "" + "c:/texlive/2018/texmf-dist/tex/latex/hyperref/pd1enc.def" 1532704428 14098 4e70bf396c7c265bd8b0e5cab3fd3d4d "" + "c:/texlive/2018/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg" 1532704577 678 4792914a8f45be57bb98413425e4c7af "" + "c:/texlive/2018/texmf-dist/tex/latex/latexconfig/hyperref.cfg" 1532704577 235 6031e5765137be07eed51a510b2b8fb7 "" + "c:/texlive/2018/texmf-dist/tex/latex/listings/listings.cfg" 1532704623 1827 d72ad54409ca5c1068a1939c63441bd2 "" + "c:/texlive/2018/texmf-dist/tex/latex/listings/listings.sty" 1532704623 80336 ff90c926c3d7bfdaa3d80ca57123b0bb "" + "c:/texlive/2018/texmf-dist/tex/latex/listings/lstmisc.sty" 1532704623 77028 c3eb00afb55a32bc13ca8da7f5234377 "" + "c:/texlive/2018/texmf-dist/tex/latex/oberdiek/auxhook.sty" 1532704885 3834 4363110eb0ef1eb2b71c8fcbcdb6c357 "" + "c:/texlive/2018/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty" 1532704885 12095 5337833c991d80788a43d3ce26bd1c46 "" + "c:/texlive/2018/texmf-dist/tex/latex/oberdiek/grfext.sty" 1532704885 7075 2fe3d848bba95f139de11ded085e74aa "" + "c:/texlive/2018/texmf-dist/tex/latex/oberdiek/kvoptions.sty" 1532704885 22417 1d9df1eb66848aa31b18a593099cf45c "" + "c:/texlive/2018/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty" 1532704885 9581 023642318cef9f4677efe364de1e2a27 "" + "c:/texlive/2018/texmf-dist/tex/latex/preprint/authblk.sty" 1532705016 7016 985a983ce041cc8959cd31133cba0244 "" + "c:/texlive/2018/texmf-dist/tex/latex/psnfss/helvet.sty" 1532705035 1500 3c2647c8649928795ededd42a6e85f85 "" + "c:/texlive/2018/texmf-dist/tex/latex/psnfss/t1ptm.fd" 1532705035 774 61d7da1e9f9e74989b196d147e623736 "" + "c:/texlive/2018/texmf-dist/tex/latex/psnfss/times.sty" 1532705035 857 6c716f26c5eadfb81029fcd6ce2d45e6 "" + "c:/texlive/2018/texmf-dist/tex/latex/tools/bm.sty" 1532705483 12626 7d9d99d0bbe65f44cc0bb90f67262000 "" + "c:/texlive/2018/texmf-dist/tex/latex/tools/calc.sty" 1532705483 10212 357072c1d20578a30d6387d8a22e72ab "" + "c:/texlive/2018/texmf-dist/tex/latex/url/url.sty" 1532705573 12796 8edb7d69a20b857904dd0ea757c14ec9 "" + "c:/texlive/2018/texmf-dist/tex/latex/xcolor/xcolor.sty" 1532705635 55589 34128738f682d033422ca125f82e5d62 "" + "c:/texlive/2018/texmf-dist/web2c/texmf.cnf" 1532704534 33362 cf75436e19743e94a92a6b1b9183c434 "" + "c:/texlive/2018/texmf-var/fonts/map/pdftex/updmap/pdftex.map" 1532705718 2912949 8f7ee2183ff143e9b4d7090a42e31c2f "" + "c:/texlive/2018/texmf-var/web2c/pdftex/pdflatex.fmt" 1532705791 4216821 c6cfb41a9e96e1693e4aebdc07e2f592 "" + "c:/texlive/2018/texmf.cnf" 1532705705 673 4ae7b2f49cee444c5343a45b5d0f169c "" + "chr.png" 1683852295 20097 8b947eba2e284b006acf447a3f577ddf "" + "jlcode.sty" 1683852295 18666 d33ccf865c532e11b9480876a6bb58b2 "" + "journal_dat.tex" 1683852295 156 e6e783a18daee23542a412a50a5ce4b0 "" + "juliacon.cls" 1683852295 31320 600c1d13c17d8cd54504ceeaf65a3e1c "" + "logojuliacon.pdf" 1683852295 4937 0cb75c4e65b0cf72a69c7716f140efe5 "" + "paper.aux" 1697252663 7715 822ea37fa57aa053d638df6ec355f458 "" + "paper.bbl" 1697252440 8412 c5f25008db6df29972edfc95473a9694 "bibtex paper" + "paper.out" 1697252663 1369 1f68aa287eaf7868c2396c35550b552d "" + "paper.tex" 1697252661 26527 fd78089a63a54012af545feb9ae77edf "" + "solnspace.png" 1683852295 8537 21548aa816215210a45ef0cf5bc6a4c7 "" + "superstructure_pfd.png" 1683852295 71484 ccb9c3d50ea30611d678638f05ee9cf0 "" + (generated) + "paper.log" + "paper.pdf" + "c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.pdf" + "paper.aux" + "c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.log" + "paper.out" diff --git a/paper/paper.fls b/paper/paper.fls new file mode 100644 index 0000000..8b55dc3 --- /dev/null +++ b/paper/paper.fls @@ -0,0 +1,282 @@ +PWD c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper +INPUT c:/texlive/2018/texmf.cnf +INPUT c:/texlive/2018/texmf-dist/web2c/texmf.cnf +INPUT c:/texlive/2018/texmf-var/web2c/pdftex/pdflatex.fmt +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.tex +OUTPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.log +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/juliacon.cls +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/juliacon.cls +INPUT c:/texlive/2018/texmf-dist/tex/latex/psnfss/helvet.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/psnfss/helvet.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/keyval.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/keyval.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/latexsym.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/latexsym.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/url/url.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/url/url.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/inputenc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/inputenc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def +INPUT c:/texlive/2018/texmf-dist/fonts/map/fontname/texfonts.map +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ecrm1000.tfm +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/journal_dat.tex +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/journal_dat.tex +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ecrm0900.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx9.tfm +INPUT c:/texlive/2018/texmf-dist/tex/latex/psnfss/times.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/psnfss/times.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/tools/bm.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/tools/bm.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/graphicx.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/graphicx.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/graphics.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/graphics.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/trig.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics/trig.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics-def/pdftex.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics-def/pdftex.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/hyperref.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/hyperref.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/ifxetex/ifxetex.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/ifxetex/ifxetex.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/auxhook.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/auxhook.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/kvoptions.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/kvoptions.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/pd1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/pd1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/latexconfig/hyperref.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/latexconfig/hyperref.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/hpdftex.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/hpdftex.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/jlcode.sty +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/jlcode.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/listings/listings.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/listings/listings.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/listings/lstmisc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/listings/lstmisc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/listings/listings.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/listings/listings.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/xcolor/xcolor.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/xcolor/xcolor.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/color.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/color.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/textcomp.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/textcomp.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.dfu +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.dfu +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amssymb.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amssymb.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amsfonts.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amsfonts.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/eurosym/eurosym.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/eurosym/eurosym.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def +INPUT c:/texlive/2018/texmf-dist/tex/latex/tools/calc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/tools/calc.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/t1cmtt.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/t1cmtt.fd +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ectt0900.tfm +INPUT c:/texlive/2018/texmf-dist/tex/latex/preprint/authblk.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/preprint/authblk.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsmath.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsmath.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amstext.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amstext.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsgen.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsgen.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsbsy.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsbsy.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsopn.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsopn.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/float/float.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/float/float.sty +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux +OUTPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ts1cmr.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ts1cmr.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/psnfss/t1ptm.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/psnfss/t1ptm.fd +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +INPUT c:/texlive/2018/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/grfext.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/oberdiek/grfext.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/nameref.sty +INPUT c:/texlive/2018/texmf-dist/tex/latex/hyperref/nameref.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/gettitlestring.sty +INPUT c:/texlive/2018/texmf-dist/tex/generic/oberdiek/gettitlestring.sty +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +OUTPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.pdf +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +OUTPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/logojuliacon.pdf +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/logojuliacon.pdf +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/logojuliacon.pdf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr17.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr12.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi12.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi12.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmex10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmex10.tfm +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ulasy.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/base/ulasy.fd +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmib10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmib10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmib10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasyb10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasyb10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasyb10.tfm +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsa.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsa.fd +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsb.fd +INPUT c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsb.fd +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmb8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr9.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr6.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi9.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi6.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex9.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy9.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy6.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy5.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx6.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx5.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib9.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib6.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib5.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam5.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm5.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmri8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmr8t.vf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8r.tfm +INPUT c:/texlive/2018/texmf-var/fonts/map/pdftex/updmap/pdftex.map +INPUT c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmr8t.vf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8r.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmr8t.vf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8r.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmb8t.vf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmb8r.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmri8t.vf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmri8r.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/solnspace.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/solnspace.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/solnspace.png +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmr8.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmmi8.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy8.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx8.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib8.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/bigm.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/bigm.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/bigm.png +INPUT c:/texlive/2018/texmf-dist/fonts/vf/adobe/times/ptmr8t.vf +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8r.tfm +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/chr.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/chr.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/chr.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/superstructure_pfd.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/superstructure_pfd.png +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/superstructure_pfd.png +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/jknappen/ec/ectt0800.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/adobe/times/ptmr8t.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/latex-fonts/lasy7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbx7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmmib7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/cm/cmbsy10.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam7.tfm +INPUT c:/texlive/2018/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/bib.tex +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/bib.tex +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.bbl +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.bbl +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out +INPUT c:/texlive/2018/texmf-dist/fonts/enc/dvips/cm-super/cm-super-t1.enc +INPUT c:/texlive/2018/texmf-dist/fonts/enc/dvips/base/8r.enc +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cmextra/cmex9.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi6.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi9.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmr6.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmr9.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/latxfont/lcircle1.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/amsfonts/symbols/msbm10.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/cm-super/sftt0800.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/public/cm-super/sftt0900.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/urw/times/utmb8a.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/urw/times/utmr8a.pfb +INPUT c:/texlive/2018/texmf-dist/fonts/type1/urw/times/utmri8a.pfb diff --git a/paper/paper.log b/paper/paper.log new file mode 100644 index 0000000..73d281b --- /dev/null +++ b/paper/paper.log @@ -0,0 +1,880 @@ +This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018/W32TeX) (preloaded format=pdflatex 2018.7.27) 13 OCT 2023 23:04 +entering extended mode + restricted \write18 enabled. + file:line:error style messages enabled. + %&-line parsing enabled. +**c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.tex +(c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.tex +LaTeX2e <2018-04-01> patch level 5 +(c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/juliacon.cls (c:/texlive/2018/texmf-dist/tex/latex/psnfss/helvet.sty +Package: helvet 2005/04/12 PSNFSS-v9.2a (WaS) + (c:/texlive/2018/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 2014/10/28 v1.15 key=value parser (DPC) +\KV@toks@=\toks14 +)) +Document Class: juliacon +(c:/texlive/2018/texmf-dist/tex/latex/base/latexsym.sty +Package: latexsym 1998/08/17 v2.2e Standard LaTeX package (lasy symbols) +\symlasy=\mathgroup4 +LaTeX Font Info: Overwriting symbol font `lasy' in version `bold' +(Font) U/lasy/m/n --> U/lasy/b/n on input line 52. +) (c:/texlive/2018/texmf-dist/tex/latex/url/url.sty +\Urlmuskip=\muskip10 +Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc. +) (c:/texlive/2018/texmf-dist/tex/latex/base/inputenc.sty +Package: inputenc 2018/04/06 v1.3b Input encoding file +\inpenc@prehook=\toks15 +\inpenc@posthook=\toks16 +) (c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty +Package: fontenc 2017/04/05 v2.0i Standard LaTeX package + (c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def +File: t1enc.def 2017/04/05 v2.0i Standard LaTeX file +LaTeX Font Info: Redeclaring font encoding T1 on input line 48. +)) +\trimheight=\dimen102 +\trimwidth=\dimen103 +\typeheight=\dimen104 +\typewidth=\dimen105 +\normaltextheight=\dimen106 +\blindfoliodrop=\dimen107 +\tempbox=\box26 + (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/journal_dat.tex) +\tempdimen=\dimen108 +\normaltextheight=\dimen109 +\c@secnumbookdepth=\count80 +\c@theorem=\count81 +\c@strategy=\count82 +\c@property=\count83 +\c@proposition=\count84 +\c@exam=\count85 +\c@part=\count86 +\c@section=\count87 +\c@subsection=\count88 +\c@subsubsection=\count89 +\c@paragraph=\count90 +\c@figure=\count91 +\c@table=\count92 +\belowcaptionskip=\skip41 +\tbbox=\box27 +\tabledim=\dimen110 +\@narrowfig=\dimen111 +\@nfigbox=\box28 +\@nfcapbox=\box29 +\@abstract=\box30 +\@terms=\box31 +\@keywords=\box32 +\bibindent=\dimen112 +LaTeX Info: Redefining \cal on input line 900. + (c:/texlive/2018/texmf-dist/tex/latex/psnfss/times.sty +Package: times 2005/04/12 PSNFSS-v9.2a (SPQR) +) (c:/texlive/2018/texmf-dist/tex/latex/tools/bm.sty +Package: bm 2017/01/16 v1.2c Bold Symbol Support (DPC/FMi) +\symboldoperators=\mathgroup5 +\symboldletters=\mathgroup6 +\symboldsymbols=\mathgroup7 +\symboldlasy=\mathgroup8 +LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 141. +LaTeX Info: Redefining \bm on input line 207. +) (c:/texlive/2018/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 2017/06/01 v1.1a Enhanced LaTeX Graphics (DPC,SPQR) + (c:/texlive/2018/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2017/06/25 v1.2c Standard LaTeX Graphics (DPC,SPQR) + (c:/texlive/2018/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 2016/01/03 v1.10 sin cos tan (DPC) +) (c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration +) +Package graphics Info: Driver file: pdftex.def on input line 99. + (c:/texlive/2018/texmf-dist/tex/latex/graphics-def/pdftex.def +File: pdftex.def 2018/01/08 v1.0l Graphics/color driver for pdftex +)) +\Gin@req@height=\dimen113 +\Gin@req@width=\dimen114 +) (c:/texlive/2018/texmf-dist/tex/latex/hyperref/hyperref.sty +Package: hyperref 2018/02/06 v6.86b Hypertext links for LaTeX + (c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty +Package: hobsub-hyperref 2016/05/16 v1.14 Bundle oberdiek, subset hyperref (HO) + (c:/texlive/2018/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty +Package: hobsub-generic 2016/05/16 v1.14 Bundle oberdiek, subset generic (HO) +Package: hobsub 2016/05/16 v1.14 Construct package bundles (HO) +Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO) +Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO) +Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO) +Package ifluatex Info: LuaTeX not detected. +Package: ifvtex 2016/05/16 v1.6 Detect VTeX and its facilities (HO) +Package ifvtex Info: VTeX not detected. +Package: intcalc 2016/05/16 v1.2 Expandable calculations with integers (HO) +Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch +Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO) +Package etexcmds Info: Could not find \expanded. +(etexcmds) That can mean that you are not using pdfTeX 1.50 or +(etexcmds) that some package has redefined \expanded. +(etexcmds) In the latter case, load this package earlier. +Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO) +Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO) +Package: pdftexcmds 2018/01/30 v0.27 Utility functions of pdfTeX for LuaTeX (HO) +Package pdftexcmds Info: LuaTeX not detected. +Package pdftexcmds Info: \pdf@primitive is available. +Package pdftexcmds Info: \pdf@ifprimitive is available. +Package pdftexcmds Info: \pdfdraftmode found. +Package: pdfescape 2016/05/16 v1.14 Implements pdfTeX's escape features (HO) +Package: bigintcalc 2016/05/16 v1.4 Expandable calculations on big integers (HO) +Package: bitset 2016/05/16 v1.2 Handle bit-vector datatype (HO) +Package: uniquecounter 2016/05/16 v1.3 Provide unlimited unique counter (HO) +) +Package hobsub Info: Skipping package `hobsub' (already loaded). +Package: letltxmacro 2016/05/16 v1.5 Let assignment for LaTeX macros (HO) +Package: hopatch 2016/05/16 v1.3 Wrapper for package hooks (HO) +Package: xcolor-patch 2016/05/16 xcolor patch +Package: atveryend 2016/05/16 v1.9 Hooks at the very end of document (HO) +Package atveryend Info: \enddocument detected (standard20110627). +Package: atbegshi 2016/06/09 v1.18 At begin shipout hook (HO) +Package: refcount 2016/05/16 v3.5 Data extraction from label references (HO) +Package: hycolor 2016/05/16 v1.8 Color options for hyperref/bookmark (HO) +) (c:/texlive/2018/texmf-dist/tex/generic/ifxetex/ifxetex.sty +Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional +) (c:/texlive/2018/texmf-dist/tex/latex/oberdiek/auxhook.sty +Package: auxhook 2016/05/16 v1.4 Hooks for auxiliary files (HO) +) (c:/texlive/2018/texmf-dist/tex/latex/oberdiek/kvoptions.sty +Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO) +) +\@linkdim=\dimen115 +\Hy@linkcounter=\count93 +\Hy@pagecounter=\count94 + (c:/texlive/2018/texmf-dist/tex/latex/hyperref/pd1enc.def +File: pd1enc.def 2018/02/06 v6.86b Hyperref: PDFDocEncoding definition (HO) +Now handling font encoding PD1 ... +... no UTF-8 mapping file for font encoding PD1 +) +\Hy@SavedSpaceFactor=\count95 + (c:/texlive/2018/texmf-dist/tex/latex/latexconfig/hyperref.cfg +File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive +) +Package hyperref Info: Hyper figures OFF on input line 4509. +Package hyperref Info: Link nesting OFF on input line 4514. +Package hyperref Info: Hyper index ON on input line 4517. +Package hyperref Info: Plain pages OFF on input line 4524. +Package hyperref Info: Backreferencing OFF on input line 4529. +Package hyperref Info: Implicit mode ON; LaTeX internals redefined. +Package hyperref Info: Bookmarks ON on input line 4762. +\c@Hy@tempcnt=\count96 +LaTeX Info: Redefining \url on input line 5115. +\XeTeXLinkMargin=\dimen116 +\Fld@menulength=\count97 +\Field@Width=\dimen117 +\Fld@charsize=\dimen118 +Package hyperref Info: Hyper figures OFF on input line 6369. +Package hyperref Info: Link nesting OFF on input line 6374. +Package hyperref Info: Hyper index ON on input line 6377. +Package hyperref Info: backreferencing OFF on input line 6384. +Package hyperref Info: Link coloring OFF on input line 6389. +Package hyperref Info: Link coloring with OCG OFF on input line 6394. +Package hyperref Info: PDF/A mode OFF on input line 6399. +LaTeX Info: Redefining \ref on input line 6439. +LaTeX Info: Redefining \pageref on input line 6443. +\Hy@abspage=\count98 +\c@Item=\count99 +\c@Hfootnote=\count100 +) +Package hyperref Info: Driver (autodetected): hpdftex. + (c:/texlive/2018/texmf-dist/tex/latex/hyperref/hpdftex.def +File: hpdftex.def 2018/02/06 v6.86b Hyperref driver for pdfTeX +\Fld@listcount=\count101 +\c@bookmark@seq@number=\count102 + (c:/texlive/2018/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty +Package: rerunfilecheck 2016/05/16 v1.8 Rerun checks for auxiliary files (HO) +Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 282. +) +\Hy@SectionHShift=\skip42 +) (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/jlcode.sty +-- Package: `jlcode' 2.1 <2018/03/06> -- +Package: jlcode 2018/03/06 2.1 +(c:/texlive/2018/texmf-dist/tex/latex/listings/listings.sty +\lst@mode=\count103 +\lst@gtempboxa=\box33 +\lst@token=\toks17 +\lst@length=\count104 +\lst@currlwidth=\dimen119 +\lst@column=\count105 +\lst@pos=\count106 +\lst@lostspace=\dimen120 +\lst@width=\dimen121 +\lst@newlines=\count107 +\lst@lineno=\count108 +\abovecaptionskip=\skip43 +\belowcaptionskip=\skip44 +\lst@maxwidth=\dimen122 + (c:/texlive/2018/texmf-dist/tex/latex/listings/lstmisc.sty +File: lstmisc.sty 2015/06/04 1.6 (Carsten Heinz) +\c@lstnumber=\count109 +\lst@skipnumbers=\count110 +\lst@framebox=\box34 +) (c:/texlive/2018/texmf-dist/tex/latex/listings/listings.cfg +File: listings.cfg 2015/06/04 1.6 listings configuration +)) +Package: listings 2015/06/04 1.6 (Carsten Heinz) + (c:/texlive/2018/texmf-dist/tex/latex/xcolor/xcolor.sty +Package: xcolor 2016/05/11 v2.12 LaTeX color extensions (UK) + (c:/texlive/2018/texmf-dist/tex/latex/graphics-cfg/color.cfg +File: color.cfg 2016/01/02 v1.6 sample color configuration +) +Package xcolor Info: Driver file: pdftex.def on input line 225. +Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1348. +Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1352. +Package xcolor Info: Model `RGB' extended on input line 1364. +Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1366. +Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1367. +Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1368. +Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1369. +Package xcolor Info: Model `Gray' substituted by `gray' on input line 1370. +Package xcolor Info: Model `wave' substituted by `hsb' on input line 1371. +) (c:/texlive/2018/texmf-dist/tex/latex/base/textcomp.sty +Package: textcomp 2017/04/05 v2.0i Standard LaTeX package +Package textcomp Info: Sub-encoding information: +(textcomp) 5 = only ISO-Adobe without \textcurrency +(textcomp) 4 = 5 + \texteuro +(textcomp) 3 = 4 + \textohm +(textcomp) 2 = 3 + \textestimated + \textcurrency +(textcomp) 1 = TS1 - \textcircled - \t +(textcomp) 0 = TS1 (full) +(textcomp) Font families with sub-encoding setting implement +(textcomp) only a restricted character set as indicated. +(textcomp) Family '?' is the default used for unknown fonts. +(textcomp) See the documentation for details. +Package textcomp Info: Setting ? sub-encoding to TS1/1 on input line 79. + (c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.def +File: ts1enc.def 2001/06/05 v3.0e (jk/car/fm) Standard LaTeX file +Now handling font encoding TS1 ... +... processing UTF-8 mapping file for font encoding TS1 + (c:/texlive/2018/texmf-dist/tex/latex/base/ts1enc.dfu +File: ts1enc.dfu 2018/04/05 v1.2c UTF-8 support for inputenc + defining Unicode char U+00A2 (decimal 162) + defining Unicode char U+00A3 (decimal 163) + defining Unicode char U+00A4 (decimal 164) + defining Unicode char U+00A5 (decimal 165) + defining Unicode char U+00A6 (decimal 166) + defining Unicode char U+00A7 (decimal 167) + defining Unicode char U+00A8 (decimal 168) + defining Unicode char U+00A9 (decimal 169) + defining Unicode char U+00AA (decimal 170) + defining Unicode char U+00AC (decimal 172) + defining Unicode char U+00AE (decimal 174) + defining Unicode char U+00AF (decimal 175) + defining Unicode char U+00B0 (decimal 176) + defining Unicode char U+00B1 (decimal 177) + defining Unicode char U+00B2 (decimal 178) + defining Unicode char U+00B3 (decimal 179) + defining Unicode char U+00B4 (decimal 180) + defining Unicode char U+00B5 (decimal 181) + defining Unicode char U+00B6 (decimal 182) + defining Unicode char U+00B7 (decimal 183) + defining Unicode char U+00B9 (decimal 185) + defining Unicode char U+00BA (decimal 186) + defining Unicode char U+00BC (decimal 188) + defining Unicode char U+00BD (decimal 189) + defining Unicode char U+00BE (decimal 190) + defining Unicode char U+00D7 (decimal 215) + defining Unicode char U+00F7 (decimal 247) + defining Unicode char U+0192 (decimal 402) + defining Unicode char U+02C7 (decimal 711) + defining Unicode char U+02D8 (decimal 728) + defining Unicode char U+02DD (decimal 733) + defining Unicode char U+0E3F (decimal 3647) + defining Unicode char U+2016 (decimal 8214) + defining Unicode char U+2020 (decimal 8224) + defining Unicode char U+2021 (decimal 8225) + defining Unicode char U+2022 (decimal 8226) + defining Unicode char U+2030 (decimal 8240) + defining Unicode char U+2031 (decimal 8241) + defining Unicode char U+203B (decimal 8251) + defining Unicode char U+203D (decimal 8253) + defining Unicode char U+2044 (decimal 8260) + defining Unicode char U+204E (decimal 8270) + defining Unicode char U+2052 (decimal 8274) + defining Unicode char U+20A1 (decimal 8353) + defining Unicode char U+20A4 (decimal 8356) + defining Unicode char U+20A6 (decimal 8358) + defining Unicode char U+20A9 (decimal 8361) + defining Unicode char U+20AB (decimal 8363) + defining Unicode char U+20AC (decimal 8364) + defining Unicode char U+20B1 (decimal 8369) + defining Unicode char U+2103 (decimal 8451) + defining Unicode char U+2116 (decimal 8470) + defining Unicode char U+2117 (decimal 8471) + defining Unicode char U+211E (decimal 8478) + defining Unicode char U+2120 (decimal 8480) + defining Unicode char U+2122 (decimal 8482) + defining Unicode char U+2126 (decimal 8486) + defining Unicode char U+2127 (decimal 8487) + defining Unicode char U+212E (decimal 8494) + defining Unicode char U+2190 (decimal 8592) + defining Unicode char U+2191 (decimal 8593) + defining Unicode char U+2192 (decimal 8594) + defining Unicode char U+2193 (decimal 8595) + defining Unicode char U+2329 (decimal 9001) + defining Unicode char U+232A (decimal 9002) + defining Unicode char U+2422 (decimal 9250) + defining Unicode char U+25E6 (decimal 9702) + defining Unicode char U+25EF (decimal 9711) + defining Unicode char U+266A (decimal 9834) + defining Unicode char U+FEFF (decimal 65279) +)) +LaTeX Info: Redefining \oldstylenums on input line 334. +Package textcomp Info: Setting cmr sub-encoding to TS1/0 on input line 349. +Package textcomp Info: Setting cmss sub-encoding to TS1/0 on input line 350. +Package textcomp Info: Setting cmtt sub-encoding to TS1/0 on input line 351. +Package textcomp Info: Setting cmvtt sub-encoding to TS1/0 on input line 352. +Package textcomp Info: Setting cmbr sub-encoding to TS1/0 on input line 353. +Package textcomp Info: Setting cmtl sub-encoding to TS1/0 on input line 354. +Package textcomp Info: Setting ccr sub-encoding to TS1/0 on input line 355. +Package textcomp Info: Setting ptm sub-encoding to TS1/4 on input line 356. +Package textcomp Info: Setting pcr sub-encoding to TS1/4 on input line 357. +Package textcomp Info: Setting phv sub-encoding to TS1/4 on input line 358. +Package textcomp Info: Setting ppl sub-encoding to TS1/3 on input line 359. +Package textcomp Info: Setting pag sub-encoding to TS1/4 on input line 360. +Package textcomp Info: Setting pbk sub-encoding to TS1/4 on input line 361. +Package textcomp Info: Setting pnc sub-encoding to TS1/4 on input line 362. +Package textcomp Info: Setting pzc sub-encoding to TS1/4 on input line 363. +Package textcomp Info: Setting bch sub-encoding to TS1/4 on input line 364. +Package textcomp Info: Setting put sub-encoding to TS1/5 on input line 365. +Package textcomp Info: Setting uag sub-encoding to TS1/5 on input line 366. +Package textcomp Info: Setting ugq sub-encoding to TS1/5 on input line 367. +Package textcomp Info: Setting ul8 sub-encoding to TS1/4 on input line 368. +Package textcomp Info: Setting ul9 sub-encoding to TS1/4 on input line 369. +Package textcomp Info: Setting augie sub-encoding to TS1/5 on input line 370. +Package textcomp Info: Setting dayrom sub-encoding to TS1/3 on input line 371. +Package textcomp Info: Setting dayroms sub-encoding to TS1/3 on input line 372. +Package textcomp Info: Setting pxr sub-encoding to TS1/0 on input line 373. +Package textcomp Info: Setting pxss sub-encoding to TS1/0 on input line 374. +Package textcomp Info: Setting pxtt sub-encoding to TS1/0 on input line 375. +Package textcomp Info: Setting txr sub-encoding to TS1/0 on input line 376. +Package textcomp Info: Setting txss sub-encoding to TS1/0 on input line 377. +Package textcomp Info: Setting txtt sub-encoding to TS1/0 on input line 378. +Package textcomp Info: Setting lmr sub-encoding to TS1/0 on input line 379. +Package textcomp Info: Setting lmdh sub-encoding to TS1/0 on input line 380. +Package textcomp Info: Setting lmss sub-encoding to TS1/0 on input line 381. +Package textcomp Info: Setting lmssq sub-encoding to TS1/0 on input line 382. +Package textcomp Info: Setting lmvtt sub-encoding to TS1/0 on input line 383. +Package textcomp Info: Setting lmtt sub-encoding to TS1/0 on input line 384. +Package textcomp Info: Setting qhv sub-encoding to TS1/0 on input line 385. +Package textcomp Info: Setting qag sub-encoding to TS1/0 on input line 386. +Package textcomp Info: Setting qbk sub-encoding to TS1/0 on input line 387. +Package textcomp Info: Setting qcr sub-encoding to TS1/0 on input line 388. +Package textcomp Info: Setting qcs sub-encoding to TS1/0 on input line 389. +Package textcomp Info: Setting qpl sub-encoding to TS1/0 on input line 390. +Package textcomp Info: Setting qtm sub-encoding to TS1/0 on input line 391. +Package textcomp Info: Setting qzc sub-encoding to TS1/0 on input line 392. +Package textcomp Info: Setting qhvc sub-encoding to TS1/0 on input line 393. +Package textcomp Info: Setting futs sub-encoding to TS1/4 on input line 394. +Package textcomp Info: Setting futx sub-encoding to TS1/4 on input line 395. +Package textcomp Info: Setting futj sub-encoding to TS1/4 on input line 396. +Package textcomp Info: Setting hlh sub-encoding to TS1/3 on input line 397. +Package textcomp Info: Setting hls sub-encoding to TS1/3 on input line 398. +Package textcomp Info: Setting hlst sub-encoding to TS1/3 on input line 399. +Package textcomp Info: Setting hlct sub-encoding to TS1/5 on input line 400. +Package textcomp Info: Setting hlx sub-encoding to TS1/5 on input line 401. +Package textcomp Info: Setting hlce sub-encoding to TS1/5 on input line 402. +Package textcomp Info: Setting hlcn sub-encoding to TS1/5 on input line 403. +Package textcomp Info: Setting hlcw sub-encoding to TS1/5 on input line 404. +Package textcomp Info: Setting hlcf sub-encoding to TS1/5 on input line 405. +Package textcomp Info: Setting pplx sub-encoding to TS1/3 on input line 406. +Package textcomp Info: Setting pplj sub-encoding to TS1/3 on input line 407. +Package textcomp Info: Setting ptmx sub-encoding to TS1/4 on input line 408. +Package textcomp Info: Setting ptmj sub-encoding to TS1/4 on input line 409. +) (c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amssymb.sty +Package: amssymb 2013/01/14 v3.01 AMS font symbols + (c:/texlive/2018/texmf-dist/tex/latex/amsfonts/amsfonts.sty +Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support +\@emptytoks=\toks18 +\symAMSa=\mathgroup9 +\symAMSb=\mathgroup10 +LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' +(Font) U/euf/m/n --> U/euf/b/n on input line 106. +)) (c:/texlive/2018/texmf-dist/tex/latex/eurosym/eurosym.sty +Package: eurosym 1998/08/06 v1.1 European currency symbol ``Euro'' +\@eurobox=\box35 +) (c:/texlive/2018/texmf-dist/tex/latex/base/fontenc.sty +Package: fontenc 2017/04/05 v2.0i Standard LaTeX package + (c:/texlive/2018/texmf-dist/tex/latex/base/t1enc.def +File: t1enc.def 2017/04/05 v2.0i Standard LaTeX file +LaTeX Font Info: Redeclaring font encoding T1 on input line 48. +)) (c:/texlive/2018/texmf-dist/tex/latex/tools/calc.sty +Package: calc 2017/05/25 v4.3 Infix arithmetic (KKT,FJ) +\calc@Acount=\count111 +\calc@Bcount=\count112 +\calc@Adimen=\dimen123 +\calc@Bdimen=\dimen124 +\calc@Askip=\skip45 +\calc@Bskip=\skip46 +LaTeX Info: Redefining \setlength on input line 80. +LaTeX Info: Redefining \addtolength on input line 81. +\calc@Ccount=\count113 +\calc@Cskip=\skip47 +) +\bfem=\skip48 +LaTeX Font Info: Try loading font information for T1+cmtt on input line 414. + (c:/texlive/2018/texmf-dist/tex/latex/base/t1cmtt.fd +File: t1cmtt.fd 2014/09/29 v2.5h Standard LaTeX font definitions +) +\xmrgn=\skip49 +) (c:/texlive/2018/texmf-dist/tex/latex/preprint/authblk.sty +Package: authblk 2001/02/27 1.3 (PWD) +\affilsep=\skip50 +\@affilsep=\skip51 +\c@Maxaffil=\count114 +\c@authors=\count115 +\c@affil=\count116 +)) (c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsmath.sty +Package: amsmath 2017/09/02 v2.17a AMS math features +\@mathmargin=\skip52 + +For additional information on amsmath, use the `?' option. +(c:/texlive/2018/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2000/06/29 v2.01 AMS text + (c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 generic functions +\@emptytoks=\toks19 +\ex@=\dimen125 +)) (c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d Bold Symbols +LaTeX Info: Redefining \boldsymbol on input line 28. +\pmbraise@=\dimen126 +) (c:/texlive/2018/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 2016/03/08 v2.02 operator names +) +\inf@bad=\count117 +LaTeX Info: Redefining \frac on input line 213. +\uproot@=\count118 +\leftroot@=\count119 +LaTeX Info: Redefining \overline on input line 375. +\classnum@=\count120 +\DOTSCASE@=\count121 +LaTeX Info: Redefining \ldots on input line 472. +LaTeX Info: Redefining \dots on input line 475. +LaTeX Info: Redefining \cdots on input line 596. +\Mathstrutbox@=\box36 +\strutbox@=\box37 +\big@size=\dimen127 +LaTeX Font Info: Redeclaring font encoding OML on input line 712. +LaTeX Font Info: Redeclaring font encoding OMS on input line 713. +\macc@depth=\count122 +\c@MaxMatrixCols=\count123 +\dotsspace@=\muskip11 +\c@parentequation=\count124 +\dspbrk@lvl=\count125 +\tag@help=\toks20 +\row@=\count126 +\column@=\count127 +\maxfields@=\count128 +\andhelp@=\toks21 +\eqnshift@=\dimen128 +\alignsep@=\dimen129 +\tagshift@=\dimen130 +\tagwidth@=\dimen131 +\totwidth@=\dimen132 +\lineht@=\dimen133 +\@envbody=\toks22 +\multlinegap=\skip53 +\multlinetaggap=\skip54 +\mathdisplay@stack=\toks23 +LaTeX Info: Redefining \[ on input line 2817. +LaTeX Info: Redefining \] on input line 2818. +) (c:/texlive/2018/texmf-dist/tex/latex/float/float.sty +Package: float 2001/11/08 v1.3d Float enhancements (AL) +\c@float@type=\count129 +\float@exts=\toks24 +\float@box=\box38 +\@float@everytoks=\toks25 +\@floatcapt=\box39 +) (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux) +\openout1 = `paper.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 6. +LaTeX Font Info: Try loading font information for TS1+cmr on input line 6. + (c:/texlive/2018/texmf-dist/tex/latex/base/ts1cmr.fd +File: ts1cmr.fd 2014/09/29 v2.5h Standard LaTeX font definitions +) +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Try loading font information for T1+ptm on input line 6. + (c:/texlive/2018/texmf-dist/tex/latex/psnfss/t1ptm.fd +File: t1ptm.fd 2001/06/04 font definitions for T1/ptm. +) (c:/texlive/2018/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count130 +\scratchdimen=\dimen134 +\scratchbox=\box40 +\nofMPsegments=\count131 +\nofMParguments=\count132 +\everyMPshowfont=\toks26 +\MPscratchCnt=\count133 +\MPscratchDim=\dimen135 +\MPnumerator=\count134 +\makeMPintoPDFobject=\count135 +\everyMPtoPDFconversion=\toks27 +) (c:/texlive/2018/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty +Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf + (c:/texlive/2018/texmf-dist/tex/latex/oberdiek/grfext.sty +Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO) +) +Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 438. +Package grfext Info: Graphics extension search list: +(grfext) [.pdf,.png,.jpg,.mps,.jpeg,.jbig2,.jb2,.PDF,.PNG,.JPG,.JPEG,.JBIG2,.JB2,.eps] +(grfext) \AppendGraphicsExtensions on input line 456. + (c:/texlive/2018/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Live +)) +\AtBeginShipoutBox=\box41 +Package hyperref Info: Link coloring OFF on input line 6. + (c:/texlive/2018/texmf-dist/tex/latex/hyperref/nameref.sty +Package: nameref 2016/05/21 v2.44 Cross-referencing by name of section + (c:/texlive/2018/texmf-dist/tex/generic/oberdiek/gettitlestring.sty +Package: gettitlestring 2016/05/16 v1.5 Cleanup title references (HO) +) +\c@section@level=\count136 +) +LaTeX Info: Redefining \ref on input line 6. +LaTeX Info: Redefining \pageref on input line 6. +LaTeX Info: Redefining \nameref on input line 6. + (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out) (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.out) +\@outlinefile=\write3 +\openout3 = `paper.out'. + +\c@lstlisting=\count137 + +File: logojuliacon.pdf Graphic file (type pdf) + +Package pdftex.def Info: logojuliacon.pdf used on input line 15. +(pdftex.def) Requested size: 72.26999pt x 24.4797pt. +LaTeX Font Info: Try loading font information for U+lasy on input line 15. + (c:/texlive/2018/texmf-dist/tex/latex/base/ulasy.fd +File: ulasy.fd 1998/08/17 v2.2e LaTeX symbol font definitions +) +LaTeX Font Info: Try loading font information for U+msa on input line 15. + (c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsa.fd +File: umsa.fd 2013/01/14 v3.01 AMS symbols A +) +LaTeX Font Info: Try loading font information for U+msb on input line 15. + (c:/texlive/2018/texmf-dist/tex/latex/amsfonts/umsb.fd +File: umsb.fd 2013/01/14 v3.01 AMS symbols B +) +LaTeX Font Info: Font shape `T1/ptm/bx/n' in size <10> not available +(Font) Font shape `T1/ptm/b/n' tried instead on input line 17. +LaTeX Font Info: Font shape `U/lasy/b/n' in size <9> not available +(Font) Font shape `U/lasy/m/n' tried instead on input line 39. +LaTeX Font Info: Font shape `U/lasy/b/n' in size <6> not available +(Font) Font shape `U/lasy/m/n' tried instead on input line 39. +LaTeX Font Info: Font shape `U/lasy/b/n' in size <5> not available +(Font) Font shape `U/lasy/m/n' tried instead on input line 39. + +Underfull \hbox (badness 10000) has occurred while \output is active + + [] + +[1{c:/texlive/2018/texmf-var/fonts/map/pdftex/updmap/pdftex.map} +Non-PDF special ignored! + papersize=8.5in,11in + + + ] + +File: solnspace.png Graphic file (type png) + +Package pdftex.def Info: solnspace.png used on input line 103. +(pdftex.def) Requested size: 231.26343pt x 173.44757pt. +LaTeX Font Info: Font shape `U/lasy/b/n' in size <8> not available +(Font) Font shape `U/lasy/m/n' tried instead on input line 104. + +File: bigm.png Graphic file (type png) + +Package pdftex.def Info: bigm.png used on input line 135. +(pdftex.def) Requested size: 231.26343pt x 173.44757pt. + +Overfull \vbox (2.39996pt too high) has occurred while \output is active [] + + +Underfull \hbox (badness 10000) has occurred while \output is active + \T1/ptm/m/n/9 2 + [] + +[2pdfTeX warning (ext4): destination with the same identifier (name{figure.1}) has been already used, duplicate ignored + +\AtBegShi@Output ...ipout \box \AtBeginShipoutBox + \fi \fi +l.146 \end{equation} + pdfTeX warning (ext4): destination with the same identifier (name{figure.2}) has been already used, duplicate ignored + +\AtBegShi@Output ...ipout \box \AtBeginShipoutBox + \fi \fi +l.146 \end{equation} + ] + +File: chr.png Graphic file (type png) + +Package pdftex.def Info: chr.png used on input line 174. +(pdftex.def) Requested size: 231.26343pt x 173.44757pt. + +Overfull \vbox (2.39996pt too high) has occurred while \output is active [] + + +Underfull \hbox (badness 10000) has occurred while \output is active + \T1/ptm/m/n/9 3 + [] + +[3pdfTeX warning (ext4): destination with the same identifier (name{figure.3}) has been already used, duplicate ignored + +\AtBegShi@Output ...ipout \box \AtBeginShipoutBox + \fi \fi +l.219 + ] +Underfull \hbox (badness 10000) in paragraph at lines 224--225 +\T1/ptm/m/n/9 The fol-low-ing sec-tion de-scribes the fea-tures of the + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 224--225 +[][]\T1/cmtt/m/n/9 DisjunctiveProgramming.jl []\T1/ptm/m/n/9 pack-age and il-lus-trates its + [] + + +File: superstructure_pfd.png Graphic file (type png) + +Package pdftex.def Info: superstructure_pfd.png used on input line 241. +(pdftex.def) Requested size: 240.09274pt x 76.28363pt. +LaTeX Font Info: Font shape `T1/cmtt/bx/n' in size <7> not available +(Font) Font shape `T1/cmtt/m/n' tried instead on input line 307. + +Overfull \vbox (2.39996pt too high) has occurred while \output is active [] + + +Underfull \hbox (badness 10000) has occurred while \output is active + \T1/ptm/m/n/9 4 + [] + +[4pdfTeX warning (ext4): destination with the same identifier (name{figure.4}) has been already used, duplicate ignored + +\AtBegShi@Output ...ipout \box \AtBeginShipoutBox + \fi \fi +l.319 # + add global constraints to model ] +LaTeX Font Info: Font shape `U/lasy/b/n' in size <7> not available +(Font) Font shape `U/lasy/m/n' tried instead on input line 331. + +Underfull \hbox (badness 10000) in paragraph at lines 331--332 +[][][][][][][][][][][][][][][][][][][][][][] + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 335--336 +[][][][][][][][][][][][][][][][][][][][][][] + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 344--345 +[][][][][][][][][][][][][][][][][][][][][][] + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 345--346 +[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][] + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 350--351 +[][][][][][][][][][][][][][][][][][][][][][] + [] + + +Underfull \vbox (badness 2828) has occurred while \output is active [] + + (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/bib.tex (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.bbl +Underfull \hbox (badness 10000) in paragraph at lines 4--9 +[]\T1/ptm/m/n/9 Anshul Agar-wal. A novel minlp re-for-mu-la-tion for + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 4--9 +\T1/ptm/m/n/9 non-lin-ear gen-er-al-ized dis-junc-tive pro-gram-ming (gdp) + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 4--9 +\T1/ptm/m/n/9 prob-lems. \T1/ptm/m/it/9 arXiv preprint arXiv:1510.01791\T1/ptm/m/n/9 , 2015. + [] + + +Underfull \hbox (badness 3758) in paragraph at lines 18--22 +[]\T1/ptm/m/n/9 Egon Balas. \T1/ptm/m/it/9 Dis-junc-tive pro-gram-ming\T1/ptm/m/n/9 . Springer, 2018. + [] + + +Underfull \hbox (badness 6842) in paragraph at lines 38--42 +[]\T1/ptm/m/n/9 Qi Chen and Ig-na-cio Gross-mann. Mod-ern mod-el-ing + [] + + +Underfull \hbox (badness 1168) in paragraph at lines 44--49 +\T1/ptm/m/n/9 Sun-jeev Kale, Johnny Bates, John D Si-irola, and Ig-na- + [] + + +Overfull \vbox (2.39996pt too high) has occurred while \output is active [] + + +Underfull \hbox (badness 10000) has occurred while \output is active + \T1/ptm/m/n/9 5 + [] + +[5] +Underfull \hbox (badness 5802) in paragraph at lines 73--77 +[]\T1/ptm/m/n/9 Ignacio E. Gross-mann. \T1/ptm/m/it/9 Logic-based outer ap-prox-i-ma- + [] + + +Underfull \hbox (badness 1590) in paragraph at lines 79--84 +[]\T1/ptm/m/n/9 Kevin C. Fur-man, Nico-las W. Sawaya, and Ig-na-cio E. + [] + + +Underfull \hbox (badness 6978) in paragraph at lines 86--91 +[]\T1/ptm/m/n/9 Shashi Gowda, Yingbo Ma, Alessan-dro Cheli, Maja + [] + + +Underfull \hbox (badness 2512) in paragraph at lines 86--91 +\T1/ptm/m/n/9 Gwó¹zd¹, Vi-ral B. Shah, Alan Edel-man, and Christo- + [] + + +Underfull \hbox (badness 7308) in paragraph at lines 86--91 +\T1/ptm/m/n/9 pher Rack-auckas. High-performance symbolic-numerics + [] + + +Underfull \hbox (badness 1168) in paragraph at lines 86--91 +\T1/ptm/m/n/9 via mul-ti-ple dis-patch. \T1/ptm/m/it/9 ACM Com-mun. Com-put. Al-ge-bra\T1/ptm/m/n/9 , + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 137--142 +[]\T1/ptm/m/n/9 Fahad Ma-tovu, Shuhaimi Ma-hadzir, Rasel Ahmed, + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 137--142 +\T1/ptm/m/n/9 and Nor Erniza Mo-ham-mad Rozali. Syn-the-sis and + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 137--142 +\T1/ptm/m/n/9 op-ti-miza-tion of mul-ti-level re-frig-er-a-tion sys-tems us- + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 137--142 +\T1/ptm/m/n/9 ing gen-er-al-ized dis-junc-tive pro-gram-ming. \T1/ptm/m/it/9 Com-put- + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 137--142 +\T1/ptm/m/it/9 ers & Chem-i-cal En-gi-neer-ing\T1/ptm/m/n/9 , 163:107856, 2022. + [] + + +Underfull \hbox (badness 3148) in paragraph at lines 144--149 +[]\T1/ptm/m/n/9 Miguel A. Navarro-Amorós, Rubén Ruiz-Femenia, and + [] + + +Underfull \hbox (badness 1496) in paragraph at lines 144--149 +\T1/ptm/m/n/9 José A. Ca-ballero. In-te-gra-tion of mod-u-lar pro-cess sim- + [] + + +Underfull \hbox (badness 4229) in paragraph at lines 144--149 +\T1/ptm/m/n/9 u-la-tors un-der the gen-er-al-ized dis-junc-tive pro-gram-ming + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 144--149 +\T1/ptm/m/n/9 frame-work for the struc-tural flow-sheet op-ti-miza-tion. + [] + + +Underfull \hbox (badness 5050) in paragraph at lines 144--149 +\T1/ptm/m/it/9 Com-put-ers & Chem-i-cal En-gi-neer-ing\T1/ptm/m/n/9 , 67:13--25, 2014. + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 151--155 +[]\T1/ptm/m/n/9 George L. Nemhauser. \T1/ptm/m/it/9 In-te-ger and com-bi-na-to- + [] + + +Underfull \hbox (badness 10000) in paragraph at lines 151--155 +\T1/ptm/m/it/9 rial op-ti-miza-tion\T1/ptm/m/n/9 . John Wi-ley and Sons, 1999. + [] + + +Underfull \hbox (badness 2205) in paragraph at lines 157--161 +[]\T1/ptm/m/n/9 Francisco Tres-pala-cios and Ig-na-cio E. Gross-mann. Im- + [] + + +Underfull \hbox (badness 1454) in paragraph at lines 157--161 +\T1/ptm/m/n/9 grams. \T1/ptm/m/it/9 Com-put-ers & Chem-i-cal En-gi-neer-ing\T1/ptm/m/n/9 , 76:98--103, + [] + + +Underfull \hbox (badness 1237) in paragraph at lines 163--167 +\T1/ptm/m/it/9 IN-FORMS Jour-nal on Com-put-ing\T1/ptm/m/n/9 , 28(2):209^^U222, 2016. + [] + +)) +Package atveryend Info: Empty hook `BeforeClearDocument' on input line 380. + +Overfull \vbox (2.39996pt too high) has occurred while \output is active [] + + +Underfull \hbox (badness 10000) has occurred while \output is active + \T1/ptm/m/n/9 6 + [] + +[6] +Package atveryend Info: Empty hook `AfterLastShipout' on input line 380. + (c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.aux) +Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 380. +Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 380. +Package rerunfilecheck Info: File `paper.out' has not changed. +(rerunfilecheck) Checksum: 1F68AA287EAF7868C2396C35550B552D;1369. +Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 380. + ) +Here is how much of TeX's memory you used: + 10232 strings out of 492646 + 139958 string characters out of 6133325 + 359689 words of memory out of 5000000 + 13800 multiletter control sequences out of 15000+600000 + 49036 words of font info for 110 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 40i,14n,44p,1244b,2610s stack positions out of 5000i,500n,10000p,200000b,80000s +{c:/texlive/2018/texmf-dist/fonts/enc/dvips/cm-super/cm-super-t1.enc}{c:/texlive/2018/texmf-dist/fonts/enc/dvips/base/8r.enc} +Output written on c:/Users/HD/Downloads/DisjunctiveProgramming.jl/paper/paper.pdf (6 pages, 349604 bytes). +PDF statistics: + 436 PDF objects out of 1000 (max. 8388607) + 399 compressed objects within 4 object streams + 149 named destinations out of 1000 (max. 500000) + 186 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/paper/paper.out b/paper/paper.out new file mode 100644 index 0000000..757f239 --- /dev/null +++ b/paper/paper.out @@ -0,0 +1,20 @@ +\BOOKMARK [1][-]{section.1}{Introduction}{}% 1 +\BOOKMARK [1][-]{section.2}{Generalized Disjunctive Programming}{}% 2 +\BOOKMARK [2][-]{subsection.2.1}{Model}{section.2}% 3 +\BOOKMARK [2][-]{subsection.2.2}{Solution Technique: Reformulation to Mixed-Integer Program}{section.2}% 4 +\BOOKMARK [3][-]{subsubsection.2.2.1}{Big-M Reformulation}{subsection.2.2}% 5 +\BOOKMARK [3][-]{subsubsection.2.2.2}{Hull Reformulation}{subsection.2.2}% 6 +\BOOKMARK [2][-]{subsection.2.3}{Logic constraint reformulation}{section.2}% 7 +\BOOKMARK [3][-]{subsubsection.2.3.1}{Propositional Logic}{subsection.2.3}% 8 +\BOOKMARK [3][-]{subsubsection.2.3.2}{Constraint Programming}{subsection.2.3}% 9 +\BOOKMARK [2][-]{subsection.2.4}{Other Solution Techniques}{section.2}% 10 +\BOOKMARK [3][-]{subsubsection.2.4.1}{Disjunctive branch and bound}{subsection.2.4}% 11 +\BOOKMARK [3][-]{subsubsection.2.4.2}{Logic-based outer approximation}{subsection.2.4}% 12 +\BOOKMARK [3][-]{subsubsection.2.4.3}{Hybrid cutting planes}{subsection.2.4}% 13 +\BOOKMARK [1][-]{section.3}{DisjunctiveProgramming.jl}{}% 14 +\BOOKMARK [2][-]{subsection.3.1}{Features}{section.3}% 15 +\BOOKMARK [2][-]{subsection.3.2}{Example}{section.3}% 16 +\BOOKMARK [1][-]{section.4}{Future Work}{}% 17 +\BOOKMARK [1][-]{section.5}{Related Work}{}% 18 +\BOOKMARK [1][-]{section.6}{Conclusion}{}% 19 +\BOOKMARK [1][-]{section.7}{References}{}% 20 diff --git a/paper/paper.pdf b/paper/paper.pdf index 5a5d12a..6881298 100644 Binary files a/paper/paper.pdf and b/paper/paper.pdf differ diff --git a/paper/paper.synctex.gz b/paper/paper.synctex.gz new file mode 100644 index 0000000..4136ae5 Binary files /dev/null and b/paper/paper.synctex.gz differ diff --git a/paper/paper.tex b/paper/paper.tex index 62d285b..09d8fa4 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -25,7 +25,7 @@ \section{Introduction} \vskip 6pt A more systematic approach to modeling such systems is to use Generalized Disjunctive Programming (GDP) \cite{chen_grossmann_2019, grossmann_trespalacios_2013}, which generalizes the Disjunctive Programming paradigm proposed by Balas \cite{balas_2018}. GDP enables the modeling of systems from a logic-based level of abstraction that captures the fundamental rules governing such systems via algebraic constraints and logic. This formulation is useful for expressing problems in an intuitive way that relies on their logical underpinnings without needing to introduce mixed-integer constraints. GDP models are often easier to understand as related constraints are grouped into disjuncts that describe clearly defined subsets of the feasible space. The models obtained via GDP can be reformulated into the pure algebraic form best suited for the application of interest. It is also often possible to exploit the explicit logical structure of a GDP model to provide tighter relaxations than corresponding MIP models, which may improve convergence speed and robustness for solutions via advanced solution algorithms \cite{chen_grossmann_2019}. \vskip 6pt -Within the optimization community, there is a high volume of ongoing research that relies on GDP to formulate models for a variety of applications. Due to the combinatorial nature of system design problems, the GDP paradigm has been applied to the synthesis of complex processes and networks \cite{MATOVU2022107856, ZHOU202269}, the planning and optimal control of energy systems \cite{CHO2022841, kim2022generalized}, and the modeling of chemical synthesis under uncertainty \cite{CHEN2022107616}. These and numerous other applications of GDP illustrate the benefit of having a robust package for GDP that removes much of the overhead associated with developing and testing GDP models. Although packages with GDP capabilities exist for \verb|Pyomo| \cite{chen2022pyomo} and \verb|GAMS| \cite{vecchietti1999logmip}, having such a package available in Julia can greatly accelerate research in optimization, where packages like \verb|JuMP.jl| \cite{dunning_huchette_lubin_2017} are gaining significant traction. +Within the optimization community, there is a high volume of ongoing research that relies on GDP to formulate models for a variety of applications. Due to the combinatorial nature of system design problems, the GDP paradigm has been applied to the synthesis of complex processes and networks \cite{MATOVU2022107856, ZHOU202269}, the planning and optimal control of energy systems \cite{CHO2022841}, and the modeling of chemical synthesis under uncertainty \cite{CHEN2022107616}. These and numerous other applications of GDP illustrate the benefit of having a robust package for GDP that removes much of the overhead associated with developing and testing GDP models. Although packages with GDP capabilities exist for \verb|Pyomo| \cite{chen2022pyomo} and \verb|GAMS| \cite{vecchietti1999logmip}, having such a package available in Julia can greatly accelerate research in optimization, where packages like \verb|JuMP.jl| \cite{dunning_huchette_lubin_2017} are gaining significant traction. \vskip 6pt This paper provides background on the GDP paradigm, and the techniques for reformulating and solving such models. It then presents the package \verb|DisjunctiveProgramming.jl| as an extension to \verb|JuMP.jl| for creating models for optimization that follow the GDP modeling paradigm and can be solved using the vast list of supported solvers \cite{dunning_huchette_lubin_2017}. A case study demonstrates the use of the package for chemical process superstructure optimization. @@ -69,7 +69,7 @@ \subsection{Model} \end{align} \vskip 6pt -\subsection{Linear GDP reformulation example} +\subsection{Solution Technique: Reformulation to Mixed-Integer Program} The simplest example of a linear GDP system is given in \eqref{eq:ex} - \eqref{eq:y}, where $Y_i$ is a Boolean indicator variable that enforces the constraints in the disjunct ($Ax \le b$ or $Cx \le d$) when $true$. \vskip 6pt \begin{equation} @@ -107,7 +107,7 @@ \subsection{Linear GDP reformulation example} \vskip 6pt \subsubsection{Big-M Reformulation} - The Big-M reformulation for this problem is given by \eqref{eq:x}, \eqref{eq:ex_bigm1} - \eqref{eq:ex_bigm4}, where $M$ is a sufficiently large scalar that makes the particular constraint redundant when its indicator variable is not selected (i.e., $y_i = 0$). Note that the Boolean variables, $Y_i$, are replaced by binary variables, $y_i$. When the integrality constraint in Eq. \eqref{eq:ex_bigm4} is relaxed to $0 \leq x_1, x_2 \leq 1$, the resulting feasible region can be visualized by projecting the relaxed model onto the $x_1, x_2$ plane. This results in the region encapsulated by the dashed line in Figure \ref{fig:bigm}. It should be noted that the relaxed feasible region is not as tight as possible around the original feasible solution space. The choice of the large $M$ value determines the tightness of this relaxation, and the minimal value of $M$ for the optimal relaxation can be found through interval arithmetic when the model is linear. For nonlinear models, the tightest $M$ can be obtained by solving the maximization problem $\{\max h_{ik}(x): x \in X\}$. An alternate method for tight Big-M relaxations is given in \cite{TRESPALACIOS201598}. + The Big-M reformulation for this problem is given by \eqref{eq:ex_bigm1} - \eqref{eq:ex_bigm5}, where $M$ is a sufficiently large scalar that makes the particular constraint redundant when its indicator variable is not selected (i.e., $y_i = 0$). Note that the Boolean variables, $Y_i$, are replaced by binary variables, $y_i$. When the integrality constraint in Eq. \eqref{eq:ex_bigm4} is relaxed to $0 \leq x_1, x_2 \leq 1$, the resulting feasible region can be visualized by projecting the relaxed model onto the $x_1, x_2$ plane. This results in the region encapsulated by the dashed line in Figure \ref{fig:bigm}. It should be noted that the relaxed feasible region is not as tight as possible around the original feasible solution space. The choice of the large $M$ value determines the tightness of this relaxation, and the minimal value of $M$ for the optimal relaxation can be found through interval arithmetic when the model is linear. For nonlinear models, the tightest $M$ can be obtained by solving the maximization problem $\{\max h_{ik}(x): x \in X\}$. An alternate method for tight Big-M relaxations is given in \cite{TRESPALACIOS201598}. \begin{equation} \label{eq:ex_bigm1} @@ -123,6 +123,10 @@ \subsection{Linear GDP reformulation example} \end{equation} \begin{equation} \label{eq:ex_bigm4} + 0 \leq x \leq U +\end{equation} +\begin{equation} + \label{eq:ex_bigm5} y_1, y_2 \in \{0,1\} \end{equation} @@ -134,24 +138,36 @@ \subsection{Linear GDP reformulation example} \end{figure} \subsubsection{Hull Reformulation} -The Hull reformulation is given by \eqref{eq:x}, \eqref{eq:ex_bigm3} - \eqref{eq:ex_hull3}, which requires lifting the model to a higher-dimensional space. When projected to the original space, the continuous relaxation of the model is tighter than its Big-M equivalent \cite{grossmann_trespalacios_2013}. The reformulation relaxation can be visualized by the region encapsulated by the dashed line in Figure \ref{fig:chr}. Note that this reformulation provides a tighter relaxation than the Big-M reformulation in Figure \ref{fig:bigm}. Also note that describing the geometry of this relaxation is more complex than the Big-M relaxation, which is made possible by the increased number of constraints and variables in the model. +The Hull reformulation is given by \eqref{eq:ex_hull0} - \eqref{eq:ex_hull6}, which requires lifting the model to a higher-dimensional space. When projected to the original space, the continuous relaxation of the model is tighter than its Big-M equivalent \cite{grossmann_trespalacios_2013}. The reformulation relaxation can be visualized by the region encapsulated by the dashed line in Figure \ref{fig:chr}. Note that this reformulation provides a tighter relaxation than the Big-M reformulation in Figure \ref{fig:bigm}. Also note that describing the geometry of this relaxation is more complex than the Big-M relaxation, which is made possible by the increased number of constraints and variables in the model. \begin{equation} - \label{eq:ex_hull1} + \label{eq:ex_hull0} Ax_1 \leq by_1 \end{equation} \begin{equation} - \label{eq:ex_hull0} + \label{eq:ex_hull1} Cx_2 \leq dy_2 \end{equation} \begin{equation} \label{eq:ex_hull2} x = x_1 + x_2 \end{equation} +\begin{equation} + \label{eq:ex_hull4} + y_1 + y_2 = 1 +\end{equation} +\begin{equation} + \label{eq:ex_hull5} + 0 \leq x \leq U +\end{equation} \begin{equation} \label{eq:ex_hull3} 0 \leq x_i \leq U y_i \quad \forall i \in \{1,2\} \end{equation} +\begin{equation} + \label{eq:ex_hull6} + y_1, y_2 \in \{0,1\} +\end{equation} \begin{figure}%[H] \centering @@ -173,10 +189,10 @@ \subsubsection{Propositional Logic} (A \land B) \lor C & \text{ is replaced by } (A \lor C) \land (B \lor C) \end{align*} -Once the logic propositions are converted to CNF, each clause can be converted into an algebraic constraint with the following equivalence (Note: any negated Boolean variables, $\neg Y_i$, are replaced with $1-y_i$ in the reformulation), +Once the logic propositions are converted to CNF, each clause can be converted into an algebraic constraint with the following equivalence, where the set $I$ represents the subset boolean variables present in the clause, and the set $J$ represents the subset of boolean variables present in the clause in negated form, \begin{align*} - \bigvee_{i \in I} Y_i & \ \ \text{becomes} \ \ \sum_{i\in I} y_i \geq 1 \\ + \left(\bigvee_{i \in I} Y_i\right) \vee \left(\bigvee_{j \in J} \neg Y_j\right) & \ \ \text{becomes} \ \ \sum_{i \in I} y_i + \sum_{j \in J} (1-y_j) \geq 1 \\ \end{align*} Alternate approaches exist for converting propositional logic statements into CNF, which involve preserving clause satisfiability rather than clause equivalence. These approaches prevent exponential size increase in clauses and yield logically consistent results \cite{jackson_sheridan_2005}. @@ -192,7 +208,7 @@ \subsubsection{Constraint Programming} Exclusive-OR constraints as the one given in Eq. \eqref{eq:simple_xor} are more generally modeled as $exactly(1,\{Y_1,Y_2\})$. -\subsection{Solution Techniques} +\subsection{Other Solution Techniques} \label{other_techniques} \subsubsection{Disjunctive branch and bound} The disjunctive branch and bound method closely mirrors the standard branch and bound approach for the solution of mixed-integer programming problems \cite{grossmann_lee_2003}. A search tree is initialized by solving the continuous relaxation of the Big-M or Hull reformulation of the original GDP to obtain a lower bound on the optimum. Branching is then done on the disjunction with an indicator binary variable closest to 1. Two nodes are created at this point: one where the respective indicator Boolean variable is fixed to $true$ (the disjunct is enforced) and another where it is fixed to $false$ (the disjunct is removed from the disjunction). Each node is reformulated and solved to obtain a candidate lower bound. If the solution to a node results in a feasible solution that satisfies all integrality constraints, the solution is an upper bound on the optimum. Any non-integral solutions that exceed an upper bound are pruned from the search tree. The process is repeated until the lower and upper bounds are within the desired tolerance. @@ -217,7 +233,7 @@ \subsection{Features} Nesting of disjunctions is also supported. \subsection{Example} -To illustrate the syntax in \verb|DisjunctiveProgramming.jl| (Version 0.3.3), consider the simple superstructure optimization problem for the chemical process given in Figure \ref{fig:superstruct_opt_diagram}. In this problem a chemical plant with two candidate reactor technologies ($R_1$ and $R_2$) must be designed. If the second reactor technology is chosen, a separation system must also be installed, for which two separation technologies ($S_1$ and $S_2$) are available. The GDP model seeks to maximize the product flow ($F_7$), while discounting for reactor ($C_R$) and separator ($C_S$) installation costs as given in \eqref{eq:example_obj}, subject to the nested disjunction in \eqref{eq:example_gdp} and the global mass balances in \eqref{eq:example_global} +To illustrate the syntax in \verb|DisjunctiveProgramming.jl| (Version 0.4.1), consider the simple superstructure optimization problem for the chemical process given in Figure \ref{fig:superstruct_opt_diagram}. In this problem a chemical plant with two candidate reactor technologies ($R_1$ and $R_2$) must be designed. If the second reactor technology is chosen, a separation system must also be installed, for which two separation technologies ($S_1$ and $S_2$) are available. The GDP model seeks to maximize the product flow ($F_7$), while discounting for reactor ($C_R$) and separator ($C_S$) installation costs as given in \eqref{eq:example_obj}, subject to the nested disjunction in \eqref{eq:example_gdp} and the global mass balances in \eqref{eq:example_global} - \eqref{eq:example_global1}. The system variables are the flows on each stream $i$ ($F_i$) and the installation costs, with their respective bounds given in \eqref{eq:example_var1} - \eqref{eq:example_var3}. The fixed cost and process yield parameters are given by $\gamma$ and $\beta$, respectively. \begin{figure} @@ -288,16 +304,19 @@ \subsection{Example} \item Create the JuMP model and define the model variables and global constraints (mass balances). \begin{lstlisting}[language = Julia] -using DisjunctiveProgramming, JuMP, HiGHS +using DisjunctiveProgramming, HiGHS # create model -m = JuMP.Model(HiGHS.Optimizer) +m = GDPModel(HiGHS.Optimizer) # add variables to model @variable(m, 0 <= F[i = 1:7] <= 10) @variable(m, 0 <= CS <= CSmax) @variable(m, CRmin <= CR <= CRmax) +# add logical variables to model +@variable(m, YR[1:2], LogicalVariable) +@variable(m, YS[1:2], LogicalVariable) -# add constraints to model +# add global constraints to model @constraints(m, begin F[1] == F[2] + F[3] @@ -307,56 +326,36 @@ \subsection{Example} \end{lstlisting} \item Define the inner (nested) disjunction for the separation technologies in the superstructure using the \verb|@disjunction| macro. \begin{lstlisting}[language = Julia] -@disjunction(m, - begin - F[5] == β[:S1]*F[4] - CS == γ[:S1] - end, - begin - F[5] == β[:S2]*F[4] - CS == γ[:S2] - end, - reformulation = :big_m, # reformulation type - name = :YS # symbol for indicator variable -) -\end{lstlisting} - \item Define constraints in the outer disjunctions. -\begin{lstlisting}[language = Julia] -# define constraints in left disjunct -R1_con = @constraints(m, - begin - F[6] == β[:R1]*F[2] - [i = 3:5], F[i] == 0 - CR == γ[:R1] - CS == 0 - end -) - -# define constraints in right disjunct -R2_con = @constraints(m, - begin - F[6] == β[:R2]*F[3] - CR == γ[:R2] - end -) +# define constraints in left YS disjunct +YS1_disjunct = DisjunctConstraint(YS[1]) +@constraint(m, F[5] == β[:S1]*F[4], YS1_disjunct) +@constraint(m, CS == γ[:S1], YS1_disjunct) +# define constraints in right YS disjunct +YS2_disjunct = DisjunctConstraint(YS[2]) +@constraint(m, F[5] == β[:S2]*F[4], YS2_disjunct) +@constraint(m, CS == γ[:S2], YS2_disjunct) +# define disjunction (specify parent disjunct) +@disjunction(m, YS, YS2_disjunct) \end{lstlisting} - \item Build the main disjunction using the constraint blocks defined in (3) and the \verb|add_disjunction!| function. Note that the reformulated constraints for the nested disjunction are stored in the \verb|.ext| dictionary of the model under the name of the disjunction (\verb|:YS| in this case). + \item Define the outer disjunctions. \begin{lstlisting}[language = Julia] -add_disjunction!(m, - R1_con, - ( - R2_con, #general constraints in R2 disj. - m.ext[:YS] #reformulated inner disj. - ), - reformulation = :big_m, # reformulation type - name = :YR # symbol for indicator variable -) +# define constraints in left YR disjunct +YR1_disjunct = DisjunctConstraint(YR[1]) +@constraint(m, F[6] == β[:R1]*F[2], YR1_disjunct) +@constraint(m, [i = 3:5], F[i] == 0, YR1_disjunct) +@constraint(m, CR == γ[:R1], YR1_disjunct) +@constraint(m, CS == 0, YR1_disjunct) +# define constraints in right YR disjunct +YR2_disjunct = DisjunctConstraint(YR[2]) +@constraint(m, F[6] == β[:R2]*F[3], YR2_disjunct) +@constraint(m, CR == γ[:R2], YR2_disjunct) +# define disjunction +@disjunction(m, YR) \end{lstlisting} \item Add the selection logical constraints using the \verb|choose!| function. The first constraint enforces that only one reactor is selected (i.e., $Y_{R_1} \ \underline{\vee} \ Y_{R_2}$). The second constraint enforces that the separation system be defined only if the second reactor ($R_2$) is selected. This constraint is equivalent to the proposition $Y_{R_2} \Leftrightarrow Y_{S_1} \ \underline{\vee} \ Y_{S_2}$. \begin{lstlisting}[language = Julia] -YR, YS = m[:YR], m[:YS] -choose!(m, 1, YR[1], YR[2]; mode = :exactly) -choose!(m, YR[2], YS[1], YS[2]; mode = :exactly) +@constraint(m, YR in Exactly(1)) +@constraint(m, YS in Exactly(YR[2])) \end{lstlisting} \item Add the objective function and optimize. \begin{lstlisting}[language = Julia] @@ -366,7 +365,7 @@ \subsection{Example} \end{enumerate} \section{Future Work} -The next steps for the \verb|DisjunctivePrograming.jl| package rely on extending \verb|JuMP.jl| further to allow creating GDP models that are not necessarily reformulated at model creation. Such models will allow using the different GDP solution strategies, such as direct reformulation to MI(N)LP, disjunctive branch and bound, logic-based outer approximation, hybrid cutting planes, and basic steps. The updated package will leverage existing JuMP extension infrastructure and make it possible to define indexing notation for disjunctions, a new Boolean variable type, and a new disjunciton constraint type. These improvements are expected to make the package more usable, flexible, and performant for advanced applications of GDP in JuMP. +Since the package is currently limited to reformulating GDP models into Mixed-Integer Programming JuMP models, future work includes developing logic-based solvers to allow optimizing GDP models directly. This will include GDP solvers that implement the other solution techniques described in Section \ref{other_techniques}. Future work also involves extending the list of suported reformulation techniques to include the \textit{P-Split} \cite{kronqvist2022p} and \textit{True-False} \cite{agarwal2015novel} reformulations. \section{Related Work} The popular Python package \verb|Pyomo| \cite{bynum2021pyomo, hart2011pyomo} is widely used for optimization development and includes an extension for generalized disjunctive programming \cite{chen2022pyomo}. \verb|GAMS| \cite{Bussieck2004} is a widely used optimization modeling language with support for GDP under the \verb|GAMS EMP| solver that uses \verb|LogMIP| \cite{vecchietti1999logmip}. Research is also being conducted to integrate modern process simulation technology, such as \verb|Aspen|, within the GDP paradigm \cite{NAVARROAMOROS201413}. diff --git a/paper/ref.bib b/paper/ref.bib index e8fbeed..36b77d0 100644 --- a/paper/ref.bib +++ b/paper/ref.bib @@ -26,7 +26,8 @@ @article{chen2022pyomo number={1}, pages={607--642}, year={2022}, - publisher={Springer} + publisher={Springer}, + doi={10.1007/978-3-030-00148-3} } @article{vecchietti1999logmip, title={LOGMIP: a disjunctive 0--1 non-linear optimizer for process system models}, @@ -98,7 +99,8 @@ @book{bynum2021pyomo edition={Third}, volume={67}, year={2021}, -publisher={Springer Science \& Business Media} +publisher={Springer Science \& Business Media}, +doi={10.1007/978-3-030-68928-5} } @article{hart2011pyomo, @@ -158,14 +160,6 @@ @article{MATOVU2022107856 abstract = {The synthesis and optimization of multilevel refrigeration systems is challenging because it’s a highly non-linear, multi-variable, and multi-modal problem. This work presents a novel approach to develop a complete generalized disjunctive programming model for the synthesis and optimization of multilevel refrigeration systems. The model is based on the application of mass, energy, and thermodynamic model equations and developed to optimize the total shaft work requirement of the system. The presented model is very systematic, easily manageable, and can be extendable to include all design features for refrigeration systems. The model is solvable using advanced solution algorithms such as the Logic-based branch and bound because of it’s disjunctive nature. Thus the solution is sought in reduced space and avoids the full scale as is the case with Mixed integer linear/non-linear models. The model solution yields optimal temperature/pressure levels, mass flow rates, and the shaft work consumption. A case study of the precooling cycle of the propane pre-cooled mixed refrigerant (C3MR) LNG process is used to test the proposed model. The model results are validated by simulation using Aspen Hysys software. Shaft work savings of up to 12.3% are obtained from the model results against the base case. Preliminary estimations show that cost savings of up to 2.55 MM$/y are realizable against the base case.} } -@article{kim2022generalized, - title={Generalized Disjunctive Programming-based, Mixed Integer Linear MPC Formulation for Optimal Operation of a District Energy System for PV Self-consumption and Grid Decarbonization: Field Implementation}, - author={Kim, Donghun}, - journal={International High Performance Buildings Conference}, - url={https://docs.lib.purdue.edu/cgi/viewcontent.cgi?article=1395\&context=ihpbc}, - year={2022} -} - @article{ZHOU202269, title = {Disjunctive programming model for the synthesis of property-based water supply network with multiple resources}, journal = {Chemical Engineering Research and Design}, @@ -198,7 +192,7 @@ @article{jackson_sheridan_2005 } @article{dunning_huchette_lubin_2017, -title={Jump: A modeling language for mathematical optimization}, +title={JuMP: A modeling language for mathematical optimization}, volume={59}, number={2}, journal={SIAM Review}, @@ -257,7 +251,8 @@ @book{balas_2018 title={Disjunctive programming}, publisher={Springer}, author={Balas, Egon}, -year={2018} +year={2018}, +doi={10.1007/978-3-030-00148-3} } @article{TRESPALACIOS201598, @@ -294,7 +289,8 @@ @book{nemhauser_1999 title={Integer and combinatorial optimization}, publisher={John Wiley and Sons}, author={Nemhauser, George L.}, -year={1999} +year={1999}, +doi={10.1002/9781118627372} } @article{grossmann_lee_2003, @@ -352,3 +348,17 @@ @article{SAWAYA20051891 keywords = {MIP, Disjunctive Programming, Cutting planes, Mixed integer linear programming, Strip-packing, Retrofit planning, Job-shop scheduling}, abstract = {Raman and Grossmann [Raman, R., \& Grossmann, I.E. (1994). Modeling and computational techniques for logic based integer programming. Computers and Chemical Engineering, 18(7), 563–578] and Lee and Grossmann [Lee, S., \& Grossmann, I.E. (2000). New algorithms for nonlinear generalized disjunctive programming. Computers and Chemical Engineering, 24, 2125–2141] have developed a reformulation of Generalized Disjunctive Programming (GDP) problems that is based on determining the convex hull of each disjunction. Although the relaxation of the reformulated problem using this method will often produce a significantly tighter lower bound when compared with the traditional big-M reformulation, the limitation of this method is that the representation of the convex hull of every disjunction requires the introduction of new disaggregated variables and additional constraints that can greatly increase the size of the problem. In order to circumvent this issue, a cutting plane method that can be applied to linear GDP problems is proposed in this paper. The method relies on converting the GDP problem into an equivalent big-M reformulation that is successively strengthened by cuts generated from an LP or QP separation problem. The sequence of problems is repeatedly solved, either until the optimal integer solution is found, or else until there is no improvement within a specified tolerance, in which case one switches to a branch and bound method. The strip-packing, retrofit planning and zero-wait job-shop scheduling problems are presented as examples to illustrate the performance of the proposed cutting plane method.} } +@article{kronqvist2022p, + title={P-split formulations: A class of intermediate formulations between big-M and convex hull for disjunctive constraints}, + author={Kronqvist, Jan and Misener, Ruth and Tsay, Calvin}, + journal={arXiv preprint arXiv:2202.05198}, + year={2022}, + doi={10.48550/arXiv.2202.05198} +} +@article{agarwal2015novel, + title={A Novel MINLP Reformulation for Nonlinear Generalized Disjunctive Programming (GDP) Problems}, + author={Agarwal, Anshul}, + journal={arXiv preprint arXiv:1510.01791}, + year={2015}, + doi={10.48550/arXiv.1510.01791} +} \ No newline at end of file diff --git a/src/bigm.jl b/src/bigm.jl index d4598c5..97d1d7f 100644 --- a/src/bigm.jl +++ b/src/bigm.jl @@ -2,7 +2,7 @@ # BIG-M VALUE ################################################################################ # Get Big-M value for a particular constraint -function _get_M_value(func::JuMP.AbstractJuMPScalar, set::_MOI.AbstractSet, method::BigM) +function _get_M_value(func::AbstractJuMPScalar, set::_MOI.AbstractSet, method::BigM) if method.tighten M = _get_tight_M(func, set, method) else @@ -12,7 +12,7 @@ function _get_M_value(func::JuMP.AbstractJuMPScalar, set::_MOI.AbstractSet, meth end # Get the tightest Big-M value for a particular constraint -function _get_tight_M(func::JuMP.AbstractJuMPScalar, set::_MOI.AbstractSet, method::BigM) +function _get_tight_M(func::AbstractJuMPScalar, set::_MOI.AbstractSet, method::BigM) M = min.(method.value, _calculate_tight_M(func, set, method)) #broadcast for when S <: MOI.Interval or MOI.EqualTo or MOI.Zeros if any(isinf.(M)) error("A finite Big-M value must be used. The value obtained was $M.") @@ -21,14 +21,14 @@ function _get_tight_M(func::JuMP.AbstractJuMPScalar, set::_MOI.AbstractSet, meth end # Get user-specified Big-M value -function _get_M(::JuMP.AbstractJuMPScalar, ::Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.Nonnegatives, _MOI.Nonpositives}, method::BigM) +function _get_M(::AbstractJuMPScalar, ::Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.Nonnegatives, _MOI.Nonpositives}, method::BigM) M = method.value if isinf(M) error("A finite Big-M value must be used. The value given was $M.") end return M end -function _get_M(::JuMP.AbstractJuMPScalar, ::Union{_MOI.Interval, _MOI.EqualTo, _MOI.Zeros}, method::BigM) +function _get_M(::AbstractJuMPScalar, ::Union{_MOI.Interval, _MOI.EqualTo, _MOI.Zeros}, method::BigM) M = method.value if isinf(M) error("A finite Big-M value must be used. The value given was $M.") @@ -37,64 +37,64 @@ function _get_M(::JuMP.AbstractJuMPScalar, ::Union{_MOI.Interval, _MOI.EqualTo, end # Apply interval arithmetic on a linear constraint to infer the tightest Big-M value from the bounds on the constraint. -function _calculate_tight_M(func::JuMP.AffExpr, set::_MOI.LessThan, method::BigM) +function _calculate_tight_M(func::AffExpr, set::_MOI.LessThan, method::BigM) return _interval_arithmetic_LessThan(func, -set.upper, method) end -function _calculate_tight_M(func::JuMP.AffExpr, set::_MOI.GreaterThan, method::BigM) +function _calculate_tight_M(func::AffExpr, set::_MOI.GreaterThan, method::BigM) return _interval_arithmetic_GreaterThan(func, -set.lower, method) end -function _calculate_tight_M(func::JuMP.AffExpr, ::_MOI.Nonpositives, method::BigM) +function _calculate_tight_M(func::AffExpr, ::_MOI.Nonpositives, method::BigM) return _interval_arithmetic_LessThan(func, 0.0, method) end -function _calculate_tight_M(func::JuMP.AffExpr, ::_MOI.Nonnegatives, method::BigM) +function _calculate_tight_M(func::AffExpr, ::_MOI.Nonnegatives, method::BigM) return _interval_arithmetic_GreaterThan(func, 0.0, method) end -function _calculate_tight_M(func::JuMP.AffExpr, set::_MOI.Interval, method::BigM) +function _calculate_tight_M(func::AffExpr, set::_MOI.Interval, method::BigM) return ( _interval_arithmetic_GreaterThan(func, -set.lower, method), _interval_arithmetic_LessThan(func, -set.upper, method) ) end -function _calculate_tight_M(func::JuMP.AffExpr, set::_MOI.EqualTo, method::BigM) +function _calculate_tight_M(func::AffExpr, set::_MOI.EqualTo, method::BigM) return ( _interval_arithmetic_GreaterThan(func, -set.value, method), _interval_arithmetic_LessThan(func, -set.value, method) ) end -function _calculate_tight_M(func::JuMP.AffExpr, ::_MOI.Zeros, method::BigM) +function _calculate_tight_M(func::AffExpr, ::_MOI.Zeros, method::BigM) return ( _interval_arithmetic_GreaterThan(func, 0.0, method), _interval_arithmetic_LessThan(func, 0.0, method) ) end # fallbacks for other scalar constraints -_calculate_tight_M(func::Union{JuMP.QuadExpr, JuMP.NonlinearExpr}, set::Union{_MOI.Interval, _MOI.EqualTo, _MOI.Zeros}, method::BigM) = (Inf, Inf) -_calculate_tight_M(func::Union{JuMP.QuadExpr, JuMP.NonlinearExpr}, set::Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.Nonnegatives, _MOI.Nonpositives}, method::BigM) = Inf +_calculate_tight_M(func::Union{QuadExpr, NonlinearExpr}, set::Union{_MOI.Interval, _MOI.EqualTo, _MOI.Zeros}, method::BigM) = (Inf, Inf) +_calculate_tight_M(func::Union{QuadExpr, NonlinearExpr}, set::Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.Nonnegatives, _MOI.Nonpositives}, method::BigM) = Inf _calculate_tight_M(func, set, method::BigM) = error("BigM method not implemented for constraint type $(typeof(func)) in $(typeof(set))") # get variable bounds for interval arithmetic -function _update_variable_bounds(vref::JuMP.VariableRef, method::BigM) - if JuMP.is_binary(vref) +function _update_variable_bounds(vref::VariableRef, method::BigM) + if is_binary(vref) lb = 0 - elseif !JuMP.has_lower_bound(vref) + elseif !has_lower_bound(vref) lb = -Inf else - lb = JuMP.lower_bound(vref) + lb = lower_bound(vref) end - if JuMP.is_binary(vref) + if is_binary(vref) ub = 1 - elseif !JuMP.has_upper_bound(vref) + elseif !has_upper_bound(vref) ub = Inf else - ub = JuMP.upper_bound(vref) + ub = upper_bound(vref) end return lb, ub end # perform interval arithmetic to update the initial M value -function _interval_arithmetic_LessThan(func::JuMP.AffExpr, M::Float64, method::BigM) +function _interval_arithmetic_LessThan(func::AffExpr, M::Float64, method::BigM) for (var,coeff) in func.terms - JuMP.is_binary(var) && continue #skip binary variables + is_binary(var) && continue #skip binary variables if coeff > 0 M += coeff*method.variable_bounds[var][2] else @@ -103,9 +103,9 @@ function _interval_arithmetic_LessThan(func::JuMP.AffExpr, M::Float64, method::B end return M + func.constant end -function _interval_arithmetic_GreaterThan(func::JuMP.AffExpr, M::Float64, method::BigM) +function _interval_arithmetic_GreaterThan(func::AffExpr, M::Float64, method::BigM) for (var,coeff) in func.terms - JuMP.is_binary(var) && continue #skip binary variables + is_binary(var) && continue #skip binary variables if coeff < 0 M += coeff*method.variable_bounds[var][2] else @@ -119,81 +119,81 @@ end # BIG-M REFORMULATION ################################################################################ function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::BigM ) where {T, S <: _MOI.LessThan} M = _get_M_value(con.func, con.set, method) - new_func = JuMP.@expression(model, con.func - M*(1-bvref)) - reform_con = JuMP.build_constraint(error, new_func, con.set) + new_func = @expression(model, con.func - M*(1-bvref)) + reform_con = build_constraint(error, new_func, con.set) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S, R}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S, R}, + bvref::VariableRef, method::BigM ) where {T, S <: _MOI.Nonpositives, R} M = [_get_M_value(func, con.set, method) for func in con.func] - new_func = JuMP.@expression(model, [i=1:con.set.dimension], + new_func = @expression(model, [i=1:con.set.dimension], con.func[i] - M[i]*(1-bvref) ) - reform_con = JuMP.build_constraint(error, new_func, con.set) + reform_con = build_constraint(error, new_func, con.set) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::BigM ) where {T, S <: _MOI.GreaterThan} M = _get_M_value(con.func, con.set, method) - new_func = JuMP.@expression(model, con.func + M*(1-bvref)) - reform_con = JuMP.build_constraint(error, new_func, con.set) + new_func = @expression(model, con.func + M*(1-bvref)) + reform_con = build_constraint(error, new_func, con.set) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S, R}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S, R}, + bvref::VariableRef, method::BigM ) where {T, S <: _MOI.Nonnegatives, R} M = [_get_M_value(func, con.set, method) for func in con.func] - new_func = JuMP.@expression(model, [i=1:con.set.dimension], + new_func = @expression(model, [i=1:con.set.dimension], con.func[i] + M[i]*(1-bvref) ) - reform_con = JuMP.build_constraint(error, new_func, con.set) + reform_con = build_constraint(error, new_func, con.set) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::BigM ) where {T, S <: Union{_MOI.Interval, _MOI.EqualTo}} M = _get_M_value(con.func, con.set, method) - new_func_gt = JuMP.@expression(model, con.func + M[1]*(1-bvref)) - new_func_lt = JuMP.@expression(model, con.func - M[2]*(1-bvref)) + new_func_gt = @expression(model, con.func + M[1]*(1-bvref)) + new_func_lt = @expression(model, con.func - M[2]*(1-bvref)) set_values = _set_values(con.set) - reform_con_gt = JuMP.build_constraint(error, new_func_gt, _MOI.GreaterThan(set_values[1])) - reform_con_lt = JuMP.build_constraint(error, new_func_lt, _MOI.LessThan(set_values[2])) + reform_con_gt = build_constraint(error, new_func_gt, _MOI.GreaterThan(set_values[1])) + reform_con_lt = build_constraint(error, new_func_lt, _MOI.LessThan(set_values[2])) return [reform_con_gt, reform_con_lt] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S, R}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S, R}, + bvref::VariableRef, method::BigM ) where {T, S <: _MOI.Zeros, R} M = [_get_M_value(func, con.set, method) for func in con.func] - new_func_nn = JuMP.@expression(model, [i=1:con.set.dimension], + new_func_nn = @expression(model, [i=1:con.set.dimension], con.func[i] + M[i][1]*(1-bvref) ) - new_func_np = JuMP.@expression(model, [i=1:con.set.dimension], + new_func_np = @expression(model, [i=1:con.set.dimension], con.func[i] - M[i][2]*(1-bvref) ) - reform_con_nn = JuMP.build_constraint(error, new_func_nn, _MOI.Nonnegatives(con.set.dimension)) - reform_con_np = JuMP.build_constraint(error, new_func_np, _MOI.Nonpositives(con.set.dimension)) + reform_con_nn = build_constraint(error, new_func_nn, _MOI.Nonnegatives(con.set.dimension)) + reform_con_np = build_constraint(error, new_func_np, _MOI.Nonpositives(con.set.dimension)) return [reform_con_nn, reform_con_np] end \ No newline at end of file diff --git a/src/constraints.jl b/src/constraints.jl index 1c8941f..7510baf 100644 --- a/src/constraints.jl +++ b/src/constraints.jl @@ -45,17 +45,17 @@ for (RefType, loc) in ((:DisjunctConstraintRef, :disjunct_constraints), JuMP.index(cref::$RefType) = cref.index @doc """ - JuMP.is_valid(model::JuMP.Model, cref::$($RefType)) + JuMP.is_valid(model::Model, cref::$($RefType)) Return `true` if `cref` refers to a valid constraint in the `GDP model`. """ - function JuMP.is_valid(model::JuMP.Model, cref::$RefType) # TODO: generalize for AbstractModel - return model === JuMP.owner_model(cref) + function JuMP.is_valid(model::Model, cref::$RefType) # TODO: generalize for AbstractModel + return model === owner_model(cref) end # Get the ConstraintData object function _constraint_data(cref::$RefType) - return gdp_data(JuMP.owner_model(cref)).$loc[JuMP.index(cref)] + return gdp_data(owner_model(cref)).$loc[index(cref)] end @doc """ @@ -74,7 +74,7 @@ for (RefType, loc) in ((:DisjunctConstraintRef, :disjunct_constraints), """ function JuMP.set_name(cref::$RefType, name::String) _constraint_data(cref).name = name - _set_ready_to_optimize(JuMP.owner_model(cref), false) + _set_ready_to_optimize(owner_model(cref), false) return end @@ -94,25 +94,25 @@ for (RefType, loc) in ((:DisjunctConstraintRef, :disjunct_constraints), end Base.copy(cref::$RefType) = cref @doc """ - Base.getindex(map::JuMP.GenericReferenceMap, cref::$($RefType)) + Base.getindex(map::GenericReferenceMap, cref::$($RefType)) ... """ - function Base.getindex(map::JuMP.ReferenceMap, cref::$RefType) - $RefType(map.model, JuMP.index(cref)) + function Base.getindex(map::ReferenceMap, cref::$RefType) + $RefType(map.model, index(cref)) end end end # Extend delete """ - JuMP.delete(model::JuMP.Model, cref::DisjunctionRef) + JuMP.delete(model::Model, cref::DisjunctionRef) Delete a disjunction constraint from the `GDP model`. """ -function JuMP.delete(model::JuMP.Model, cref::DisjunctionRef) - @assert JuMP.is_valid(model, cref) "Disjunctive constraint does not belong to model." - cidx = JuMP.index(cref) +function JuMP.delete(model::Model, cref::DisjunctionRef) + @assert is_valid(model, cref) "Disjunctive constraint does not belong to model." + cidx = index(cref) dict = _disjunctions(model) delete!(dict, cidx) _set_ready_to_optimize(model, false) @@ -120,13 +120,13 @@ function JuMP.delete(model::JuMP.Model, cref::DisjunctionRef) end """ - JuMP.delete(model::JuMP.Model, cref::DisjunctConstraintRef) + JuMP.delete(model::Model, cref::DisjunctConstraintRef) Delete a disjunct constraint from the `GDP model`. """ -function JuMP.delete(model::JuMP.Model, cref::DisjunctConstraintRef) - @assert JuMP.is_valid(model, cref) "Disjunctive constraint does not belong to model." - cidx = JuMP.index(cref) +function JuMP.delete(model::Model, cref::DisjunctConstraintRef) + @assert is_valid(model, cref) "Disjunctive constraint does not belong to model." + cidx = index(cref) dict = _disjunct_constraints(model) delete!(dict, cidx) _set_ready_to_optimize(model, false) @@ -134,13 +134,13 @@ function JuMP.delete(model::JuMP.Model, cref::DisjunctConstraintRef) end """ - JuMP.delete(model::JuMP.Model, cref::LogicalConstraintRef) + JuMP.delete(model::Model, cref::LogicalConstraintRef) Delete a logical constraint from the `GDP model`. """ -function JuMP.delete(model::JuMP.Model, cref::LogicalConstraintRef) - @assert JuMP.is_valid(model, cref) "Logical constraint does not belong to model." - cidx = JuMP.index(cref) +function JuMP.delete(model::Model, cref::LogicalConstraintRef) + @assert is_valid(model, cref) "Logical constraint does not belong to model." + cidx = index(cref) dict = _logical_constraints(model) delete!(dict, cidx) _set_ready_to_optimize(model, false) @@ -151,9 +151,9 @@ end # Disjunct Constraints ################################################################################ function _check_expression(expr) - vars = Set{JuMP.VariableRef}() + vars = Set{VariableRef}() _interrogate_variables(v -> push!(vars, v), expr) - if any(JuMP.is_binary.(vars)) || any(JuMP.is_integer.(vars)) + if any(is_binary.(vars)) || any(is_integer.(vars)) error("Disjunct constraints cannot contain binary or integer variables.") end return @@ -163,29 +163,29 @@ end _error::Function, func, set::_MOI.AbstractScalarSet, - tag::DisjunctConstraint + tag::Disjunct )::_DisjunctConstraint Extend `JuMP.build_constraint` to add constraints to disjuncts. This in combination with `JuMP.add_constraint` enables the use of `@constraint(model, [name], constr_expr, tag)`, where tag is a -`DisjunctConstraint(::Type{LogicalVariableRef})`. The user must specify the +`Disjunct(::Type{LogicalVariableRef})`. The user must specify the `LogicalVariable` to use as the indicator for the `_DisjunctConstraint` being created. """ function JuMP.build_constraint( _error::Function, func, set::_MOI.AbstractScalarSet, - tag::DisjunctConstraint + tag::Disjunct ) _check_expression(func) - constr = JuMP.build_constraint(_error, func, set) + constr = build_constraint(_error, func, set) return _DisjunctConstraint(constr, tag.indicator) end # Allows for building DisjunctConstraints for VectorConstraints since these get parsed differently by JuMP (JuMP changes the set to a MOI.AbstractScalarSet) for SetType in ( - JuMP.Nonnegatives, JuMP.Nonpositives, JuMP.Zeros, + Nonnegatives, Nonpositives, Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.Zeros ) @eval begin @@ -194,7 +194,7 @@ for SetType in ( _error::Function, func, set::$($SetType), - tag::DisjunctConstraint + tag::Disjunct )::_DisjunctConstraint Extend `JuMP.build_constraint` to add `VectorConstraint`s to disjuncts. @@ -203,10 +203,10 @@ for SetType in ( _error::Function, func, set::$SetType, - tag::DisjunctConstraint + tag::Disjunct ) _check_expression(func) - constr = JuMP.build_constraint(_error, func, set) + constr = build_constraint(_error, func, set) return _DisjunctConstraint(constr, tag.indicator) end end @@ -215,30 +215,30 @@ end # Allow intervals to handle tags function JuMP.build_constraint( _error::Function, - func::JuMP.AbstractJuMPScalar, + func::AbstractJuMPScalar, lb::Real, ub::Real, - tag::DisjunctConstraint + tag::Disjunct ) _check_expression(func) - constr = JuMP.build_constraint(_error, func, lb, ub) - func = JuMP.jump_function(constr) - set = JuMP.moi_set(constr) - return JuMP.build_constraint(_error, func, set, tag) + constr = build_constraint(_error, func, lb, ub) + func = jump_function(constr) + set = moi_set(constr) + return build_constraint(_error, func, set, tag) end """ JuMP.add_constraint( - model::JuMP.Model, + model::Model, con::_DisjunctConstraint, name::String = "" )::DisjunctConstraintRef -Extend `JuMP.add_constraint` to add a [`_DisjunctConstraint`](@ref) to a [`GDPModel`](@ref). +Extend `JuMP.add_constraint` to add a [`Disjunct`](@ref) to a [`GDPModel`](@ref). The constraint is added to the `GDPData` in the `.ext` dictionary of the `GDPModel`. """ function JuMP.add_constraint( - model::JuMP.Model, + model::Model, con::_DisjunctConstraint, name::String = "" ) @@ -257,8 +257,8 @@ function _add_indicator_var( con::_DisjunctConstraint{C, LogicalVariableRef}, cref, model - ) where {C <: JuMP.AbstractConstraint} - JuMP.is_valid(model, con.lvref) || error("Logical variable belongs to a different model.") + ) where {C <: AbstractConstraint} + is_valid(model, con.lvref) || error("Logical variable belongs to a different model.") if !haskey(_indicator_to_constraints(model), con.lvref) _indicator_to_constraints(model)[con.lvref] = Vector{Union{DisjunctConstraintRef, DisjunctionRef}}() end @@ -266,10 +266,10 @@ function _add_indicator_var( return end # check disjunction -function _check_disjunction(_error, lvrefs::AbstractVector{LogicalVariableRef}, model::JuMP.Model) +function _check_disjunction(_error, lvrefs::AbstractVector{LogicalVariableRef}, model::Model) isequal(unique(lvrefs),lvrefs) || _error("Not all the logical indicator variables are unique.") for lvref in lvrefs - if !JuMP.is_valid(model, lvref) + if !is_valid(model, lvref) _error("`$lvref` is not a valid logical variable reference.") end end @@ -277,14 +277,14 @@ function _check_disjunction(_error, lvrefs::AbstractVector{LogicalVariableRef}, end # fallback -function _check_disjunction(_error, lvrefs, model::JuMP.Model) +function _check_disjunction(_error, lvrefs, model::Model) _error("Unrecognized disjunction input structure.") # TODO add details on proper syntax end # Write the main function for creating disjunctions that is macro friendly function _create_disjunction( _error::Function, - model::JuMP.Model, # TODO: generalize to AbstractModel + model::Model, # TODO: generalize to AbstractModel structure::AbstractVector, #generalize for containers name::String, nested::Bool @@ -306,7 +306,7 @@ end # Disjunction build for unnested disjunctions function _disjunction( _error::Function, - model::JuMP.Model, # TODO: generalize to AbstractModel + model::Model, # TODO: generalize to AbstractModel structure::AbstractVector, #generalize for containers name::String ) @@ -316,7 +316,7 @@ end # Fallback disjunction build for nonvector structure function _disjunction( _error::Function, - model::JuMP.Model, # TODO: generalize to AbstractModel + model::Model, # TODO: generalize to AbstractModel structure, name::String ) @@ -326,13 +326,13 @@ end # Disjunction build for nested disjunctions function _disjunction( _error::Function, - model::JuMP.Model, # TODO: generalize to AbstractModel + model::Model, # TODO: generalize to AbstractModel structure, name::String, - tag::DisjunctConstraint + tag::Disjunct ) dref = _create_disjunction(_error, model, structure, name, true) - obj = JuMP.constraint_object(dref) + obj = constraint_object(dref) _add_indicator_var(_DisjunctConstraint(obj, tag.indicator), dref, model) return dref end @@ -340,7 +340,7 @@ end # General fallback for additional arguments function _disjunction( _error::Function, - model::JuMP.Model, # TODO: generalize to AbstractModel + model::Model, # TODO: generalize to AbstractModel structure, name::String, extra... @@ -352,7 +352,7 @@ end """ disjunction( - model::JuMP.Model, + model::Model, disjunct_indicators::Vector{LogicalVariableRef} name::String = "" ) @@ -360,26 +360,26 @@ end Function to add a [`Disjunction`](@ref) to a [`GDPModel`](@ref). disjunction( - model::JuMP.Model, + model::Model, disjunct_indicators::Vector{LogicalVariableRef}, - nested_tag::DisjunctConstraint, + nested_tag::Disjunct, name::String = "" ) Function to add a nested [`Disjunction`](@ref) to a [`GDPModel`](@ref). """ function disjunction( - model::JuMP.Model, + model::Model, disjunct_indicators, name::String = "" ) # TODO add kw argument to build exactly 1 constraint return _disjunction(error, model, disjunct_indicators, name) end function disjunction( - model::JuMP.Model, + model::Model, disjunct_indicators, - nested_tag::DisjunctConstraint, - name::String = "", + nested_tag::Disjunct, + name::String = "" ) # TODO add kw argument to build exactly 1 constraint return _disjunction(error, model, disjunct_indicators, name, nested_tag) end @@ -417,10 +417,11 @@ cardinality sets: `AtLeast(n)`, `AtMost(n)`, or `Exactly(n)`. To select exactly 1 logical variable `Y` to be `true`, do (the same can be done with `AtLeast(n)` and `AtMost(n)`): -```jldoctest -julia> model = GDPModel(); -julia> @variable(model, Y[i = 1:2], LogicalVariable); -julia> @constraint(model, [Y[1], Y[2]] in Exactly(1)); +```julia +using DisjunctiveProgramming +model = GDPModel(); +@variable(model, Y[i = 1:2], LogicalVariable); +@constraint(model, [Y[1], Y[2]] in Exactly(1)); ``` JuMP.build_constraint( @@ -441,7 +442,7 @@ function JuMP.build_constraint( # Cardinality logical constraint ) where {T <: LogicalVariableRef, S <: Union{Exactly, AtLeast, AtMost}} new_set = _jump_to_moi_selector(set)(length(func) + 1) new_func = Union{Number,LogicalVariableRef}[set.value, func...] - return JuMP.VectorConstraint(new_func, new_set) + return VectorConstraint(new_func, new_set) end function JuMP.build_constraint( # Cardinality logical constraint _error::Function, @@ -460,7 +461,7 @@ function JuMP.build_constraint( if !(func.head in _LogicalOperatorHeads) _error("Unrecognized logical operator `$(func.head)`.") else - return JuMP.ScalarConstraint(func, set) + return ScalarConstraint(func, set) end end @@ -479,7 +480,7 @@ end # Fallback for Affine/Quad expressions function JuMP.build_constraint( _error::Function, - expr::Union{JuMP.GenericAffExpr{C, LogicalVariableRef}, JuMP.GenericQuadExpr{C, LogicalVariableRef}}, + expr::Union{GenericAffExpr{C, LogicalVariableRef}, GenericQuadExpr{C, LogicalVariableRef}}, set::_MOI.AbstractScalarSet ) where {C} _error("Cannot add, subtract, or multiply with logical variables.") @@ -496,8 +497,8 @@ end """ function JuMP.add_constraint( - model::JuMP.Model, - c::JuMP.ScalarConstraint{<:F, S}, + model::Model, + c::ScalarConstraint{<:F, S}, name::String = "" ) where {F <: Union{LogicalVariableRef, _LogicalExpr}, S} @@ -505,8 +506,8 @@ Extend `JuMP.add_constraint` to allow creating logical proposition constraints for a [`GDPModel`](@ref) with the `@constraint` macro. function JuMP.add_constraint( - model::JuMP.Model, - c::JuMP.VectorConstraint{<:F, S, Shape}, + model::Model, + c::VectorConstraint{<:F, S, Shape}, name::String = "" ) where {F <: Union{Number, LogicalVariableRef, _LogicalExpr}, S, Shape} @@ -514,24 +515,24 @@ Extend `JuMP.add_constraint` to allow creating logical cardinality constraints for a [`GDPModel`](@ref) with the `@constraint` macro. """ function JuMP.add_constraint( - model::JuMP.Model, - c::JuMP.ScalarConstraint{F, S}, + model::Model, + c::ScalarConstraint{F, S}, name::String = "" ) where {F <: Union{LogicalVariableRef, _LogicalExpr}, S <: IsTrue} is_gdp_model(model) || error("Can only add logical constraints to `GDPModel`s.") - @assert all(JuMP.is_valid.(model, _get_constraint_variables(model, c))) "Constraint variables do not belong to model." + @assert all(is_valid.(model, _get_constraint_variables(model, c))) "Constraint variables do not belong to model." constr_data = ConstraintData(c, name) idx = _MOIUC.add_item(_logical_constraints(model), constr_data) _set_ready_to_optimize(model, false) return LogicalConstraintRef(model, idx) end function JuMP.add_constraint( - model::JuMP.Model, - c::JuMP.VectorConstraint{F, S, Shape}, + model::Model, + c::VectorConstraint{F, S, Shape}, name::String = "" ) where {F, S <: Union{_MOIAtLeast, _MOIAtMost, _MOIExactly}, Shape} is_gdp_model(model) || error("Can only add logical constraints to `GDPModel`s.") - @assert all(JuMP.is_valid.(model, _get_constraint_variables(model, c))) "Constraint variables do not belong to model." + @assert all(is_valid.(model, _get_constraint_variables(model, c))) "Constraint variables do not belong to model." constr_data = ConstraintData(c, name) idx = _MOIUC.add_item(_logical_constraints(model), constr_data) _set_ready_to_optimize(model, false) diff --git a/src/datatypes.jl b/src/datatypes.jl index a51d6f6..268b6fc 100644 --- a/src/datatypes.jl +++ b/src/datatypes.jl @@ -3,7 +3,7 @@ ################################################################################ """ - LogicalVariable <: JuMP.AbstractVariable + LogicalVariable <: AbstractVariable A variable type the logical variables associated with disjuncts in a [`Disjunction`](@ref). @@ -11,11 +11,13 @@ A variable type the logical variables associated with disjuncts in a [`Disjuncti - `fix_value::Union{Nothing, Bool}`: A fixed boolean value if there is one. - `start_value::Union{Nothing, Bool}`: An initial guess if there is one. """ -struct LogicalVariable <: JuMP.AbstractVariable +struct LogicalVariable <: AbstractVariable fix_value::Union{Nothing, Bool} start_value::Union{Nothing, Bool} end +const Logical = LogicalVariable + """ LogicalVariableData @@ -48,8 +50,8 @@ end A type for looking up logical variables. """ -struct LogicalVariableRef <: JuMP.AbstractVariableRef - model::JuMP.Model # TODO: generalize for AbstractModels +struct LogicalVariableRef <: AbstractVariableRef + model::Model # TODO: generalize for AbstractModels index::LogicalVariableIndex end @@ -97,29 +99,29 @@ end # Create our own JuMP level sets to infer the dimension using the expression """ - AtLeast{T<:Union{Int,LogicalVariableRef}} <: JuMP.AbstractVectorSet + AtLeast{T<:Union{Int,LogicalVariableRef}} <: AbstractVectorSet Convenient alias for using [`_MOIAtLeast`](@ref). """ -struct AtLeast{T<:Union{Int,LogicalVariableRef}} <: JuMP.AbstractVectorSet +struct AtLeast{T<:Union{Int,LogicalVariableRef}} <: AbstractVectorSet value::T end """ - AtMost{T<:Union{Int,LogicalVariableRef}} <: JuMP.AbstractVectorSet + AtMost{T<:Union{Int,LogicalVariableRef}} <: AbstractVectorSet Convenient alias for using [`_MOIAtMost`](@ref). """ -struct AtMost{T<:Union{Int,LogicalVariableRef}} <: JuMP.AbstractVectorSet +struct AtMost{T<:Union{Int,LogicalVariableRef}} <: AbstractVectorSet value::T end """ - Exactly <: JuMP.AbstractVectorSet + Exactly <: AbstractVectorSet Convenient alias for using [`_MOIExactly`](@ref). """ -struct Exactly{T<:Union{Int,LogicalVariableRef}} <: JuMP.AbstractVectorSet +struct Exactly{T<:Union{Int,LogicalVariableRef}} <: AbstractVectorSet value::T end @@ -131,10 +133,10 @@ JuMP.moi_set(set::Exactly, dim::Int) = _MOIExactly(dim) ################################################################################ # LOGICAL CONSTRAINTS ################################################################################ -const _LogicalExpr = JuMP.GenericNonlinearExpr{LogicalVariableRef} +const _LogicalExpr = GenericNonlinearExpr{LogicalVariableRef} """ - ConstraintData{C <: JuMP.AbstractConstraint} + ConstraintData{C <: AbstractConstraint} A type for storing constraint objects in [`GDPData`](@ref) and any meta-data they possess. @@ -143,7 +145,7 @@ they possess. - `constraint::C`: The constraint. - `name::String`: The name of the proposition. """ -mutable struct ConstraintData{C <: JuMP.AbstractConstraint} +mutable struct ConstraintData{C <: AbstractConstraint} constraint::C name::String end @@ -166,7 +168,7 @@ end A type for looking up logical constraints. """ struct LogicalConstraintRef - model::JuMP.Model # TODO: generalize for AbstractModels + model::Model # TODO: generalize for AbstractModels index::LogicalConstraintIndex end @@ -174,25 +176,25 @@ end # DISJUNCT CONSTRAINTS ################################################################################ """ - DisjunctConstraint + Disjunct Used as a tag for constraints that will be used in disjunctions. This is done via the following syntax: ```julia-repl -julia> @constraint(model, [constr_expr], DisjunctConstraint) +julia> @constraint(model, [constr_expr], Disjunct) -julia> @constraint(model, [constr_expr], DisjunctConstraint(lvref)) +julia> @constraint(model, [constr_expr], Disjunct(lvref)) ``` where `lvref` is a [`LogicalVariableRef`](@ref) that will ultimately be associated with the disjunct the constraint is added to. If no `lvref` is given, then one is generated when the disjunction is created. """ -struct DisjunctConstraint +struct Disjunct indicator::LogicalVariableRef end # Create internal type for temporarily packaging constraints for disjuncts -struct _DisjunctConstraint{C <: JuMP.AbstractConstraint, L <: LogicalVariableRef} +struct _DisjunctConstraint{C <: AbstractConstraint, L <: LogicalVariableRef} constr::C lvref::L end @@ -200,7 +202,7 @@ end """ DisjunctConstraintIndex -A type for storing the index of a [`DisjunctConstraint`](@ref). +A type for storing the index of a [`Disjunct`](@ref). **Fields** - `value::Int64`: The index value. @@ -215,7 +217,7 @@ end A type for looking up disjunctive constraints. """ struct DisjunctConstraintRef - model::JuMP.Model # TODO: generalize for AbstractModels + model::Model # TODO: generalize for AbstractModels index::DisjunctConstraintIndex end @@ -223,7 +225,7 @@ end # DISJUNCTIONS ################################################################################ """ - Disjunction <: JuMP.AbstractConstraint + Disjunction <: AbstractConstraint A type for a disjunctive constraint that is comprised of a collection of disjuncts of indicated by a unique [`LogicalVariableRef`](@ref). @@ -233,7 +235,7 @@ disjuncts of indicated by a unique [`LogicalVariableRef`](@ref). (indicators) that uniquely identify each disjunct in the disjunction. - `nested::Bool`: Is this disjunction nested within another disjunction? """ -struct Disjunction <: JuMP.AbstractConstraint +struct Disjunction <: AbstractConstraint indicators::Vector{LogicalVariableRef} nested::Bool end @@ -256,7 +258,7 @@ end A type for looking up disjunctive constraints. """ struct DisjunctionRef - model::JuMP.Model # TODO: generalize for AbstractModels + model::Model # TODO: generalize for AbstractModels index::DisjunctionIndex end @@ -323,9 +325,9 @@ A type for using the big-M reformulation approach for disjunctive constraints. struct BigM <: AbstractReformulationMethod value::Float64 tighten::Bool - variable_bounds::Dict{JuMP.VariableRef, Tuple{Float64, Float64}} # TODO support other number types? + variable_bounds::Dict{VariableRef, Tuple{Float64, Float64}} # TODO support other number types? function BigM(val = 1e9, tight = true) - new(val, tight, Dict{JuMP.VariableRef, Tuple{Float64, Float64}}()) + new(val, tight, Dict{VariableRef, Tuple{Float64, Float64}}()) end end # TODO add fields if needed @@ -340,11 +342,11 @@ constraints. """ struct Hull <: AbstractReformulationMethod # TODO add fields if needed value::Float64 - variable_bounds::Dict{JuMP.VariableRef, Tuple{Float64, Float64}} # TODO support other number types? + variable_bounds::Dict{VariableRef, Tuple{Float64, Float64}} # TODO support other number types? function Hull(ϵ::Float64 = 1e-6) - new(ϵ, Dict{JuMP.VariableRef, Tuple{Float64, Float64}}()) + new(ϵ, Dict{VariableRef, Tuple{Float64, Float64}}()) end - function Hull(ϵ::Float64, v_bounds::Dict{JuMP.VariableRef, Tuple{Float64, Float64}}) + function Hull(ϵ::Float64, v_bounds::Dict{VariableRef, Tuple{Float64, Float64}}) new(ϵ, v_bounds) end end @@ -353,15 +355,15 @@ end # temp struct to store variable disaggregations (reset for each disjunction) mutable struct _Hull <: AbstractReformulationMethod value::Float64 - variable_bounds::Dict{JuMP.VariableRef, Tuple{Float64, Float64}} # TODO support other number types? - disjunction_variables::Dict{JuMP.VariableRef, Vector{JuMP.VariableRef}} - disjunct_variables::Dict{Tuple{JuMP.VariableRef,JuMP.VariableRef}, JuMP.VariableRef} - function _Hull(method::Hull, vrefs::Set{JuMP.VariableRef}) + variable_bounds::Dict{VariableRef, Tuple{Float64, Float64}} # TODO support other number types? + disjunction_variables::Dict{VariableRef, Vector{VariableRef}} + disjunct_variables::Dict{Tuple{VariableRef,VariableRef}, VariableRef} + function _Hull(method::Hull, vrefs::Set{VariableRef}) new( method.value, method.variable_bounds, - Dict{JuMP.VariableRef, Vector{JuMP.VariableRef}}(vref => Vector{JuMP.VariableRef}() for vref in vrefs), - Dict{Tuple{JuMP.VariableRef,JuMP.VariableRef}, JuMP.VariableRef}() + Dict{VariableRef, Vector{VariableRef}}(vref => Vector{VariableRef}() for vref in vrefs), + Dict{Tuple{VariableRef,VariableRef}, VariableRef}() ) end end @@ -416,12 +418,12 @@ mutable struct GDPData disjunctions::_MOIUC.CleverDict{DisjunctionIndex, ConstraintData{Disjunction}} # Indicator variable mappings - indicator_to_binary::Dict{LogicalVariableRef, JuMP.VariableRef} + indicator_to_binary::Dict{LogicalVariableRef, VariableRef} indicator_to_constraints::Dict{LogicalVariableRef, Vector{Union{DisjunctConstraintRef, DisjunctionRef}}} # Reformulation variables and constraints - reformulation_variables::Vector{JuMP.VariableRef} - reformulation_constraints::Vector{JuMP.ConstraintRef} + reformulation_variables::Vector{VariableRef} + reformulation_constraints::Vector{ConstraintRef} # Solution data solution_method::Union{Nothing, AbstractSolutionMethod} @@ -433,10 +435,10 @@ mutable struct GDPData _MOIUC.CleverDict{LogicalConstraintIndex, ConstraintData}(), _MOIUC.CleverDict{DisjunctConstraintIndex, ConstraintData}(), _MOIUC.CleverDict{DisjunctionIndex, ConstraintData{Disjunction}}(), - Dict{LogicalVariableRef, JuMP.VariableRef}(), + Dict{LogicalVariableRef, VariableRef}(), Dict{LogicalVariableRef, Vector{Union{DisjunctConstraintRef, DisjunctionRef}}}(), - Vector{JuMP.VariableRef}(), - Vector{JuMP.ConstraintRef}(), + Vector{VariableRef}(), + Vector{ConstraintRef}(), nothing, false, ) diff --git a/src/hull.jl b/src/hull.jl index a80acd1..7229b4e 100644 --- a/src/hull.jl +++ b/src/hull.jl @@ -1,49 +1,43 @@ ################################################################################ # VARIABLE DISAGGREGATION ################################################################################ -function _update_variable_bounds(vref::JuMP.VariableRef, method::Hull) - if JuMP.is_binary(vref) #not used +function _update_variable_bounds(vref::VariableRef, method::Hull) + if is_binary(vref) #not used lb, ub = 0, 1 - elseif !JuMP.has_lower_bound(vref) || !JuMP.has_upper_bound(vref) + elseif !has_lower_bound(vref) || !has_upper_bound(vref) error("Variable $vref must have both lower and upper bounds defined when using the Hull reformulation.") else - lb = min(0, JuMP.lower_bound(vref)) - ub = max(0, JuMP.upper_bound(vref)) + lb = min(0, lower_bound(vref)) + ub = max(0, upper_bound(vref)) end return lb, ub end -function _disaggregate_variables(model::JuMP.Model, lvref::LogicalVariableRef, vrefs::Set{JuMP.VariableRef}, method::_Hull) +function _disaggregate_variables(model::Model, lvref::LogicalVariableRef, vrefs::Set{VariableRef}, method::_Hull) #create disaggregated variables for that disjunct for vref in vrefs - JuMP.is_binary(vref) && continue #skip binary variables + is_binary(vref) && continue #skip binary variables _disaggregate_variable(model, lvref, vref, method) #create disaggregated var for that disjunct end end -function _disaggregate_variable(model::JuMP.Model, lvref::LogicalVariableRef, vref::JuMP.VariableRef, method::_Hull) +function _disaggregate_variable(model::Model, lvref::LogicalVariableRef, vref::VariableRef, method::_Hull) #create disaggregated vref lb, ub = method.variable_bounds[vref] - dvref = JuMP.@variable(model, base_name = "$(vref)_$(lvref)", lower_bound = lb, upper_bound = ub) + dvref = @variable(model, base_name = "$(vref)_$(lvref)", lower_bound = lb, upper_bound = ub) push!(_reformulation_variables(model), dvref) #get binary indicator variable bvref = _indicator_to_binary(model)[lvref] #temp storage - if !haskey(method.disjunction_variables, vref) - method.disjunction_variables[vref] = Vector{JuMP.VariableRef}() + if !haskey(method.disjunction_variables, vref) #NOTE: not needed because _Hull disjunction_variables is initialized with all the variables in the disjunction + method.disjunction_variables[vref] = Vector{VariableRef}() end push!(method.disjunction_variables[vref], dvref) method.disjunct_variables[vref, bvref] = dvref #create bounding constraints - dvname = JuMP.name(dvref) + dvname = name(dvref) lbname = isempty(dvname) ? "" : "$(dvname)_lower_bound" ubname = isempty(dvname) ? "" : "$(dvname)_upper_bound" - new_con_lb_ref = JuMP.add_constraint(model, - JuMP.build_constraint(error, lb*bvref - dvref, _MOI.LessThan(0)), - lbname - ) - new_con_ub_ref = JuMP.add_constraint(model, - JuMP.build_constraint(error, dvref - ub*bvref, _MOI.LessThan(0)), - ubname - ) + new_con_lb_ref = @constraint(model, lb*bvref - dvref <= 0, base_name = lbname) + new_con_ub_ref = @constraint(model, dvref - ub*bvref <= 0, base_name = ubname) push!(_reformulation_constraints(model), new_con_lb_ref, new_con_ub_ref) return dvref end @@ -51,11 +45,11 @@ end ################################################################################ # VARIABLE AGGREGATION ################################################################################ -function _aggregate_variable(model::JuMP.Model, ref_cons::Vector{JuMP.AbstractConstraint}, vref::JuMP.VariableRef, method::_Hull) - JuMP.is_binary(vref) && return #skip binary variables - con_expr = JuMP.@expression(model, -vref + sum(method.disjunction_variables[vref])) +function _aggregate_variable(model::Model, ref_cons::Vector{AbstractConstraint}, vref::VariableRef, method::_Hull) + is_binary(vref) && return #skip binary variables + con_expr = @expression(model, -vref + sum(method.disjunction_variables[vref])) push!(ref_cons, - JuMP.build_constraint(error, con_expr, _MOI.EqualTo(0)) + build_constraint(error, con_expr, _MOI.EqualTo(0)) ) return end @@ -64,22 +58,22 @@ end # CONSTRAINT DISAGGREGATION ################################################################################ # variable -function _disaggregate_expression(model::JuMP.Model, vref::JuMP.VariableRef, bvref::JuMP.VariableRef, method::_Hull) - if JuMP.is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged - return vref +function _disaggregate_expression(model::Model, vref::VariableRef, bvref::VariableRef, method::_Hull) + if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged + return vref #NOTE: not needed because nested constraint of the form `vref in MOI.AbstractScalarSet` gets reformulated to an affine expression. else #replace with disaggregated form return method.disjunct_variables[vref, bvref] end end # affine expression -function _disaggregate_expression(model::JuMP.Model, aff::JuMP.AffExpr, bvref::JuMP.VariableRef, method::_Hull) - new_expr = JuMP.@expression(model, aff.constant*bvref) #multiply constant by binary indicator variable +function _disaggregate_expression(model::Model, aff::AffExpr, bvref::VariableRef, method::_Hull) + new_expr = @expression(model, aff.constant*bvref) #multiply constant by binary indicator variable for (vref, coeff) in aff.terms - if JuMP.is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged - JuMP.add_to_expression!(new_expr, coeff*vref) + if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged + add_to_expression!(new_expr, coeff*vref) else #replace other vars with disaggregated form dvref = method.disjunct_variables[vref, bvref] - JuMP.add_to_expression!(new_expr, coeff*dvref) + add_to_expression!(new_expr, coeff*dvref) end end return new_expr @@ -87,7 +81,7 @@ end # quadratic expression # TODO review what happens when there are bilinear terms with binary variables involved since these are not being disaggregated # (e.g., complementarity constraints; though likely irrelevant)... -function _disaggregate_expression(model::JuMP.Model, quad::JuMP.QuadExpr, bvref::JuMP.VariableRef, method::_Hull) +function _disaggregate_expression(model::Model, quad::QuadExpr, bvref::VariableRef, method::_Hull) #get affine part new_expr = _disaggregate_expression(model, quad.aff, bvref, method) #get nonlinear part @@ -100,32 +94,37 @@ function _disaggregate_expression(model::JuMP.Model, quad::JuMP.QuadExpr, bvref: return new_expr end # constant in NonlinearExpr -function _disaggregate_nl_expression(model::JuMP.Model, c::Number, ::JuMP.VariableRef, method::_Hull) +function _disaggregate_nl_expression(model::Model, c::Number, ::VariableRef, method::_Hull) return c end # variable in NonlinearExpr -function _disaggregate_nl_expression(model::JuMP.Model, vref::JuMP.VariableRef, bvref::JuMP.VariableRef, method::_Hull) +function _disaggregate_nl_expression(model::Model, vref::VariableRef, bvref::VariableRef, method::_Hull) ϵ = method.value - dvref = method.disjunct_variables[vref, bvref] - new_var = dvref / ((1-ϵ)*bvref+ϵ) - return new_var + if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged + dvref = vref + else #replace with disaggregated form + dvref = method.disjunct_variables[vref, bvref] + end + return dvref / ((1-ϵ)*bvref+ϵ) end # affine expression in NonlinearExpr -function _disaggregate_nl_expression(model::JuMP.Model, aff::JuMP.AffExpr, bvref::JuMP.VariableRef, method::_Hull) +function _disaggregate_nl_expression(model::Model, aff::AffExpr, bvref::VariableRef, method::_Hull) new_expr = aff.constant ϵ = method.value for (vref, coeff) in aff.terms - if JuMP.is_binary(vref) #keep any binary variables undisaggregated + if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged dvref = vref else #replace other vars with disaggregated form dvref = method.disjunct_variables[vref, bvref] end - new_expr += coeff * dvref / ((1-ϵ)*bvref+ϵ) + new_expr += coeff * dvref / ((1-ϵ)*bvref+ϵ) end return new_expr end # quadratic expression in NonlinearExpr -function _disaggregate_nl_expression(model::JuMP.Model, quad::JuMP.QuadExpr, bvref::JuMP.VariableRef, method::_Hull) +# TODO review what happens when there are bilinear terms with binary variables involved since these are not being disaggregated +# (e.g., complementarity constraints; though likely irrelevant)... +function _disaggregate_nl_expression(model::Model, quad::QuadExpr, bvref::VariableRef, method::_Hull) #get affine part new_expr = _disaggregate_nl_expression(model, quad.aff, bvref, method) #get quadratic part @@ -138,12 +137,12 @@ function _disaggregate_nl_expression(model::JuMP.Model, quad::JuMP.QuadExpr, bvr return new_expr end # nonlinear expression in NonlinearExpr -function _disaggregate_nl_expression(model::JuMP.Model, nlp::JuMP.NonlinearExpr, bvref::JuMP.VariableRef, method::_Hull) +function _disaggregate_nl_expression(model::Model, nlp::NonlinearExpr, bvref::VariableRef, method::_Hull) new_args = Vector{Any}(undef, length(nlp.args)) for (i,arg) in enumerate(nlp.args) new_args[i] = _disaggregate_nl_expression(model, arg, bvref, method) end - new_expr = JuMP.NonlinearExpr(nlp.head, new_args) + new_expr = NonlinearExpr(nlp.head, new_args) return new_expr end @@ -151,95 +150,95 @@ end # HULL REFORMULATION ################################################################################ function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::_Hull -) where {T <: Union{JuMP.VariableRef, JuMP.AffExpr, JuMP.QuadExpr}, S <: Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.EqualTo}} +) where {T <: Union{VariableRef, AffExpr, QuadExpr}, S <: Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.EqualTo}} new_func = _disaggregate_expression(model, con.func, bvref, method) set_value = _set_value(con.set) new_func -= set_value*bvref - reform_con = JuMP.build_constraint(error, new_func, S(0)) + reform_con = build_constraint(error, new_func, S(0)) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S, R}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S, R}, + bvref::VariableRef, method::_Hull -) where {T <: Union{JuMP.VariableRef, JuMP.AffExpr, JuMP.QuadExpr}, S <: Union{_MOI.Nonpositives, _MOI.Nonnegatives, _MOI.Zeros}, R} - new_func = JuMP.@expression(model, [i=1:con.set.dimension], +) where {T <: Union{VariableRef, AffExpr, QuadExpr}, S <: Union{_MOI.Nonpositives, _MOI.Nonnegatives, _MOI.Zeros}, R} + new_func = @expression(model, [i=1:con.set.dimension], _disaggregate_expression(model, con.func[i], bvref, method) ) - reform_con = JuMP.build_constraint(error, new_func, con.set) + reform_con = build_constraint(error, new_func, con.set) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::_Hull -) where {T <: JuMP.GenericNonlinearExpr, S <: Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.EqualTo}} +) where {T <: GenericNonlinearExpr, S <: Union{_MOI.LessThan, _MOI.GreaterThan, _MOI.EqualTo}} con_func = _disaggregate_nl_expression(model, con.func, bvref, method) - con_func0 = JuMP.value(v -> 0.0, con.func) + con_func0 = value(v -> 0.0, con.func) if isinf(con_func0) error("Operator `$(con.func.head)` is not defined at 0, causing the perspective function on the Hull reformulation to fail.") end ϵ = method.value set_value = _set_value(con.set) - new_func = JuMP.@expression(model, ((1-ϵ)*bvref+ϵ)*con_func - ϵ*(1-bvref)*con_func0 - set_value*bvref) - reform_con = JuMP.build_constraint(error, new_func, S(0)) + new_func = @expression(model, ((1-ϵ)*bvref+ϵ)*con_func - ϵ*(1-bvref)*con_func0 - set_value*bvref) + reform_con = build_constraint(error, new_func, S(0)) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S, R}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S, R}, + bvref::VariableRef, method::_Hull -) where {T <: JuMP.GenericNonlinearExpr, S <: Union{_MOI.Nonpositives, _MOI.Nonnegatives, _MOI.Zeros}, R} - con_func = JuMP.@expression(model, [i=1:con.set.dimension], +) where {T <: GenericNonlinearExpr, S <: Union{_MOI.Nonpositives, _MOI.Nonnegatives, _MOI.Zeros}, R} + con_func = @expression(model, [i=1:con.set.dimension], _disaggregate_nl_expression(model, con.func[i], bvref, method) ) - con_func0 = JuMP.value.(v -> 0.0, con.func) + con_func0 = value.(v -> 0.0, con.func) if any(isinf.(con_func0)) error("At least of of the operators `$([func.head for func in con.func])` is not defined at 0, causing the perspective function on the Hull reformulation to fail.") end ϵ = method.value - new_func = JuMP.@expression(model, [i=1:con.set.dimension], + new_func = @expression(model, [i=1:con.set.dimension], ((1-ϵ)*bvref+ϵ)*con_func[i] - ϵ*(1-bvref)*con_func0[i] ) - reform_con = JuMP.build_constraint(error, new_func, con.set) + reform_con = build_constraint(error, new_func, con.set) return [reform_con] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::_Hull -) where {T <: Union{JuMP.VariableRef, JuMP.AffExpr, JuMP.QuadExpr}, S <: _MOI.Interval} +) where {T <: Union{VariableRef, AffExpr, QuadExpr}, S <: _MOI.Interval} new_func = _disaggregate_expression(model, con.func, bvref, method) - new_func_gt = JuMP.@expression(model, new_func - con.set.lower*bvref) - new_func_lt = JuMP.@expression(model, new_func - con.set.upper*bvref) - reform_con_gt = JuMP.build_constraint(error, new_func_gt, _MOI.GreaterThan(0)) - reform_con_lt = JuMP.build_constraint(error, new_func_lt, _MOI.LessThan(0)) + new_func_gt = @expression(model, new_func - con.set.lower*bvref) + new_func_lt = @expression(model, new_func - con.set.upper*bvref) + reform_con_gt = build_constraint(error, new_func_gt, _MOI.GreaterThan(0)) + reform_con_lt = build_constraint(error, new_func_lt, _MOI.LessThan(0)) return [reform_con_gt, reform_con_lt] end function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::_Hull -) where {T <: JuMP.GenericNonlinearExpr, S <: _MOI.Interval} +) where {T <: GenericNonlinearExpr, S <: _MOI.Interval} con_func = _disaggregate_nl_expression(model, con.func, bvref, method) - con_func0 = JuMP.value(v -> 0.0, con.func) + con_func0 = value(v -> 0.0, con.func) if isinf(con_func0) error("Operator `$(con.func.head)` is not defined at 0, causing the perspective function on the Hull reformulation to fail.") end ϵ = method.value - new_func = JuMP.@expression(model, ((1-ϵ)*bvref+ϵ) * con_func - ϵ*(1-bvref)*con_func0) - new_func_gt = JuMP.@expression(model, new_func - con.set.lower*bvref) - new_func_lt = JuMP.@expression(model, new_func - con.set.upper*bvref) - reform_con_gt = JuMP.build_constraint(error, new_func_gt, _MOI.GreaterThan(0)) - reform_con_lt = JuMP.build_constraint(error, new_func_lt, _MOI.LessThan(0)) + new_func = @expression(model, ((1-ϵ)*bvref+ϵ) * con_func - ϵ*(1-bvref)*con_func0) + new_func_gt = @expression(model, new_func - con.set.lower*bvref) + new_func_lt = @expression(model, new_func - con.set.upper*bvref) + reform_con_gt = build_constraint(error, new_func_gt, _MOI.GreaterThan(0)) + reform_con_lt = build_constraint(error, new_func_lt, _MOI.LessThan(0)) return [reform_con_gt, reform_con_lt] end \ No newline at end of file diff --git a/src/indicator.jl b/src/indicator.jl index 2aabb13..d199827 100644 --- a/src/indicator.jl +++ b/src/indicator.jl @@ -3,32 +3,32 @@ ################################################################################ #scalar disjunct constraint function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.ScalarConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::ScalarConstraint{T, S}, + bvref::VariableRef, method::Indicator ) where {T, S} - reform_con = JuMP.build_constraint(error, [1*bvref, con.func], _MOI.Indicator{_MOI.ACTIVATE_ON_ONE}(con.set)) + reform_con = build_constraint(error, [1*bvref, con.func], _MOI.Indicator{_MOI.ACTIVATE_ON_ONE}(con.set)) return [reform_con] end #vectorized disjunct constraint function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S}, + bvref::VariableRef, method::Indicator ) where {T, S} set = _vec_to_scalar_set(con.set) return [ - JuMP.build_constraint(error, [1*bvref, f], _MOI.Indicator{_MOI.ACTIVATE_ON_ONE}(set)) + build_constraint(error, [1*bvref, f], _MOI.Indicator{_MOI.ACTIVATE_ON_ONE}(set)) for f in con.func ] end #nested indicator reformulation. NOTE: the user needs to provide the appropriate linking constraint for the logical variables for this to work (e.g. w in Exactly(y[1]) to link the parent disjunct y[1] to the nested disjunction w) function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.VectorConstraint{T, S}, - bvref::JuMP.VariableRef, + model::Model, + con::VectorConstraint{T, S}, + bvref::VariableRef, method::Indicator ) where {T, S <: _MOI.Indicator} return [con] diff --git a/src/logic.jl b/src/logic.jl index 56eb198..a902351 100644 --- a/src/logic.jl +++ b/src/logic.jl @@ -13,8 +13,8 @@ for (name, alt, head) in ( ) # make operators @eval begin - const $name = JuMP.NonlinearOperator((vs...) -> _op_fallback($(Meta.quot(name))), $(Meta.quot(head))) - const $alt = JuMP.NonlinearOperator((vs...) -> _op_fallback($(Meta.quot(alt))), $(Meta.quot(head))) + const $name = NonlinearOperator((vs...) -> _op_fallback($(Meta.quot(name))), $(Meta.quot(head))) + const $alt = NonlinearOperator((vs...) -> _op_fallback($(Meta.quot(alt))), $(Meta.quot(head))) end end for (name, alt, head, func) in ( @@ -24,27 +24,11 @@ for (name, alt, head, func) in ( ) # make operators @eval begin - const $name = JuMP.NonlinearOperator($func, $(Meta.quot(head))) - const $alt = JuMP.NonlinearOperator($func, $(Meta.quot(head))) + const $name = NonlinearOperator($func, $(Meta.quot(head))) + const $alt = NonlinearOperator($func, $(Meta.quot(head))) end end -""" - to_cnf!(expr::Expr) - -Convert an expression of symbolic Boolean variables and operators to CNF. -""" -function to_cnf!(expr::Expr) - check_logical_proposition(expr) #check that valid boolean symbols and variables are used in the logical proposition - eliminate_equivalence!(expr) #eliminate ⇔ - eliminate_implication!(expr) #eliminmate ⇒ - move_negations_inwards!(expr) #expand ¬ - clause_list = distribute_and_over_or_recursively!(expr) #distribute ∧ over ∨ recursively - @assert !isempty(clause_list) "Conversion to CNF failed." - - return clause_list -end - ################################################################################ # CONJUNCTIVE NORMAL FORM ################################################################################ @@ -73,7 +57,7 @@ function _eliminate_equivalence(lexpr::_LogicalExpr) elseif length(lexpr.args) == 2 B = _eliminate_equivalence(lexpr.args[2]) else - error("The equivalence logic operator must have at least two arguments.") + error("The equivalence logic operator must have at least two clauses.") end new_lexpr = _LogicalExpr(:&&, Any[ _LogicalExpr(:(=>), Any[A, B]), @@ -117,7 +101,7 @@ end function _move_negations_inward(lexpr::_LogicalExpr) if lexpr.head == :! if length(lexpr.args) != 1 - error("The negation operator can only have 1 clause.") + error("The negation operator can only have one clause.") end new_lexpr = _negate(lexpr.args[1]) else @@ -234,29 +218,25 @@ end # SELECTOR REFORMULATION ################################################################################ # cardinality constraint reformulation -function _reformulate_selector(model::JuMP.Model, func, set::Union{_MOIAtLeast, _MOIAtMost, _MOIExactly}) +function _reformulate_selector(model::Model, func, set::Union{_MOIAtLeast, _MOIAtMost, _MOIExactly}) dict = _indicator_to_binary(model) bvrefs = [dict[lvref] for lvref in func[2:end]] new_set = _vec_to_scalar_set(set)(func[1].constant) - cref = JuMP.add_constraint(model, - JuMP.build_constraint(error, JuMP.@expression(model, sum(bvrefs)), new_set) - ) + cref = @constraint(model, sum(bvrefs) in new_set) push!(_reformulation_constraints(model), cref) end -function _reformulate_selector(model::JuMP.Model, func::Vector{LogicalVariableRef}, set::Union{_MOIAtLeast, _MOIAtMost, _MOIExactly}) +function _reformulate_selector(model::Model, func::Vector{LogicalVariableRef}, set::Union{_MOIAtLeast, _MOIAtMost, _MOIExactly}) dict = _indicator_to_binary(model) bvref, bvrefs... = [dict[lvref] for lvref in func] new_set = _vec_to_scalar_set(set)(0) - cref = JuMP.add_constraint(model, - JuMP.build_constraint(error, JuMP.@expression(model, sum(bvrefs) - bvref), new_set) - ) + cref = @constraint(model, sum(bvrefs) - bvref in new_set) push!(_reformulation_constraints(model), cref) end ################################################################################ # PROPOSITION REFORMULATION ################################################################################ -function _reformulate_proposition(model::JuMP.Model, lexpr::_LogicalExpr) +function _reformulate_proposition(model::Model, lexpr::_LogicalExpr) expr = _to_cnf(lexpr) if expr.head == :&& for arg in expr.args @@ -264,7 +244,7 @@ function _reformulate_proposition(model::JuMP.Model, lexpr::_LogicalExpr) end elseif expr.head in (:||, :!) && all(_isa_literal.(expr.args)) _add_reformulated_proposition(model, expr) - else + else #NOTE: should never enter the `else` section error("Expression $expr was not converted to proper Conjunctive Normal Form.") end end @@ -274,31 +254,30 @@ _isa_literal(v::LogicalVariableRef) = true _isa_literal(v::_LogicalExpr) = (v.head == :!) && (length(v.args) == 1) && _isa_literal(v.args[1]) _isa_literal(v) = false -function _add_reformulated_proposition(model::JuMP.Model, arg::Union{LogicalVariableRef,_LogicalExpr}) +function _add_reformulated_proposition(model::Model, arg::Union{LogicalVariableRef,_LogicalExpr}) func = _reformulate_clause(model, arg) if !isempty(func.terms) && !all(iszero.(values(func.terms))) - con = JuMP.build_constraint(error, func, _MOI.GreaterThan(1)) - cref = JuMP.add_constraint(model, con) + cref = @constraint(model, func >= 1) push!(_reformulation_constraints(model), cref) end return end -function _reformulate_clause(model::JuMP.Model, lvref::LogicalVariableRef) +function _reformulate_clause(model::Model, lvref::LogicalVariableRef) func = 1 * _indicator_to_binary(model)[lvref] return func end -function _reformulate_clause(model::JuMP.Model, lexpr::_LogicalExpr) - func = zero(JuMP.AffExpr) #initialize func expression +function _reformulate_clause(model::Model, lexpr::_LogicalExpr) + func = zero(AffExpr) #initialize func expression if _isa_literal(lexpr) - JuMP.add_to_expression!(func, 1 - _reformulate_clause(model, lexpr.args[1])) + add_to_expression!(func, 1 - _reformulate_clause(model, lexpr.args[1])) elseif lexpr.head == :|| for literal in lexpr.args if literal isa LogicalVariableRef - JuMP.add_to_expression!(func, _reformulate_clause(model, literal)) + add_to_expression!(func, _reformulate_clause(model, literal)) elseif _isa_literal(literal) - JuMP.add_to_expression!(func, 1 - _reformulate_clause(model, literal.args[1])) + add_to_expression!(func, 1 - _reformulate_clause(model, literal.args[1])) else error("Expression was not converted to proper Conjunctive Normal Form:\n$literal is not a literal.") end @@ -307,4 +286,4 @@ function _reformulate_clause(model::JuMP.Model, lexpr::_LogicalExpr) error("Expression was not converted to proper Conjunctive Normal Form:\n$lexpr.") end return func -end \ No newline at end of file +end diff --git a/src/macros.jl b/src/macros.jl index 1ea2aff..d2a7344 100644 --- a/src/macros.jl +++ b/src/macros.jl @@ -46,7 +46,7 @@ function _name_call(base_name, idxvars) return ex end -# Process macro arugments +# Process macro arguments function _extract_kwargs(args) arg_list = collect(args) if !isempty(args) && isexpr(args[1], :parameters) @@ -89,15 +89,6 @@ function _add_positional_args(call, args) return end -# Determine if an expression contains any index variable symbols -function _has_idxvars(expr, idxvars) - expr in idxvars && return true - if expr isa Expr - return any(_has_idxvars(a, idxvars) for a in expr.args) - end - return false -end - # Ensure a model argument is valid # Inspired from https://github.com/jump-dev/JuMP.jl/blob/d9cd5fb16c2d0a7e1c06aa9941923492fc9a28b5/src/macros.jl#L38-L44 function _valid_model(_error::Function, model, name) @@ -111,7 +102,7 @@ function _error_if_cannot_register( model, name::Symbol ) - if haskey(JuMP.object_dictionary(model), name) + if haskey(object_dictionary(model), name) _error("An object of name $name is already attached to this model. If ", "this is intended, consider using the anonymous construction ", "syntax, e.g., `x = @macro_name(model, ...)` where the name ", @@ -181,7 +172,7 @@ macro disjunction(model, args...) _error("Invalid syntax. Did you mean to use `@disjunctions`?") end - # TODO: three cases lead to problems when julia variables are used for DisjunctConstraint tags + # TODO: three cases lead to problems when julia variables are used for Disjunct tags # which violate the cases considered in the table further below. The three cases are # (i) @disjunction(m, Y[1, :], tag[1]) --> gets confused for @disjunction(m, name[...], Y[1, :]) (Case 2 below) # (ii) @disjunction(m, Y, tagref) --> gets confused for @disjunction(m, name, Y) (Case 1 below) @@ -248,7 +239,7 @@ macro disjunction(model, args...) _add_kwargs(creation_code, extra_kwargs) else # we have a container of parameters - idxvars, inds = JuMP.Containers.build_ref_sets(_error, c) + idxvars, inds = Containers.build_ref_sets(_error, c) if model in idxvars _error("Index $(model) is the same symbol as the model. Use a ", "different name for the index.") @@ -257,7 +248,7 @@ macro disjunction(model, args...) disjunction_call = :( _disjunction($_error, $esc_model, $x, $name_code) ) _add_positional_args(disjunction_call, extra) _add_kwargs(disjunction_call, extra_kwargs) - creation_code = JuMP.Containers.container_code(idxvars, inds, disjunction_call, + creation_code = Containers.container_code(idxvars, inds, disjunction_call, container_type) end @@ -285,23 +276,17 @@ The macro returns a tuple containing the disjunctions that were defined. ## Example -```jldoctest -julia> model = GDPModel(); - -julia> @variable(model, w); - -julia> @variable(model, x); - -julia> @variable(model, Y[1:4], LogicalVariable); - -julia> @constraint(model, [i=1:2], w == i, DisjunctConstraint(Y[i])); - -julia> @constraint(model, [i=3:4], x == i, DisjunctConstraint(Y[i])); - -julia> @disjunctions(model, begin - [Y[1], Y[2]] - [Y[3], Y[4]] - end); +```julia +model = GDPModel(); +@variable(model, w); +@variable(model, x); +@variable(model, Y[1:4], LogicalVariable); +@constraint(model, [i=1:2], w == i, Disjunct(Y[i])); +@constraint(model, [i=3:4], x == i, Disjunct(Y[i])); +@disjunctions(model, begin + [Y[1], Y[2]] + [Y[3], Y[4]] +end); ```` """ macro disjunctions(m, x) diff --git a/src/model.jl b/src/model.jl index 288a077..e53984e 100644 --- a/src/model.jl +++ b/src/model.jl @@ -3,27 +3,27 @@ ################################################################################ """ - GDPModel([optimizer]; [kwargs...])::JuMP.Model + GDPModel([optimizer]; [kwargs...])::Model The core model object for building general disjunction programming models. """ function GDPModel(args...; kwargs...) - model = JuMP.Model(args...; kwargs...) + model = Model(args...; kwargs...) model.ext[:GDP] = GDPData() - JuMP.set_optimize_hook(model, _optimize_hook) + set_optimize_hook(model, _optimize_hook) return model end # Define what should happen to solve a GDPModel # See https://github.com/jump-dev/JuMP.jl/blob/9ea1df38fd320f864ab4c93c78631d0f15939c0b/src/JuMP.jl#L718-L745 function _optimize_hook( - model::JuMP.Model; + model::Model; method::AbstractSolutionMethod ) # can add more kwargs if wanted if !_ready_to_optimize(model) || _solution_method(model) != method reformulate_model(model, method) end - return JuMP.optimize!(model; ignore_optimize_hook = true) + return optimize!(model; ignore_optimize_hook = true) end ################################################################################ @@ -31,54 +31,44 @@ end ################################################################################ """ - gdp_data(model::JuMP.Model)::GDPData + gdp_data(model::Model)::GDPData Extract the [`GDPData`](@ref) from a `GDPModel`. """ -function gdp_data(model::JuMP.Model) +function gdp_data(model::Model) is_gdp_model(model) || error("Cannot access GDP data from a regular `JuMP.Model`.") return model.ext[:GDP] end """ - is_gdp_model(model::JuMP.Model)::Bool + is_gdp_model(model::Model)::Bool Return if `model` was created via the [`GDPModel`](@ref) constructor. """ -function is_gdp_model(model::JuMP.Model) +function is_gdp_model(model::Model) return haskey(model.ext, :GDP) end -""" - disjunction_indicators(disjunction::DisjunctionRef) - -Return LogicalVariableRefs associated with a disjunction. -""" -function disjunction_indicators(disjunction::DisjunctionRef) - model, idx = disjunction.model, disjunction.index - return _disjunctions(model)[idx].constraint.indicators -end - # Create accessors for GDP data fields -_logical_variables(model::JuMP.Model) = gdp_data(model).logical_variables -_logical_constraints(model::JuMP.Model) = gdp_data(model).logical_constraints -_disjunct_constraints(model::JuMP.Model) = gdp_data(model).disjunct_constraints -_disjunctions(model::JuMP.Model) = gdp_data(model).disjunctions -_indicator_to_binary(model::JuMP.Model) = gdp_data(model).indicator_to_binary -_indicator_to_constraints(model::JuMP.Model) = gdp_data(model).indicator_to_constraints -_reformulation_variables(model::JuMP.Model) = gdp_data(model).reformulation_variables -_reformulation_constraints(model::JuMP.Model) = gdp_data(model).reformulation_constraints -_ready_to_optimize(model::JuMP.Model) = gdp_data(model).ready_to_optimize # Determine if the model is ready to call `optimize!` without a optimize hook -_solution_method(model::JuMP.Model) = gdp_data(model).solution_method # Get the current solution method +_logical_variables(model::Model) = gdp_data(model).logical_variables +_logical_constraints(model::Model) = gdp_data(model).logical_constraints +_disjunct_constraints(model::Model) = gdp_data(model).disjunct_constraints +_disjunctions(model::Model) = gdp_data(model).disjunctions +_indicator_to_binary(model::Model) = gdp_data(model).indicator_to_binary +_indicator_to_constraints(model::Model) = gdp_data(model).indicator_to_constraints +_reformulation_variables(model::Model) = gdp_data(model).reformulation_variables +_reformulation_constraints(model::Model) = gdp_data(model).reformulation_constraints +_ready_to_optimize(model::Model) = gdp_data(model).ready_to_optimize # Determine if the model is ready to call `optimize!` without a optimize hook +_solution_method(model::Model) = gdp_data(model).solution_method # Get the current solution method # Update the ready_to_optimize field -function _set_ready_to_optimize(model::JuMP.Model, is_ready::Bool) +function _set_ready_to_optimize(model::Model, is_ready::Bool) gdp_data(model).ready_to_optimize = is_ready return end # Set the solution method -function _set_solution_method(model::JuMP.Model, method::AbstractSolutionMethod) +function _set_solution_method(model::Model, method::AbstractSolutionMethod) gdp_data(model).solution_method = method return -end \ No newline at end of file +end diff --git a/src/reformulate.jl b/src/reformulate.jl index fd1c3c8..031a148 100644 --- a/src/reformulate.jl +++ b/src/reformulate.jl @@ -2,12 +2,12 @@ # REFORMULATE ################################################################################ """ - reformulate_model(model::JuMP.Model, method::AbstractSolutionMethod) + reformulate_model(model::Model, method::AbstractSolutionMethod) Reformulate a `GDPModel` using the specified `method`. Prior to reformulation, all previous reformulation variables and constraints are deleted. """ -function reformulate_model(model::JuMP.Model, method::AbstractSolutionMethod) +function reformulate_model(model::Model, method::AbstractSolutionMethod) #clear all previous reformulations _clear_reformulations(model) #reformulate @@ -19,9 +19,9 @@ function reformulate_model(model::JuMP.Model, method::AbstractSolutionMethod) _set_ready_to_optimize(model, true) end -function _clear_reformulations(model::JuMP.Model) - JuMP.delete.(model, _reformulation_constraints(model)) - JuMP.delete.(model, _reformulation_variables(model)) +function _clear_reformulations(model::Model) + delete.(model, _reformulation_constraints(model)) + delete.(model, _reformulation_variables(model)) empty!(gdp_data(model).reformulation_constraints) empty!(gdp_data(model).reformulation_variables) end @@ -30,13 +30,13 @@ end # LOGICAL VARIABLES ################################################################################ # create binary (indicator) variables for logic variables. -function _reformulate_logical_variables(model::JuMP.Model) +function _reformulate_logical_variables(model::Model) for (lv_idx, lv_data) in _logical_variables(model) lv = lv_data.variable lvref = LogicalVariableRef(model, lv_idx) - bvref = JuMP.@variable(model, base_name = lv_data.name, binary = true, start = lv.start_value) - if JuMP.is_fixed(lvref) - JuMP.fix(bvref, JuMP.fix_value(lvref)) + bvref = @variable(model, base_name = lv_data.name, binary = true, start = lv.start_value) + if is_fixed(lvref) + fix(bvref, fix_value(lvref)) end push!(_reformulation_variables(model), bvref) _indicator_to_binary(model)[lvref] = bvref @@ -47,25 +47,25 @@ end # DISJUNCTIONS ################################################################################ # disjunctions -function _reformulate_all_disjunctions(model::JuMP.Model, method::AbstractReformulationMethod) +function _reformulate_all_disjunctions(model::Model, method::AbstractReformulationMethod) for (_, disj) in _disjunctions(model) disj.constraint.nested && continue #only reformulate top level disjunctions ref_cons = reformulate_disjunction(model, disj.constraint, method) for (i, ref_con) in enumerate(ref_cons) name = isempty(disj.name) ? "" : string(disj.name,"_$i") - cref = JuMP.add_constraint(model, ref_con, name) + cref = add_constraint(model, ref_con, name) push!(_reformulation_constraints(model), cref) end end end -function _reformulate_disjunctions(model::JuMP.Model, method::AbstractReformulationMethod) +function _reformulate_disjunctions(model::Model, method::AbstractReformulationMethod) _reformulate_all_disjunctions(model, method) end -function _reformulate_disjunctions(model::JuMP.Model, method::BigM) +function _reformulate_disjunctions(model::Model, method::BigM) method.tighten && _query_variable_bounds(model, method) _reformulate_all_disjunctions(model, method) end -function _reformulate_disjunctions(model::JuMP.Model, method::Hull) +function _reformulate_disjunctions(model::Model, method::Hull) _query_variable_bounds(model, method) _reformulate_all_disjunctions(model, method) end @@ -73,7 +73,7 @@ end # disjuncts """ reformulate_disjunction( - model::JuMP.Model, + model::Model, disj::Disjunction, method::AbstractReformulationMethod ) where {T<:Disjunction} @@ -85,16 +85,16 @@ The `disj` field is the `ConstraintData` object for the disjunction, stored in t `disjunctions` field of the `GDPData` object. """ # generic fallback (e.g., BigM, Indicator) -function reformulate_disjunction(model::JuMP.Model, disj::Disjunction, method::AbstractReformulationMethod) - ref_cons = Vector{JuMP.AbstractConstraint}() #store reformulated constraints +function reformulate_disjunction(model::Model, disj::Disjunction, method::AbstractReformulationMethod) + ref_cons = Vector{AbstractConstraint}() #store reformulated constraints for d in disj.indicators _reformulate_disjunct(model, ref_cons, d, method) end return ref_cons end # hull specific -function reformulate_disjunction(model::JuMP.Model, disj::Disjunction, method::Hull) - ref_cons = Vector{JuMP.AbstractConstraint}() #store reformulated constraints +function reformulate_disjunction(model::Model, disj::Disjunction, method::Hull) + ref_cons = Vector{AbstractConstraint}() #store reformulated constraints disj_vrefs = _get_disjunction_variables(model, disj) hull = _Hull(method, disj_vrefs) for d in disj.indicators #reformulate each disjunct @@ -106,35 +106,32 @@ function reformulate_disjunction(model::JuMP.Model, disj::Disjunction, method::H end return ref_cons end -function reformulate_disjunction(model::JuMP.Model, disj::Disjunction, method::_Hull) +function reformulate_disjunction(model::Model, disj::Disjunction, method::_Hull) return reformulate_disjunction(model, disj, Hull(method.value, method.variable_bounds)) end # individual disjuncts -function _reformulate_disjunct(model::JuMP.Model, ref_cons::Vector{JuMP.AbstractConstraint}, lvref::LogicalVariableRef, method::AbstractReformulationMethod) +function _reformulate_disjunct(model::Model, ref_cons::Vector{AbstractConstraint}, lvref::LogicalVariableRef, method::AbstractReformulationMethod) #reformulate each constraint and add to the model bvref = _indicator_to_binary(model)[lvref] !haskey(_indicator_to_constraints(model), lvref) && return #skip if disjunct is empty for cref in _indicator_to_constraints(model)[lvref] - con = JuMP.constraint_object(cref) + con = constraint_object(cref) append!(ref_cons, reformulate_disjunct_constraint(model, con, bvref, method)) end return end -_index_to_constraint(model::JuMP.Model, cidx::DisjunctConstraintIndex) = _disjunct_constraints(model)[cidx] -_index_to_constraint(model::JuMP.Model, cidx::DisjunctionIndex) = _disjunctions(model)[cidx] - # reformulation for nested disjunction # NOTE: name of inner disjunction (if given) is currently lost (not passed upwards) function reformulate_disjunct_constraint( - model::JuMP.Model, + model::Model, con::Disjunction, - bvref::JuMP.VariableRef, + bvref::VariableRef, method::AbstractReformulationMethod ) ref_cons = reformulate_disjunction(model, con, method) - new_ref_cons = Vector{JuMP.AbstractConstraint}() + new_ref_cons = Vector{AbstractConstraint}() for ref_con in ref_cons append!(new_ref_cons, reformulate_disjunct_constraint(model, ref_con, bvref, method)) end @@ -143,9 +140,9 @@ end # reformulation fallback for individual disjunct constraints function reformulate_disjunct_constraint( - model::JuMP.Model, - con::JuMP.AbstractConstraint, - bvref::JuMP.VariableRef, + model::Model, + con::AbstractConstraint, + bvref::VariableRef, method::AbstractReformulationMethod ) error("$(typeof(method)) reformulation for constraint $con is not supported yet.") @@ -155,15 +152,15 @@ end # LOGICAL CONSTRAINT REFORMULATION ################################################################################ # all logical constraints -function _reformulate_logical_constraints(model::JuMP.Model) +function _reformulate_logical_constraints(model::Model) for (_, lcon) in _logical_constraints(model) _reformulate_logical_constraint(model, lcon.constraint.func, lcon.constraint.set) end end # individual logical constraints -function _reformulate_logical_constraint(model::JuMP.Model, func, set::Union{_MOIAtMost, _MOIAtLeast, _MOIExactly}) +function _reformulate_logical_constraint(model::Model, func, set::Union{_MOIAtMost, _MOIAtLeast, _MOIExactly}) return _reformulate_selector(model, func, set) end -function _reformulate_logical_constraint(model::JuMP.Model, func, set::IsTrue) +function _reformulate_logical_constraint(model::Model, func, set::IsTrue) return _reformulate_proposition(model, func) -end \ No newline at end of file +end diff --git a/src/variables.jl b/src/variables.jl index a3f79a8..91f6454 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -2,7 +2,7 @@ # LOGICAL VARIABLES ################################################################################ """ - JuMP.build_variable(_error::Function, info::JuMP.VariableInfo, + JuMP.build_variable(_error::Function, info::VariableInfo, ::Type{LogicalVariable})::LogicalVariable Extend `JuMP.build_variable` to work with logical variables. This in @@ -11,7 +11,7 @@ combination with `JuMP.add_variable` enables the use of """ function JuMP.build_variable( _error::Function, - info::JuMP.VariableInfo, + info::VariableInfo, tag::Type{LogicalVariable}; kwargs... ) @@ -23,27 +23,27 @@ function JuMP.build_variable( _error("Logical variables cannot have bounds.") elseif info.integer _error("Logical variables cannot be integer valued.") - elseif info.has_fix && !isone(info.fix) && !iszero(info.fix) - _error("Invalid fix value, must be 0 or 1.") + elseif info.has_fix && !isone(info.fixed_value) && !iszero(info.fixed_value) + _error("Invalid fix value, must be false or true.") elseif info.has_start && !isone(info.start) && !iszero(info.start) - _error("Invalid start value, must be 0 or 1.") + _error("Invalid start value, must be false or true.") end # create the variable - fix = info.has_fix ? Bool(info.fix) : nothing + fix = info.has_fix ? Bool(info.fixed_value) : nothing start = info.has_start ? Bool(info.start) : nothing return LogicalVariable(fix, start) end """ - JuMP.add_variable(model::JuMP.Model, v::LogicalVariable, + JuMP.add_variable(model::Model, v::LogicalVariable, name::String = "")::LogicalVariableRef Extend `JuMP.add_variable` for [`LogicalVariable`](@ref)s. This -helps enable `@variable(model, [var_expr], LogicalVariable)`. +helps enable `@variable(model, [var_expr], Logical)`. """ function JuMP.add_variable( - model::JuMP.Model, + model::Model, v::LogicalVariable, name::String = "" ) @@ -61,8 +61,8 @@ Base.length(v::LogicalVariableRef) = 1 function Base.:(==)(v::LogicalVariableRef, w::LogicalVariableRef) return v.model === w.model && v.index == w.index end -function Base.getindex(map::JuMP.ReferenceMap, vref::LogicalVariableRef) - return LogicalVariableRef(map.model, JuMP.index(vref)) +function Base.getindex(map::ReferenceMap, vref::LogicalVariableRef) + return LogicalVariableRef(map.model, index(vref)) end # JuMP extensions @@ -89,12 +89,12 @@ Return `true` if `v` and `w` refer to the same logical variable in the same JuMP.isequal_canonical(v::LogicalVariableRef, w::LogicalVariableRef) = v == w """ - JuMP.is_valid(model::JuMP.Model, vref::LogicalVariableRef) + JuMP.is_valid(model::Model, vref::LogicalVariableRef) Return `true` if `vref` refers to a valid logical variable in `GDP model`. """ -function JuMP.is_valid(model::JuMP.Model, vref::LogicalVariableRef) - return model === JuMP.owner_model(vref) +function JuMP.is_valid(model::Model, vref::LogicalVariableRef) + return model === owner_model(vref) end """ @@ -103,8 +103,8 @@ end Get a logical variable's name attribute. """ function JuMP.name(vref::LogicalVariableRef) - data = gdp_data(JuMP.owner_model(vref)) - return data.logical_variables[JuMP.index(vref)].name + data = gdp_data(owner_model(vref)) + return data.logical_variables[index(vref)].name end """ @@ -113,9 +113,9 @@ end Set a logical variable's name attribute. """ function JuMP.set_name(vref::LogicalVariableRef, name::String) - model = JuMP.owner_model(vref) + model = owner_model(vref) data = gdp_data(model) - data.logical_variables[JuMP.index(vref)].name = name + data.logical_variables[index(vref)].name = name _set_ready_to_optimize(model, false) return end @@ -126,8 +126,8 @@ end Return the start value of the logical variable `vref`. """ function JuMP.start_value(vref::LogicalVariableRef) - data = gdp_data(JuMP.owner_model(vref)) - return data.logical_variables[JuMP.index(vref)].variable.start_value + data = gdp_data(owner_model(vref)) + return data.logical_variables[index(vref)].variable.start_value end """ @@ -141,11 +141,11 @@ function JuMP.set_start_value( vref::LogicalVariableRef, value::Union{Nothing, Bool} ) - model = JuMP.owner_model(vref) + model = owner_model(vref) data = gdp_data(model) - var = data.logical_variables[JuMP.index(vref)].variable + var = data.logical_variables[index(vref)].variable new_var = LogicalVariable(var.fix_value, value) - data.logical_variables[JuMP.index(vref)].variable = new_var + data.logical_variables[index(vref)].variable = new_var _set_ready_to_optimize(model, false) return end @@ -157,8 +157,8 @@ Return `true` if `vref` is a fixed variable. If fix_value. """ function JuMP.is_fixed(vref::LogicalVariableRef) - data = gdp_data(JuMP.owner_model(vref)) - return !isnothing(data.logical_variables[JuMP.index(vref)].variable.fix_value) + data = gdp_data(owner_model(vref)) + return !isnothing(data.logical_variables[index(vref)].variable.fix_value) end """ @@ -167,8 +167,8 @@ end Return the value to which a logical variable is fixed. """ function JuMP.fix_value(vref::LogicalVariableRef) - data = gdp_data(JuMP.owner_model(vref)) - return data.logical_variables[JuMP.index(vref)].variable.fix_value + data = gdp_data(owner_model(vref)) + return data.logical_variables[index(vref)].variable.fix_value end """ @@ -179,11 +179,11 @@ constraint if one exists, otherwise create a new one. """ function JuMP.fix(vref::LogicalVariableRef, value::Bool) - model = JuMP.owner_model(vref) + model = owner_model(vref) data = gdp_data(model) - var = data.logical_variables[JuMP.index(vref)].variable + var = data.logical_variables[index(vref)].variable new_var = LogicalVariable(value, var.start_value) - data.logical_variables[JuMP.index(vref)].variable = new_var + data.logical_variables[index(vref)].variable = new_var _set_ready_to_optimize(model, false) return end @@ -194,42 +194,42 @@ end Delete the fixed value of a logical variable. """ function JuMP.unfix(vref::LogicalVariableRef) - model = JuMP.owner_model(vref) + model = owner_model(vref) data = gdp_data(model) - var = data.logical_variables[JuMP.index(vref)].variable + var = data.logical_variables[index(vref)].variable new_var = LogicalVariable(nothing, var.start_value) - data.logical_variables[JuMP.index(vref)].variable = new_var + data.logical_variables[index(vref)].variable = new_var _set_ready_to_optimize(model, false) return end """ - JuMP.delete(model::JuMP.Model, vref::LogicalVariableRef) + JuMP.delete(model::Model, vref::LogicalVariableRef) Delete the logical variable associated with `vref` from the `GDP model`. """ -function JuMP.delete(model::JuMP.Model, vref::LogicalVariableRef) - @assert JuMP.is_valid(model, vref) "Variable does not belong to model." - vidx = JuMP.index(vref) +function JuMP.delete(model::Model, vref::LogicalVariableRef) + @assert is_valid(model, vref) "Variable does not belong to model." + vidx = index(vref) dict = _logical_variables(model) #delete any disjunct constraints associated with the logical variables in the disjunction if haskey(_indicator_to_constraints(model), vref) crefs = _indicator_to_constraints(model)[vref] - JuMP.delete.(model, crefs) + delete.(model, crefs) delete!(_indicator_to_constraints(model), vref) end #delete any disjunctions that have the logical variable for (didx, ddata) in _disjunctions(model) if vref in ddata.constraint.indicators setdiff!(ddata.constraint.indicators, [vref]) - JuMP.delete(model, DisjunctionRef(model, didx)) + delete(model, DisjunctionRef(model, didx)) end end #delete any logical constraints involving the logical variables for (cidx, cdata) in _logical_constraints(model) lvars = _get_constraint_variables(model, cdata.constraint) if vref in lvars - JuMP.delete(model, LogicalConstraintRef(model, cidx)) + delete(model, LogicalConstraintRef(model, cidx)) end end #delete the logical variable @@ -243,26 +243,26 @@ end ################################################################################ # VARIABLE INTERROGATION ################################################################################ -function _query_variable_bounds(model::JuMP.Model, method::Union{Hull, BigM}) - for var in JuMP.all_variables(model) +function _query_variable_bounds(model::Model, method::Union{Hull, BigM}) + for var in all_variables(model) method.variable_bounds[var] = _update_variable_bounds(var, method) end end -function _get_disjunction_variables(model::JuMP.Model, disj::Disjunction) - vars = Set{JuMP.VariableRef}() +function _get_disjunction_variables(model::Model, disj::Disjunction) + vars = Set{VariableRef}() for lvref in disj.indicators !haskey(_indicator_to_constraints(model), lvref) && continue #skip if disjunct is empty for cref in _indicator_to_constraints(model)[lvref] - con = JuMP.constraint_object(cref) + con = constraint_object(cref) _interrogate_variables(v -> push!(vars, v), con) end end return vars end -function _get_constraint_variables(model::JuMP.Model, con::Union{JuMP.ScalarConstraint, JuMP.VectorConstraint}) - vars = Set{Union{JuMP.VariableRef, LogicalVariableRef}}() +function _get_constraint_variables(model::Model, con::Union{ScalarConstraint, VectorConstraint}) + vars = Set{Union{VariableRef, LogicalVariableRef}}() _interrogate_variables(v -> push!(vars, v), con.func) return vars end @@ -273,13 +273,13 @@ function _interrogate_variables(interrogator::Function, c::Number) end # VariableRef/LogicalVariableRef -function _interrogate_variables(interrogator::Function, var::Union{JuMP.VariableRef, LogicalVariableRef}) +function _interrogate_variables(interrogator::Function, var::Union{VariableRef, LogicalVariableRef}) interrogator(var) return end # AffExpr -function _interrogate_variables(interrogator::Function, aff::JuMP.GenericAffExpr) +function _interrogate_variables(interrogator::Function, aff::GenericAffExpr) for (var, _) in aff.terms interrogator(var) end @@ -287,7 +287,7 @@ function _interrogate_variables(interrogator::Function, aff::JuMP.GenericAffExpr end # QuadExpr -function _interrogate_variables(interrogator::Function, quad::JuMP.QuadExpr) +function _interrogate_variables(interrogator::Function, quad::QuadExpr) for (pair, _) in quad.terms interrogator(pair.a) interrogator(pair.b) @@ -296,8 +296,8 @@ function _interrogate_variables(interrogator::Function, quad::JuMP.QuadExpr) return end -# NonlinearExpr and _LogicalExpr (T <: Union{JuMP.VariableRef, LogicalVariableRef}) -function _interrogate_variables(interrogator::Function, nlp::JuMP.GenericNonlinearExpr{T}) where {T} +# NonlinearExpr and _LogicalExpr (T <: Union{VariableRef, LogicalVariableRef}) +function _interrogate_variables(interrogator::Function, nlp::GenericNonlinearExpr{T}) where {T} for arg in nlp.args _interrogate_variables(interrogator, arg) end @@ -307,7 +307,7 @@ function _interrogate_variables(interrogator::Function, nlp::JuMP.GenericNonline end # Constraint -function _interrogate_variables(interrogator::Function, con::Union{JuMP.ScalarConstraint, JuMP.VectorConstraint}) +function _interrogate_variables(interrogator::Function, con::Union{ScalarConstraint, VectorConstraint}) _interrogate_variables(interrogator, con.func) end @@ -325,7 +325,7 @@ end # Nested disjunction function _interrogate_variables(interrogator::Function, disj::Disjunction) - model = JuMP.owner_model(disj.indicators[1]) + model = owner_model(disj.indicators[1]) dvars = _get_disjunction_variables(model, disj) _interrogate_variables(interrogator, dvars) return diff --git a/test/constraints/bigm.jl b/test/constraints/bigm.jl index b1666b9..f097228 100644 --- a/test/constraints/bigm.jl +++ b/test/constraints/bigm.jl @@ -19,8 +19,8 @@ end function test_get_M_1sided() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, 3*x <= 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, 3*x <= 1, Disjunct(y)) cobj = constraint_object(con) M = DP._get_M(cobj.func, cobj.set, BigM(100, false)) @test M == 100 @@ -30,8 +30,8 @@ end function test_get_tight_M_1sided() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, 3*x <= 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, 3*x <= 1, Disjunct(y)) cobj = constraint_object(con) method = BigM(100) @@ -53,8 +53,8 @@ end function test_get_M_2sided() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, 3*x == 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, 3*x == 1, Disjunct(y)) cobj = constraint_object(con) method = BigM(100) @@ -69,8 +69,8 @@ end function test_get_tight_M_2sided() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, 3*x == 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, 3*x == 1, Disjunct(y)) cobj = constraint_object(con) method = BigM(100) @@ -176,8 +176,8 @@ end function test_lessthan_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, x <= 5, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, x <= 5, Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -190,8 +190,8 @@ end function test_nonpositives_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, [x; x] <= [5; 5], DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, [x; x] <= [5; 5], Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -202,11 +202,11 @@ function test_nonpositives_bigm() @test ref[1].set == MOI.Nonpositives(2) end -function test_greaterhan_bigm() +function test_greaterthan_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, x >= 5, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, x >= 5, Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -219,8 +219,8 @@ end function test_nonnegatives_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, [x; x] >= [5; 5], DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, [x; x] >= [5; 5], Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -231,11 +231,11 @@ function test_nonnegatives_bigm() @test ref[1].set == MOI.Nonnegatives(2) end -function test_greaterhan_bigm() +function test_equalto_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, x == 5, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, x == 5, Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -247,11 +247,11 @@ function test_greaterhan_bigm() @test ref[2].set == MOI.LessThan(5.0 + 100) end -function test_greaterhan_bigm() +function test_interval_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, 5 <= x <= 5, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, 5 <= x <= 5, Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -266,8 +266,8 @@ end function test_zeros_bigm() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, con, [x; x] == [5; 5], DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, con, [x; x] == [5; 5], Disjunct(y)) DP._reformulate_logical_variables(model) bvref = DP._indicator_to_binary(model)[y] @@ -284,13 +284,13 @@ end function test_nested_bigm() model = GDPModel() @variable(model, -100 <= x <= 100) - @variable(model, y[1:2], LogicalVariable) - @variable(model, z[1:2], LogicalVariable) - @constraint(model, x <= 5, DisjunctConstraint(y[1])) - @constraint(model, x >= 5, DisjunctConstraint(y[2])) - @disjunction(model, inner, y, DisjunctConstraint(z[1])) - @constraint(model, x <= 10, DisjunctConstraint(z[1])) - @constraint(model, x >= 10, DisjunctConstraint(z[2])) + @variable(model, y[1:2], Logical) + @variable(model, z[1:2], Logical) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[2])) + @disjunction(model, inner, y, Disjunct(z[1])) + @constraint(model, x <= 10, Disjunct(z[1])) + @constraint(model, x >= 10, Disjunct(z[2])) @disjunction(model, outer, z) reformulate_model(model, BigM()) @@ -320,10 +320,10 @@ end test_calculate_tight_M() test_lessthan_bigm() test_nonpositives_bigm() - test_greaterhan_bigm() + test_greaterthan_bigm() test_nonnegatives_bigm() - test_greaterhan_bigm() - test_greaterhan_bigm() + test_equalto_bigm() + test_interval_bigm() test_zeros_bigm() test_nested_bigm() end \ No newline at end of file diff --git a/test/constraints/disjunct.jl b/test/constraints/disjunct.jl index c840199..91f79f6 100644 --- a/test/constraints/disjunct.jl +++ b/test/constraints/disjunct.jl @@ -1,20 +1,21 @@ function test_disjunct_add_fail() model = GDPModel() @variable(model, x) - @variable(GDPModel(), y, LogicalVariable) - @test_macro_throws UndefVarError @constraint(model, x == 1, DisjunctConstraint(y)) # logical variable from another model + @variable(GDPModel(), y, Logical) + @test_macro_throws UndefVarError @constraint(model, x == 1, Disjunct(y)) # logical variable from another model - @variable(model, w, LogicalVariable) + @variable(model, w, Logical) @variable(model, z, Bin) - @test_macro_throws UndefVarError @constraint(model, z == 1, DisjunctConstraint(w)) # binary variable + @test_macro_throws UndefVarError @constraint(model, z == 1, Disjunct(w)) # binary variable + @test_throws ErrorException build_constraint(error, 1z, MOI.EqualTo(1), Disjunct(w)) # binary variable end function test_disjunct_add_success() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - c1 = @constraint(model, x == 1, DisjunctConstraint(y)) - @constraint(model, c2, x == 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + c1 = @constraint(model, x == 1, Disjunct(y)) + @constraint(model, c2, x == 1, Disjunct(y)) @test owner_model(c1) == model @test is_valid(model, c1) @test index(c1) == DisjunctConstraintIndex(1) @@ -34,8 +35,8 @@ end function test_disjunct_add_array() model = GDPModel() @variable(model, x) - @variable(model, y[1:2, 1:3], LogicalVariable) - @constraint(model, con[i=1:2, j=1:3], x == 1, DisjunctConstraint(y[i,j])) + @variable(model, y[1:2, 1:3], Logical) + @constraint(model, con[i=1:2, j=1:3], x == 1, Disjunct(y[i,j])) @test con isa Matrix{DisjunctConstraintRef} @test length(con) == 6 end @@ -45,8 +46,8 @@ function test_disjunct_add_dense_axis() @variable(model, x) I = ["a", "b", "c"] J = [1, 2] - @variable(model, y[I, J], LogicalVariable) - @constraint(model, con[i=I, j=J], x == 1, DisjunctConstraint(y[i,j])) + @variable(model, y[I, J], Logical) + @constraint(model, con[i=I, j=J], x == 1, Disjunct(y[i,j])) @test con isa Containers.DenseAxisArray @test con.axes[1] == ["a","b","c"] @@ -57,8 +58,8 @@ end function test_disjunct_add_sparse_axis() model = GDPModel() @variable(model, x) - @variable(model, y[1:3, 1:3], LogicalVariable) - @constraint(model, con[i=1:3, j=1:3; j > i], x==i+j, DisjunctConstraint(y[i,j])) + @variable(model, y[1:3, 1:3], Logical) + @constraint(model, con[i=1:3, j=1:3; j > i], x==i+j, Disjunct(y[i,j])) @test con isa Containers.SparseAxisArray @test length(con) == 3 @@ -69,8 +70,8 @@ end function test_disjunct_set_name() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - c1 = @constraint(model, x == 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + c1 = @constraint(model, x == 1, Disjunct(y)) set_name(c1, "new name") @test name(c1) == "new name" end @@ -78,8 +79,8 @@ end function test_disjunct_delete() model = GDPModel() @variable(model, x) - @variable(model, y, LogicalVariable) - @constraint(model, c1, x == 1, DisjunctConstraint(y)) + @variable(model, y, Logical) + @constraint(model, c1, x == 1, Disjunct(y)) @test_throws AssertionError delete(GDPModel(), c1) delete(model, c1) diff --git a/test/disjunction.jl b/test/constraints/disjunction.jl similarity index 66% rename from test/disjunction.jl rename to test/constraints/disjunction.jl index 1032e6e..9804ba8 100644 --- a/test/disjunction.jl +++ b/test/constraints/disjunction.jl @@ -1,23 +1,37 @@ +function test_macro_helpers() + @test DP._esc_non_constant(1) == 1 + @test DP._get_name(:x) == :x + @test DP._get_name("x") == "x" + @test DP._get_name(nothing) == () + @test DP._get_name(Expr(:string,"x")) == Expr(:string,"x") + @test DP._name_call("",[]) == "" + @test DP._name_call("name",[]) == "name" +end + function test_disjunction_add_fail() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, x == 5, DisjunctConstraint(y[1])) - + @variable(model, y[1:2], Logical) + @constraint(model, x == 5, Disjunct(y[1])) + @test_macro_throws ErrorException @disjunction(model) #not enough arguments @test_macro_throws UndefVarError @disjunction(model, y) #unassociated indicator @test_macro_throws UndefVarError @disjunction(GDPModel(), y) #wrong model @test_macro_throws ErrorException @disjunction(Model(), y) #not a GDPModel @test_macro_throws UndefVarError @disjunction(model, [y[1], y[1]]) #duplicate indicator - @test_macro_throws UndefVarError @disjunction(model, y[1]) #no disjunction expression + @test_macro_throws UndefVarError @disjunction(model, y[1]) #unrecognized disjunction expression + @test_throws ErrorException disjunction(model, y[1]) #unrecognized disjunction expression + @test_throws ErrorException disjunction(model, [1]) #unrecognized disjunction expression @test_macro_throws UndefVarError @disjunction(model, y, "random_arg") #unrecognized extra argument + @test_throws ErrorException DP._disjunction(error, model, y, "y", "random_arg") #unrecognized extra argument @test_macro_throws ErrorException @disjunction(model, "ABC") #unrecognized structure @test_macro_throws ErrorException @disjunction(model, begin y end) #@disjunctions (plural) @test_macro_throws UndefVarError @disjunction(model, x, y) #name x already exists - @constraint(model, x == 10, DisjunctConstraint(y[2])) + @constraint(model, x == 10, Disjunct(y[2])) @disjunction(model, disj, y) @test_macro_throws UndefVarError @disjunction(model, disj, y) #duplicate name + @test_throws ErrorException DP._error_if_cannot_register(error, model, :disj) #duplicate name @test_macro_throws ErrorException @disjunction(model, "bad"[i=1:2], y) #wrong expression for disjunction name @test_macro_throws ErrorException @disjunction(model, [model=1:2], y) #index name can't be same as model name @@ -26,9 +40,9 @@ end function test_disjunction_add_success() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, x == 5, DisjunctConstraint(y[1])) - @constraint(model, x == 10, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, x == 5, Disjunct(y[1])) + @constraint(model, x == 10, Disjunct(y[2])) disj = @disjunction(model, y) @disjunction(model, disj2, y) @test owner_model(disj) == model @@ -47,13 +61,13 @@ end function test_disjunction_add_nested() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @variable(model, z[1:2], LogicalVariable) - @constraint(model, x <= 5, DisjunctConstraint(y[1])) - @constraint(model, x >= 5, DisjunctConstraint(y[2])) - @disjunction(model, inner, y, DisjunctConstraint(z[1])) - @constraint(model, x <= 10, DisjunctConstraint(z[1])) - @constraint(model, x >= 10, DisjunctConstraint(z[2])) + @variable(model, y[1:2], Logical) + @variable(model, z[1:2], Logical) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[2])) + @disjunction(model, inner, y, Disjunct(z[1])) + @constraint(model, x <= 10, Disjunct(z[1])) + @constraint(model, x >= 10, Disjunct(z[2])) @disjunction(model, outer, z) @test is_valid(model, inner) @@ -69,8 +83,8 @@ end function test_disjunction_add_array() model=GDPModel() @variable(model, x) - @variable(model, y[1:2, 1:3, 1:4], LogicalVariable) - @constraint(model, con[i=1:2, j=1:3, k=1:4], x==i+j+k, DisjunctConstraint(y[i,j,k])) + @variable(model, y[1:2, 1:3, 1:4], Logical) + @constraint(model, con[i=1:2, j=1:3, k=1:4], x==i+j+k, Disjunct(y[i,j,k])) @disjunction(model, disj[i=1:2, j=1:3], y[i,j,:]) @test disj isa Matrix{DisjunctionRef} @@ -83,8 +97,8 @@ function test_disjunciton_add_dense_axis() @variable(model, x) I = ["a", "b", "c"] J = [1, 2] - @variable(model, y[I, J, 1:4], LogicalVariable) - @constraint(model, con[i=I, j=J, k=1:4], x==k, DisjunctConstraint(y[i,j,k])) + @variable(model, y[I, J, 1:4], Logical) + @constraint(model, con[i=I, j=J, k=1:4], x==k, Disjunct(y[i,j,k])) @disjunction(model, disj[i=I, j=J], y[i,j,:]) @test disj isa Containers.DenseAxisArray @@ -96,8 +110,8 @@ end function test_disjunction_add_sparse_axis() model = GDPModel() @variable(model, x) - @variable(model, y[1:3, 1:3, 1:4], LogicalVariable) - @constraint(model, con[i=1:3, j=1:3, k=1:4; j > i], x==i+j+k, DisjunctConstraint(y[i,j,k])) + @variable(model, y[1:3, 1:3, 1:4], Logical) + @constraint(model, con[i=1:3, j=1:3, k=1:4; j > i], x==i+j+k, Disjunct(y[i,j,k])) @disjunction(model, disj[i=1:3, j=1:3; j > i], y[i,j,:]) @test disj isa Containers.SparseAxisArray @@ -106,15 +120,25 @@ function test_disjunction_add_sparse_axis() @test Set(keys(disj.data)) == Set([(1,2),(1,3),(2,3)]) end +function test_disjunctions_add_fail() + model = GDPModel() + @variable(model, x) + @variable(model, y[1:2], Logical) + @variable(model, z[1:2], Logical) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[2])) + @test_macro_throws ErrorException @disjunctions(model, y) +end + function test_disjunctions_add_success() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @variable(model, z[1:2], LogicalVariable) - @constraint(model, x <= 5, DisjunctConstraint(y[1])) - @constraint(model, x >= 5, DisjunctConstraint(y[2])) - @constraint(model, x <= 10, DisjunctConstraint(z[1])) - @constraint(model, x >= 10, DisjunctConstraint(z[2])) + @variable(model, y[1:2], Logical) + @variable(model, z[1:2], Logical) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[2])) + @constraint(model, x <= 10, Disjunct(z[1])) + @constraint(model, x >= 10, Disjunct(z[2])) @disjunctions(model, begin disj1, y disj2, z @@ -136,9 +160,9 @@ end function test_disjunction_set_name() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, x == 5, DisjunctConstraint(y[1])) - @constraint(model, x == 10, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, x == 5, Disjunct(y[1])) + @constraint(model, x == 10, Disjunct(y[2])) @disjunction(model, disj, y) set_name(disj, "new_name") @test name(disj) == "new_name" @@ -147,9 +171,9 @@ end function test_disjunction_delete() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, x == 5, DisjunctConstraint(y[1])) - @constraint(model, x == 10, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, x == 5, Disjunct(y[1])) + @constraint(model, x == 10, Disjunct(y[2])) @disjunction(model, disj, y) @test_throws AssertionError delete(GDPModel(), disj) @@ -161,9 +185,9 @@ end function test_disjunction_function() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, x == 5, DisjunctConstraint(y[1])) - @constraint(model, x == 10, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, x == 5, Disjunct(y[1])) + @constraint(model, x == 10, Disjunct(y[2])) disj = disjunction(model, y, "name") @test is_valid(model, disj) @@ -176,13 +200,13 @@ end function test_disjunction_function_nested() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @variable(model, z[1:2], LogicalVariable) - @constraint(model, x <= 5, DisjunctConstraint(y[1])) - @constraint(model, x >= 5, DisjunctConstraint(y[2])) - @constraint(model, x <= 10, DisjunctConstraint(z[1])) - @constraint(model, x >= 10, DisjunctConstraint(z[2])) - disj1 = disjunction(model, y, DisjunctConstraint(z[1]), "inner") + @variable(model, y[1:2], Logical) + @variable(model, z[1:2], Logical) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[2])) + @constraint(model, x <= 10, Disjunct(z[1])) + @constraint(model, x >= 10, Disjunct(z[2])) + disj1 = disjunction(model, y, Disjunct(z[1]), "inner") disj2 = disjunction(model, z, "outer") @test is_valid(model, disj1) @@ -196,6 +220,9 @@ function test_disjunction_function_nested() end @testset "Disjunction" begin + @testset "Macro Helpers" begin + test_macro_helpers() + end @testset "Add Disjunction" begin test_disjunction_add_fail() test_disjunction_add_success() @@ -203,6 +230,7 @@ end test_disjunction_add_array() test_disjunciton_add_dense_axis() test_disjunction_add_sparse_axis() + test_disjunctions_add_fail() test_disjunctions_add_success() test_disjunction_function() test_disjunction_function_nested() diff --git a/test/constraints/fallback.jl b/test/constraints/fallback.jl new file mode 100644 index 0000000..9e256fb --- /dev/null +++ b/test/constraints/fallback.jl @@ -0,0 +1,10 @@ +function test_reformulate_disjunct_constraint_fallback() + model = GDPModel() + @variable(model, x) + c = build_constraint(error, 1x, MOI.LessThan(1)) + @test_throws ErrorException reformulate_disjunct_constraint(model, c, x, DummyReformulation()) +end + +@testset "Fallbacks" begin + test_reformulate_disjunct_constraint_fallback() +end \ No newline at end of file diff --git a/test/constraints/hull.jl b/test/constraints/hull.jl index a6be5c1..8eca869 100644 --- a/test/constraints/hull.jl +++ b/test/constraints/hull.jl @@ -38,10 +38,11 @@ function test_disaggregate_variables() model = GDPModel() @variable(model, 10 <= x <= 100) @variable(model, y, Bin) - @variable(model, z, LogicalVariable) - vrefs = Set([x,y]) + @variable(model, z, Logical) + vrefs = Set{VariableRef}() #initialize empty set to check if method.disjunct_variables has variables added to it in _disaggregate_variable call DP._reformulate_logical_variables(model) method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), vrefs) + vrefs = Set([x,y]) DP._disaggregate_variables(model, z, vrefs, method) refvars = DP._reformulation_variables(model) @@ -64,7 +65,7 @@ end function test_aggregate_variable() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) vrefs = Set([x]) DP._reformulate_logical_variables(model) method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), vrefs) @@ -76,10 +77,42 @@ function test_aggregate_variable() @test refcons[1].set == MOI.EqualTo(0.) end +function test_disaggregate_expression_var() + model = GDPModel() + @variable(model, 10 <= x <= 100) + @variable(model, z, Logical) + DP._reformulate_logical_variables(model) + bvrefs = DP._indicator_to_binary(model) + + vrefs = Set([x]) + method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), vrefs) + DP._disaggregate_variables(model, z, vrefs, method) + + refexpr = DP._disaggregate_expression(model, x, bvrefs[z], method) + x_z = variable_by_name(model, "x_z") + @test refexpr == x_z +end + +function test_disaggregate_expression_var_binary() + model = GDPModel() + @variable(model, x, Bin) + @variable(model, z, Logical) + DP._reformulate_logical_variables(model) + bvrefs = DP._indicator_to_binary(model) + + vrefs = Set([x]) + method = DP._Hull(Hull(1e-3, Dict(x => (0., 1.))), vrefs) + DP._disaggregate_variables(model, z, vrefs, method) + @test isnothing(variable_by_name(model, "x_z")) + + refexpr = DP._disaggregate_expression(model, x, bvrefs[z], method) + @test refexpr == x +end + function test_disaggregate_expression_affine() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -93,10 +126,28 @@ function test_disaggregate_expression_affine() @test refexpr == 2x_z + 1zbin end +function test_disaggregate_expression_affine_mip() + model = GDPModel() + @variable(model, 10 <= x <= 100) + @variable(model, y, Bin) + @variable(model, z, Logical) + DP._reformulate_logical_variables(model) + bvrefs = DP._indicator_to_binary(model) + + vrefs = Set([x, y]) + method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.), y => (0., 1.))), vrefs) + DP._disaggregate_variables(model, z, vrefs, method) + + refexpr = DP._disaggregate_expression(model, 2x + y + 1, bvrefs[z], method) + x_z = variable_by_name(model, "x_z") + zbin = variable_by_name(model, "z") + @test refexpr == 2x_z + y + 1zbin +end + function test_disaggregate_expression_quadratic() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -119,7 +170,7 @@ end function test_disaggregate_nl_expression_c() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -131,10 +182,28 @@ function test_disaggregate_nl_expression_c() @test refexpr == 1 end +function test_disaggregate_nl_expression_var_binary() + model = GDPModel() + @variable(model, x, Bin) + @variable(model, z, Logical) + DP._reformulate_logical_variables(model) + bvrefs = DP._indicator_to_binary(model) + + vrefs = Set([x]) + method = DP._Hull(Hull(1e-3, Dict(x => (0., 1.))), vrefs) + DP._disaggregate_variables(model, z, vrefs, method) + + refexpr = DP._disaggregate_nl_expression(model, x, bvrefs[z], method) + ϵ = method.value + @test refexpr.head == :/ + @test x in refexpr.args + @test (1-ϵ)*bvrefs[z]+ϵ in refexpr.args +end + function test_disaggregate_nl_expression_var() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -154,7 +223,7 @@ end function test_disaggregate_nl_expression_aff() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -174,10 +243,37 @@ function test_disaggregate_nl_expression_aff() @test (1-ϵ)*zbin+ϵ in arg2.args end +function test_disaggregate_nl_expression_aff_mip() + model = GDPModel() + @variable(model, 10 <= x <= 100) + @variable(model, y, Bin) + @variable(model, z, Logical) + DP._reformulate_logical_variables(model) + bvrefs = DP._indicator_to_binary(model) + + vrefs = Set([x,y]) + method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.), y => (0., 1.))), vrefs) + DP._disaggregate_variables(model, z, vrefs, method) + + refexpr = DP._disaggregate_nl_expression(model, 2x + y + 1, bvrefs[z], method) + flatten!(refexpr) + x_z = variable_by_name(model, "x_z") + zbin = variable_by_name(model, "z") + ϵ = method.value + @test refexpr.head == :+ + @test 1 in refexpr.args + args2 = setdiff(refexpr.args, [1]) + for arg in args2 + @test arg.head == :/ + @test 2x_z in arg.args || 1y in arg.args + @test (1-ϵ)*zbin+ϵ in arg.args + end +end + function test_disaggregate_nl_expression_quad() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -200,7 +296,7 @@ end function test_disaggregate_nl_expession() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) + @variable(model, z, Logical) DP._reformulate_logical_variables(model) bvrefs = DP._indicator_to_binary(model) @@ -228,8 +324,8 @@ end function test_scalar_var_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, x in moiset(5), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, x in moiset(5), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), Set([x])) @@ -245,8 +341,8 @@ end function test_scalar_affine_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, 1x in moiset(5), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, 1x in moiset(5), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), Set([x])) @@ -262,8 +358,8 @@ end function test_vector_var_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, [x; x] in moiset(2), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, [x; x] in moiset(2), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), Set([x])) @@ -278,8 +374,8 @@ end function test_vector_affine_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, [x - 5; x - 5] in moiset(2), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, [x - 5; x - 5] in moiset(2), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), Set([x])) @@ -294,8 +390,8 @@ end function test_scalar_quadratic_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, x^2 in moiset(5), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, x^2 in moiset(5), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -319,8 +415,8 @@ end function test_vector_quadratic_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, [x^2 - 5; x^2 - 5] in moiset(2), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, [x^2 - 5; x^2 - 5] in moiset(2), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -341,11 +437,23 @@ function test_vector_quadratic_hull_1sided(moiset) @test ref[1].set == moiset(2) end #less than, greater than, equalto +function test_scalar_nonlinear_hull_1sided_error() + model = GDPModel() + @variable(model, 10 <= x <= 100) + @variable(model, z, Logical) + @constraint(model, con, log(x) <= 10, Disjunct(z)) + DP._reformulate_logical_variables(model) + zbin = variable_by_name(model, "z") + ϵ = 1e-3 + method = DP._Hull(Hull(ϵ, Dict(x => (0., 100.))), Set([x])) + DP._disaggregate_variables(model, z, Set([x]), method) + @test_throws ErrorException reformulate_disjunct_constraint(model, constraint_object(con), zbin, method) +end function test_scalar_nonlinear_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, x^3 in moiset(5), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, x^3 in moiset(5), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -371,11 +479,23 @@ function test_scalar_nonlinear_hull_1sided(moiset) @test DP._set_value(ref[1].set) == 0 end #nonpositives, nonnegatives, zeros +function test_vector_nonlinear_hull_1sided_error() + model = GDPModel() + @variable(model, 10 <= x <= 100) + @variable(model, z, Logical) + @constraint(model, con, [log(x),log(x)] <= [10,10], Disjunct(z)) + DP._reformulate_logical_variables(model) + zbin = variable_by_name(model, "z") + ϵ = 1e-3 + method = DP._Hull(Hull(ϵ, Dict(x => (0., 100.))), Set([x])) + DP._disaggregate_variables(model, z, Set([x]), method) + @test_throws ErrorException reformulate_disjunct_constraint(model, constraint_object(con), zbin, method) +end function test_vector_nonlinear_hull_1sided(moiset) model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, [x^3 - 5; x^3 - 5] in moiset(2), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, [x^3 - 5; x^3 - 5] in moiset(2), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -407,8 +527,8 @@ end function test_scalar_var_hull_2sided() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, x in MOI.Interval(5,5), DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, x in MOI.Interval(5,5), Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -427,8 +547,8 @@ end function test_scalar_affine_hull_2sided() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, 5 <= x <= 5, DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, 5 <= x <= 5, Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -447,8 +567,8 @@ end function test_scalar_quadratic_hull_2sided() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, 5 <= x^2 <= 5, DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, 5 <= x^2 <= 5, Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -471,11 +591,23 @@ function test_scalar_quadratic_hull_2sided() @test DP._set_value(ref[i].set) == 0 end end +function test_scalar_nonlinear_hull_2sided_error() + model = GDPModel() + @variable(model, 10 <= x <= 100) + @variable(model, z, Logical) + @constraint(model, con, 0 <= log(x) <= 10, Disjunct(z)) + DP._reformulate_logical_variables(model) + zbin = variable_by_name(model, "z") + ϵ = 1e-3 + method = DP._Hull(Hull(ϵ, Dict(x => (0., 100.))), Set([x])) + DP._disaggregate_variables(model, z, Set([x]), method) + @test_throws ErrorException reformulate_disjunct_constraint(model, constraint_object(con), zbin, method) +end function test_scalar_nonlinear_hull_2sided() model = GDPModel() @variable(model, 10 <= x <= 100) - @variable(model, z, LogicalVariable) - @constraint(model, con, 5 <= x^3 <= 5, DisjunctConstraint(z)) + @variable(model, z, Logical) + @constraint(model, con, 5 <= x^3 <= 5, Disjunct(z)) DP._reformulate_logical_variables(model) zbin = variable_by_name(model, "z") ϵ = 1e-3 @@ -512,11 +644,16 @@ end test_query_variable_bounds_error2() test_disaggregate_variables() test_aggregate_variable() + test_disaggregate_expression_var() + test_disaggregate_expression_var_binary() test_disaggregate_expression_affine() + test_disaggregate_expression_affine_mip() test_disaggregate_expression_quadratic() test_disaggregate_nl_expression_c() test_disaggregate_nl_expression_var() + test_disaggregate_nl_expression_var_binary() test_disaggregate_nl_expression_aff() + test_disaggregate_nl_expression_aff_mip() test_disaggregate_nl_expression_quad() test_disaggregate_nl_expession() for s in (MOI.LessThan, MOI.GreaterThan, MOI.EqualTo) @@ -525,14 +662,17 @@ end test_scalar_quadratic_hull_1sided(s) test_scalar_nonlinear_hull_1sided(s) end + test_scalar_nonlinear_hull_1sided_error() for s in (MOI.Nonpositives, MOI.Nonnegatives, MOI.Zeros) test_vector_var_hull_1sided(s) test_vector_affine_hull_1sided(s) test_vector_quadratic_hull_1sided(s) test_vector_nonlinear_hull_1sided(s) end + test_vector_nonlinear_hull_1sided_error() test_scalar_var_hull_2sided() test_scalar_affine_hull_2sided() test_scalar_quadratic_hull_2sided() test_scalar_nonlinear_hull_2sided() + test_scalar_nonlinear_hull_2sided_error() end \ No newline at end of file diff --git a/test/constraints/indicator.jl b/test/constraints/indicator.jl index f4f7c0a..14a29c9 100644 --- a/test/constraints/indicator.jl +++ b/test/constraints/indicator.jl @@ -1,13 +1,13 @@ function test_indicator_scalar_constraints() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, x == 5, DisjunctConstraint(y[1])) - @constraint(model, x <= 5, DisjunctConstraint(y[1])) - @constraint(model, x >= 5, DisjunctConstraint(y[1])) - @constraint(model, x == 10, DisjunctConstraint(y[2])) - @constraint(model, x <= 10, DisjunctConstraint(y[2])) - @constraint(model, x >= 10, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, x == 5, Disjunct(y[1])) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[1])) + @constraint(model, x == 10, Disjunct(y[2])) + @constraint(model, x <= 10, Disjunct(y[2])) + @constraint(model, x >= 10, Disjunct(y[2])) @disjunction(model, y) reformulate_model(model, Indicator()) @@ -23,15 +23,16 @@ function test_indicator_vector_constraints() model = GDPModel() A = [1 0; 0 1] @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, A*[x,x] == [5,5], DisjunctConstraint(y[1])) - @constraint(model, A*[x,x] == [10,10], DisjunctConstraint(y[2])) + @variable(model, y[1:3], Logical) + @constraint(model, A*[x,x] == [5,5], Disjunct(y[1])) + @constraint(model, A*[x,x] <= [0,0], Disjunct(y[2])) + @constraint(model, A*[x,x] >= [10,10], Disjunct(y[3])) @disjunction(model, y) reformulate_model(model, Indicator()) ref_cons = DP._reformulation_constraints(model) ref_cons_obj = constraint_object.(ref_cons) - @test length(ref_cons) == 4 + @test length(ref_cons) == 6 @test all(is_valid.(model, ref_cons)) @test all(isa.(ref_cons_obj, VectorConstraint)) @test all([cobj.set isa MOI.Indicator for cobj in ref_cons_obj]) @@ -40,9 +41,9 @@ end function test_indicator_array() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, [1:3, 1:2], x <= 6, DisjunctConstraint(y[1])) - @constraint(model, [1:3, 1:2], x >= 6, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, [1:3, 1:2], x <= 6, Disjunct(y[1])) + @constraint(model, [1:3, 1:2], x >= 6, Disjunct(y[2])) @disjunction(model, y) reformulate_model(model, Indicator()) @@ -57,9 +58,9 @@ end function test_indicator_dense_axis() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, [["a","b","c"],[1,2]], x <= 7, DisjunctConstraint(y[1])) - @constraint(model, [["a","b","c"],[1,2]], x >= 7, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, [["a","b","c"],[1,2]], x <= 7, Disjunct(y[1])) + @constraint(model, [["a","b","c"],[1,2]], x >= 7, Disjunct(y[2])) @disjunction(model, y) reformulate_model(model, Indicator()) @@ -74,9 +75,9 @@ end function test_indicator_sparse_axis() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @constraint(model, [i = 1:3, j = 1:3; j > i], x <= 7, DisjunctConstraint(y[1])) - @constraint(model, [i = 1:3, j = 1:3; j > i], x >= 7, DisjunctConstraint(y[2])) + @variable(model, y[1:2], Logical) + @constraint(model, [i = 1:3, j = 1:3; j > i], x <= 7, Disjunct(y[1])) + @constraint(model, [i = 1:3, j = 1:3; j > i], x >= 7, Disjunct(y[2])) @disjunction(model, y) reformulate_model(model, Indicator()) @@ -91,13 +92,13 @@ end function test_indicator_nested() model = GDPModel() @variable(model, x) - @variable(model, y[1:2], LogicalVariable) - @variable(model, z[1:2], LogicalVariable) - @constraint(model, x <= 5, DisjunctConstraint(y[1])) - @constraint(model, x >= 5, DisjunctConstraint(y[2])) - @disjunction(model, y, DisjunctConstraint(z[1])) - @constraint(model, x <= 10, DisjunctConstraint(z[1])) - @constraint(model, x >= 10, DisjunctConstraint(z[2])) + @variable(model, y[1:2], Logical) + @variable(model, z[1:2], Logical) + @constraint(model, x <= 5, Disjunct(y[1])) + @constraint(model, x >= 5, Disjunct(y[2])) + @disjunction(model, y, Disjunct(z[1])) + @constraint(model, x <= 10, Disjunct(z[1])) + @constraint(model, x >= 10, Disjunct(z[2])) @disjunction(model, z) reformulate_model(model, Indicator()) diff --git a/test/constraints/proposition.jl b/test/constraints/proposition.jl index 75cfb46..7e2173f 100644 --- a/test/constraints/proposition.jl +++ b/test/constraints/proposition.jl @@ -1,6 +1,14 @@ +function test_op_fallback() + @test_throws ErrorException iff(1,1) + @test_throws ErrorException implies(1,1) + @test_throws ErrorException 1 ⇔ 1 + @test_throws ErrorException 1 ⟹ 1 +end + function test_proposition_add_fail() m = GDPModel() - @variable(m, y[1:3], LogicalVariable) + @variable(m, y[1:3], Logical) + @test_throws ErrorException @constraint(m, y[1] in IsTrue()) @test_throws ErrorException @constraint(Model(), logical_or(y...) in IsTrue()) @test_throws ErrorException @constraint(m, logical_or(y...) == 2) @test_throws ErrorException @constraint(m, logical_or(y...) <= 1) @@ -13,7 +21,7 @@ end function test_negation_add_success() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) c1 = @constraint(model, logical_not(y) in IsTrue()) @constraint(model, c2, ¬y in IsTrue()) @test is_valid(model, c1) @@ -40,7 +48,7 @@ end function test_implication_add_success() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) @constraint(model, c1, implies(y...) in IsTrue()) @constraint(model, c2, (y[1] ⟹ y[2]) in IsTrue()) @test_macro_throws ErrorException @constraint(model, y[1] ⟹ y[2] in IsTrue()) @@ -54,7 +62,7 @@ end function test_equivalence_add_success() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) @constraint(model, c1, iff(y...) in IsTrue()) @constraint(model, c2, (y[1] ⇔ y[2]) in IsTrue()) @test_macro_throws ErrorException @constraint(model, y[1] ⇔ y[2] in IsTrue()) @@ -68,7 +76,7 @@ end function test_intersection_and_flatten_add_success() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, c1, logical_and(y...) in IsTrue()) @constraint(model, c2, ∧(y...) in IsTrue()) @constraint(model, c3, y[1] ∧ y[2] ∧ y[3] in IsTrue()) @@ -88,7 +96,7 @@ end function test_union_and_flatten_add_success() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, c1, logical_or(y...) in IsTrue()) @constraint(model, c2, ∨(y...) in IsTrue()) @constraint(model, c3, y[1] ∨ y[2] ∨ y[3] in IsTrue()) @@ -108,7 +116,7 @@ end function test_proposition_add_array() model = GDPModel() - @variable(model, y[1:2, 1:3, 1:4], LogicalVariable) + @variable(model, y[1:2, 1:3, 1:4], Logical) @constraint(model, con[i=1:2,j=1:3], ∨(y[i,j,:]...) in IsTrue()) @test con isa Matrix{LogicalConstraintRef} @test length(con) == 6 @@ -118,7 +126,7 @@ function test_proposition_add_dense_axis() model = GDPModel() I = ["a", "b", "c"] J = [1, 2] - @variable(model, y[I, J, 1:4], LogicalVariable) + @variable(model, y[I, J, 1:4], Logical) @constraint(model, con[i=I,j=J], ∨(y[i,j,:]...) in IsTrue()) @test con isa Containers.DenseAxisArray @test con.axes[1] == ["a","b","c"] @@ -128,7 +136,7 @@ end function test_proposition_add_sparse_axis() model = GDPModel() - @variable(model, y[1:3, 1:3, 1:4], LogicalVariable) + @variable(model, y[1:3, 1:3, 1:4], Logical) @constraint(model, con[i=1:3,j=1:3; j > i], ∨(y[i,j,:]...) in IsTrue()) @test con isa Containers.SparseAxisArray @test length(con) == 3 @@ -138,7 +146,7 @@ end function test_proposition_set_name() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) c1 = @constraint(model, logical_not(y...) in IsTrue()) set_name(c1, "proposition") @test name(c1) == "proposition" @@ -146,7 +154,7 @@ end function test_proposition_delete() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) c1 = @constraint(model, logical_not(y...) in IsTrue()) @test_throws AssertionError delete(GDPModel(), c1) @@ -157,7 +165,7 @@ end function test_negation_reformulation() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @constraint(model, ¬y in IsTrue()) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -169,7 +177,7 @@ end function test_implication_reformulation() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) @constraint(model, implies(y[1], y[2]) in IsTrue()) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -183,14 +191,14 @@ end function test_implication_reformulation_fail() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, implies(y...) in IsTrue()) @test_throws ErrorException reformulate_model(model, DummyReformulation()) end function test_equivalence_reformulation() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) @constraint(model, iff(y[1], y[2]) in IsTrue()) reformulate_model(model, DummyReformulation()) ref_cons = DP._reformulation_constraints(model) @@ -208,7 +216,7 @@ end function test_intersection_reformulation() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) @constraint(model, ∧(y[1], y[2]) in IsTrue()) reformulate_model(model, DummyReformulation()) ref_cons = DP._reformulation_constraints(model) @@ -224,7 +232,7 @@ end function test_implication_reformulation() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) @constraint(model, ∨(y[1], y[2]) in IsTrue()) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -238,7 +246,7 @@ end function test_lvar_cnf_functions() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test DP._eliminate_equivalence(y) == y @test DP._eliminate_implication(y) == y @test DP._move_negations_inward(y) == y @@ -251,7 +259,7 @@ end function test_eliminate_equivalence() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) ex = y[1] ⇔ y[2] new_ex = DP._eliminate_equivalence(ex) @test new_ex.head == :&& @@ -262,9 +270,16 @@ function test_eliminate_equivalence() @test Set(new_ex.args[2].args) == Set{Any}(y) end +function test_eliminate_equivalence_error() + model = GDPModel() + @variable(model, y, Logical) + ex = iff(y) + @test_throws ErrorException DP._eliminate_equivalence(ex) +end + function test_eliminate_equivalence_flat() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) ex = iff(y...) new_ex = DP._eliminate_equivalence(ex) @test new_ex.head == :&& @@ -281,7 +296,7 @@ end function test_eliminate_equivalence_nested() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) ex = iff(y[1], iff(y[2],y[3])) new_ex = DP._eliminate_equivalence(ex) @test new_ex.head == :&& @@ -298,7 +313,7 @@ end function test_eliminate_implication() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) ex = y[1] ⟹ y[2] new_ex = DP._eliminate_implication(ex) @test new_ex.head == :|| @@ -309,14 +324,14 @@ end function test_eliminate_implication_error() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) ex = implies(y...) @test_throws ErrorException DP._eliminate_implication(ex) end function test_eliminate_implication_nested() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) ex = (y[1] ⟹ y[2]) ⟹ y[3] new_ex = DP._eliminate_implication(ex) @test new_ex.head == :|| @@ -330,14 +345,14 @@ end function test_move_negation_inward_error() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) ex = ¬(y, y) @test_throws ErrorException DP._move_negations_inward(ex) end function test_move_negation_inward() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) ex = ¬y new_ex = DP._move_negations_inward(ex) @test new_ex.head == :! @@ -346,20 +361,20 @@ end function test_move_negation_inward_nested() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) ex = ¬¬y @test DP._move_negations_inward(ex) == y end function test_negate_error() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test_throws ErrorException DP._negate(iff(y,y)) end function test_negate_or() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) ex = ∨(y...) new_ex = DP._negate_or(ex) @test new_ex.head == :&& @@ -371,13 +386,13 @@ end function test_negate_or_error() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test_throws ErrorException DP._negate_or(∨(y)) end function test_negate_and() model = GDPModel() - @variable(model, y[1:2], LogicalVariable) + @variable(model, y[1:2], Logical) ex = ∧(y...) new_ex = DP._negate_and(ex) @test new_ex.head == :|| @@ -389,25 +404,25 @@ end function test_negate_and_error() model = GDPModel() - @variable(model, y, LogicalVariable) - @test_throws ErrorException DP._negate_or(∧(y)) + @variable(model, y, Logical) + @test_throws ErrorException DP._negate_and(∧(y)) end function test_negate_negation() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test DP._negate_negation(¬y) == y end function test_negate_negation_error() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test_throws ErrorException DP._negate_negation(¬(y,y)) end function test_distribute_and_over_or() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) ex = y[1] ∨ (y[2] ∧ y[3]) new_ex = DP._distribute_and_over_or(ex) @test new_ex.head == :&& @@ -419,9 +434,16 @@ function test_distribute_and_over_or() @test y[3] in new_ex.args[1].args || y[3] in new_ex.args[2].args end +function test_distribute_and_over_or_error() + model = GDPModel() + @variable(model, y[1:2], Logical) + ex = ∨(y[1] ∧ y[2]) + @test_throws ErrorException DP._distribute_and_over_or(ex) +end + function test_distribute_and_over_or_nested() model = GDPModel() - @variable(model, y[1:4], LogicalVariable) + @variable(model, y[1:4], Logical) ex = (y[1] ∧ y[2]) ∨ (y[3] ∧ y[4]) new_ex = DP._flatten(DP._distribute_and_over_or(ex)) for arg in new_ex.args @@ -450,7 +472,7 @@ end function test_to_cnf() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) ex = iff(y...) new_ex = DP._to_cnf(ex) @test new_ex.head == :&& @@ -486,7 +508,21 @@ function test_to_cnf() (!(y[1] in new_ex.args[6].args) && !(y[2] in new_ex.args[6].args) && y[3] in new_ex.args[6].args) end +function test_isa_literal_other() + @test !DP._isa_literal(1) +end + +function test_reformulate_clause_error() + model = GDPModel() + @variable(model, y[1:2], Logical) + ex = y[1] ∧ y[2] + @test_throws ErrorException DP._reformulate_clause(model, ex) +end + @testset "Logical Proposition Constraints" begin + @testset "Logical Operators" begin + test_op_fallback() + end @testset "Add Proposition" begin test_proposition_add_fail() test_negation_add_success() @@ -505,10 +541,13 @@ end test_equivalence_reformulation() test_intersection_reformulation() test_implication_reformulation() + test_reformulate_clause_error() end @testset "Conjunctive Normal Form" begin + test_isa_literal_other() test_lvar_cnf_functions() test_eliminate_equivalence() + test_eliminate_equivalence_error() test_eliminate_equivalence_flat() test_eliminate_equivalence_nested() test_eliminate_implication() @@ -525,6 +564,7 @@ end test_negate_negation() test_negate_negation_error() test_distribute_and_over_or() + test_distribute_and_over_or_error() test_distribute_and_over_or_nested() test_to_cnf() end diff --git a/test/constraints/selector.jl b/test/constraints/selector.jl index ab7ae37..cfbc521 100644 --- a/test/constraints/selector.jl +++ b/test/constraints/selector.jl @@ -1,6 +1,6 @@ function test_selector_add_fail() m = GDPModel() - @variable(m, y[1:3], LogicalVariable) + @variable(m, y[1:3], Logical) @test_throws ErrorException @constraint(Model(), y in AtMost(2)) @test_throws ErrorException @constraint(m, logical_or(y...) in Exactly(1)) @test_throws ErrorException @constraint(m, sin.(y) in Exactly(1)) @@ -11,7 +11,7 @@ end function test_selector_add_success() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) c1 = @constraint(model, y in Exactly(1)) @constraint(model, c2, y in Exactly(1)) @test owner_model(c1) == model @@ -34,7 +34,7 @@ end function test_nested_selector_add_success() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) c1 = @constraint(model, y[1:2] in Exactly(y[3])) @test is_valid(model, c1) @test length(constraint_object(c1).func) == 3 @@ -45,7 +45,7 @@ end function test_selector_add_array() model = GDPModel() - @variable(model, y[1:2, 1:3, 1:4], LogicalVariable) + @variable(model, y[1:2, 1:3, 1:4], Logical) @constraint(model, con[i=1:2, j=1:3], y[i,j,:] in Exactly(1)) @test con isa Matrix{LogicalConstraintRef} @test length(con) == 6 @@ -55,7 +55,7 @@ function test_selector_add_dense_axis() model = GDPModel() I = ["a", "b", "c"] J = [1, 2] - @variable(model, y[I, J, 1:4], LogicalVariable) + @variable(model, y[I, J, 1:4], Logical) @constraint(model, con[i=I, j=J], y[i,j,:] in Exactly(1)) @test con isa Containers.DenseAxisArray @test con.axes[1] == ["a","b","c"] @@ -65,7 +65,7 @@ end function test_selector_add_sparse_axis() model = GDPModel() - @variable(model, y[1:3, 1:3, 1:4], LogicalVariable) + @variable(model, y[1:3, 1:3, 1:4], Logical) @constraint(model, con[i=1:3, j=1:3; j > i], y[i,j,:] in Exactly(1)) @test con isa Containers.SparseAxisArray @test length(con) == 3 @@ -75,7 +75,7 @@ end function test_selector_set_name() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) c1 = @constraint(model, y in Exactly(1)) set_name(c1, "selector") @test name(c1) == "selector" @@ -83,7 +83,7 @@ end function test_selector_delete() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) c1 = @constraint(model, y in Exactly(1)) @test_throws AssertionError delete(GDPModel(), c1) @@ -95,7 +95,7 @@ end function test_exactly_reformulation() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, y in Exactly(1)) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -107,7 +107,7 @@ end function test_atleast_reformulation() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, y in AtLeast(1)) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -119,7 +119,7 @@ end function test_atmost_reformulation() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, y in AtMost(1)) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -131,7 +131,7 @@ end function test_nested_exactly_reformulation() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, y[1:2] in Exactly(y[3])) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -146,7 +146,7 @@ end function test_nested_atleast_reformulation() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, y[1:2] in AtLeast(y[3])) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] @@ -161,7 +161,7 @@ end function test_nested_atmost_reformulation() model = GDPModel() - @variable(model, y[1:3], LogicalVariable) + @variable(model, y[1:3], Logical) @constraint(model, y[1:2] in AtMost(y[3])) reformulate_model(model, DummyReformulation()) ref_con = DP._reformulation_constraints(model)[1] diff --git a/test/jump.jl b/test/jump.jl new file mode 100644 index 0000000..22db7ca --- /dev/null +++ b/test/jump.jl @@ -0,0 +1,13 @@ +function test_moi_set() + for (jumpset, moisettype) in [(AtLeast(1), DP._MOIAtLeast), + (AtMost(1), DP._MOIAtMost), + (Exactly(1), DP._MOIExactly)] + moiset = moi_set(jumpset, 10) + @test moiset isa moisettype + @test moiset.dimension == 10 + end +end + +@testset "JuMP" begin + test_moi_set() +end \ No newline at end of file diff --git a/test/model.jl b/test/model.jl index 83a2f4b..efbbd26 100644 --- a/test/model.jl +++ b/test/model.jl @@ -1,5 +1,21 @@ using HiGHS +function test_GDPData() + gdpdata = GDPData( + DP._MOIUC.CleverDict{LogicalVariableIndex, LogicalVariableData}(), + DP._MOIUC.CleverDict{LogicalConstraintIndex, ConstraintData}(), + DP._MOIUC.CleverDict{DisjunctConstraintIndex, ConstraintData}(), + DP._MOIUC.CleverDict{DisjunctionIndex, ConstraintData{Disjunction}}(), + Dict{LogicalVariableRef, JuMP.VariableRef}(), + Dict{LogicalVariableRef, Vector{Union{DisjunctConstraintRef, DisjunctionRef}}}(), + Vector{JuMP.VariableRef}(), + Vector{JuMP.ConstraintRef}(), + nothing, + false + ) + gdpdata isa GDPData +end + function test_empty_model() model = GDPModel() @test gdp_data(model) isa GDPData @@ -32,6 +48,7 @@ function test_set_optimizer() end @testset "GDP Model" begin + test_GDPData() test_empty_model() test_non_gdp_model() test_creation_optimizer() diff --git a/test/runtests.jl b/test/runtests.jl index e06b246..f607a9e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,4 @@ using DisjunctiveProgramming -using JuMP using Test const DP = DisjunctiveProgramming @@ -28,6 +27,7 @@ end include("aqua.jl") include("model.jl") +include("jump.jl") include("variables/query.jl") include("variables/logical.jl") include("constraints/selector.jl") @@ -36,5 +36,6 @@ include("constraints/disjunct.jl") include("constraints/indicator.jl") include("constraints/bigm.jl") include("constraints/hull.jl") -include("disjunction.jl") +include("constraints/fallback.jl") +include("constraints/disjunction.jl") include("solve.jl") \ No newline at end of file diff --git a/test/solve.jl b/test/solve.jl index 697ccde..0cc2edb 100644 --- a/test/solve.jl +++ b/test/solve.jl @@ -4,14 +4,14 @@ function test_linear_gdp_example() m = GDPModel(HiGHS.Optimizer) set_attribute(m, MOI.Silent(), true) @variable(m, 1 ≤ x[1:2] ≤ 9) - @variable(m, Y[1:2], LogicalVariable) - @variable(m, W[1:2], LogicalVariable) + @variable(m, Y[1:2], Logical) + @variable(m, W[1:2], Logical) @objective(m, Max, sum(x)) - @constraint(m, y1[i=1:2], [1,4][i] ≤ x[i] ≤ [3,6][i], DisjunctConstraint(Y[1])) - @constraint(m, w1[i=1:2], [1,5][i] ≤ x[i] ≤ [2,6][i], DisjunctConstraint(W[1])) - @constraint(m, w2[i=1:2], [2,4][i] ≤ x[i] ≤ [3,5][i], DisjunctConstraint(W[2])) - @constraint(m, y2[i=1:2], [8,1][i] ≤ x[i] ≤ [9,2][i], DisjunctConstraint(Y[2])) - @disjunction(m, inner, [W[1], W[2]], DisjunctConstraint(Y[1])) + @constraint(m, y1[i=1:2], [1,4][i] ≤ x[i] ≤ [3,6][i], Disjunct(Y[1])) + @constraint(m, w1[i=1:2], [1,5][i] ≤ x[i] ≤ [2,6][i], Disjunct(W[1])) + @constraint(m, w2[i=1:2], [2,4][i] ≤ x[i] ≤ [3,5][i], Disjunct(W[2])) + @constraint(m, y2[i=1:2], [8,1][i] ≤ x[i] ≤ [9,2][i], Disjunct(Y[2])) + @disjunction(m, inner, [W[1], W[2]], Disjunct(Y[1])) @disjunction(m, outer, [Y[1], Y[2]]) @constraint(m, Y in Exactly(1)) @constraint(m, W in Exactly(Y[1])) diff --git a/test/variables/logical.jl b/test/variables/logical.jl index 489474f..255c2ef 100644 --- a/test/variables/logical.jl +++ b/test/variables/logical.jl @@ -1,12 +1,26 @@ # test creating, modifying, and reformulating logical variables + +function test_base() + model = GDPModel() + @variable(model, y, Logical) + @test Base.broadcastable(y) isa Base.RefValue{LogicalVariableRef} + @test length(y) == 1 +end + function test_lvar_add_fail() model = Model() - @test_throws ErrorException @variable(model, y, LogicalVariable) + @test_throws ErrorException @variable(model, y, Logical) + @test_throws ErrorException @variable(model, y, Logical; kwarg=true) + @test_throws ErrorException @variable(model, 0 <= y, Logical) + @test_throws ErrorException @variable(model, y <= 1, Logical) + @test_throws ErrorException @variable(model, y, Logical, integer=true) + @test_throws ErrorException @variable(model, y, Logical, start=2) + @test_throws ErrorException @variable(model, y == 2, Logical) end function test_lvar_add_success() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test typeof(y) == LogicalVariableRef @test owner_model(y) == model @test is_valid(model, y) @@ -24,14 +38,14 @@ end function test_lvar_add_array() model = GDPModel() - @variable(model, y[1:3, 1:2], LogicalVariable) + @variable(model, y[1:3, 1:2], Logical) @test y isa Array{LogicalVariableRef, 2} @test length(y) == 6 end function test_lvar_add_dense_axis() model = GDPModel() - @variable(model, y[["a","b","c"],[1,2]], LogicalVariable) + @variable(model, y[["a","b","c"],[1,2]], Logical) @test y isa Containers.DenseAxisArray @test length(y) == 6 @test y.axes[1] == ["a","b","c"] @@ -41,7 +55,7 @@ end function test_lvar_add_sparse_axis() model = GDPModel() - @variable(model, y[i = 1:3, j = 1:3; j > i], LogicalVariable) + @variable(model, y[i = 1:3, j = 1:3; j > i], Logical) @test y isa Containers.SparseAxisArray @test length(y) == 3 @test y.names == (:i, :j) @@ -50,7 +64,7 @@ end function test_lvar_set_name() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) set_name(y, "z") @test name(y) == "z" #reformulate the variable @@ -59,7 +73,7 @@ end function test_lvar_creation_start_value() model = GDPModel() - @variable(model, y, LogicalVariable, start = true) + @variable(model, y, Logical, start = true) @test start_value(y) #reformulate the variable test_lvar_reformulation(model, y) @@ -67,7 +81,7 @@ end function test_lvar_set_start_value() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test isnothing(start_value(y)) set_start_value(y, false) @test !start_value(y) @@ -75,9 +89,15 @@ function test_lvar_set_start_value() test_lvar_reformulation(model, y) end +function test_lvar_creation_fix_value() + model = GDPModel() + @variable(model, y == true, Logical) + @test fix_value(y) +end + function test_lvar_fix_value() model = GDPModel() - @variable(model, y, LogicalVariable) + @variable(model, y, Logical) @test isnothing(fix_value(y)) fix(y, true) @test fix_value(y) @@ -90,11 +110,11 @@ end function test_lvar_delete() model = GDPModel() - @variable(model, y, LogicalVariable) - @variable(model, z, LogicalVariable) + @variable(model, y, Logical) + @variable(model, z, Logical) @variable(model, x) - @constraint(model, con, x <= 10, DisjunctConstraint(y)) - @constraint(model, con2, x >= 50, DisjunctConstraint(z)) + @constraint(model, con, x <= 10, Disjunct(y)) + @constraint(model, con2, x >= 50, Disjunct(z)) @disjunction(model, disj, [y, z]) @constraint(model, lcon, y ∨ z in IsTrue()) DP._reformulate_logical_variables(model) @@ -115,7 +135,7 @@ end function test_lvar_reformulation() model = GDPModel() - @variable(model, y, LogicalVariable, start = false) + @variable(model, y, Logical, start = false) fix(y, true) test_lvar_reformulation(model, y) end @@ -146,6 +166,9 @@ function test_lvar_reformulation(model::Model, lvref::LogicalVariableRef) end @testset "Logical Variables" begin + @testset "Base Methods" begin + test_base() + end @testset "Add Logical Variables" begin test_lvar_add_fail() test_lvar_add_success() @@ -157,6 +180,7 @@ end test_lvar_set_name() test_lvar_creation_start_value() test_lvar_set_start_value() + test_lvar_creation_fix_value() test_lvar_fix_value() end @testset "Delete Logical Variables" begin diff --git a/test/variables/query.jl b/test/variables/query.jl index 8ed7015..294ff74 100644 --- a/test/variables/query.jl +++ b/test/variables/query.jl @@ -18,7 +18,7 @@ function test_interrogate_variables() f = Base.Fix1(push!, vars) #interrogator m = GDPModel() @variable(m, x) - @variable(m, y, LogicalVariable) + @variable(m, y, Logical) DP._interrogate_variables(f, [x, y]) @test x in vars @test y in vars @@ -30,7 +30,7 @@ function test_interrogate_affexpr() f = Base.Fix1(push!, vars) #interrogator m = GDPModel() @variable(m, x) - @variable(m, y, LogicalVariable) + @variable(m, y, Logical) @variable(m, z) DP._interrogate_variables(f, x + y + z) @test x in vars @@ -44,7 +44,7 @@ function test_interrogate_quadexpr() f = Base.Fix1(push!, vars) #interrogator m = GDPModel() @variable(m, x) - @variable(m, y, LogicalVariable) + @variable(m, y, Logical) @variable(m, z) DP._interrogate_variables(f, x^2 + x*y + z + 1) @test x in vars @@ -59,7 +59,7 @@ function test_interrogate_nonlinear_expr() f = Base.Fix1(push!, vars) #interrogator m = GDPModel() @variable(m, x) - @variable(m, y, LogicalVariable) + @variable(m, y, Logical) @variable(m, z) DP._interrogate_variables(f, sin(exp(x^2 + 1)) + cos(x) + y + 2) @test x in vars @@ -72,8 +72,8 @@ function test_interrogate_logical_expr() vars = Set() f = Base.Fix1(push!, vars) #interrogator m = GDPModel() - @variable(m, y, LogicalVariable) - @variable(m, w[1:5], LogicalVariable) + @variable(m, y, Logical) + @variable(m, w[1:5], Logical) ex = (implies(w[1], w[2]) ∧ w[3]) ⇔ (¬w[4] ∨ y) DP._interrogate_variables(f, ex) @test w[1] in vars @@ -87,8 +87,8 @@ end function test_interrogate_proposition_constraint() m = GDPModel() - @variable(m, y, LogicalVariable) - @variable(m, w[1:5], LogicalVariable) + @variable(m, y, Logical) + @variable(m, w[1:5], Logical) ex = (implies(w[1], w[2]) ∧ w[3]) ⇔ (¬w[4] ∨ y) @constraint(m, con, ex in IsTrue()) obj = constraint_object(con) @@ -104,8 +104,8 @@ end function test_interrogate_selector_constraint() m = GDPModel() - @variable(m, y, LogicalVariable) - @variable(m, w[1:5], LogicalVariable) + @variable(m, y, Logical) + @variable(m, w[1:5], Logical) @constraint(m, con, w[1:4] in AtMost(y)) obj = constraint_object(con) vars = DP._get_constraint_variables(m, obj) @@ -121,9 +121,9 @@ end function test_interrogate_disjunction() m = GDPModel() @variable(m, -5 ≤ x[1:2] ≤ 10) - @variable(m, Y[1:2], LogicalVariable) - @constraint(m, [i = 1:2], 0 ≤ x[i] ≤ [3,4][i], DisjunctConstraint(Y[1])) - @constraint(m, [i = 1:2], [5,4][i] ≤ x[i] ≤ [9,6][i], DisjunctConstraint(Y[2])) + @variable(m, Y[1:2], Logical) + @constraint(m, [i = 1:2], 0 ≤ x[i] ≤ [3,4][i], Disjunct(Y[1])) + @constraint(m, [i = 1:2], [5,4][i] ≤ x[i] ≤ [9,6][i], Disjunct(Y[2])) @disjunction(m, Y) disj = DP._disjunctions(m)[DisjunctionIndex(1)].constraint vars = DP._get_disjunction_variables(m, disj) @@ -134,20 +134,20 @@ function test_interrogate_nested_disjunction() m = GDPModel() @variable(m, -5 <= x[1:3] <= 5) - @variable(m, y[1:2], LogicalVariable) - @constraint(m, x[1] <= -2, DisjunctConstraint(y[1])) - @constraint(m, x[1] >= 2, DisjunctConstraint(y[2])) + @variable(m, y[1:2], Logical) + @constraint(m, x[1] <= -2, Disjunct(y[1])) + @constraint(m, x[1] >= 2, Disjunct(y[2])) @disjunction(m, y) - @variable(m, w[1:2], LogicalVariable) - @constraint(m, x[2] <= -3, DisjunctConstraint(w[1])) - @constraint(m, x[2] >= 3, DisjunctConstraint(w[2])) - @disjunction(m, w, DisjunctConstraint(y[1])) + @variable(m, w[1:2], Logical) + @constraint(m, x[2] <= -3, Disjunct(w[1])) + @constraint(m, x[2] >= 3, Disjunct(w[2])) + @disjunction(m, w, Disjunct(y[1])) - @variable(m, z[1:2], LogicalVariable) - @constraint(m, x[3] <= -4, DisjunctConstraint(z[1])) - @constraint(m, x[3] >= 4, DisjunctConstraint(z[2])) - @disjunction(m, z, DisjunctConstraint(w[1])) + @variable(m, z[1:2], Logical) + @constraint(m, x[3] <= -4, Disjunct(z[1])) + @constraint(m, x[3] >= 4, Disjunct(z[2])) + @disjunction(m, z, Disjunct(w[1])) disj = DP._disjunctions(m)[DisjunctionIndex(1)].constraint vars = DP._get_disjunction_variables(m, disj)