# JuMP vs SAS

**URL:** https://discourse.julialang.org/t/jump-vs-sas/34520
**Category:** Performance
**Tags:** first-steps
**Created:** [February 12, 2020, 3:23pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520 "2020-02-12T15:23:58Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![Dominic\_Pazzula](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dominic_pazzula/32/12783_2.png) [@Dominic\_Pazzula](https://discourse.julialang.org/u/Dominic_Pazzula)
#### Post date: [February 12, 2020, 3:23pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/1 "2020-02-12T15:23:58Z")

</div>

New to Julia, so I apologize if this is simple…

I am evaluating new technologies to potentially replace SAS for some decision support tools. One in particular is a non-linear optimization of decent (but not huge) size. For the record, that runs in a few seconds (~5) and that time is acceptable to users.

Looking into JuMP I used the example in the documentation. While simplistic, an interior point algorithm is what we use in SAS – so this can give me apples to apples.

```julia
using Ipopt
using JuMP

model = Model(with_optimizer(Ipopt.Optimizer, print_level=0))
@variable(model, x, start = 0.0)
@variable(model, y, start = 0.0)

@NLobjective(model, Min, (1 - x)^2 + 100 * (y - x^2)^2)
optimize!(model)
println("x = ", value(x), " y = ", value(y))

# adding a (linear) constraint

@constraint(model, x + y == 10)
optimize!(model)
println("x = ", value(x), " y = ", value(y))

```

Running this I get

> $ time julia nlopt.jl
> 
> * * *
> 
> This program contains Ipopt, a library for large-scale nonlinear optimization.  
> Ipopt is released as open source code under the Eclipse Public License (EPL).  
> For more information visit [http://projects.coin-or.org/Ipopt](http://projects.coin-or.org/Ipopt)
> 
> * * *
> 
> x = 0.9999999999999899 y = 0.9999999999999792  
> x = 2.701147124098218 y = 7.2988528759017814
> 
> real 0m45.834s  
> user 0m0.000s  
> sys 0m0.000s

Creating this problem in SAS (code just incase someone wants it):

```julia
proc optmodel;

var x init 0;
var y init 0;

min m=(1-x)**2 + 100 * (y - x**2)**2;
solve with nlp;
print x;
print y;

con x + y=10;
solve with nlp;
print x;
print y;

quit;

```

Run time:

> $ time sas nlopt.sas
> 
> real 0m0.385s  
> user 0m0.000s  
> sys 0m0.015s

45 seconds in Julia vs 0.39 seconds in SAS. I’d love to save clients SAS licensing fees, but I am not sure I can justify that big of a time reduction. What can I do to speed this up?

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [February 12, 2020, 3:45pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/2 "2020-02-12T15:45:10Z")

</div>

You’re largely measuring compilation time rather than execution. First of all try timing the solution using `BenchmarkTools` to see how that compares to SAS.

If it then turns out to be compilation time your options depend on your use case, e.g. if it is an option to keep a Julia process running you don’t really have an issue with compilation (as it’s a one time cost), while if you need to cold start every time you can look into precompiling via `PackageCompilerX`

EDIT: FWIW when benchmarking your example with `BenchmarkTools` I get roughly 0.01 seconds, so this should be competitive with SAS

---

<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: [February 12, 2020, 4:11pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/3 "2020-02-12T16:11:36Z")

</div>

To add the the previous answer, if your use-case is to launch a single script from the command line, then JuMP won’t be competitive with SAS due to the start-up and compilation costs.

If the script is to be run often, we typically recommend that you start a single Julia instance, pay the compilation once, and keep the instance running serving requests.

Ignoring the compilation costs, JuMP should be virtually the same speed as SAS.

---

<div class="post-metadata">

### Author: ![Dominic\_Pazzula](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dominic_pazzula/32/12783_2.png) [@Dominic\_Pazzula](https://discourse.julialang.org/u/Dominic_Pazzula)
#### Post date: [February 12, 2020, 4:12pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/4 "2020-02-12T16:12:47Z")

</div>

Thanks. I’m not sure of the technology stack at this point. This would be a service but how it gets called is open for debate. Getting smart about the precompilation is something we will have to look at.

---

<div class="post-metadata">

### Author: ![Albert\_Zevelev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albert_zevelev/32/11844_2.png) [@Albert\_Zevelev](https://discourse.julialang.org/u/Albert_Zevelev)
#### Post date: [February 12, 2020, 4:35pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/5 "2020-02-12T16:35:44Z")

</div>

@Dominic_Pazzula  
1 welcome to Julia Discourse  
2 When ppl [benchmark program speeds](https://discourse.julialang.org/t/julia-slower-than-matlab-python-no/33128) they usually wanna put the program inside a function & separately do a warmup run to separate “compile time” from “run time”.  
Consider below:

```nohighlight
using BenchmarkTools
using Ipopt
using JuMP

function f()
    model = Model(with_optimizer(Ipopt.Optimizer, print_level=0))
    @variable(model, x, start = 0.0)
    @variable(model, y, start = 0.0)

    @NLobjective(model, Min, (1 - x)^2 + 100 * (y - x^2)^2)
    optimize!(model)
    println("x = ", value(x), " y = ", value(y))

    # adding a (linear) constraint
    @constraint(model, x + y == 10)
    optimize!(model)
    println("x = ", value(x), " y = ", value(y))
end

@time f() #warmup: 15.044558 seconds (44.22 M allocations: 2.180 GiB, 7.24% gc time)
@time f() #0.012105 seconds (2.12 k allocations: 145.898 KiB)
@benchmark f() #

function g()
    model = Model(with_optimizer(Ipopt.Optimizer, print_level=0))
    @variable(model, x, start = 0.0)
    @variable(model, y, start = 0.0)

    @NLobjective(model, Min, (5 - x)^2 + 100 * (y - x^2)^2)
    optimize!(model)
    println("x = ", value(x), " y = ", value(y))

    # adding a (linear) constraint
    @constraint(model, x + y == 10)
    optimize!(model)
    println("x = ", value(x), " y = ", value(y))
end

@time g() #0.077067 seconds (97.75 k allocations: 4.977 MiB)
@time g() #0.023970 seconds (2.50 k allocations: 162.836 KiB)
@benchmark g() #

```

You only have to pay the price of compile the first time you open Julia REPL. The founders are [well aware of this](https://www.youtube.com/watch?v=TPuJsgyu87U) & reducing compiler latency is a top priority.  
I personally only minded it my first few weeks w/ Julia.

---

<div class="post-metadata">

### Author: ![Albert\_Zevelev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albert_zevelev/32/11844_2.png) [@Albert\_Zevelev](https://discourse.julialang.org/u/Albert_Zevelev)
#### Post date: [February 12, 2020, 4:52pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/6 "2020-02-12T16:52:31Z")

</div>

@Dominic_Pazzula  
Can you try benchmarking the optimization in SAS again (w/ a few runs) to compare times w/ Julia?

---

<div class="post-metadata">

### Author: ![Dominic\_Pazzula](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dominic_pazzula/32/12783_2.png) [@Dominic\_Pazzula](https://discourse.julialang.org/u/Dominic_Pazzula)
#### Post date: [February 12, 2020, 5:14pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/7 "2020-02-12T17:14:06Z")

</div>

SAS:

> ELAPSE : 5.60199999809265 seconds over 500 iterations  
> AVERAGE: 0.01120399999618

Julia:

```julia
function model1()
    model = Model(with_optimizer(Ipopt.Optimizer, print_level=0))
    @variable(model, x, start = 0.0)
    @variable(model, y, start = 0.0)

    @NLobjective(model, Min, (1 - x)^2 + 100 * (y - x^2)^2)
    optimize!(model)
    #println("x = ", value(x), " y = ", value(y))
end

@benchmark model1()

```

> ## BenchmarkTools.Trial: memory estimate: 109.65 KiB allocs estimate: 1528
> 
> ## minimum time: 5.224 ms (0.00% GC) median time: 6.867 ms (0.00% GC) mean time: 7.500 ms (0.00% GC) maximum time: 31.579 ms (0.00% GC)
> 
> samples: 665  
> evals/sample: 1

So faster than SAS 11.2 vs 7.5 ms. I tried to make the SAS bit apples to apples by redefining the objective each iteration but not starting/stopping `PROC OPTMODEL` and turning off all output.

---

<div class="post-metadata">

### Author: ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)
#### Post date: [February 12, 2020, 5:20pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/8 "2020-02-12T17:20:06Z")

</div>

As a frequent SAS user, let me just say that I am completely not surprised at these results.

---

<div class="post-metadata">

### Author: ![lwhitefox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lwhitefox/32/4363_2.png) [@lwhitefox](https://discourse.julialang.org/u/lwhitefox)
#### Post date: [February 12, 2020, 9:33pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/9 "2020-02-12T21:33:40Z")

</div>

> [@odow](#):
>
> we typically recommend that you start a single Julia instance, pay the compilation once, and keep the instance running serving requests.

This would be helpful for my needs; can you point to some background information on how to “serve requests”? I’m mainly used to running in REPL or else using C to call Julia code but this alternative would be better

---

<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: [February 12, 2020, 9:56pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/10 "2020-02-12T21:56:49Z")

</div>

It depends heavily on the application/how you intend to deploy/etc.

I guess the main options are:

1. Have Julia periodically poll a directory for new files. When you want to run a job, write a new data file to the directory, wait for the process to poll the directory.
2. Another option that is probably possible, but I’ve never tried, is connecting from C to Julia via a socket: [Networking and Streams · The Julia Language](https://docs.julialang.org/en/v1/manual/networking-and-streams/#A-simple-TCP-example-1)

---

<div class="post-metadata">

### Author: ![lwhitefox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lwhitefox/32/4363_2.png) [@lwhitefox](https://discourse.julialang.org/u/lwhitefox)
#### Post date: [February 12, 2020, 9:58pm UTC](https://discourse.julialang.org/t/jump-vs-sas/34520/11 "2020-02-12T21:58:15Z")

</div>

Thanks!
