Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@constraint uses more memory with AffExpr #1113

Closed
daschw opened this issue Oct 5, 2017 · 5 comments
Closed

@constraint uses more memory with AffExpr #1113

daschw opened this issue Oct 5, 2017 · 5 comments

Comments

@daschw
Copy link
Contributor

daschw commented Oct 5, 2017

Consider the following code:

using JuMP

function addconst1(n)
    demand = zeros(n)

    model = Model()
    supply1 = @variable(model, [1:n], lowerbound = 0, upperbound = 0.5)
    supply2 = @variable(model, [1:n], lowerbound = 0, upperbound = 0.5)

    @time @constraint(model, [i in 1:n], supply1[i] + supply2[i] == demand[i])
end

function addconst2(n)
    demand = zeros(n)
    supply = zeros(AffExpr, n)

    model = Model()
    supply1 = @variable(model, [1:n], lowerbound = 0, upperbound = 0.5)
    supply2 = @variable(model, [1:n], lowerbound = 0, upperbound = 0.5)
    push!.(supply, 1.0, supply1)
    push!.(supply, 1.0, supply2)

    @time @constraint(model, [i in 1:n], supply[i] == demand[i])
end

for n in (1, 10, 100, 1000, 10000)
    println("addconst1 - n = $n:")
    addconst1(n)
    println("addconst2 - n = $n:")
    addconst2(n)
end

I get:

addconst1 - n = 1:
  0.000006 seconds (9 allocations: 496 bytes)
addconst2 - n = 1:
  0.000008 seconds (9 allocations: 496 bytes)
addconst1 - n = 10:
  0.000008 seconds (74 allocations: 3.859 KiB)
addconst2 - n = 10:
  0.000010 seconds (74 allocations: 6.359 KiB)
addconst1 - n = 100:
  0.000039 seconds (707 allocations: 37.438 KiB)
addconst2 - n = 100:
  0.000257 seconds (707 allocations: 346.813 KiB)
addconst1 - n = 1000:
  0.000400 seconds (7.99 k allocations: 383.344 KiB)
addconst2 - n = 1000:
  0.027967 seconds (7.99 k allocations: 30.922 MiB)
addconst1 - n = 10000:
  0.004602 seconds (88.99 k allocations: 3.973 MiB)
addconst2 - n = 10000:
  4.710471 seconds (88.99 k allocations: 2.984 GiB, 35.66% gc time)

Why does the second version of @constraints consume so much more memory?
Is there a way to make this more efficient?
I would like to have a demand and a supply AffExpr, to which I can programatically add different variables. Is this possible in a more memory-friendly way?

@mlubin
Copy link
Member

mlubin commented Nov 25, 2017

push!.(supply, 1.0, supply1) allocates an array to store the output of each operation. You probably want to call push! in a loop instead.

@daschw
Copy link
Contributor Author

daschw commented Dec 18, 2017

That should not really be related, right? I'm only timing the line with @constraint.

@mlubin
Copy link
Member

mlubin commented Dec 18, 2017

I don't know if the lines

    push!.(supply, 1.0, supply1)
    push!.(supply, 1.0, supply2)

are doing what you expect. When n = 10000, supply[1] is an expression with 20,000 terms. It's not surprising that it would be slower to add this constraint.

The version below runs in about the same time and memory as addconst1:

function addconst3(n)
    demand = zeros(n)

    model = Model()
    supply1 = @variable(model, [1:n], lowerbound = 0, upperbound = 0.5)
    supply2 = @variable(model, [1:n], lowerbound = 0, upperbound = 0.5)
    supply = supply1 .+ supply2

    @time @constraint(model, [i in 1:n], supply[i] == demand[i])
end

@daschw
Copy link
Contributor Author

daschw commented Dec 18, 2017

Indeed, push!. does not what I expected it to do. As expected, it does the same as

for i in 1:n
    push!(supply[i], 1.0, supply1[i])
    push!(supply[i], 1.0, supply2[i])
end

I wrongly assumed that this would add supply1[i] and supply2[i] to the AffExpr supply[i] for each i. Thanks a lot for pointing this out!

@daschw daschw closed this as completed Dec 18, 2017
@daschw
Copy link
Contributor Author

daschw commented Dec 18, 2017

Changing

supply = zeros(AffExpr, n)

to

supply = [AffExpr(0) for i in 1:n]

Fixes addconst2 above and makes it run in the same time and memory with addconst1 and @mlubin 's addconst3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants