/* * MIT License * * Copyright (c) 2019 Frank Fischer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ use grb_sys::*; use std::ffi::CString; use std::os::raw::{c_char, c_int}; use std::ptr::{null, null_mut}; #[test] fn test_cflp() -> std::result::Result<(), Box> { let n = 3; let m = 5; let f = [1000.0, 1000.0, 1000.0]; let cap = [500.0, 500.0, 500.0]; let c = [ [4.0, 5.0, 6.0, 8.0, 10.0], // [6.0, 4.0, 3.0, 5.0, 8.0], // [9.0, 7.0, 4.0, 3.0, 4.0], // ]; let demand = [80.0, 270.0, 250.0, 160.0, 180.0]; let mut env = null_mut(); trygrb!(GRBloadenv(&mut env, null())); trygrb!(GRBsetintparam(env, GRB_INT_PAR_LOGTOCONSOLE, 0)); let mut model = null_mut(); trygrb!(GRBnewmodel( env, &mut model, null(), 0, null_mut(), null_mut(), null_mut(), null_mut(), null_mut() )); // variables { let mut vnames = Vec::with_capacity(n + n * m); let mut costs = Vec::with_capacity(n + n * m); let mut vtypes = Vec::with_capacity(n + n * m); // facility vars for (i, &c) in f.iter().enumerate() { vnames.push(CString::new(format!("y#{}", i))?); costs.push(c); vtypes.push(GRB_BINARY); } // transport vars for (i, ci) in c.iter().enumerate() { for (j, (&d, &c)) in demand.iter().zip(ci).enumerate() { vnames.push(CString::new(format!("x#{}#{}", i, j))?); costs.push(d * c); vtypes.push(GRB_CONTINUOUS); } } trygrb!(GRBaddvars( model, vnames.len() as c_int, 0, null_mut(), null_mut(), null_mut(), costs.as_mut_ptr(), null_mut(), null_mut(), vtypes.as_mut_ptr(), vnames .iter_mut() .map(|n| n.as_ptr() as *mut c_char) .collect::>() .as_mut_ptr() )); } // constraints { let mut inds = Vec::with_capacity(n + m); let mut vals = Vec::with_capacity(n + m); for j in 0..m { inds.clear(); vals.clear(); for i in 0..n { inds.push((n + i * m + j) as c_int); vals.push(1.0); } trygrb!(GRBaddconstr( model, inds.len() as c_int, inds.as_mut_ptr(), vals.as_mut_ptr(), GRB_EQUAL, 1.0, null() )); } for (i, &capacity) in cap.iter().enumerate() { inds.clear(); vals.clear(); for (j, &d) in demand.iter().enumerate() { inds.push((n + i * m + j) as c_int); vals.push(d); } inds.push(i as c_int); vals.push(-capacity); trygrb!(GRBaddconstr( model, inds.len() as c_int, inds.as_mut_ptr(), vals.as_mut_ptr(), GRB_LESS_EQUAL, 0.0, null() )); } } trygrb!(GRBoptimize(model)); let mut objval = 0.0; trygrb!(GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &mut objval)); assert_eq!(objval, 5610.0); let mut ysol = vec![0.0; n]; let mut xsol = vec![0.0; n * m]; trygrb!(GRBgetdblattrarray( model, GRB_DBL_ATTR_X, 0, n as c_int, ysol.as_mut_ptr() )); trygrb!(GRBgetdblattrarray( model, GRB_DBL_ATTR_X, n as c_int, (n * m) as c_int, xsol.as_mut_ptr() )); assert!(ysol[0] < 0.5); assert!(ysol[1] > 0.5); assert!(ysol[2] > 0.5); assert!((xsol[m] - 1.0).abs() < 1e-6); assert!((xsol[m + 1] - 1.0).abs() < 1e-6); assert!((xsol[m + 2] - 0.6).abs() < 1e-6); assert!((xsol[2 * m + 2] - 0.4).abs() < 1e-6); assert!((xsol[2 * m + 3] - 1.0).abs() < 1e-6); assert!((xsol[2 * m + 4] - 1.0).abs() < 1e-6); trygrb!(GRBfreemodel(model)); unsafe { GRBfreeenv(env) }; Ok(()) }