GithubHelp home page GithubHelp logo

chkwon / pathsolver.jl Goto Github PK

View Code? Open in Web Editor NEW
47.0 7.0 15.0 2.08 MB

provides a Julia wrapper for the PATH Solver for solving mixed complementarity problems

Home Page: http://pages.cs.wisc.edu/%7Eferris/path.html

License: MIT License

Julia 100.00%
path-solver mcp complementarity

pathsolver.jl's Introduction

PATHSolver.jl

Build Status codecov

PATHSolver.jl is a wrapper for the PATH solver.

The wrapper has two components:

You can solve any complementarity problem using the wrapper around the C API, although you must manually provide the callback functions, including the Jacobian.

The MathOptInterface wrapper is more limited, supporting only linear complementarity problems, but it enables PATHSolver to be used with JuMP.

Affiliation

This wrapper is maintained by the JuMP community and is not an official wrapper of PATH. However, we are in close contact with the PATH developers, and they have given us permission to re-distribute the PATH binaries for automatic installation.

License

PATHSolver.jl is licensed under the MIT License.

The underlying solver, path is closed source and requires a license.

Without a license, the PATH Solver can solve problem instances up to with up to 300 variables and 2000 non-zeros. For larger problems, this web page provides a temporary license that is valid for a year.

You can either store the license in the PATH_LICENSE_STRING environment variable, or you can use the PATHSolver.c_api_License_SetString function immediately after importing the PATHSolver package:

import PATHSolver
PATHSolver.c_api_License_SetString("<LICENSE STRING>")

where <LICENSE STRING> is replaced by the current license string.

Installation

Install PATHSolver.jl as follows:

import Pkg
Pkg.add("PATHSolver")

By default, PATHSolver.jl will download a copy of the underlying PATH solver. To use a different version of PATH, see the Manual Installation section below.

Use with JuMP

julia> using JuMP, PATHSolver

julia> M = [
           0  0 -1 -1
           0  0  1 -2
           1 -1  2 -2
           1  2 -2  4
       ]
4×4 Array{Int64,2}:
 0   0  -1  -1
 0   0   1  -2
 1  -1   2  -2
 1   2  -2   4

julia> q = [2, 2, -2, -6]
4-element Array{Int64,1}:
  2
  2
 -2
 -6

julia> model = Model(PATHSolver.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Path 5.0.00

julia> set_optimizer_attribute(model, "output", "no")

julia> @variable(model, x[1:4] >= 0)
4-element Array{VariableRef,1}:
 x[1]
 x[2]
 x[3]
 x[4]

julia> @constraint(model, M * x .+ q  x)
[-x[3] - x[4] + 2, x[3] - 2 x[4] + 2, x[1] - x[2] + 2 x[3] - 2 x[4] - 2, x[1] + 2 x[2] - 2 x[3] + 4 x[4] - 6, x[1], x[2], x[3], x[4]]  MOI.Complements(4)

julia> optimize!(model)
Reading options file /var/folders/bg/dzq_hhvx1dxgy6gb5510pxj80000gn/T/tmpiSsCRO
Read of options file complete.

Path 5.0.00 (Mon Aug 19 10:57:18 2019)
Written by Todd Munson, Steven Dirkse, Youngdae Kim, and Michael Ferris

julia> value.(x)
4-element Array{Float64,1}:
 2.8
 0.0
 0.7999999999999998
 1.2

julia> termination_status(model)
LOCALLY_SOLVED::TerminationStatusCode = 4

Note that options are set using JuMP.set_optimizer_attribute.

The list of options supported by PATH can be found here: https://pages.cs.wisc.edu/~ferris/path/options.pdf

MathOptInterface API

The Path 5.0.03 optimizer supports the following constraints and attributes.

List of supported variable types:

List of supported constraint types:

List of supported model attributes:

Use with the C API

PATHSolver.jl wraps the PATH C API using PATHSolver.c_api_XXX for the C method XXX. However, using the C API directly from Julia can be challenging, particularly with respect to avoiding issues with Julia's garbage collector.

Instead, we recommend that you use the PATHSolver.solve_mcp function, which wrappers the C API into a single call. See the docstring of PATHSolver.solve_mcp for a detailed description of the arguments.

Here is the same example using PATHSolver.solve_mcp. Note that you must manually construct the sparse Jacobian callback.

julia> import PATHSolver

julia> M = [
           0  0 -1 -1
           0  0  1 -2
           1 -1  2 -2
           1  2 -2  4
       ]
4×4 Matrix{Int64}:
 0   0  -1  -1
 0   0   1  -2
 1  -1   2  -2
 1   2  -2   4

julia> q = [2, 2, -2, -6]
4-element Vector{Int64}:
  2
  2
 -2
 -6

julia> function F(n::Cint, x::Vector{Cdouble}, f::Vector{Cdouble})
           @assert n == length(x) == length(f)
           f .= M * x .+ q
           return Cint(0)
       end
F (generic function with 1 method)

julia> function J(
           n::Cint,
           nnz::Cint,
           x::Vector{Cdouble},
           col::Vector{Cint},
           len::Vector{Cint},
           row::Vector{Cint},
           data::Vector{Cdouble},
       )
           @assert n == length(x) == length(col) == length(len) == 4
           @assert nnz == length(row) == length(data)
           i = 1
           for c in 1:n
               col[c], len[c] = i, 0
               for r in 1:n
                   if !iszero(M[r, c])
                       row[i], data[i] = r, M[r, c]
                       len[c] += 1
                       i += 1
                   end
               end
           end
           return Cint(0)
       end
J (generic function with 1 method)

julia> status, z, info = PATHSolver.solve_mcp(
           F,
           J,
           fill(0.0, 4),  # Lower bounds
           fill(Inf, 4),  # Upper bounds
           fill(0.0, 4);  # Starting point
           nnz = 12,      # Number of nonzeros in the Jacobian
           output = "yes",
       )
Reading options file /var/folders/bg/dzq_hhvx1dxgy6gb5510pxj80000gn/T/jl_iftYBS
 > output yes
Read of options file complete.

Path 5.0.03 (Fri Jun 26 09:58:07 2020)
Written by Todd Munson, Steven Dirkse, Youngdae Kim, and Michael Ferris

Crash Log
major  func  diff  size  residual    step       prox   (label)
    0     0             1.2649e+01             0.0e+00 (f[    4])
    1     2     4     2 1.0535e+01  8.0e-01    0.0e+00 (f[    1])
    2     3     2     4 8.4815e-01  1.0e+00    0.0e+00 (f[    4])
    3     4     0     3 4.4409e-16  1.0e+00    0.0e+00 (f[    3])
pn_search terminated: no basis change.

Major Iteration Log
major minor  func  grad  residual    step  type prox    inorm  (label)
    0     0     5     4 4.4409e-16           I 0.0e+00 4.4e-16 (f[    3])

Major Iterations. . . . 0
Minor Iterations. . . . 0
Restarts. . . . . . . . 0
Crash Iterations. . . . 3
Gradient Steps. . . . . 0
Function Evaluations. . 5
Gradient Evaluations. . 4
Basis Time. . . . . . . 0.000016
Total Time. . . . . . . 0.044383
Residual. . . . . . . . 4.440892e-16
(PATHSolver.MCP_Solved, [2.8, 0.0, 0.8, 1.2], PATHSolver.Information(4.4408920985006247e-16, 0.0, 0.0, 0.044383, 1.6e-5, 0.0, 0, 0, 3, 5, 4, 0, 0, 0, 0, false, false, false, true, false, false, false))

julia> status
MCP_Solved::MCP_Termination = 1

julia> z
4-element Vector{Float64}:
 2.8
 0.0
 0.8
 1.2

Thread safety

PATH is not thread-safe and there are no known work-arounds. Do not run it in parallel using Threads.@threads. See issue #62 for more details.

Factorization methods

By default, PATHSolver.jl will download the LUSOL shared library. To use LUSOL, set the following options:

model = Model(PATHSolver.Optimizer)
set_optimizer_attribute(model, "factorization_method", "blu_lusol")
set_optimizer_attribute(model, "factorization_library_name", PATHSolver.LUSOL_LIBRARY_PATH)

To use factorization_method umfpack you will need the umfpack shared library that is available directly from the developers of that code for academic use.

Manual installation

By default PATHSolver.jl will download a copy of the libpath library. If you already have one installed and want to use that, set the PATH_JL_LOCATION environment variable to point to the libpath50.xx library.

pathsolver.jl's People

Contributors

andradetiago avatar chkwon avatar davidanthoff avatar jlperla avatar jrevels avatar lassepe avatar michaelcferris avatar odow avatar rdeits avatar staticfloat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

pathsolver.jl's Issues

Error in version v0.6, v0.6.2 works

The version v0.6 gives the error described in this issue: #42

However, just switching to v0.6.2 makes this issue disappear. For other who may encounter the issue: could the Readme be changed to include this line instead:

Pkg.add(Pkg.PackageSpec(name = "PATHSolver", version = v"0.6.2"))

Thanks!

solve_mcp(): NNZ or NNZ+1

In the code for solve_mcp() is this line:

nnz = Int(dnnz + 1)

This essentially adds an extra/unused Cint or Cdouble to the vectors of length nnz that are passed to J(). It doesn't really matter if J() is always resetting nnz to the actual count, but it's a little confusing or offputting to call solve_mcp(...,nnz=8) but get nnz=9 in the call to J().

There might have been a purpose to this bumping of NNZ with PATH 4.x, but with PATH 5.x I don't see any need for this.

Of course, if you change it, anybody who was running with solve_mcp(...,nnz=actualNNZ-1) is going to be unhappy. And there is surely at least one such user . . .

Scaling of equations and variables

Hallo,

I am using your julia package and have moved from GAMS to julia recently. I really appreciate your work. However, there is one part I am missing, or maybe haven't found yet:

In order to avoid poorly scaled models, GAMS offers the possibility to scale individual equations or variables (described a.o. on page 48 of the PhD Todd Munson, also here https://gams.com/help/index.jsp?topic=%2Fgams.doc%2Fuserguides%2Fmccarl%2Fscale.htm).

I have achieved very good improvements in times of computation time using this. I was wondering if this is possible within Julia and the PathSolver/Complementary/ JuMP framework.

Thanks again for your work

Feedback

Steve Dirkse sent me an email:

[A user] sent an example of how they are using PATH: not via JuMP but by calling

status, z, info = PATHSolver.solve_mcp(
F,
J,
lower_bounds,
upper_bounds,
initial_guess;
silent = false,
)

with function F and it's Jacobian given by J. Perhaps not the usual way to approach this but that's my story. Based on this, here's what I noticed:

  1. The README mentions that only linear problems are supported. I guess that limitation is for the JuMP interface only. The PATHSolver.solve_mcp call does support nonlinear models.

  2. There is some pervasive confusion around the structure of the Jacobian and any variable whose name is nnz or a near variant. I believe this is created by PATH itself. There are two ways to think about the Jacobian nonzero pattern:
    a) Structural nonzeros: the nonzero pattern does not depend on numerical values. We treat xx (zero deriv at x=0) the same as exp(x) (never has a zero deriv). Viewed this way, the Jacobian has a constant structure: PATH gets it once, via the first Jacobian call, and uses only numerical values from subsequent Jacobian calls.
    b) Numerical nonzeros: the nonzero pattern is determined by the numerical values of the Jacobian, so x
    x has a zero Jacobian if x=0 but not otherwise. This implies that the Jacobian pattern can change with each evaluation (i.e. it depends on x) and must be specified via each call to the J in the code above. Also, NNZ can mean different things: it might be the max possible (i.e. the structural NNZ) or the NZ count for the current numerical Jacobian.

It's useful to understand that PATH supports both modes, even if you don't use both modes. It helps to make sense of the PATH API and its requirements. I can say more about how to polish this up but I'd like to know first which interface you intend to use. I've found that most users want to have a structural Jacobian, but not all. Once you make the choice then things become clearer. Also I suppose you would mention this somewhere so users of PATHSolver.mcp_solve would know what is required.

  1. The PATH presolver is able to make substantial model reductions in many cases. One way to get maximum benefit from this is to specify which entries of the Jacobian are linear: more can be done with such entries than with nonlinear entries. There is a callback function that enables a user to provide this information. If this is of interest, we can talk more about how a user (JuMP or a human) would provide this and how it gets passed through PATHSolver to PATH.

Distribute binaries as artifacts

We should drop 1.0 support and use the artifact system. This is currently blocked because I don't know how to make an artifact out of a single file. We might have to get Michael to upload a tarball to his FTP server.

Tag a version

Could a version that is compatible with MOI 0.10 be tagged? CC @odow Thanks :)

Need to upgrade to BinDeps 1.0 for supporting Julia 1.3+

With the change in the location of 7z.exe on Julia 1.3, installation with the default package versions listed here won't work. In particular, you get a

│ ERROR: LoadError: IOError: could not spawn `'C:\Users\jlperla\AppData\Local\Programs\Julia\Julia-1.4.1\bin\7z.exe' x 'C:\Users\jlperla\.julia\packages\PATHSolver\lRj12\deps\downloads\pathlib.zip' -y '-oC:\Users\jlperla\.julia\packages\PATHSolver\lRj12\deps\src'`: no such file or directory (ENOENT)

etc. error if using on Windows. I believe that the solution is pretty easy, and all you need to do is lowerbound the BinDeps 1.0 in https://github.com/chkwon/PATHSolver.jl/blob/master/REQUIRE#L3 and tag a new version?

What is the difference between Julia PATH and GAMS PATH?

Hi, I'm trying to transfer GAMS code to Julia, but I met some problem in kind of "large" scale model.

For example, a simple multi-region tech planning model. If there is only 1 region, both PATHSolver.jl and GAMS PATH can obtain the same solution. When repeating the 1 region to 10 regions for example, GAMS can still find solution while Julia cannot.

The Julia code could give termination_status such as "SLOW_PROGRESS::TerminationStatusCode = 19" or "ITERATION_LIMIT::TerminationStatusCode = 11"

I put the codes here, thank you very much for your help!

GAMS code (change the set r to /1*n/ to change the amount of regions )

set r /1*10/,
t /1*3/;

parameter
fixcost(t)/
1 4
2 1
3 12/,
variablecost(t)/
1 0.03
2 0.05
3 0.001/,
efficient(t)/
1 40
2 20
3 80/,
maxtech(t);

maxtech(t)=100;

parameter demand(r);
demand(r)= 10000;

positive variables
newtech(t,r),
sell(t,r),
buy(t,r),
price(t,r);

newtech.up(t,r)=maxtech(t);

negative variable
a_outputmax(t,r);

free variable
b_demandmeet(r);

equations
outputmax(t,r),
kkt_newtech(t,r),
kkt_sell(t,r),
demandmeet(r),
kkt_buy(t,r),
mc(t,r);

outputmax(t,r)..   sell(t,r)-newtech(t,r)*efficient(t) =l= 0;
kkt_newtech(t,r)..  fixcost(t)+a_outputmax(t,r)*efficient(t) =e=0;
kkt_sell(t,r)..  (variablecost(t)-price(t,r))-a_outputmax(t,r) =e=0;
demandmeet(r)..  sum(t,buy(t,r))-demand(r) =e= 0;
kkt_buy(t,r)..  price(t,r)-b_demandmeet(r)=e=0;
mc(t,r)..       sell(t,r)-buy(t,r)=e=0;


model m /outputmax.a_outputmax,kkt_newtech.newtech,kkt_sell.sell,demandmeet.b_demandmeet,kkt_buy.buy,mc.price/;
solve m using mcp;

Julia code (change the regions to 1:n to change the amount of regions)

using PATHSolver, JuMP
PATHSolver.c_api_License_SetString("2830898829&Courtesy&&&USR&45321&5_1_2021&1000&PATH&GEN&31_12_2025&0_0_0&6000&0_0")

regions=1:5
tech=1:3

fixcost=[4,1,12]
variablecost=[0.03,0.05,0.001]
efficient=[40,20,80]
maxtech=[100 for t in tech]
demand=[10000 for i in regions]

m=Model(PATHSolver.Optimizer)
@variable(m, 0<= newtech[t in tech, r in regions] <= maxtech[t])
@variable(m, sell[t in tech,r in regions] >= 0)
@variable(m, buy[t in tech,r in regions] >= 0)
@variable(m, price[t in tech,r in regions])

@variable(m, a_outputmax[t in tech,r in regions] <= 0)
@variable(m, b_demandmeet[r in regions])

@constraint(m, outputmax[t in tech,r in regions], sell[t,r]-newtech[t,r]*efficient[t] ⟂ a_outputmax[t,r])

@constraint(m, kkt_newtech[t in tech,r in regions],fixcost[t]+a_outputmax[t,r]*efficient[t] ⟂ newtech[t,r])
@constraint(m, kkt_sell[t in tech,r in regions],(variablecost[t]-price[t,r])-a_outputmax[t,r] ⟂ sell[t,r])

@constraint(m,demandmeet[r in regions],sum(buy[t,r] for t in tech)- demand[r] ⟂ b_demandmeet[r])

@constraint(m, kkt_buy[t in tech,r in regions],price[t,r]-b_demandmeet[r] ⟂ buy[t,r])

@constraint(m, mc[t in tech,r in regions],sell[t,r]-buy[t,r] ⟂ price[t,r])

set_optimizer_attribute(m, "minor iteration limit", "10000000")
set_optimizer_attribute(m, "major iteration limit", "10000000")
optimize!(m)
termination_status(m)

EXCEPTION_ACCESS_VIOLATION

Hallo,

I get the following errors for a model that I have transferred from GAMS to julia. GAMS together with the PATH solver returns a solution for the model.

However, julia exits to an error. Moreover, the error changes with model parameters. I have invested quite some time in checking that I have not made a mistake in the transfer. I am a bit stuck here.

Unfortunately, the error messages are not that rich:

Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: EXCEPTION_ACCESS_VIOLATION at 0x7fee72ca5d0 -- Memory_Default at C:\Users\hhoschle\.julia\v0.5\PATHSolver\deps\usr\lib\path47.dll (unknown line)
while loading C:\PhD\journals\2017_interconnected_cm\julia\model/dev_model.jl, in expression starting on line 923
Memory_Default at C:\Users\hhoschle\.julia\v0.5\PATHSolver\deps\usr\lib\path47.dll (unknown line)
unknown function (ip: 000000002964203F)
Allocations: 250906427 (Pool: 250895190; Big: 11237); GC: 885

