Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Move `SubModel` to submodule `guessmodels::GuessModel` |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | garbage |
| Files: | files | file ages | folders |
| SHA1: |
b7b6413301594be00e82cae55542afe2 |
| User & Date: | fifr 2020-06-11 18:35:26.941 |
Context
|
2020-06-11
| ||
| 18:35 | Move `SubModel` to submodule `guessmodels::GuessModel` Closed-Leaf check-in: b7b6413301 user: fifr tags: garbage | |
| 11:55 | asyn: add some constructors for `Guess` check-in: 32006728e6 user: fifr tags: async-simplify | |
Changes
Changes to Cargo.toml.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
c_str_macro = "^1.0"
cplex-sys = "^0.6"
float-pretty-print = "^0.1"
rs-crossbeam = { version = "^0.7", optional = true, package = "crossbeam" }
threadpool = "^1.7"
num_cpus = "^1.2"
num-traits = "^0.2.8"
rs-blas = { version = "^0.20.0", optional = true, package = "blas" }
openblas-src = { version = "^0.9", optional = true, features = ["system"], default-features = false }
assert_float_eq = "^1.0"
[dev-dependencies]
env_logger = "^0.7"
ordered-float = "^1.0"
| > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
c_str_macro = "^1.0"
cplex-sys = "^0.6"
float-pretty-print = "^0.1"
rs-crossbeam = { version = "^0.7", optional = true, package = "crossbeam" }
threadpool = "^1.7"
num_cpus = "^1.2"
num-traits = "^0.2.8"
rand = "^0.7.3"
rs-blas = { version = "^0.20.0", optional = true, package = "blas" }
openblas-src = { version = "^0.9", optional = true, features = ["system"], default-features = false }
assert_float_eq = "^1.0"
[dev-dependencies]
env_logger = "^0.7"
ordered-float = "^1.0"
|
| ︙ | ︙ |
Changes to src/mcf/problem.rs.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
use crate::problem::{
FirstOrderProblem as ParallelProblem, ResultSender, UpdateSender, UpdateState as ParallelUpdateState,
};
use crate::{DVector, Minorant, Real};
use log::{debug, warn};
use num_traits::Float;
use threadpool::ThreadPool;
use std::f64::INFINITY;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::result;
use std::sync::{Arc, RwLock};
/// An error in the mmcf file format.
#[derive(Debug)]
#[non_exhaustive]
pub enum MMCFReadError {
Format(String),
MissingNodField(&'static str),
| > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
use crate::problem::{
FirstOrderProblem as ParallelProblem, ResultSender, UpdateSender, UpdateState as ParallelUpdateState,
};
use crate::{DVector, Minorant, Real};
use log::{debug, warn};
use num_traits::Float;
use rand::{rngs::ThreadRng, thread_rng, Rng};
use threadpool::ThreadPool;
use std::f64::INFINITY;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::result;
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;
/// An error in the mmcf file format.
#[derive(Debug)]
#[non_exhaustive]
pub enum MMCFReadError {
Format(String),
MissingNodField(&'static str),
|
| ︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
struct Elem {
ind: usize,
val: Real,
}
/// A single MMCF subproblem, i.e. one network.
struct Subproblem {
net: mcf::Solver,
lhs: Vec<Vec<Elem>>,
/// The right-hand side ... might be empty.
rhs: DVector,
cbase: DVector,
c: DVector,
}
unsafe impl Send for Subproblem {}
unsafe impl Sync for Subproblem {}
pub struct MMCFProblem {
pub multimodel: bool,
| > > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
struct Elem {
ind: usize,
val: Real,
}
/// A single MMCF subproblem, i.e. one network.
struct Subproblem {
fidx: usize,
net: mcf::Solver,
lhs: Vec<Vec<Elem>>,
/// The right-hand side ... might be empty.
rhs: DVector,
cbase: DVector,
c: DVector,
rng: ThreadRng,
}
unsafe impl Send for Subproblem {}
unsafe impl Sync for Subproblem {}
pub struct MMCFProblem {
pub multimodel: bool,
|
| ︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
(-self.net.objective()?, dvec![0.0; y.len()])
};
let sol = self.net.get_solution()?;
for (i, lhs) in lhs.enumerate() {
subg[i] -= lhs.iter().map(|elem| elem.val * sol[elem.ind]).sum::<Real>();
}
Ok((objective, subg, sol))
}
fn evaluate_constraint(&self, primal: &DVector, cidx: usize) -> Real {
let rhs = self.rhs.get(cidx).unwrap_or(&0.0);
let lhs = self.lhs[cidx]
| > > > > > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
(-self.net.objective()?, dvec![0.0; y.len()])
};
let sol = self.net.get_solution()?;
for (i, lhs) in lhs.enumerate() {
subg[i] -= lhs.iter().map(|elem| elem.val * sol[elem.ind]).sum::<Real>();
}
if self.fidx == 1 || self.fidx == 5 || self.fidx == 7 || self.fidx == 10 {
sleep(Duration::from_millis(self.rng.gen_range(10, 100)));
//sleep(Duration::from_millis(10));
}
Ok((objective, subg, sol))
}
fn evaluate_constraint(&self, primal: &DVector, cidx: usize) -> Real {
let rhs = self.rhs.get(cidx).unwrap_or(&0.0);
let lhs = self.lhs[cidx]
|
| ︙ | ︙ | |||
345 346 347 348 349 350 351 |
.collect::<Vec<_>>();
let subproblems = nets
.into_iter()
.zip(cbase)
.zip(lhs)
.zip(std::iter::once(rhs).chain(std::iter::repeat(dvec![])))
| > | > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
.collect::<Vec<_>>();
let subproblems = nets
.into_iter()
.zip(cbase)
.zip(lhs)
.zip(std::iter::once(rhs).chain(std::iter::repeat(dvec![])))
.enumerate()
.map(|(fidx, (((net, cbase), lhs), rhs))| Subproblem {
fidx,
net,
cbase,
c: dvec![],
lhs,
rhs,
rng: thread_rng(),
})
.map(RwLock::new)
.map(Arc::new)
.collect();
Ok(MMCFProblem {
multimodel: false,
|
| ︙ | ︙ |
Changes to src/solver/asyn.rs.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
use super::masterprocess::{self, MasterConfig, MasterProcess, MasterResponse, Response};
use crate::data::Minorant;
use crate::master::{Builder as MasterBuilder, MasterProblem};
use crate::problem::{FirstOrderProblem, UpdateState};
use crate::terminator::{StandardTerminatable, StandardTerminator, Terminator};
use crate::weighter::{HKWeightable, HKWeighter, Weighter};
| | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
use super::masterprocess::{self, MasterConfig, MasterProcess, MasterResponse, Response};
use crate::data::Minorant;
use crate::master::{Builder as MasterBuilder, MasterProblem};
use crate::problem::{FirstOrderProblem, UpdateState};
use crate::terminator::{StandardTerminatable, StandardTerminator, Terminator};
use crate::weighter::{HKWeightable, HKWeighter, Weighter};
pub mod guessmodels;
use guessmodels::{Guess, GuessModel, NearestValue};
/// The default iteration limit.
pub const DEFAULT_ITERATION_LIMIT: usize = 10_000;
/// The default solver.
pub type DefaultSolver<P> = Solver<P, StandardTerminator, HKWeighter, crate::master::FullMasterBuilder>;
|
| ︙ | ︙ | |||
456 457 458 459 460 461 462 |
fn aggregated_primal(&self, i: usize) -> &Pr {
&self.primal_aggrs[i]
}
}
/// An evaluation point.
#[derive(Clone)]
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
fn aggregated_primal(&self, i: usize) -> &Pr {
&self.primal_aggrs[i]
}
}
/// An evaluation point.
#[derive(Clone)]
pub struct Point {
/// The globally unique index of the evaluation point.
index: usize,
/// The evaluation point itself.
point: Arc<DVector>,
}
impl Point {
fn distance(&self, p: &Point) -> Real {
if self.index != p.index {
let mut d = self.point.as_ref().clone();
d.add_scaled(-1.0, &p.point);
d.norm2()
} else {
Real::zero()
}
}
}
/// Model data of a single subproblem.
///
/// This struct does not handle the subproblem model itself. However, it handles
/// the asynchronous precision data, i.e. the guessed Lipschitz-constant and the
/// distance of the evaluation points to the candidate.
///
/// The concrete model used for computing the guessed values in the candidate
/// and the center must be provided by an implementation of `SubProblem`.
struct SubData {
/// The index associated with this subproblem.
fidx: usize,
/// The subproblem.
sub: Box<dyn GuessModel>,
/// The current candidate index.
candidate_index: usize,
/// The last index at which the evaluation has been started.
last_eval_index: usize,
/// Whether a subproblem evaluation is currently running.
is_running: bool,
/// Whether the last evaluation has been sufficiently close.
is_close_enough: bool,
/// The guess value and its evaluation distance in the current center.
center_guess: Guess,
/// The current guess of the Lipschitz constant.
l_guess: Real,
}
impl SubData {
fn new(fidx: usize, sub: Box<dyn GuessModel>) -> SubData {
SubData {
fidx,
sub,
last_eval_index: 0,
candidate_index: 0,
is_running: false,
is_close_enough: false,
|
| ︙ | ︙ | |||
862 863 864 865 866 867 868 |
tx,
&mut self.threadpool,
));
debug!("Initial problem evaluation");
// We need an initial evaluation of all oracles for the first center.
self.data.subs = (0..m)
| | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 |
tx,
&mut self.threadpool,
));
debug!("Initial problem evaluation");
// We need an initial evaluation of all oracles for the first center.
self.data.subs = (0..m)
.map(|fidx| SubData::new(fidx, Box::new(NearestValue::new())))
.collect();
self.data.nxt_y = self.data.cur_y.clone();
// The initial evaluation point.
let point = Point {
index: self.data.candidate_index,
point: self.data.cur_y.clone(),
|
| ︙ | ︙ |
Added src/solver/asyn/guessmodels.rs.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/*
* Copyright (c) 2020 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 super::Point;
use crate::{data::Minorant, Real};
use num_traits::{Float, Zero};
use std::sync::Arc;
mod nearestvalue;
pub use nearestvalue::NearestValue;
/// A guessed function value.
#[derive(Clone, Copy)]
pub struct Guess {
/// The guessed value.
pub value: Real,
/// The accuracy distance.
pub dist: Real,
}
impl Guess {
/// Create a new guess value.
///
/// If `dist` is zero the value is assumed to be exact.
pub fn new(value: Real, dist: Real) -> Guess {
Guess { value, dist }
}
/// Create an approximate guess value.
pub fn new_approx(value: Real, dist: Real) -> Guess {
Guess { value, dist }
}
/// Create an exact guess value.
pub fn new_exact(value: Real) -> Guess {
Guess {
value,
dist: Real::zero(),
}
}
/// Return `true` if this is an exact guess value.
///
/// In other words, the value is not `guessed` anymore.
pub fn is_exact(&self) -> bool {
self.dist.is_zero()
}
}
impl Default for Guess {
fn default() -> Guess {
Guess {
value: Real::zero(),
dist: Real::infinity(),
}
}
}
/// A subproblem model for guessing candidate and center values.
pub trait GuessModel {
/// Set the center of this model.
fn set_center(&mut self, y: &Point);
/// Set the candidate of this model.
fn set_candidate(&mut self, y: &Point);
/// Add a function value to this model.
fn add_function_value(&mut self, y: &Point, value: Real);
/// Add a minorant to this model.
///
/// The minorant must be centered at the global 0.
fn add_minorant(&mut self, y: &Point, m: &Arc<Minorant>);
/// Return the current guess value at the current candidate.
///
/// The function might return `None` if no guess value is available.
fn candidate_value(&self) -> Option<Guess>;
/// Return the current lower bound value at the center.
///
/// In case no lower bound is available, the function should return
/// -infinity.
fn center_lb(&self) -> Real;
}
|
Name change from src/solver/asyn/subzero.rs to src/solver/asyn/guessmodels/nearestvalue.rs.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
use num_traits::{Float, Zero};
use std::collections::VecDeque;
use std::sync::Arc;
use crate::data::Minorant;
use crate::Real;
| | | | | | | | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
use num_traits::{Float, Zero};
use std::collections::VecDeque;
use std::sync::Arc;
use crate::data::Minorant;
use crate::Real;
use super::{Guess, GuessModel, Point};
/// The maximal number of last evaluation points to be kept in the model.
#[allow(non_upper_case_globals)]
const MaxEvalPoints: usize = 5;
/// The maximal number of last minorants to be kept in the model.
#[allow(non_upper_case_globals)]
const MaxMinorants: usize = 5;
/// Information associated with one subproblem.
pub struct NearestValue {
/// The current center point and the known lower bound.
center: Option<(Point, Real)>,
/// The current candidate point.
candidate: Option<Point>,
/// The last evaluation points (y, function_value).
eval_points: VecDeque<(Point, Real)>,
/// The last minorants.
minorants: VecDeque<Arc<Minorant>>,
/// The candidate guess value and distance.
candidate_value: Option<Guess>,
}
impl NearestValue {
pub fn new() -> NearestValue {
NearestValue {
center: None,
candidate: None,
eval_points: VecDeque::new(),
minorants: VecDeque::new(),
candidate_value: None,
}
}
}
impl Default for NearestValue {
fn default() -> NearestValue {
NearestValue::new()
}
}
impl GuessModel for NearestValue {
fn set_center(&mut self, y: &Point) {
// compute the best lower bound for the new center.
let lb = self
.minorants
.iter()
.map(|m| m.eval(&y.point))
.max_by(|a, b| a.partial_cmp(b).unwrap())
|
| ︙ | ︙ |