# Range constraint

**URL:** <https://discourse.julialang.org/t/range-constraint/64819>\
**Category:** Optimization (Mathematical)\
**Tags:** jump\
**Created:** [July 17, 2021, 4:31pm UTC](https://discourse.julialang.org/t/range-constraint/64819 "2021-07-17T16:31:26Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![mjanun](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@mjanun](https://discourse.julialang.org/u/mjanun)\
**Post date:** [July 17, 2021, 4:31pm UTC](https://discourse.julialang.org/t/range-constraint/64819/1 "2021-07-17T16:31:26Z")

</div>

I have a constraint that can be either a range or an equality depending upon whether a user passes a range (i.e. two arguments) or a single value as a constraint. I convert the range constraint to an equality using the standard technique, by defining a slack variable `u`. I define an abstract type `SPECIAL_CONS` with two subtypes `Range` and `Equality`.  
What’s the correct way of generating this constraint and adding it to the model (we don’t know in advance whether a a single value or two values will be passed so that correct constraint is generated)?

```julia
using JuMP, Cbc

abstract type SPECIAL_CONS end
struct Range <: SPECIAL_CONS end
struct Equality <: SPECIAL_CONS end

function constraint_gen(lb,ub,::Range)
    @variable(model,0<=u<=ub-lb)
    return @constraint(model,u+sum(C[i]*x[i] for i in 1:10) == ub)
end
function constraint_gen(ub,::Equality)
    return @constraint(model,sum(C[i]*x[i] for i in 1:10) == ub)
end

function solve_model(constraint_gen::Function)
    c = rand(10)
    d = rand(10)
    model = Model(Cbc.Optimizer)
    @variable(model, x[1:10] >= 0)
    @constraint(model,sum(x[i]*c[i] for i=1:10) >=sum(d))
    constraint_gen(constraint_gen::Function)
    optimize!(model)
end

```

If I run the code using the following, it errors as model is not defined, but adding model as argument to the `constraint_gen` function also errors.

```julia
solve_model(constraint_gen(1,Equality()))

```

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [July 17, 2021, 4:34pm UTC](https://discourse.julialang.org/t/range-constraint/64819/2 "2021-07-17T16:34:04Z")

</div>

> [@mjanun](#):
>
> adding model as argument to the `constraint_gen` function also errors

That sounds like it should work, what code did you run and what error did you get?

---

<div class="post-metadata">

**Author:** ![mjanun](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@mjanun](https://discourse.julialang.org/u/mjanun)\
**Post date:** [July 17, 2021, 4:57pm UTC](https://discourse.julialang.org/t/range-constraint/64819/3 "2021-07-17T16:57:07Z")

</div>

```julia
abstract type SPECIAL_CONS end
struct Range <: SPECIAL_CONS end
struct Equality <: SPECIAL_CONS end

function constraint_gen(model,lb,ub,::Range)
    @variable(model,0<=u<=ub-lb)
    return @constraint(model,u+sum(C[i]*x[i] for i in 1:10) == ub)
end
function constraint_gen(model,ub,::Equality)
    return @constraint(model,sum(C[i]*x[i] for i in 1:10) == ub)
end

function solve_model(constraint_gen::Function)
    c = rand(10)
    d = rand(10)
    model = Model(Cbc.Optimizer)
    @variable(model, x[1:10] >= 0)
    @constraint(model,sum(x[i]*c[i] for i=1:10) >=sum(d))
    constraint_gen(constraint_gen::Function)
    optimize!(model)
end

solve_model(constraint_gen(model,1,Equality()))

```

This gives error “UndefVarError: model not defined”. I understand why I get this error, but how to correct it as model is generated by the function `solve_model()`?

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [July 17, 2021, 5:00pm UTC](https://discourse.julialang.org/t/range-constraint/64819/4 "2021-07-17T17:00:55Z")

</div>

Ah ok, you just need to pass the `model` along when you call `constraint_gen`. So change the line

> [@mjanun](#):
>
> `constraint_gen(constraint_gen::Function)`

to

```julia
constraint_gen(model, constraint_gen)

```

---

<div class="post-metadata">

**Author:** ![mjanun](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@mjanun](https://discourse.julialang.org/u/mjanun)\
**Post date:** [July 17, 2021, 5:13pm UTC](https://discourse.julialang.org/t/range-constraint/64819/5 "2021-07-17T17:13:08Z")

</div>

Changing to

> [@ericphanson](#):
>
> `constraint_gen(model, constraint_gen)`

gives the same error. Calling `solve_model(constraint_gen(model,1,Equality()))` expects `model` to be an argument, and I am generating the model inside the function `solve_model`.

It is not obvious how the code will work to use the correct function definition depending upon if one value is passed `solve_model(ub)` or a range is passed `solve_model(lb,ub)`

Do I need to use something like below?

```julia
if one_input  
    solve_model(constraint_gen(model,1,Equality()))
elseif range
    solve_model(constraint_gen(model,0.5,1,Range()))
end

```

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [July 17, 2021, 5:18pm UTC](https://discourse.julialang.org/t/range-constraint/64819/6 "2021-07-17T17:18:31Z")

</div>

Looking closer, it seems you are also not passing the variables `C` and `x`, and are passing `constraint_gen` to itself! You need to put all the variables you need to use in function signature and then pass those variables when you call the function. So if you define the function `constraint_gen(lb,ub,::Range)` then you only have access to those variables inside the function (except if they are global variables, which it’s best to avoid), and you need to pass them all when you call the function.

Maybe the [docs on functions](https://docs.julialang.org/en/v1/manual/functions/) might be helpful?

---

<div class="post-metadata">

**Author:** ![mjanun](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@mjanun](https://discourse.julialang.org/u/mjanun)\
**Post date:** [July 17, 2021, 5:26pm UTC](https://discourse.julialang.org/t/range-constraint/64819/7 "2021-07-17T17:26:31Z")

</div>

> [@ericphanson](#):
>
> Looking closer, it seems you are also not passing the variables `C` and `x` , and are passing `constraint_gen` to itself!

Yes, I realised that I need to pass `C` and `x` as well so the function is defined like `constraint_gen(model,x,C,lb,ub,::Range)`. This will still not address what my question is about. When I call the `solve_model()` it will then expect all these arguments. And how can I code so that it calls the right definition as shown in this pseudocode below?

```julia
if one_input  
    solve_model(constraint_gen(model,1,Equality()))
elseif range
    solve_model(constraint_gen(model,0.5,1,Range()))
end

```

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [July 17, 2021, 5:39pm UTC](https://discourse.julialang.org/t/range-constraint/64819/8 "2021-07-17T17:39:18Z")

</div>

You can use splatting, e.g. if `args = (1,)` (a one-element tuple containing the integer 1), then `f(args...)` calls the function `f` with one argument, the integer 1, whereas if `args = (0.5, 1)` then `f(args...)` calls `f` with two arguments, 0.5 and 1. So you use `f(model, args..., Range())` or something like that. But I think I still don’t really understand the broader context of your code structure.

---

<div class="post-metadata">

**Author:** ![mjanun](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@mjanun](https://discourse.julialang.org/u/mjanun)\
**Post date:** [July 17, 2021, 5:51pm UTC](https://discourse.julialang.org/t/range-constraint/64819/9 "2021-07-17T17:51:39Z")

</div>

> [@ericphanson](#):
>
> I still don’t really understand the broader context of your code structure

The code structure is weird because I don’t know how to implement this constraint depending upon what inputs are passed; hence the question.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [July 17, 2021, 9:14pm UTC](https://discourse.julialang.org/t/range-constraint/64819/10 "2021-07-17T21:14:28Z")

</div>

Structure your code like this

```nohighlight
using JuMP, Cbc

function constraint_gen(model, c, x, bound::Tuple{Float64,Float64})
    lb, ub = bound
    @variable(model, 0 <= u <= ub - lb)
    @constraint(model, u + sum(c[i] * x[i] for i in 1:10) == ub)
    return
end

function constraint_gen(model, c, x, bound::Float64)
    @constraint(model, sum(c[i] * x[i] for i in 1:10) == bound)
    return
end

function solve_model(bound)
    c = rand(10)
    d = rand(10)
    model = Model(Cbc.Optimizer)
    @variable(model, x[1:10] >= 0)
    @constraint(model,sum(x[i] * c[i] for i in 1:10) >= sum(d))
    constraint_gen(model, c, x, bound)
    optimize!(model)
end

solve_model(1.0)
solve_model((1.0, 2.0))

```

---

<div class="post-metadata">

**Author:** ![mjanun](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@mjanun](https://discourse.julialang.org/u/mjanun)\
**Post date:** [July 17, 2021, 9:35pm UTC](https://discourse.julialang.org/t/range-constraint/64819/11 "2021-07-17T21:35:16Z")

</div>

Thank you
