Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Refactor several lint warnings. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
f0ef5ba392b7cb5fc13637b7fe90f798 |
| User & Date: | fifr 2017-01-20 09:19:39.444 |
References
|
2020-07-27
| ||
| 09:52 | boxed: fix computation in `get_norm_subg2` introduced in [f0ef5ba392]. check-in: eba6824e6a user: fifr tags: release | |
Context
|
2017-01-20
| ||
| 09:35 | mcf: Do not use temporaries for static CStrings. check-in: f4dea49467 user: fifr tags: trunk | |
| 09:19 | Refactor several lint warnings. check-in: f0ef5ba392 user: fifr tags: trunk | |
|
2017-01-19
| ||
| 21:53 | vector: use iterators instead of unchecked access. check-in: 80c0335251 user: fifr tags: trunk | |
Changes
Changes to src/cplex.rs.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 |
//! trycpx!(CPXNETchgobj(cplex::env(), net, CPX_MAX))
//! }
//! ```
#![allow(dead_code)]
use libc::{c_int, c_double, c_char};
| < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
//! trycpx!(CPXNETchgobj(cplex::env(), net, CPX_MAX))
//! }
//! ```
#![allow(dead_code)]
use libc::{c_int, c_double, c_char};
use std::fmt;
use std::error;
pub use std::result::Result as cplex_std_Result;
pub use std::convert::From as cplex_std_From;
pub const CPXMSGBUFSIZE: usize = 1024;
|
| ︙ | ︙ | |||
71 72 73 74 75 76 77 |
pub const CPX_ALG_NET: CPXINT = 3;
pub const CPX_ALG_BARRIER: CPXINT = 4;
/// Globally unique environment.
static mut ENV: *mut CPXenv = 0 as *mut CPXenv;
pub unsafe fn env() -> *mut CPXenv {
| | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
pub const CPX_ALG_NET: CPXINT = 3;
pub const CPX_ALG_BARRIER: CPXINT = 4;
/// Globally unique environment.
static mut ENV: *mut CPXenv = 0 as *mut CPXenv;
pub unsafe fn env() -> *mut CPXenv {
if ENV.is_null() {
let mut status: c_int = 0;
ENV = CPXopenCPLEX(&mut status);
if status != 0 {
panic!("Can't open CPLEX environment");
}
}
ENV
|
| ︙ | ︙ |
Changes to src/hkweighter.rs.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
eps_weight: 1e30,
m_r: m_r,
iter: 0,
model_max: NEG_INFINITY,
}
}
}
impl Weighter for HKWeighter {
fn weight(&mut self, state: &BundleState, params: &SolverParams) -> Real {
assert!(params.min_weight > 0.0);
assert!(params.max_weight >= params.min_weight);
debug!("HKWeighter {:?} iter:{}", state.step, self.iter);
| > > > > > > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
eps_weight: 1e30,
m_r: m_r,
iter: 0,
model_max: NEG_INFINITY,
}
}
}
impl Default for HKWeighter {
fn default() -> Self {
Self::new()
}
}
impl Weighter for HKWeighter {
fn weight(&mut self, state: &BundleState, params: &SolverParams) -> Real {
assert!(params.min_weight > 0.0);
assert!(params.max_weight >= params.min_weight);
debug!("HKWeighter {:?} iter:{}", state.step, self.iter);
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
sgnorm,
state.cur_val,
state.new_cutval,
lin_err,
self.eps_weight);
debug!(" new_weight={}", new_weight);
| | | < < | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
sgnorm,
state.cur_val,
state.new_cutval,
lin_err,
self.eps_weight);
debug!(" new_weight={}", new_weight);
new_weight
} else {
self.model_max = self.model_max.max(state.nxt_mod);
let new_weight = if self.iter > 0 && cur_nxt > self.m_r * cur_mod {
w
} else if self.iter > 3 || state.nxt_val < self.model_max {
state.weight / 2.0
} else {
state.weight
}
.max(state.weight / FACTOR)
.max(params.min_weight);
self.eps_weight = self.eps_weight.max(2.0 * cur_mod);
if new_weight < state.weight {
self.iter = 1;
self.model_max = NEG_INFINITY;
} else {
self.iter = max(self.iter + 1, 1);
}
debug!(" model_max={}", self.model_max);
debug!(" new_weight={}", new_weight);
new_weight
}
}
}
|
Name change from src/master/master.rs to src/master/base.rs.
| ︙ | ︙ |
Changes to src/master/boxed.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 |
// Copyright (c) 2016, 2017 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 {Real, DVector, Minorant};
use master::{MasterProblem, Error, Result};
use master::UnconstrainedMasterProblem;
use std::f64::{INFINITY, NEG_INFINITY};
/**
* Turn unconstrained master problem into box-constrained one.
*
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 |
self.eta[i] = neweta;
}
debug!("Eta update");
debug!(" primopt={}", self.primopt);
debug!(" eta ={}", self.eta);
| | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
self.eta[i] = neweta;
}
debug!("Eta update");
debug!(" primopt={}", self.primopt);
debug!(" eta ={}", self.eta);
updated_eta
}
// Compute the new candidate point.
//
// This consists of two steps:
//
// 1. the new point is computed as $-\tfrac{1}{u}\bar{g}$, where $\bar{g}$
|
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
fn eta_cutval(&self) -> Real {
let mut val = 0.0;
for i in 0..self.lb.len() {
if self.eta[i] >= 0.0 {
if self.lb[i] > NEG_INFINITY {
val += self.lb[i] * self.eta[i];
}
| < | | | | < | < | < < < < | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
fn eta_cutval(&self) -> Real {
let mut val = 0.0;
for i in 0..self.lb.len() {
if self.eta[i] >= 0.0 {
if self.lb[i] > NEG_INFINITY {
val += self.lb[i] * self.eta[i];
}
} else if self.ub[i] < INFINITY {
val += self.ub[i] * self.eta[i];
}
}
val
}
/**
* Return $\\|G \alpha - \eta\\|_2\^2$.
*
* This is the norm-square of the dual optimal solution including
* the current box-multipliers $\eta$.
*/
fn get_norm_subg2(&self) -> Real {
let dualopt = self.master.dualopt();
dualopt.iter().zip(self.eta.iter()).map(|(x,y)| x * y).sum()
}
}
impl<M: UnconstrainedMasterProblem> MasterProblem for BoxedMasterProblem<M> {
type MinorantIndex = M::MinorantIndex;
|
| ︙ | ︙ | |||
316 317 318 319 320 321 322 |
fn multiplier(&self, min: Self::MinorantIndex) -> Real {
self.master.multiplier(min)
}
fn move_center(&mut self, alpha: Real, d: &DVector) {
self.need_new_candidate = true;
self.master.move_center(alpha, d);
| < | | < | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
fn multiplier(&self, min: Self::MinorantIndex) -> Real {
self.master.multiplier(min)
}
fn move_center(&mut self, alpha: Real, d: &DVector) {
self.need_new_candidate = true;
self.master.move_center(alpha, d);
self.lb.add_scaled(-alpha, d);
self.ub.add_scaled(-alpha, d);
}
fn set_max_updates(&mut self, max_updates: usize) {
BoxedMasterProblem::set_max_updates(self, max_updates);
}
fn cnt_updates(&self) -> usize {
self.cnt_updates
}
}
|
Changes to src/master/cpx.rs.
|
| | | 1 2 3 4 5 6 7 8 | // Copyright (c) 2016, 2017 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 |
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
if nvars == 0 {
return Err(Error::NoMinorants);
}
// update linear costs
{
let mut c = Vec::with_capacity(nvars);
let mut inds = Vec::with_capacity(nvars);
| | | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
if nvars == 0 {
return Err(Error::NoMinorants);
}
// update linear costs
{
let mut c = Vec::with_capacity(nvars);
let mut inds = Vec::with_capacity(nvars);
for mins in &self.minorants {
for m in mins {
inds.push(c.len() as c_int);
c.push(-m.constant * self.weight - m.linear.dot(eta));
}
}
trycpx!(CPXchgobj(env(), self.lp, nvars as c_int, inds.as_ptr(), c.as_ptr()));
}
|
| ︙ | ︙ | |||
353 354 355 356 357 358 359 |
}
self.qterm[aggr_idx][aggr_idx] = aggr_diag;
Ok((aggr_idx, aggr_coeffs))
}
fn move_center(&mut self, alpha: Real, d: &DVector) {
| | | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
}
self.qterm[aggr_idx][aggr_idx] = aggr_diag;
Ok((aggr_idx, aggr_coeffs))
}
fn move_center(&mut self, alpha: Real, d: &DVector) {
for mins in &mut self.minorants {
for m in mins.iter_mut() {
m.move_center(alpha, d);
}
}
}
}
impl CplexMaster {
fn init_qp(&mut self) -> Result<()> {
if !self.lp.is_null() {
trycpx!(CPXfreeprob(env(), &mut self.lp));
}
trycpx!({
let mut status = 0;
self.lp = CPXcreateprob(env(), &mut status, CString::new("mcf").unwrap().as_ptr());
status
});
|
| ︙ | ︙ | |||
438 439 440 441 442 443 444 |
self.qterm[idx_i][idx_j] = x;
self.qterm[idx_j][idx_i] = x;
}
}
}
if cfg!(debug_assertions) {
| | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
self.qterm[idx_i][idx_j] = x;
self.qterm[idx_j][idx_i] = x;
}
}
}
if cfg!(debug_assertions) {
for &idx_i in &activeinds {
for &idx_j in &activeinds {
let (fidx_i, i) = self.index2min[idx_i];
let (fidx_j, j) = self.index2min[idx_j];
let m_i = &self.minorants[fidx_i][i];
let m_j = &self.minorants[fidx_j][j];
debug_assert!((self.qterm[idx_i][idx_j] - m_i.linear.dot(&m_j.linear)).abs() < 1e-6);
}
}
|
| ︙ | ︙ |
Changes to src/master/minimal.rs.
| ︙ | ︙ | |||
184 185 186 187 188 189 190 |
}
fn eval_model(&self, y: &DVector) -> Real {
let mut result = NEG_INFINITY;
for m in &self.minorants {
result = result.max(m.eval(y));
}
| | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
}
fn eval_model(&self, y: &DVector) -> Real {
let mut result = NEG_INFINITY;
for m in &self.minorants {
result = result.max(m.eval(y));
}
result
}
fn aggregate(&mut self, fidx: usize, mins: &[usize]) -> Result<(usize, DVector)> {
assert!(fidx == 0);
if mins.len() == 2 {
debug!("Aggregate");
debug!(" {} * {}", self.opt_mult[0], self.minorants[0]);
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
Ok((mins[0], dvec![1.0]))
} else {
panic!("No minorants specified to be aggregated");
}
}
fn move_center(&mut self, alpha: Real, d: &DVector) {
| | | 209 210 211 212 213 214 215 216 217 218 219 220 |
Ok((mins[0], dvec![1.0]))
} else {
panic!("No minorants specified to be aggregated");
}
}
fn move_center(&mut self, alpha: Real, d: &DVector) {
for m in &mut self.minorants {
m.move_center(alpha, d);
}
}
}
|
Changes to src/master/mod.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 |
// Copyright (c) 2016, 2017 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/>
//
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
//! Bundle master problem solver.
//!
//! This module contains solvers for the bundle master problem, i.e.
//! for solving convex optimization problems of the form
//!
//! \\[ \min \left\\{ \hat{f}(d) + \frac{w}{2} \\|d\\|\^2 \colon d \in [l,u] \right\\}, \\]
//!
|
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
//! * solving the problem,
//! * changing the weight parameter $w$,
//! * modifying $\hat{f}$ by adding or removing linear functions $\ell_i$,
//! * moving the center of the linear functions $\ell_i$ (and the
//! bounds), i.e. replacing $\hat{f}$ by $d \mapsto \hat{f}(d -
//! \hat{d})$ for some given $\hat{d} \in \mathbb{R}\^n$.
| | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
//! * solving the problem,
//! * changing the weight parameter $w$,
//! * modifying $\hat{f}$ by adding or removing linear functions $\ell_i$,
//! * moving the center of the linear functions $\ell_i$ (and the
//! bounds), i.e. replacing $\hat{f}$ by $d \mapsto \hat{f}(d -
//! \hat{d})$ for some given $\hat{d} \in \mathbb{R}\^n$.
mod base;
pub use self::base::{MasterProblem, Error, Result};
mod boxed;
pub use self::boxed::BoxedMasterProblem;
mod unconstrained;
pub use self::unconstrained::UnconstrainedMasterProblem;
|
| ︙ | ︙ |
Changes to src/mcf/problem.rs.
|
| | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Copyright (c) 2016, 2017 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 {Real, Vector, DVector, Minorant, FirstOrderProblem, SimpleEvaluation};
use mcf;
use std::fs::File;
use std::io::{self, Read};
use std::result;
use std::num::{ParseIntError, ParseFloatError};
|
| ︙ | ︙ | |||
187 188 189 190 191 192 193 |
rhsval: 0.0,
cbase: cbase,
c: vec![dvec![]; ncom],
})
}
/// Compute costs for a primal solution.
| | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
rhsval: 0.0,
cbase: cbase,
c: vec![dvec![]; ncom],
})
}
/// Compute costs for a primal solution.
pub fn get_primal_costs(&self, fidx: usize, primals: &[DVector]) -> Real {
if self.multimodel {
primals[0].iter().enumerate().map(|(i, x)| x * self.cbase[fidx][i]).sum()
} else {
let mut sum = 0.0;
for (fidx, p) in primals.iter().enumerate() {
for (i, x) in p.iter().enumerate() {
sum += x * self.cbase[fidx][i];
|
| ︙ | ︙ |
Changes to src/mcf/solver.rs.
| ︙ | ︙ | |||
61 62 63 64 65 66 67 |
let mut net = ptr::null_mut();
let logfile;
unsafe {
loop {
logfile = CPXfopen(CString::new("mcf.cpxlog").unwrap().as_ptr(),
CString::new("w").unwrap().as_ptr());
| | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
let mut net = ptr::null_mut();
let logfile;
unsafe {
loop {
logfile = CPXfopen(CString::new("mcf.cpxlog").unwrap().as_ptr(),
CString::new("w").unwrap().as_ptr());
if logfile.is_null() {
return Err(Error::Cplex(CplexError {
code: 0,
msg: "Can't open log-file".to_string(),
}));
}
status = CPXsetlogfile(env(), logfile);
if status != 0 {
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
return Err(Error::Cplex(CplexError {
code: status,
msg: CString::from_raw(msg).to_string_lossy().into_owned(),
}));
}
}
| | | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
return Err(Error::Cplex(CplexError {
code: status,
msg: CString::from_raw(msg).to_string_lossy().into_owned(),
}));
}
}
Ok(Solver {
net: net,
logfile: logfile,
})
}
pub fn num_nodes(&self) -> usize {
unsafe { CPXNETgetnumnodes(env(), self.net) as usize }
}
pub fn num_arcs(&self) -> usize {
|
| ︙ | ︙ | |||
168 169 170 171 172 173 174 |
self.net,
&mut stat as *mut c_int,
&mut objval as *mut c_double,
sol.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut()));
| | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
self.net,
&mut stat as *mut c_int,
&mut objval as *mut c_double,
sol.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut()));
Ok(sol)
}
pub fn writelp(&self, filename: &str) -> Result<()> {
Ok(trycpx!(CPXNETwriteprob(env(),
self.net,
CString::new(filename).unwrap().as_ptr(),
ptr::null_mut())))
}
}
|
Changes to src/solver.rs.
|
| | | 1 2 3 4 5 6 7 8 | // Copyright (c) 2016, 2017 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 |
| ︙ | ︙ | |||
768 769 770 771 772 773 774 |
self.nxt_y.add(&self.cur_y, &self.nxt_d);
self.nxt_mod = self.master.get_primoptval();
self.sgnorm = self.master.get_dualoptnorm2().sqrt();
self.expected_progress = self.cur_val - self.nxt_mod;
// update multiplier from master solution
for i in 0..self.problem.num_subproblems() {
| | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 |
self.nxt_y.add(&self.cur_y, &self.nxt_d);
self.nxt_mod = self.master.get_primoptval();
self.sgnorm = self.master.get_dualoptnorm2().sqrt();
self.expected_progress = self.cur_val - self.nxt_mod;
// update multiplier from master solution
for i in 0..self.problem.num_subproblems() {
for m in &mut self.minorants[i] {
m.multiplier = self.master.multiplier(m.index);
}
}
debug!("Model result");
debug!(" cur_val ={}", self.cur_val);
debug!(" nxt_mod ={}", self.nxt_mod);
|
| ︙ | ︙ | |||
920 921 922 923 924 925 926 |
if nxt_ub > descent_bnd {
// upper bound will produce null-step
if self.cur_val - nxt_lb > (self.cur_val - self.nxt_mod) * self.params.nullstep_factor.max(0.5) {
warn!("Relative precision of returned objective interval enforces null-step.");
self.iterinfos.push(IterationInfo::UpperBoundNullStep);
}
}
| | > < | | | < | | | 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 |
if nxt_ub > descent_bnd {
// upper bound will produce null-step
if self.cur_val - nxt_lb > (self.cur_val - self.nxt_mod) * self.params.nullstep_factor.max(0.5) {
warn!("Relative precision of returned objective interval enforces null-step.");
self.iterinfos.push(IterationInfo::UpperBoundNullStep);
}
}
} else if self.cur_val - nxt_lb > 0.8 * (self.cur_val - self.nxt_mod) {
// TODO: double check with ConicBundle if this test makes sense.
// lower bound gives already a null step
// subgradient won't yield much improvement
warn!("Shallow cut (subgradient won't yield much improvement)");
self.iterinfos.push(IterationInfo::ShallowCut);
}
debug!("Step");
debug!(" cur_val ={}", self.cur_val);
debug!(" nxt_mod ={}", self.nxt_mod);
debug!(" nxt_ub ={}", self.nxt_val);
debug!(" descent_bnd={}", descent_bnd);
// do a descent step or null step
if nxt_ub <= descent_bnd {
self.descent_step();
Ok(Step::Descent)
} else {
self.null_step();
Ok(Step::Null)
}
}
/**
* Return the bound on the function value that enforces a
* nullstep.
*
|
| ︙ | ︙ |
Changes to src/vector.rs.
|
| | | 1 2 3 4 5 6 7 8 | // Copyright (c) 2016, 2017 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 |
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
elems: Vec<(usize, Real)>,
},
}
impl fmt::Display for Vector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
| | | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
elems: Vec<(usize, Real)>,
},
}
impl fmt::Display for Vector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Vector::Dense(ref v) => write!(f, "{}", v),
Vector::Sparse { size, ref elems } => {
let mut it = elems.iter();
try!(write!(f, "{}:(", size));
if let Some(&(i, x)) = it.next() {
try!(write!(f, "{}:{}", i, x));
for &(i, x) in it {
try!(write!(f, ", {}:{}", i, x));
}
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
/**
* Convert vector to a dense vector.
*
* This function always returns a copy of the vector.
*/
pub fn to_dense(&self) -> DVector {
| | | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
/**
* Convert vector to a dense vector.
*
* This function always returns a copy of the vector.
*/
pub fn to_dense(&self) -> DVector {
match *self {
Vector::Dense(ref x) => x.clone(),
Vector::Sparse { size: n, elems: ref xs } => {
let mut v = vec![0.0; n];
for &(i, x) in xs {
unsafe { *v.get_unchecked_mut(i) = x };
}
DVector(v)
}
}
}
}
|