#[cfg(test)]
#[macro_use]
extern crate assert;
extern crate matrix;
pub mod model;
#[cfg(test)]
mod tests;
pub struct Analysis {
config: Config,
system: System,
}
pub struct Circuit {
pub cores: uint,
pub nodes: uint,
pub capacitance: Vec<f64>,
pub conductance: Vec<f64>,
}
#[allow(missing_copy_implementations)]
pub struct Config {
pub time_step: f64,
pub ambience: f64,
}
#[allow(non_snake_case)]
struct System {
cores: uint,
nodes: uint,
#[allow(dead_code)] U: Vec<f64>,
#[allow(dead_code)] L: Vec<f64>,
D: Vec<f64>,
E: Vec<f64>,
F: Vec<f64>,
}
impl Analysis {
#[allow(non_snake_case)]
pub fn new(circuit: Circuit, config: Config) -> Result<Analysis, &'static str> {
use std::num::Float;
use matrix::multiply;
use matrix::decomp::sym_eig;
#[inline(always)]
fn zero(length: uint) -> Vec<f64> {
use std::iter::repeat;
repeat(0.0).take(length).collect()
}
let (nc, nn) = (circuit.cores, circuit.nodes);
let mut D = circuit.capacitance; for i in range(0u, nn) {
D[i] = (1.0 / D[i]).sqrt();
}
let mut A = circuit.conductance; for i in range(0u, nn) {
for j in range(0u, nn) {
A[j * nn + i] = -1.0 * D[i] * D[j] * A[j * nn + i];
}
}
let mut U = zero(nn * nn);
let mut L = zero(nn);
if sym_eig(A.as_slice(), U.as_mut_slice(), L.as_mut_slice(), nn).is_err() {
return Err("cannot perform the eigendecomposition");
}
let dt = config.time_step;
let mut coef = zero(nn);
let mut temp = A;
for i in range(0u, nn) {
coef[i] = (dt * L[i]).exp();
}
for i in range(0u, nn) {
for j in range(0u, nn) {
temp[j * nn + i] = coef[i] * U[i * nn + j];
}
}
let mut E = zero(nn * nn);
multiply(U.as_slice(), temp.as_slice(), E.as_mut_slice(), nn, nn, nn);
for i in range(0u, nn) {
coef[i] = (coef[i] - 1.0) / L[i];
}
for i in range(0u, nn) {
for j in range(0u, nc) {
temp[j * nn + i] = coef[i] * U[i * nn + j] * D[j];
}
}
let mut F = zero(nn * nc);
multiply(U.as_slice(), temp.as_slice(), F.as_mut_slice(), nn, nn, nc);
Ok(Analysis {
config: config,
system: System {
cores: nc,
nodes: nn,
L: L,
U: U,
D: D,
E: E,
F: F,
},
})
}
#[allow(non_snake_case)]
pub fn compute_transient(&self, P: &[f64], Q: &mut [f64], S: &mut [f64], steps: uint) {
use matrix::{multiply, multiply_add};
use std::mem::transmute_copy;
let (nc, nn) = (self.system.cores, self.system.nodes);
let D = self.system.D.as_slice();
let E = self.system.E.as_slice();
let F = self.system.F.as_slice();
multiply(F, P, S, nn, nc, steps);
let Z: &mut [f64] = unsafe { transmute_copy(&S) };
for i in range(1u, steps) {
let (j, k) = ((i - 1) * nn, i * nn);
multiply_add(E, S.slice(j, k), S.slice(k, k + nn),
Z.slice_mut(k, k + nn), nn, nn, 1);
}
for i in range(0u, nc) {
for j in range(0u, steps) {
Q[nc * j + i] = D[i] * S[nn * j + i] + self.config.ambience;
}
}
}
}
impl std::default::Default for Config {
#[inline]
fn default() -> Config {
Config {
time_step: 1e-3,
ambience: 318.15,
}
}
}