Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Must problem variables be of type "&str"? #62

Open
heartsh opened this issue Feb 1, 2021 · 3 comments
Open

Must problem variables be of type "&str"? #62

heartsh opened this issue Feb 1, 2021 · 3 comments

Comments

@heartsh
Copy link

heartsh commented Feb 1, 2021

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.

@jcavat
Copy link
Collaborator

jcavat commented Feb 1, 2021

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 ?

@heartsh
Copy link
Author

heartsh commented Feb 1, 2021

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.

@jcavat
Copy link
Collaborator

jcavat commented Feb 11, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants