rust-lp-modeler icon indicating copy to clipboard operation
rust-lp-modeler copied to clipboard

Must problem variables be of type "&str"?

Open heartsh opened this issue 4 years ago • 3 comments

Hi Developer,

I am writing the software that solves mixture integer programming. In this software, an objective function maximizes the sum of the scores of possible certain index pairs(, as you show as an example of an assignment problem). I noticed that your assignment problem example shows the error "Cannot open file" when I replace the type of men and women (&str) with u8. (e.g., men: "A", "B", "C" -> 1, 2, 3, women: "D", "E", "F" -> 4, 5, 6.) Am I forced to use type "&str"?

Thank you in advance.

heartsh avatar Feb 01 '21 09:02 heartsh

Hello heartsh, It should work if you transform u8 to str when you give a unique identifier for the variables : LpBinary::new(&format!("{}_{}", m,w));

Can you provide a minimalist snippet we can test ?

jcavat avatar Feb 01 '21 12:02 jcavat

The code below (which slightly modifies your assignment problem example) gives the error "thread 'main' panicked at 'Cannot open file', examples/assignment.rs:64:5" when I execute "cargo run --example assignment":

extern crate lp_modeler;

use std::collections::HashMap;

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

fn main() {
    // Problem Data
    let men = vec![1, 2, 3];
    let women = vec![4, 5, 6];
    let compatibility_score: HashMap<(u8, u8),f32> = vec![
        ((1, 4), 50.0),
        ((1, 5), 75.0),
        ((1, 6), 75.0),
        ((2, 4), 60.0),
        ((2, 5), 95.0),
        ((2, 6), 80.0),
        ((3, 4), 60.0),
        ((3, 5), 70.0),
        ((3, 6), 80.0),
    ].into_iter().collect();

    // Define Problem
    let mut problem = LpProblem::new("Matchmaking", LpObjective::Maximize);

    // Define Variables
    let vars: HashMap<(u8,u8), LpBinary> =
        men.iter()
            .flat_map(|&m| women.iter()
            .map(move |&w| {
                let key = (m,w);
                let value = LpBinary::new(&format!("{}_{}", m,w));
                (key, value)
            }))
            .collect();

    // Define Objective Function
    let obj_vec: Vec<LpExpression> = {
       vars.iter().map( |(&(m,w), bin)| {
           let &coef = compatibility_score.get(&(m, w)).unwrap();
           coef * bin
       } )
    }.collect();
    problem += obj_vec.sum();

    // Define Constraints
    // - constraint 1: Each man must be assigned to exactly one woman
    for &m in &men{
        problem += sum(&women, |&w| vars.get(&(m,w)).unwrap() ).equal(1);
    }

    // - constraint 2: Each woman must be assigned to exactly one man
    for &w in &women{
        problem += sum(&men, |&m| vars.get(&(m,w)).unwrap() ).equal(1);
    }

    // Run Solver
    let solver = CbcSolver::new();
    let result = solver.run(&problem);

    // Compute final objective function value
    // (terminate if error, or assign status & variable values)
    assert!(result.is_ok(), result.unwrap_err());
    let solution = result.unwrap();
    let mut obj_value = 0f32;
    for (&(m, w), var) in &vars{
        let obj_coef = compatibility_score.get(&(m, w)).unwrap();
        let var_value = solution.results.get(&var.name).unwrap();

        obj_value += obj_coef * var_value;
    }

    // Print output
    println!("Status: {:?}", solution.status);
    println!("Objective Value: {}", obj_value);
    for (var_name, var_value) in &solution.results{
        let int_var_value = *var_value as u32;
        if int_var_value == 1{
            println!("{} = {}", var_name, int_var_value);
        }
    }
}

However, it works when I replaced

let value = LpBinary::new(&format!("{}_{}", m,w));

with

let value = LpBinary::new(&format!("A{}_B{}", m,w));

resulting

Status: Optimal
Objective Value: 230
A3_B4 = 1
A2_B5 = 1
A1_B6 = 1

My CBC MILP solver is version 2.10.5.

heartsh avatar Feb 01 '21 23:02 heartsh

I got it. It's to the underlying file format. The variable name should start by a letter and must respect some rules (typically +-^/ ). Mhmmm. I will mention rules for naming convention and try to find a way to crash with a better indication.

jcavat avatar Feb 11 '21 08:02 jcavat