Skip to content

The solver will panic if a goal or constraint reduces to a constant expression #77

@zeta12ti

Description

@zeta12ti

UPDATE: it seems the actual problem is literal expressions. Empty sums work fine, but they return a literal zero.

If a problem has an LpExpression::literal and no variables in a constraint or objective, trying to solve it will cause a panic.

Here's a reproduction:

// lp_modeler 0.5.0
use lp_modeler::dsl::*;
use lp_modeler::solvers::{CbcSolver, SolverTrait};

fn main() {
    let mut problem = LpProblem::new("problem", LpObjective::Maximize);

    problem += LpExpression::literal(0.0);

    let solver = CbcSolver::new();
    let _ = solver.run(&problem); // Here's where the panic happens
}

The backtrace is

thread 'main' panicked at 'Requested index out of bound of LpExpression vector. This should not happen.', /home/user/cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/dsl/variables.rs:368:21
stack backtrace:
   0: std::panicking::begin_panic
             at /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:519:12
   1: lp_modeler::dsl::variables::LpExpression::expr_clone_at
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/dsl/variables.rs:368:21
   2: lp_modeler::dsl::variables::LpExpression::simplify
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/dsl/variables.rs:567:23
   3: <lp_modeler::dsl::variables::LpExpression as lp_modeler::format::lp_format::LpFileFormat>::to_lp_file_format
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/format/lp_format.rs:158:25
   4: lp_modeler::format::lp_format::objective_lp_file_block
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/format/lp_format.rs:61:44
   5: <lp_modeler::dsl::problem::LpProblem as lp_modeler::format::lp_format::LpFileFormat>::to_lp_file_format
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/format/lp_format.rs:25:27
   6: lp_modeler::format::lp_format::LpFileFormat::write_lp
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/format/lp_format.rs:12:22
   7: <lp_modeler::solvers::cbc::CbcSolver as lp_modeler::solvers::SolverTrait>::run
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/lp-modeler-0.5.0/src/solvers/cbc.rs:138:9
   8: tmp::main
             at ./src/main.rs:13:13
   9: core::ops::function::FnOnce::call_once
             at /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Even if the problem is otherwise perfectly valid, adding such a constraint causes a panic.

// lp_modeler 0.5.0
use lp_modeler::dsl::*;
use lp_modeler::solvers::{CbcSolver, SolverTrait};

fn main() {
    // adapted from the README example
    let a = &LpInteger::new("a");
    let b = &LpInteger::new("b");
    let c = &LpInteger::new("c");
    let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
    problem += 10.0 * a + 20.0 * b;
    problem += (500 * a + 1200 * b + 1500 * c).le(10000);
    problem += a.le(b);

    // The problematic constraint
    problem += LpExpression::literal(0.0).equal(0);

    let solver = CbcSolver::new();
    let _ = solver.run(&problem); // panic right here
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions