Skip to content

Commit

Permalink
Merge 20aa915 into 66d7943
Browse files Browse the repository at this point in the history
  • Loading branch information
tspooner committed Nov 21, 2018
2 parents 66d7943 + 20aa915 commit 560832a
Show file tree
Hide file tree
Showing 34 changed files with 348 additions and 456 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Expand Up @@ -2,7 +2,7 @@
name = "lfa"
description = "Native rust implementations of linear function approximators."

version = "0.5.0"
version = "0.6.0"
authors = ["Tom Spooner <t.spooner@liverpool.ac.uk>"]

license = "MIT"
Expand All @@ -18,8 +18,8 @@ travis-ci = { repository = "tspooner/lfa", branch = "master" }
coveralls = { repository = "tspooner/lfa", branch = "master", service = "github" }

[dependencies]
rand = "0.5"
spaces = "3.3"
rand = "0.6"
spaces = "4.1"
ndarray = "0.12"
itertools = "0.7"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -12,7 +12,7 @@
## Installation
```toml
[dependencies]
lfa = "0.5"
lfa = "0.6"
```


Expand Down
4 changes: 2 additions & 2 deletions src/approximators/mod.rs
@@ -1,2 +1,2 @@
import_all!(simple);
import_all!(multi);
import_all!(scalar);
import_all!(vector);
28 changes: 13 additions & 15 deletions src/approximators/simple.rs → src/approximators/scalar.rs
@@ -1,17 +1,15 @@
use core::{Approximator, Parameterised};
use error::{AdaptError, AdaptResult, EvaluationResult, UpdateResult};
use core::*;
use geometry::{Matrix, Vector, norms::l1};
use projectors::{IndexSet, IndexT, Projection};
use std::{collections::HashMap, mem::replace};

#[derive(Clone, Serialize, Deserialize)]
pub struct Simple {
pub struct ScalarFunction {
pub weights: Vector<f64>,
}

impl Simple {
impl ScalarFunction {
pub fn new(n_features: usize) -> Self {
Simple {
ScalarFunction {
weights: Vector::zeros((n_features,)),
}
}
Expand All @@ -26,7 +24,7 @@ impl Simple {
}
}

impl Approximator<Projection> for Simple {
impl Approximator<Projection> for ScalarFunction {
type Value = f64;

fn evaluate(&self, p: &Projection) -> EvaluationResult<f64> {
Expand Down Expand Up @@ -76,7 +74,7 @@ impl Approximator<Projection> for Simple {
}
}

impl Parameterised for Simple {
impl Parameterised for ScalarFunction {
fn weights(&self) -> Matrix<f64> {
let n_rows = self.weights.len();

Expand All @@ -88,18 +86,18 @@ impl Parameterised for Simple {
mod tests {
extern crate seahash;

use LFA;
use approximators::Simple;
use ::LFA;
use approximators::ScalarFunction;
use basis::fixed::{Fourier, TileCoding};
use core::Approximator;
use projectors::fixed::{Fourier, TileCoding};
use std::{collections::{BTreeSet, HashMap}, hash::BuildHasherDefault};

type SHBuilder = BuildHasherDefault<seahash::SeaHasher>;

#[test]
fn test_sparse_update_eval() {
let p = TileCoding::new(SHBuilder::default(), 4, 100);
let mut f = LFA::simple(p);
let mut f = LFA::scalar_valued(p);
let input = vec![5.0];

let _ = f.update(&input, 50.0);
Expand All @@ -111,7 +109,7 @@ mod tests {
#[test]
fn test_dense_update_eval() {
let p = Fourier::new(3, vec![(0.0, 10.0)]);
let mut f = LFA::simple(p);
let mut f = LFA::scalar_valued(p);

let input = vec![5.0];

Expand All @@ -123,7 +121,7 @@ mod tests {

#[test]
fn test_adapt() {
let mut f = Simple::new(100);
let mut f = ScalarFunction::new(100);

let mut new_features = HashMap::new();
new_features.insert(100, {
Expand All @@ -141,7 +139,7 @@ mod tests {
assert_eq!(f.weights.len(), 101);
assert_eq!(f.weights[100], f.weights[10] / 2.0 + f.weights[90] / 2.0);
}
Err(err) => panic!("Simple::adapt failed with AdaptError::{:?}", err),
Err(err) => panic!("ScalarFunction::adapt failed with AdaptError::{:?}", err),
}
}
}
28 changes: 13 additions & 15 deletions src/approximators/multi.rs → src/approximators/vector.rs
@@ -1,17 +1,15 @@
use core::{Approximator, Parameterised};
use error::{AdaptError, AdaptResult, EvaluationResult, UpdateResult};
use core::*;
use geometry::{Matrix, Vector, norms::l1};
use projectors::{IndexSet, IndexT, Projection};
use std::{collections::HashMap, mem::replace};

#[derive(Clone, Serialize, Deserialize)]
pub struct Multi {
pub struct VectorFunction {
pub weights: Matrix<f64>,
}

impl Multi {
impl VectorFunction {
pub fn new(n_features: usize, n_outputs: usize) -> Self {
Multi {
VectorFunction {
weights: Matrix::zeros((n_features, n_outputs)),
}
}
Expand All @@ -35,7 +33,7 @@ impl Multi {
}
}

impl Approximator<Projection> for Multi {
impl Approximator<Projection> for VectorFunction {
type Value = Vector<f64>;

fn evaluate(&self, p: &Projection) -> EvaluationResult<Vector<f64>> {
Expand Down Expand Up @@ -105,7 +103,7 @@ impl Approximator<Projection> for Multi {
}
}

impl Parameterised for Multi {
impl Parameterised for VectorFunction {
fn weights(&self) -> Matrix<f64> {
self.weights.clone()
}
Expand All @@ -115,19 +113,19 @@ impl Parameterised for Multi {
mod tests {
extern crate seahash;

use LFA;
use approximators::Multi;
use ::LFA;
use approximators::VectorFunction;
use basis::fixed::{Fourier, TileCoding};
use core::Approximator;
use geometry::Vector;
use projectors::fixed::{Fourier, TileCoding};
use std::{collections::{BTreeSet, HashMap}, hash::BuildHasherDefault};

type SHBuilder = BuildHasherDefault<seahash::SeaHasher>;

#[test]
fn test_sparse_update_eval() {
let p = TileCoding::new(SHBuilder::default(), 4, 100);
let mut f = LFA::multi(p, 2);
let mut f = LFA::vector_valued(p, 2);
let input = vec![5.0];

let _ = f.update(input.as_slice(), Vector::from_vec(vec![20.0, 50.0]));
Expand All @@ -140,7 +138,7 @@ mod tests {
#[test]
fn test_dense_update_eval() {
let p = Fourier::new(3, vec![(0.0, 10.0)]);
let mut f = LFA::multi(p, 2);
let mut f = LFA::vector_valued(p, 2);

let input = vec![5.0];

Expand All @@ -153,7 +151,7 @@ mod tests {

#[test]
fn test_adapt() {
let mut f = Multi::new(100, 2);
let mut f = VectorFunction::new(100, 2);

let mut new_features = HashMap::new();
new_features.insert(100, {
Expand All @@ -176,7 +174,7 @@ mod tests {
assert_eq!(c0[100], c0[10] / 2.0 + c0[90] / 2.0);
assert_eq!(c1[100], c1[10] / 2.0 + c1[90] / 2.0);
}
Err(err) => panic!("Simple::adapt failed with AdaptError::{:?}", err),
Err(err) => panic!("VectorFunction::adapt failed with AdaptError::{:?}", err),
}
}
}
27 changes: 5 additions & 22 deletions src/projectors/adaptive/ifdd.rs → src/basis/adaptive/ifdd.rs
@@ -1,10 +1,7 @@
use core::*;
use geometry::{Card, Space, Vector};
use projectors::{CandidateFeature, Feature, IndexSet, IndexT};
use {AdaptiveProjector, Projection, Projector};

use std::collections::HashMap;
use rand::{Rng, seq::sample_indices};
use itertools::Itertools;
use std::collections::HashMap;

pub struct IFDD<P: Projector<[f64]>> {
pub base: P,
Expand Down Expand Up @@ -82,13 +79,6 @@ impl<P: Projector<[f64]>> IFDD<P> {
impl<P: Projector<[f64]>> Space for IFDD<P> {
type Value = Projection;

fn sample<R: Rng + ?Sized>(&self, mut rng: &mut R) -> Projection {
let d = self.dim();
let n = rng.gen_range(1, d);

sample_indices(&mut rng, d, n).into()
}

fn dim(&self) -> usize {
self.features.len()
}
Expand Down Expand Up @@ -125,11 +115,9 @@ impl<P: Projector<[f64]>> Projector<[f64]> for IFDD<P> {

impl<P: Projector<[f64]>> AdaptiveProjector<[f64]> for IFDD<P> {
fn discover(&mut self, input: &[f64], error: f64) -> Option<HashMap<IndexT, IndexSet>> {
use Projection::*;

let new_features = match self.base.project(input) {
Sparse(active_indices) => self.discover_sparse(active_indices, error),
Dense(activations) => self.discover_dense(activations, error),
Projection::Sparse(active_indices) => self.discover_sparse(active_indices, error),
Projection::Dense(activations) => self.discover_dense(activations, error),
};

self.features.reserve_exact(new_features.len());
Expand Down Expand Up @@ -161,20 +149,15 @@ impl<P: Projector<[f64]>> AdaptiveProjector<[f64]> for IFDD<P> {
mod tests {
extern crate seahash;

use projectors::{adaptive::IFDD, fixed::TileCoding};
use basis::adaptive::IFDD;
use super::*;
use std::hash::BuildHasherDefault;

#[derive(Clone)]
struct BaseProjector;

impl Space for BaseProjector {
type Value = Projection;

fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> Projection {
unimplemented!()
}

fn dim(&self) -> usize {
5
}
Expand Down
File renamed without changes.
25 changes: 1 addition & 24 deletions src/projectors/fixed/constant.rs → src/basis/fixed/constant.rs
@@ -1,6 +1,5 @@
use core::{Projector, Projection};
use geometry::{Card, Space};
use projectors::{Projection, Projector};
use rand::Rng;

/// Fixed uniform basis projector.
#[derive(Clone)]
Expand Down Expand Up @@ -29,10 +28,6 @@ impl Constant {
impl Space for Constant {
type Value = Projection;

fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> Projection {
vec![self.value; self.n_features].into()
}

fn dim(&self) -> usize {
self.n_features
}
Expand All @@ -50,7 +45,6 @@ impl Projector<[f64]> for Constant {

#[cfg(test)]
mod tests {
use rand::thread_rng;
use super::*;

#[test]
Expand All @@ -67,21 +61,4 @@ mod tests {
assert_eq!(Constant::new(10, 5.6).project(&[0.0]), vec![5.6; 10].into());
assert_eq!(Constant::new(10, 123.0).project(&[0.0]), vec![123.0; 10].into());
}

#[test]
fn test_sample() {
let mut rng = thread_rng();

assert_eq!(Constant::zeros(1).sample(&mut rng), vec![0.0; 1].into());
assert_eq!(Constant::zeros(10).sample(&mut rng), vec![0.0; 10].into());
assert_eq!(Constant::zeros(100).sample(&mut rng), vec![0.0; 100].into());

assert_eq!(Constant::ones(1).sample(&mut rng), vec![1.0; 1].into());
assert_eq!(Constant::ones(10).sample(&mut rng), vec![1.0; 10].into());
assert_eq!(Constant::ones(100).sample(&mut rng), vec![1.0; 100].into());

assert_eq!(Constant::new(10, -1.5).sample(&mut rng), vec![-1.5; 10].into());
assert_eq!(Constant::new(10, 5.6).sample(&mut rng), vec![5.6; 10].into());
assert_eq!(Constant::new(10, 123.0).sample(&mut rng), vec![123.0; 10].into());
}
}
20 changes: 5 additions & 15 deletions src/projectors/fixed/fourier.rs → src/basis/fixed/fourier.rs
@@ -1,6 +1,5 @@
use geometry::{BoundedSpace, Card, product::RegularSpace, Space, continuous::Interval};
use projectors::{Projection, Projector};
use rand::{Rng, distributions::{Distribution, Range}};
use core::{Projector, Projection};
use geometry::{BoundedSpace, Card, product::LinearSpace, Space, continuous::Interval};
use std::{
f64::consts::PI,
iter,
Expand Down Expand Up @@ -32,7 +31,7 @@ impl Fourier {
}
}

pub fn from_space(order: u8, input_space: RegularSpace<Interval>) -> Self {
pub fn from_space(order: u8, input_space: LinearSpace<Interval>) -> Self {
Fourier::new(
order,
input_space.iter().map(|d| (d.inf().unwrap(), d.sup().unwrap())).collect(),
Expand All @@ -54,15 +53,6 @@ impl Fourier {
impl Space for Fourier {
type Value = Projection;

fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Projection {
let random_input: Vec<f64> = self.limits
.iter()
.map(|&(ll, ul)| Range::new(ll, ul).sample(rng))
.collect();

self.project(&random_input)
}

fn dim(&self) -> usize {
self.coefficients.len() + 1
}
Expand All @@ -81,8 +71,8 @@ impl Projector<[f64]> for Fourier {
.collect::<Vec<f64>>();

Projection::Dense(self.coefficients
.iter().enumerate()
.map(|(i, cfs)| {
.iter()
.map(|cfs| {
let cx = scaled_state
.iter()
.zip(cfs)
Expand Down

0 comments on commit 560832a

Please sign in to comment.