/*
* Copyright (c) 2016, 2017, 2018, 2019 Frank Fischer <frank-fischer@shadow-soft.de>
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
use env_logger;
use env_logger::fmt::Color;
use log::{info, Level};
use rustop::opts;
use std::io::Write;
use bundle::master::{Builder, FullMasterBuilder, MasterProblem, MinimalMasterBuilder};
use bundle::mcf::MMCFProblem;
use bundle::solver::sync::Solver;
use bundle::{terminator::StandardTerminator, weighter::HKWeighter};
use std::error::Error;
use std::result::Result;
fn solve_parallel<M>(master: M, mmcf: MMCFProblem) -> Result<(), Box<dyn Error>>
where
M: Builder,
M::MasterProblem: MasterProblem<MinorantIndex = usize>,
{
let mut slv = Solver::<_, StandardTerminator, HKWeighter, M>::with_master(mmcf, master);
slv.weighter.set_weight_bounds(1e-1, 100.0);
slv.terminator.termination_precision = 1e-6;
slv.solve()?;
let costs: f64 = (0..slv.problem().num_subproblems())
.map(|i| {
let aggr_primals = slv.aggregated_primal(i).unwrap();
slv.problem().get_primal_costs(i, &[aggr_primals])
})
.sum();
info!("Primal costs: {}", costs);
Ok(())
}
fn main() -> Result<(), Box<dyn Error>> {
better_panic::install();
env_logger::builder()
.format(|buf, record| {
let mut style = buf.style();
let color = match record.level() {
Level::Error | Level::Warn => Color::Red,
Level::Trace => Color::Blue,
Level::Debug => Color::Yellow,
_ => Color::White,
};
style.set_color(color);
writeln!(
buf,
"{}{:5}{} {}",
style.value("["),
style.value(record.level()),
style.value("]"),
style.value(record.args())
)
})
.init();
let (args, _) = opts! {
synopsis "Solve MMCF problems using a bundle method.";
opt separate:bool, desc:"Separate capacity constraints";
opt minimal:bool, desc:"Use the minimal master model";
opt aggregated:bool, desc:"Use aggregated model";
opt bundle_size:usize = 0, name:"NUM", desc:"The bundle size";
param file:String, desc:"Input file in MNetGen format";
}
.parse_or_exit();
let filename = args.file;
info!("Reading instance: {}", filename);
if !args.minimal {
let mut mmcf = MMCFProblem::read_mnetgen(&filename)?;
mmcf.set_separate_constraints(args.separate);
mmcf.multimodel = true;
let mut master = FullMasterBuilder::default();
if args.aggregated {
master.max_bundle_size(if args.bundle_size <= 1 { 50 } else { args.bundle_size });
master.use_full_aggregation();
} else {
master.max_bundle_size(if args.bundle_size <= 1 { 5 } else { args.bundle_size });
}
solve_parallel(master, mmcf)?;
} else {
let mut mmcf = MMCFProblem::read_mnetgen(&filename)?;
mmcf.set_separate_constraints(args.separate);
mmcf.multimodel = true;
let master = MinimalMasterBuilder::default();
solve_parallel(master, mmcf)?;
}
Ok(())
}