another error:

    1     1  1819   267 3.6891e+007  1.0e+000    1.0e+001 (RES_target_lambda_res[s)
    2     2  5467  1819 3.3916e+007  1.0e+000    9.0e+000 (RES_target_lambda_res[s)
    3     5  3884  5734 3.2877e+007  6.4e-001    8.1e+000 (RES_target_lambda_res[s)
    4     6   576  5728 2.8918e+007  1.0e+000    7.3e+000 (RES_target_lambda_res[s)
    5     7  1194  5377 2.6426e+007  1.0e+000    6.6e+000 (KKT_res_certs[s001,BE,W)
    6     8   139  4206 2.3117e+007  1.0e+000    5.9e+000 (KKT_res_certs[s001,BE,W)
    7    12     2  4070 2.1072e+007  4.1e-001    5.3e+000 (KKT_res_certs[s001,BE,W)
pn_search terminated: no basis change.
  ** WARNING **
Basis modifications: 4759

Major Iteration Log
major minor  func  grad  residual    step  type prox    inorm  (label)
    0     0    13     8 2.1072e+007           I 4.8e+000 8.5e+006 (KKT_res_certs[s)
  ** SOLVER ERROR **
Too small.

If I can somehow overcome this problem, I would be really thankful. If I need to provide more information, please let me know.

Add support for MOI.VariableName and MOI.ConstraintName

Names from MOI do not make it to PATH. This makes printing and messages hard to read.

x-ref https://discourse.julialang.org/t/can-i-recover-variable-names-to-path-labels-jump-moi-pathsolver-path-jump/110703

The C API has

PATHSolver.jl/src/C_API.jl

Lines 742 to 743 in f03d0a7

variable_names::Vector{String} = String[],
constraint_names::Vector{String} = String[],

But we do not pass from MOI:

status, x, info = solve_mcp(
F,
J,
lower,
upper,
initial;
nnz = nnz,
silent = model.ext[:silent],
jacobian_structure_constant = true,
jacobian_data_contiguous = true,
[k => v for (k, v) in model.ext[:kwargs]]...,
)

cc @EliLazarus

Add error message when solve fails due to missing license - Feature Request

Issue

The solver silently fails when a model has more than ~300 variables and no license. Since the PATH license needs to be updated on a yearly basis it's possible it expires unknowingly. This leads to many issues debugging models when the license has silently lapsed.

Proposed Solution

Throw an error when a model does not solve due to a license error.

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

If you'd like for me to do this for you, comment TagBot fix on this issue.
I'll open a PR within a few hours, please be patient!

Different Windows Issue

I think the install script fails when your user directory has a space in it, as Windows allows. See the Copy-Item line of:

┌ Error: Error building `PATHSolver`:
│
│ 7-Zip 18.05 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2018-04-30
│
│ Scanning the drive for archives:
│ 1 file, 3860585 bytes (3771 KiB)
│
│ Extracting archive: C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\downloads\pathlib.zip
│ --
│ Path = C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\downloads\pathlib.zip
│ Type = zip
│ Physical Size = 3860585
│ Comment = a11966f36875748820583e41455800470c971171
│
│ Everything is Ok
│
│ Folders: 13
│ Files: 43
│ Size:       11230861
│ Compressed: 3860585
│ Copy-Item : A positional parameter cannot be found that accepts argument
│ 'Sood\.julia\packages\PATHSolver\xjazJ\deps\src\pathlib-4.7.03\lib\win64\path47.dll'.
│ At line:1 char:1
│ + Copy-Item -Path C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\ ...
│ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
│     + CategoryInfo          : InvalidArgument: (:) [Copy-Item], ParameterBindingException
│     + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
│
│ [ Info: Attempting to create directory C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\usr\lib
│ [ Info: Attempting to create directory C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Attempting to create directory C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\downloads
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Downloading file https://github.com/ampl/pathlib/archive/4.7.03.zip
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Done downloading file https://github.com/ampl/pathlib/archive/4.7.03.zip
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Attempting to create directory C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps
│ [ Info: Directory C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps already exists
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ [ Info: Changing directory to C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src
│ ERROR: LoadError: failed process: Process(`powershell -NoProfile -Command 'Copy-Item -Path C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\src\pathlib-4.7.03\lib\win64\path47.dll -Destination C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\usr\lib -force'`, ProcessExited(1)) [1]
│ Stacktrace:
│  [1] error(::String, ::Base.Process, ::String, ::Int64, ::String) at .\error.jl:42
│  [2] pipeline_error at .\process.jl:785 [inlined]
│  [3] #run#515(::Bool, ::Function, ::Cmd) at .\process.jl:726
│  [4] run(::Cmd) at .\process.jl:724
│  [5] run(::BinDeps.SynchronousStepCollection) at C:\Users\Arnav Sood\.julia\packages\BinDeps\ZEval\src\BinDeps.jl:521 (repeats 2 times)
│  [6] satisfy!(::BinDeps.LibraryDependency, ::Array{DataType,1}) at C:\Users\Arnav Sood\.julia\packages\BinDeps\ZEval\src\dependencies.jl:944
│  [7] satisfy!(::BinDeps.LibraryDependency) at C:\Users\Arnav Sood\.julia\packages\BinDeps\ZEval\src\dependencies.jl:922
│  [8] top-level scope at C:\Users\Arnav Sood\.julia\packages\BinDeps\ZEval\src\dependencies.jl:977
│  [9] include at .\boot.jl:326 [inlined]
│  [10] include_relative(::Module, ::String) at .\loading.jl:1038
│  [11] include(::Module, ::String) at .\sysimg.jl:29
│  [12] include(::String) at .\client.jl:403
│  [13] top-level scope at none:0
│ in expression starting at C:\Users\Arnav Sood\.julia\packages\PATHSolver\xjazJ\deps\build.jl:96

For context:

julia> versioninfo()
Julia Version 1.1.0
Commit 80516ca202 (2019-01-21 21:24 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

Calling from python via pyjulia - allow any callable object, not just ::Function arguments #8

I'm working on calling the PATHSolver from Python as there is no adequate solution of solving LCPs within Python. I tried to work through the example case from the manual:


In [1]: import julia
In [2]: j = julia.Julia()
In [3]: j.sind(10)  #works as planned
Out[3]: 0.17364817766693036 
In [8]: j.using("PATHSolver")
In [9]: M = np.array([[0, 0, -1, -1], [0, 0, 1, -2], [1, -1, 2, -2], [1, 2, -2, 4]])
In [12]: q = np.array([2, 2, -2, -6])
In [13]: myf = lambda x: M*x + q
In [14]: lb = np.zeros((4,))
In [15]: ub = 100*np.ones((4,))
In [16]: j.solveMCP(myf, lb, ub)
RuntimeError: Julia exception: MethodError(PATHSolver.solveMCP,(PyObject <function <lambda> at 0x7f6a70eeb048>,[0.0,0.0,0.0,0.0],[100.0,100.0,100.0,100.0]))

Perhaps it helps to report that I found a similar issue from someone trying to work with another solver via pyjulia, they discussed it as an issue of DASSL.jl:

It would be better to leave the arguments untyped rather than specify ::Function, in order that any callable object can be passed. Note that there is no performance advantage to declaring argument types; the main reason to declare arguments is to avoid method ambiguities.


When I try to use the proposed workaroudn in the mailing list, I get

fwrap = j.eval('f -> (args...) -> f(args...)')
In [20]: j.solveMCP(fwrap(myf), lb, ub)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-20-05aae9205059> in <module>()
----> 1 j.solveMCP(fwrap(myf), lb, ub)

RuntimeError: Julia exception: MethodError(convert,(Float64,Dual(0.0,1.0,0.0,0.0,0.0)))

Support MOI.SolveTimeSec

According to this example in JuMP's documentation, JuMP.solution_summary(model) may report the following information:

  • CPU time required by a completed optimization run
  • the identified solution (if any)
  • and numbers of different types of iterations.

Could PATHSolver.jl's JuMP.solution_summary report this information as well? This would be helpful when performing quick one-off experiments or perturbations in the REPL. (Currently only the termination status is reported.)

Error: Missing Function path_main

Hi,

since the most recent update I get the following error when I try to solve a MCP using the PATH solver:

ERROR: LoadError: ccall: could not find function path_main in library libpath47julia in solveMCP(::Function, ::Complementarity.#myjac#3{JuMP.Model}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{String,1}, ::Ptr{Void}) at C:\Users\hhoschle\.julia\v0.5\PATHSolver\src\PATHSolver.jl:63 in _solve_path(::JuMP.Model) at C:\Users\hhoschle\.julia\v0.5\Complementarity\src\mcp.jl:164 in #solveMCP#1(::Symbol, ::Symbol, ::Function, ::JuMP.Model) at C:\Users\hhoschle\.julia\v0.5\Complementarity\src\mcp.jl:94

I run the model on a Windows 7 64bit.

  • Complementarity 0.1.0
  • JuMP 0.15.1
  • PATHSolver 0.1.0

I have already tried to rebuild the package but this did not help.

Any ideas, recommendations? More information needed?

Thank you

disable output completely

I wonder if it is possible to kill the output completely when using solveLCP. Even with options(output=:no), it prints some results. I suspect printing options are embedded in the source library and one may not have access to it, still wanted to ask.

Support MOI.UserDefinedFunction

x-ref https://discourse.julialang.org/t/help-with-performance-in-large-mixed-complementarity-problem/106052

using JuMP
import BitOperations
import PATHSolver

function possible_shock_combinations(J)
    return [BitOperations.bget(j, i) for j in 0:(2^J-1), i in 0:(J-1)]
end

function shock_probabilities(sequences, probs)
    @assert size(sequences, 2) == length(probs)
    return map(1:size(sequences, 1)) do i
        return prod(
            s_i ? p_i : (1 - p_i) for (s_i, p_i) in zip(sequences[i, :], probs)
        )
    end
end

function solve_complementarity(param1, param2, shock, probs, w, i)
    model = Model(PATHSolver.Optimizer)
    set_silent(model)
    @variable(model, x[1:J] >= 0, start = 0.5)
    A = 1 .- shock .* (1 - param2)
    b = -(1 - param1) * w[i]
    @constraint(model, c[j in 1:J],
        b * sum(probs[s] * A[s, j] / (A[s, :]' * x) for s in 1:2^J) + w[j]  x[j]
    )
    optimize!(model)
    return value.(x)
end

function solve_complementarity(param1, param2, shock, probs, w, i)
    model = Model(PATHSolver.Optimizer)
    set_silent(model)
    @variable(model, x[1:J] >= 0, start = 0.5)
    A = 1 .- shock .* (1 - param2)
    b = -(1 - param1) * w[i]
    f(x...) = sum(probs[s] * A[s, j] / (A[s, :]' * x) for s in 1:2^J)
    function 𝝯f(g, x...)
        g .= 0.0
        for s in 1:2^J
            demoninator = A[s, :]' * x
            for j in 1:J
                g[j] += probs[s] * A[s, j]^2 / demoninator^2
            end
        end
        return
    end
    @operator(model, op_f, J, f, 𝝯f)
    @constraint(model, c[j in 1:J], b * op_f(x...) + w[j]  x[j])
    optimize!(model)
    return value.(x)
end

J = 10
param1 = 0.5
param2 = 0.1
prob = fill(0.5, J)
shock = possible_shock_combinations(J)
probs = shock_probabilities(shock, prob)
w = ones(J)
i = 1
x = solve_complementarity(param1, param2, shock, probs, w, i)

Solver info reported incorrectly?

When inspecting the Information object returned by the solver in order to debug the robustness for my problem, I noticed that some of the output appears to be wrong. For example, the information object claims that 72 restarts were taken (despite the fact that 3 is the maximum by default and I did not change that), only 1 jacobian evaluation was performed, and 0 minor and major iterations were performed.

I did inspect the type definition of the Information struct in the Types.h of pathlib (link but couldn't find any obvious inconsistencies with the Julia definition.

Here's an example output:

PATHSolver.Information
  residual: Float64 1.3042986523364064e-8
  distance: Float64 0.0
  steplength: Float64 0.0
  total_time: Float64 1.008433
  maximum_distance: Float64 0.8244709999999807
  major_iterations: Int32 0
  mainor_iterations: Int32 0
  crash_iterations: Int32 68
  function_evaluations: Int32 19843
  jacobian_evaluations: Int32 1
  gradient_steps: Int32 485
  restarts: Int32 72
  generate_output: Int32 10
  generated_output: Int32 2
  forward: Bool false
  backtrace: Bool false
  gradient: Bool false
  use_start: Bool true
  use_basics: Bool false
  used_start: Bool false
  used_basics: Bool false

v1.4.0 is giving incorrect solutions

After upgrading PATHSolver.jl from v1.3.0 to v1.4.0, it now seems to produce incorrect solutions via JuMP v1.6.0. We have seen consistently incorrect results across a few setups: a 2016 MacBook Pro (Intel), a more recent MacBook Pro (M1), and a Windows laptop. If we revert PATHSolver.jl back to v1.3.0, then we get correct solutions again.

Here are summaries of two examples illustrating this behavior. The corresponding REPL output for each example is pasted subsequently.

  1. When attempting to replicate the LCP example in PATHSolver.jl's README, PATHSolver.jl v1.4.0 instead reports the incorrect solution: x = [6.0, 0.0, 0.0, 0.0].

  2. When attempting to solve the simple MLCP: -1.0 + 2.0*u ⟂ u with u unbounded, PATHSolver.jl v1.4.0 reports the solution as u = 0.0, which is incorrect. (Since u is otherwise unbounded, this MLCP should instead be equivalent to the equation -1.0 + 2.0*u == 0.0, by my reading of JuMP's documentation on complementarity constraints.)

Here is the corresponding REPL output for Example 1 above (attempting to replicate the LCP in the README):

julia> using JuMP, PATHSolver

julia> M = [
            0 0 -1 -1
            0 0 1 -2
            1 -1 2 -2
            1 2 -2 4
        ]
4×4 Matrix{Int64}:
 0   0  -1  -1
 0   0   1  -2
 1  -1   2  -2
 1   2  -2   4

julia> q = [2, 2, -2, -6]
4-element Vector{Int64}:
  2
  2
 -2
 -6

julia> model = Model(PATHSolver.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Path 5.0.03

julia> set_optimizer_attribute(model, "output", "no")

julia> @variable(model, x[1:4] >= 0)
4-element Vector{VariableRef}:
 x[1]
 x[2]
 x[3]
 x[4]

julia> @constraint(model, M * x .+ q  x)
[-x[3] - x[4] + 2, x[3] - 2 x[4] + 2, x[1] - x[2] + 2 x[3] - 2 x[4] - 2, x[1] + 2 x[2] - 2 x[3] + 4 x[4] - 6, x[1], x[2], x[3], x[4]]  MathOptInterface.Complements(8)

julia> optimize!(model)
Reading options file /var/folders/sw/8x_srljj1wn1njw0jsp4vyqm0000gn/T/jl_T2HyeD
Read of options file complete.

Path 5.0.03 (Fri Jun 26 09:58:07 2020)
Written by Todd Munson, Steven Dirkse, Youngdae Kim, and Michael Ferris

Zero:     1 Single:     0 Double:     3
Postsolved residual: 1.6754e+00

julia> value.(x)
4-element Vector{Float64}:
 6.0
 0.0
 0.0
 0.0

julia> termination_status(model)
LOCALLY_SOLVED::TerminationStatusCode = 4

And here is the REPL output for Example 2 above (a simple MCP):

julia> import JuMP, PATHSolver

julia> optimizer = PATHSolver.Optimizer
MathOptInterface.Utilities.GenericOptimizer{T, MathOptInterface.Utilities.ObjectiveContainer{T}, MathOptInterface.Utilities.VariablesContainer{T}, MathOptInterface.Utilities.VectorOfConstraints{MathOptInterface.VectorAffineFunction{T}, MathOptInterface.Complements}} where T

julia> solverAttributes = ("output" => "no",)
("output" => "no",)

julia> model = JuMP.Model(JuMP.optimizer_with_attributes(optimizer, solverAttributes...))
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Path 5.0.03

julia> JuMP.@variable(model, u)
u

julia> JuMP.@constraint(model, complements(-1.0 + 2.0*u, u))
[2 u - 1, u]  MathOptInterface.Complements(2)

julia> JuMP.optimize!(model)
Reading options file /var/folders/sw/8x_srljj1wn1njw0jsp4vyqm0000gn/T/jl_5O5srS
Read of options file complete.

Path 5.0.03 (Fri Jun 26 09:58:07 2020)
Written by Todd Munson, Steven Dirkse, Youngdae Kim, and Michael Ferris

MCPR: One:    0 Two:    0 Thr:    0 Qua:    0 WBd:    0 Fix:    1 IFx:    0
Postsolved residual: 1.0000e+00
julia> uStar = JuMP.value.(u)
-0.0

julia> terminationStatus = JuMP.termination_status(model)
LOCALLY_SOLVED::TerminationStatusCode = 4

Global state?

During my hunt for #70 I noticed some weird behavior which looks to me like PATH has some global state either in C or in Julia. Specifically, the #70 only showed up if I solve another specific MCP before it. I suspect that some solver object is not fully reset leading to this interdependence between solves. I'm calling the solver through the MCP C-api so I wouldn't expect any side-effects between calls as I'm not carrying over any solver object. This issue is part of the reason why I cannot give a compact reproducer for #70 -- it only shows up if I run my research code in a specific sequence.

Binaries

I talked to Michael about the binaries hosted at https://pages.cs.wisc.edu/~ferris/path/julia/

We have the problem that if he updates these, then we're going to break users because these hashes will break:

libpath = Dict(
"windows" => (
"path50.dll",
"e227d19109f56628fccfdfedd7ecbdfd1667a3c975dd1d16a160a69d374d5474",
),
"macos" => (
"libpath50.dylib",
"8787de93d21f49a46146ebe2ef5844d1c20a80f934a85f60164f9ddc670412f8",
),
"silicon" => (
"libpath50.silicon.dylib",
"4e667615180565062013ab50a3968bbeddf3e510a9cdbfc27aa685152742b637",
),
"linux" => (
"libpath50.so",
"8c36baaea0952729788ec8d964253305b04b0289a1d74ca5606862c9ddb8f2fd",
),

The solution is for us to host the binaries, likely as release assets or in a different branch of this repo, and then use Artifacts.toml. That'll let us decide when to update the binaries, and we we can have control over the versioning.

Non linear problems

I'm trying to use PATHSolver with JuMP for non linear problems, but when I add a non linear constraint, I get an error message saying that the solver doesn't support non linear problems.

My understanding is that the underlying PATH solver of course does support non linear problems, so I'm wondering whether I just need to do something slightly different, or whether this is just not yet exposed via JuMP?

v0.7/v1.0 solveMCP cannot find library

In Julia v0.7/v1.0, with PATHSolver v0.5.0

using PATHSolver

M = [0  0 -1 -1 ;
     0  0  1 -2 ;
     1 -1  2 -2 ;
     1  2 -2  4 ]

q = [2; 2; -2; -6]

myfunc(x) = M*x + q

n = 4
lb = zeros(n)
ub = 100*ones(n)

status, z, f = solveMCP(myfunc, lb, ub)

This produces the following error:

ERROR: error compiling #solveMCP#8: could not load library "libpath47julia"
dlopen(libpath47julia.dylib, 1): image not found
Stacktrace:
 [1] (::getfield(PATHSolver, Symbol("#kw##solveMCP")))(::NamedTuple{(:user_nnz,),Tuple{Int64}}, ::typeof(solveMCP), ::Function, ::Function, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{String,1}, ::Array{String,1}) at ./none:0
 [2] #solveMCP#3 at /Users/chkwon/.julia/dev/PATHSolver/src/PATHSolver.jl:157 [inlined]
 [3] solveMCP at /Users/chkwon/.julia/dev/PATHSolver/src/PATHSolver.jl:135 [inlined] (repeats 3 times)
 [4] top-level scope at none:0

But interestingly, after solving the problem as an LCP, this runs okay:

status, z, f = solveLCP(myfunc, M, lb, ub)
status, z, f = solveMCP(myfunc, lb, ub)

I couldn't figure out what is happening. Any ideas? @rdeits @tkoolen
I used FunctionWrapperQuickFix.jl as done in tkoolen/Parametron.jl#76.

Solver error crashes Julia session

Within my research code I hit a very confusing behavior of PATH that cased my entire Julia session to just silently close. Debugging with GDB gave no sbacktrace and I did not get any error on the Julia side -- the session just closed.

Upon further inspection of the solver log, it looks like this is happening due to a PATH internal error that is not gracefully handled on the Julia side; the log ends with,

  ** SOLVER ERROR **
Lemke: invertible basis could not be computed.
       You may avoid this error by increasing the
       lemke_rank_deficiency_iterations option.

then the Julia session crashes.

Can this bet caught within PATHSolver.jl and converted to a recoverable error? Or is this considered a Julia bug and should be filed upstream?

Can we hide the options reading output somehow?

Right now there is always an output like this:

Reading options file /var/folders/bg/dzq_hhvx1dxgy6gb5510pxj80000gn/T/tmpiSsCRO
Read of options file complete.

I think that is printed by PATH itself, right? Is there some option that we could flip so that this isn't shown by PATH? Would be nice if we could disable printing that particular message.

Can't load in 1.5

Thanks for the package. It seems jl_function_ptr was removed. Here's a link with a issue that seems similar and the error message.

JuliaGraphics/Gtk.jl#512

ERROR: LoadError: LoadError: could not load symbol "jl_function_ptr":
The specified procedure could not be found.
Stacktrace:
 [1] PATHSolver.FunctionWrappersQuickFix.FunctionWrapper{Any,Tuple{Any}}(::typeof(identity)) at C:\Users\XXXXXXX\.julia\packages\PATHSolver\tJVDr\src\FunctionWrappersQuickFix.jl:89
 [2] top-level scope at C:\Users\XXXXXXX\.julia\packages\PATHSolver\tJVDr\src\FunctionWrappersQuickFix.jl:132
 [3] include(::Function, ::Module, ::String) at .\Base.jl:380
 [4] include at .\Base.jl:368 [inlined]
 [5] include(::String) at C:\Users\XXXXXXX\.julia\packages\PATHSolver\tJVDr\src\PATHSolver.jl:1
 [6] top-level scope at C:\Users\XXXXXXX\.julia\packages\PATHSolver\tJVDr\src\PATHSolver.jl:3
 [7] include(::Function, ::Module, ::String) at .\Base.jl:380
 [8] include(::Module, ::String) at .\Base.jl:368
 [9] top-level scope at none:2
 [10] eval at .\boot.jl:331 [inlined]
 [11] eval(::Expr) at .\client.jl:467
 [12] top-level scope at .\none:3
in expression starting at C:\Users\XXXXXXX\.julia\packages\PATHSolver\tJVDr\src\FunctionWrappersQuickFix.jl:132
in expression starting at C:\Users\XXXXXXX\.julia\packages\PATHSolver\tJVDr\src\PATHSolver.jl:3
ERROR: LoadError: Failed to precompile PATHSolver [f5f7c340-0bb3-5c69-969a-41884d311d1b] to C:\Users\XXXXXXX\.julia\compiled\v1.5\PATHSolver\xyGrF_xqMiq.ji.
Stacktrace:
 [1] error(::String) at .\error.jl:33
 [2] compilecache(::Base.PkgId, ::String) at .\loading.jl:1290
 [3] _require(::Base.PkgId) at .\loading.jl:1030
 [4] require(::Base.PkgId) at .\loading.jl:928
 [5] require(::Module, ::Symbol) at .\loading.jl:923
 [6] include(::Function, ::Module, ::String) at .\Base.jl:380
 [7] include(::Module, ::String) at .\Base.jl:368
 [8] top-level scope at none:2
 [9] eval at .\boot.jl:331 [inlined]
 [10] eval(::Expr) at .\client.jl:467
 [11] top-level scope at .\none:3
in expression starting at C:\Users\XXXXXXX\.julia\packages\Complementarity\jpfgn\src\Complementarity.jl:1

Gurobi to PathSolver

I have this code working in Julia whit the gurobi solver. But i wanna made it work whit PathSolver. Can i have any feedback on how to do it?
Thanks!!
This is my code whit gurobi
import Pkg
Pkg.add("Gurobi")

A=[300,350,400,450,500];
theta=[0.2,0.2,0.2,0.2,0.2];
B=1;
I=90;
C=60;
tau=8760;

using JuMP,Gurobi
model=Model(Gurobi.Optimizer)

#Variables
@variable(model, x>=0) #Capacidad
@variable(model, Y[i in 1:5]>=0) # Produccion en escenario w
@variable(model,Q[i in 1:5]>=0) # Demanda en escenario w

#Restricciones
@constraint(model, demanda[i in 1:5], Y[i] == Q[i] )
@constraint(model, capacidad[i in 1:5], Y[i]-x<=0.0)

#FO
@objective(model, Min, I1000x + tau*(sum(theta[i](CY[i] - A[i]Q[i] + B0.5*(Q[i]^2)) for i in 1:5) ))

#Resolver
JuMP.optimize!(model)

println("Q = ", JuMP.value.(Q))
Qlist=JuMP.value.(Q)

j=1
P=[]
while j<6
Pi=A[j]-B*Qlist[j]
append!(P, Pi)
j=j+1
end
println("P = ",P)

println("x = ", JuMP.value(x))

Allow for manually setting number of non-zero jacobian elements

I ran into the issue that the initial Jacobian has fewer non-zero elements than whatever comes up during iterations. This only requires few lines of code changes, e.g. via calling with a named argument where a user can provide the number of non-zero elements and otherwise default to the current setup.

Thread Safety

When I call the PATH solver from multiple threads at the same time, I reliably run into a segfault. Is there a workaround to avoid this?

Here is an MWE (make sure to start the Julia REPL with multiple threads):

using PATHSolver: PATHSolver
using SparseArrays: SparseArrays

PATHSolver.c_api_License_SetString("2830898829&Courtesy&&&USR&45321&5_1_2021&1000&PATH&GEN&31_12_2025&0_0_0&6000&0_0")

function solve_example()
    M = convert(
        SparseArrays.SparseMatrixCSC{Cdouble,Cint},
        SparseArrays.sparse([
            0 0 -1 -1
            0 0 1 -2
            1 -1 2 -2
            1 2 -2 4
        ]),
    )
    status, z, info = PATHSolver.solve_mcp(
        M,
        Float64[2, 2, -2, -6],
        fill(0.0, 4),
        fill(10.0, 4),
        [0.0, 0.0, 0.0, 0.0];
        output = "yes"
    )
end

Threads.@threads for _ in 1:10
    solve_example()
end

Memory issues in Windows

win32: test passed, but cannot run multiple times

win64; test failed, after solving all the problem. when the error
message is ignored, it's fine.

Seems like there is a memory-management issue in PathJulia code and compile.

norm(matrix) -> opnorm(matrix) in Julia 0.7

It looks like may be using norm(matrix). In Julia 0.7, this will compute the Frobenius norm (vecnorm in Julia 0.6), due to JuliaLang/julia#27401. If you want the induced/operator norm as in Julia 0.6, use opnorm(matrix) instead, or Compat.opnorm(matrix) to work in 0.6 and 0.7 (JuliaLang/Compat.jl#577).

Note that, for testing purposes, rather than @test norm(A - B) ≤ tol, it is usually preferred to do @test A ≈ B or @test A ≈ B rtol=... (which uses isapprox).

Bounds Error solving model in v1.7.3

Description of Issue

Version 1.7.3 passes constraint names to the PATH solver. The issue is that this doesn't take into account when variables are created so there is an issue extracting the correct names. Additionally, this will throw an error if you define two variables but only use the second.

Example of the issue

To illustrate the issue, here is a very simple example.

using JuMP
using PATHSolver

M = Model(PATHSolver.Optimizer)

@variables(M, begin
    not_used_in_model>=0
    x>=0
end)

@constraint(M, x_bound,
    x^2 +2*x - 1 ⟂ x
)

optimize!(M)

This code runs on version 1.7.2 but not on 1.7.3. On 1.7.2 the solver makes reference to f([2]), referring to the second variable, but there is only one constraint which causes an error on 1.7.3.

Note that this will not error if x is defined before not_used_in_model.

Sets in PATH for equations as JuMPDict

Hallo,

here is a minor thing I saw when run my model which could be fixed with the next version:

  • The name of the indexes are not forwarded to the PATH solver if the equation is of type JuMPDict

Here is a MWE:

using Complementarity
model = MCPModel()
scenarios = [@sprintf "s%03d" s for s=1:3]
INDEX = Dict("s001" => 1., "s002" => 0., "s003" => 0.5)
COST = Dict("s001" => 10., "s002" => 2., "s003" => 5)
COST_INDEX = Dict("s001" => 2., "s002" => 1., "s003" => 3.)
@variable(model, xname[s in scenarios] >= 0) 
@variable(model, ynoname[s in scenarios; INDEX[s] >0] >= 0)
@show typeof(xname)
@show typeof(ynoname)
@variable(model, lambda1 >= 0)
@variable(model, lambda2 >= 0)
@NLexpression(model, lambda,
    lambda1 - lambda2)

@mapping(model, market_lambda1,
    + sum(xname[s] for s in scenarios)
    + sum(ynoname[s] for s in scenarios if INDEX[s] > 0)
    - 10)
@complementarity(model, market_lambda1, lambda1)
                
@mapping(model, market_lambda2,
    - sum(xname[s] for s in scenarios)
    - sum(ynoname[s] for s in scenarios if INDEX[s] > 0)
    + 10)
@complementarity(model, market_lambda2, lambda2)
@mapping(model, KKT_xname[s in scenarios],
    - lambda
    + COST[s])
@complementarity(model, KKT_xname, xname)
@show typeof(KKT_xname)
@mapping(model, KKT_ynoname[s in scenarios; INDEX[s] >0],
    - lambda
    + COST_INDEX[s])
# @complementarity(model, KKT_ynoname, ynoname)
for s in scenarios
    if INDEX[s] > 0
        @complementarity(model, KKT_ynoname[s], ynoname[s])
    end
end
@show typeof(KKT_ynoname)

PATHSolver.options(
    convergence_tolerance=1e-6, 
    output=:yes, 
    time_limit=3600*12, 
    # time_limit=0.1, 
    minor_iteration_limit=1000,
    cumulative_iteration_limit=1000000000)

stat = solveMCP(model)
# Inf-Norm of Complementarity . .  1.1410e-006 eqn: (KKT_ynoname[s]) <---- NAME of index set not included
# Inf-Norm of Normal Map. . . . .  2.2820e-007 eqn: (KKT_xname[s002])
# Inf-Norm of Minimum Map . . . .  2.2820e-007 eqn: (KKT_xname[s002])
# Inf-Norm of Fischer Function. .  2.2820e-007 eqn: (KKT_xname[s002])
# Inf-Norm of Grad Fischer Fcn. .  4.5641e-007 eqn: (market_lambda2)

license management function

http://pages.cs.wisc.edu/~ferris/path/LICENSE

Alternatively, (for advanced users) in your interface code, you can set the license with the following function call

License_SetString("3413119131&Courtesy&&&USR&54784&12_1_2016&1000&PATH&GEN&31_12_2017&0_0_0&5000&0_0");

which, if used, must be issued before a call to Path_Solve() or any other
license management functions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.