lanl-ansi / Juniper.jl

A JuMP-based Nonlinear Integer Program Solver
https://lanl-ansi.github.io/Juniper.jl/stable/
MIT License
179 stars 22 forks source link

solutions and functions from parent to child #256

Closed GabrielPonte closed 1 year ago

GabrielPonte commented 1 year ago

Hi, I'm using Juniper with KNITRO as nl_solver, and I would like to ask two questions about Juniper, please.

Here is the code that I'm using

 nl_solver = () ->  MOI.Utilities.CachingOptimizer(
                            MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
                            KNITRO.Optimizer(
            OUTLEV = 0,
            CONVEX = 1,
            GRADOPT = 1,
            FEASTOL = 5e-6,
            OPTTOL = 5e-6,
            ALGORITHM = 1,
            HESSOPT = 3,
            BAR_FEASIBLE = 1,
        )
                        )
    model = Model(optimizer_with_attributes(Juniper.Optimizer, 
                "nl_solver"=>nl_solver,
                "branch_strategy" => :StrongPseudoCost,
            ))
    register(model, :my_dopt_func, n, dopt_f, dopt_∇f)
    @variable(model, x[1:n],Int);
    set_start_value.(x, vec(x_ls))
    @NLobjective(model, Max, my_dopt_func(x...))
    @constraint(model, sum(x) - s == 0);
    for i = (1:n)
        set_lower_bound(x[i],lb[i]);
        set_upper_bound(x[i],ub[i]);
    end

and I would like to say that in some branches, doptf and dopt∇f are different.

Thank you!

odow commented 1 year ago

I would like to say that in some branches, doptf and dopt∇f are different.

I don't think this is possible.

But can't you just write a single function that looks at the current values of x being passed in? Why do you need to change the entire function?

For example, you could write:

function dopt_f(x...)
    if x[1] <= 0
        return sum(x[i]^2 for i in 2:length(x))
    else
        return sum(x[i] for i in 2:length(x))
    end
end
GabrielPonte commented 1 year ago

It's a really nice idea, thank you! I'm not doing this because I needed some information from the node, and I think this function doesn't accept other arguments as input. Still, I could try to use an auxiliary global variable and set it equal to the node information to help me decide it.

odow commented 1 year ago

You could try the global variable thing, but be wary. You're likely violating a lot of assumptions about how Juniper works, so there's no guarantee that you won't run into an error or incorrect solution.

GabrielPonte commented 1 year ago

Ok, thanks. And is there a way to set an initial solution to KNITRO inside Juniper?

odow commented 1 year ago

Juniper will Warmstart the continuous solves with solutions that it has available. I assume if you set one initially, it will also use that.

But as a general comment, Juniper is not designed so that you can mess with the solvers deep in the tree.

GabrielPonte commented 1 year ago

Understood, thank you so much!