# JuMP write\_to\_file: Writing legacy model to file is much smaller

**URL:** <https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299>\
**Category:** Optimization (Mathematical)\
**Tags:** jump\
**Created:** [June 6, 2024, 8:56pm UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299 "2024-06-06T20:56:47Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Stuart\_Rogers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stuart_rogers/32/10694_2.png) [@Stuart\_Rogers](https://discourse.julialang.org/u/Stuart_Rogers)\
**Post date:** [June 6, 2024, 8:56pm UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/1 "2024-06-06T20:56:47Z")

</div>

I construct a model for a nonlinear optimization problem in the Julia JuMP code below, using either the non-legacy (use\_legacy\_model = false) or legacy (use\_legacy\_model = true) model interface and save the model to a .nl file using write\_to\_file. The .nl file created from the legacy model interface is much smaller (e.g. 229KB) than the .nl created from the non-legacy model interface (e.g. 4.5MB). What is the reason for the significantly different file sizes?

-rw-rw-r-- 1 stuart stuart 229K Jun 6 13:43 model\_legacy.nl  
-rw-rw-r-- 1 stuart stuart 4.5M Jun 6 13:44 model\_non\_legacy.nl

* * *

```julia
using JuMP

use_legacy_model = false # Whether to use legacy JuMP nonlinear constraints, expressions, and objectives.

N1 = 64
N = 64
zpad = 2
M = zpad*N

s = rand(M,1) 
Br = rand(M, N1)
Bi = rand(M, N1)

Mt = trunc(Int,floor(M/2))+1
Br = Br[1:Mt,:]
Bi = Bi[1:Mt,:]
s = s[1:Mt]
Me = Mt

# Construct the JuMP model.
model_construction_time = @elapsed begin # Start elapsed.

model = Model()

@variable(model, y[1:N1], Bin)

if(~use_legacy_model)
        print("Constructing non-legacy model.\n")

        @expression(model, yh, y.-.5)
        #@expression(model, yh[n=1:N1], y[n]-.5)

        @expression(model, spec_r, Br*yh)
        @expression(model, spec_i, Bi*yh)

        #@expression(model, spec_sq_mag, spec_r.^2 .+ spec_i.^2) # Slow
        @expression(model, spec_sq_mag[m=1:Me], spec_r[m]^2 + spec_i[m]^2) # Fast

        #@expression(model, gamma, sum((spec_sq_mag.-s).^2)) # Slow
        @expression(model, gamma, sum((spec_sq_mag[m]-s[m])^2 for m in 1:Me)) # Fast

        @objective(model, Min, gamma)
else
        print("Constructing legacy model.\n")

        @expression(model, yh[n=1:N1], y[n]-.5)
        @expression(model, spec_r, Br*yh)
        @expression(model, spec_i, Bi*yh)

        @NLexpression(model, spec_sq_mag[m=1:Me], spec_r[m]^2 + spec_i[m]^2)

        @variable(model, gamma >= 0)

        @NLconstraint(model, gamma >= sum((spec_sq_mag[m]-s[m])^2 for m in 1:Me))
        @objective(model, Min, gamma)
end

end # End elapsed.
println("\nJuMP model construction time: $(model_construction_time) [s].")

# Write the JuMP model to a .nl file.
model_write_time = @elapsed begin # Start elapsed.

write_to_file(model,"model.nl")

end # End elapsed.
println("\nJuMP model write time: $(model_write_time) [s].")

```

---

<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:** [June 6, 2024, 10:05pm UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/2 "2024-06-06T22:05:22Z")

</div>

The issue is quite subtle, and is because of:

```julia
@expression(model, spec_sq_mag[m=1:Me], spec_r[m]^2 + spec_i[m]^2) 

```

This line will automatically try to create `QuadExpr` objects.

In most cases, this is the right thing to do, because it allows solvers to specialize on quadratic constraints and objectives. However, when writing to a `.nl` file, this has a bad outcome.

Consider this simple example:

```julia
julia> model = Model();

julia> @variable(model, x[1:2]);

julia> y = sum(x)
x[1] + x[2]

julia> y^2
x[1]² + 2 x[2]*x[1] + x[2]²

julia> @force_nonlinear(y^2)
(x[1] + x[2]) ^ 2

```

The `.nl` file writes things out as a tape of the expression graph.

If we write out the `QuadExpr` `y^2` as a tape, it requires 11 nodes:

```julia
[+, *, x[1], x[2], *, 2, x[2], x[1], *, x[2], x[2]]

```

If we write out the `NonlinearExpr`, it requires only 5 nodes:

```julia
[^, +, x[1], x[2], 2]

```

You can fix things for your code with:

```julia
@expression(
    model, 
    spec_sq_mag[m=1:Me],
    @force_nonlinear(spec_r[m]^2 + spec_i[m]^2),
)

```

See: [JuMP · JuMP](https://jump.dev/JuMP.jl/stable/api/JuMP/#@force_nonlinear)

---

<div class="post-metadata">

**Author:** ![Stuart\_Rogers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stuart_rogers/32/10694_2.png) [@Stuart\_Rogers](https://discourse.julialang.org/u/Stuart_Rogers)\
**Post date:** [June 6, 2024, 10:48pm UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/3 "2024-06-06T22:48:36Z")

</div>

If @force\_nonlinear is used, will the solver still recognize the constraint or expression as being quadratic? If not, then it seems that @force\_nonlinear should only be used if the model must be written to a file and the file size must be small.

---

<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:** [June 7, 2024, 12:07am UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/4 "2024-06-07T00:07:22Z")

</div>

> will the solver still recognize the constraint or expression as being quadratic

No.

> it seems that `@force_nonlinear` should only be used if the model must be written to a file and the file size must be small

Yes. This is why `@force_nonlinear` is not the default, and it is one reason that we added it.

You can do better by slightly reformulating your problem:

```Julia
using JuMP
N1, N, zpad = 64, 64, 2
M = zpad * N
Mt = ceil(Int, M / 2)
s, Br, Bi = rand(Mt), rand(Mt, N1), rand(Mt, N1);
model = Model();
@variable(model, y[1:N1], Bin);
@expression(model, yh, y .- 0.5);
@variable(model, spec_r[1:Mt])
@variable(model, spec_i[1:Mt])
@expression(model, spec_r .== Br * yh)
@expression(model, spec_i .== Bi * yh)
@expression(model, spec_sq_mag[m in 1:Mt], spec_r[m]^2 + spec_i[m]^2)
@expression(model, gamma, sum((spec_sq_mag[m]-s[m])^2 for m in 1:Mt))
@objective(model, Min, gamma)
write_to_file(model, "model.nl")

```

Now it is only `207K`:

```julia
-rw-r--r-- 1 oscar staff 207K Jun 7 12:06 model.nl

```

---

<div class="post-metadata">

**Author:** ![Stuart\_Rogers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stuart_rogers/32/10694_2.png) [@Stuart\_Rogers](https://discourse.julialang.org/u/Stuart_Rogers)\
**Post date:** [June 7, 2024, 12:23am UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/5 "2024-06-07T00:23:58Z")

</div>

Thanks for your suggestions. Your formula for `Mt` is not the same as in my original code. `ceil(Int, M / 2)` does not equal `floor(Int, M / 2)+1` when `Mt` is even.

---

<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:** [June 7, 2024, 12:38am UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/6 "2024-06-07T00:38:04Z")

</div>

> [@Stuart\_Rogers](#):
>
> does not equal

Indeed 😬 I guess I didn’t think carefully enough

---

<div class="post-metadata">

**Author:** ![Stuart\_Rogers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stuart_rogers/32/10694_2.png) [@Stuart\_Rogers](https://discourse.julialang.org/u/Stuart_Rogers)\
**Post date:** [June 7, 2024, 12:50am UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/7 "2024-06-07T00:50:47Z")

</div>

> [@odow](#):
>
> ```julia
> using JuMP
> N1, N, zpad = 64, 64, 2
> M = zpad * N
> Mt = ceil(Int, M / 2)
> s, Br, Bi = rand(Mt), rand(Mt, N1), rand(Mt, N1);
> model = Model();
> @variable(model, y[1:N1], Bin);
> @expression(model, yh, y .- 0.5);
> @variable(model, spec_r[1:Mt])
> @variable(model, spec_i[1:Mt])
> @expression(model, spec_r .== Br * yh)
> @expression(model, spec_i .== Bi * yh)
> @expression(model, spec_sq_mag[m in 1:Mt], spec_r[m]^2 + spec_i[m]^2)
> @expression(model, gamma, sum((spec_sq_mag[m]-s[m])^2 for m in 1:Mt))
> @objective(model, Min, gamma)
> write_to_file(model, "model.nl")
> 
> ```

When I ran your JuMP code, the resulting .nl file is only 6.7 KB, rather than 207 KB!

```julia
-rw-rw-r-- 1 stuart stuart 6.7K Jun 6 17:48 model.nl

```

---

<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:** [June 7, 2024, 12:57am UTC](https://discourse.julialang.org/t/jump-write-to-file-writing-legacy-model-to-file-is-much-smaller/115299/8 "2024-06-07T00:57:40Z")

</div>

I copied the wrong thing:

```Julia
using JuMP
N1, N, zpad = 64, 64, 2
M = zpad * N
Mt = ceil(Int, M / 2)
s, Br, Bi = rand(Mt), rand(Mt, N1), rand(Mt, N1);
model = Model();
@variable(model, y[1:N1], Bin);
@expression(model, yh, y .- 0.5);
@variable(model, spec_r[1:Mt])
@variable(model, spec_i[1:Mt])
@constraint(model, spec_r .== Br * yh)
@constraint(model, spec_i .== Bi * yh)
@expression(model, spec_sq_mag[m in 1:Mt], spec_r[m]^2 + spec_i[m]^2)
@expression(model, gamma, sum((spec_sq_mag[m]-s[m])^2 for m in 1:Mt))
@objective(model, Min, gamma)
write_to_file(model, "model.nl")

```

Note `@constraint(model, spec_r .== Br * yh)`
