Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev v0.3.0 #47

Merged
merged 16 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ updates:
directory: /macros
schedule:
interval: daily
- package-ecosystem: cargo
directory: /tensor
schedule:
interval: daily
30 changes: 26 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,17 @@ on:

jobs:
build:
name: Build and Test
name: Build
strategy:
matrix:
platform: [ ubuntu-latest ]
toolchain: [ stable, nightly ]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: setup (langspace)
run: |
rustup update
rustup default ${{ matrix.toolchain }}
rustup default nightly
- name: Build
id: rust-build
run: cargo build -F full -r -v --workspace
Expand All @@ -46,8 +45,31 @@ jobs:
~/.cargo/git
target/release
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
test:
name: Test
strategy:
matrix:
platform: [ ubuntu-latest ]
toolchain: [ nightly ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: setup (langspace)
run: |
rustup update
rustup default ${{ matrix.toolchain }}
- name: Test
id: rust-test
run: cargo test --all -F full -r -v
bench:
name: Bench
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: setup (langspace)
run: |
rustup update
rustup default nightly
- name: Bench
if: matrix.toolchain == 'nightly'
id: rust-bench
run: cargo bench --all -F full -r -v
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ version = "0.3.0" # TODO - Update cargo package version
default-members = [
"acme"
]
exclude = [ "xtask" ]
exclude = [ ]
members = [
"acme",
"core",
"derive",
"macros"
, "tensor"]
"macros",
"tensor"
]
resolver = "2"

[workspace.dependencies]
Expand Down
17 changes: 13 additions & 4 deletions acme/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ readme.workspace = true
repository.workspace = true
version.workspace = true

[[example]]
name = "autodiff"
required-features = ["macros"]

[[test]]
name = "autodiff"
required-features = ["macros"]

[features]
default = ["core", "tensor"]
Expand All @@ -24,19 +30,20 @@ full = [
]

core = [
"acme-core"
"dep:acme-core"
]

derive = [
"acme-derive"
"dep:acme-derive",
"macros"
]

macros = [
"acme-macros"
"dep:acme-macros"
]

tensor = [
"acme-tensor"
"dep:acme-tensor"
]

[lib]
Expand All @@ -54,6 +61,8 @@ acme-macros = { features = [], optional = true, path = "../macros", version = "0
acme-tensor = { features = [], optional = true, path = "../tensor", version = "0.3.0" }

[dev-dependencies]
approx = "0.5"
num = "0.4"

[package.metadata.docs.rs]
all-features = true
Expand Down
33 changes: 33 additions & 0 deletions acme/examples/autodiff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Appellation: autodiff <example>
Contrib: FL03 <jo3mccain@icloud.com>
*/
#![feature(fn_traits)]
extern crate acme;

use acme::{autodiff, show_item};
use acme::prelude::sigmoid;

macro_rules! eval {
($var:ident: $ex:expr) => {
println!("Eval: {:?}", $ex);
println!("Gradient: {:?}", autodiff!($var: $ex));
}
}

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let x: f64 = 2.0;

eval!(x: x.tan());

eval!(x: x.sin());

eval!(x: x.cos().sin());
// show_item!(sigmoid::<f64>);
unsafe {
println!("{:?}", sigmoid::<f64>.call((2_f64,)));
}


Ok(())
}
16 changes: 8 additions & 8 deletions acme/examples/cgraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
*/
extern crate acme;

use acme::prelude::{Graph, Result};
use acme::prelude::{Result, Scg};

fn main() -> Result<()> {
let mut dcg = Graph::new();
let x = dcg.variable(1.0);
let y = dcg.variable(2.0);
let mut scg = Scg::new();
let x = scg.variable(1.0);
let y = scg.variable(2.0);

let z = dcg.add(x, y)?;
let w = dcg.mul(z, y)?;
let z = scg.add(x, y)?;
let w = scg.mul(z, y)?;

let eval = dcg.get_value(w).unwrap();
let eval = scg.get_value(w).unwrap();
println!("{:?}", *eval);

let grad = dcg.backward();
let grad = scg.backward();
println!("{:?}", grad);

Ok(())
Expand Down
1 change: 0 additions & 1 deletion acme/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//! Acme is an autodifferentiaion library for Rust. It is designed to be a
//! flexible and powerful tool for building machine learning models and
//! other differentiable programs.

#[cfg(feature = "core")]
pub use acme_core as core;
#[cfg(feature = "derive")]
Expand Down
185 changes: 185 additions & 0 deletions acme/tests/autodiff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
Appellation: gradient <test>
Contrib: FL03 <jo3mccain@icloud.com>
*/
#![allow(unused_variables)]

#[cfg(test)]
extern crate acme;

use acme::prelude::{autodiff, sigmoid};
use approx::assert_abs_diff_eq;
use num::traits::Float;
use std::ops::Add;

pub fn add<A, B, C>(a: A, b: B) -> C
where
A: std::ops::Add<B, Output = C>,
{
a + b
}

pub fn sigmoid_prime<T>(x: T) -> T
where
T: Float,
{
x.neg().exp() / (T::one() + x.neg().exp()).powi(2)
}

pub trait Sigmoid {
fn sigmoid(self) -> Self;
}

impl<T> Sigmoid for T
where
T: Float,
{
fn sigmoid(self) -> Self {
(T::one() + self.neg().exp()).recip()
}
}
trait Square {
fn square(self) -> Self;
}

impl<T> Square for T
where
T: Copy + std::ops::Mul<Output = T>,
{
fn square(self) -> Self {
self * self
}
}

#[test]
fn test_autodiff() {
let (x, y) = (1.0, 2.0);
// differentiating a function item w.r.t. a
assert_eq!(
autodiff!(a: fn addition(a: f64, b: f64) -> f64 { a + b }),
1.0
);
// differentiating a closure item w.r.t. x
assert_eq!(autodiff!(x: | x: f64, y: f64 | x * y ), 2.0);
// differentiating a function call w.r.t. x
assert_eq!(autodiff!(x: add(x, y)), 1.0);
// differentiating a function call w.r.t. some variable
assert_eq!(autodiff!(a: add(x, y)), 0.0);
// differentiating a method call w.r.t. the reciever (x)
assert_eq!(autodiff!(x: x.add(y)), 1.0);
// differentiating an expression w.r.t. x
assert_eq!(autodiff!(x: x + y), 1.0);
assert_eq!(autodiff!(y: x += y), 1.0);
}

#[test]
fn test_array() {
let x = [1.0, 2.0];
let y = [2.0, 2.0];
assert_eq!(autodiff!(x: x + y), 1.0);
}

#[test]
fn test_add() {
let x = [1.0];
let y = 2.0;
assert_eq!(autodiff!(x: x + y), 1.0);
assert_eq!(autodiff!(y: x += y), 1.0);
}

#[test]
fn test_div() {
let x = 1.0;
let y = 2.0;
assert_eq!(autodiff!(x: x / y), 1.0 / 2.0);
assert_eq!(autodiff!(y: x / y), -1.0 / 4.0);
assert_eq!(autodiff!(x: x /= y), 1.0 / 2.0);
assert_eq!(autodiff!(y: x /= y), -1.0 / 4.0);
}

#[test]
fn test_mul() {
let x = 1.0;
let y = 2.0;
assert_eq!(autodiff!(x: x * y), 2.0);
assert_eq!(autodiff!(y: x * y), 1.0);
assert_eq!(autodiff!(x: x *= y), 2.0);
assert_eq!(autodiff!(y: x *= y), 1.0);
assert_eq!(autodiff!(y: x * y + 3.0), 1.0);
}

#[test]
fn test_sub() {
let x = 1.0;
let y = 2.0;
assert_eq!(autodiff!(x: x - y), 1.0);
assert_eq!(autodiff!(y: x - y), -1.0);
assert_eq!(autodiff!(x: x -= y), 1.0);
assert_eq!(autodiff!(y: x -= y), -1.0);
}

#[test]
fn test_foil() {
let (x, y) = (1_f64, 2_f64);

assert_eq!(autodiff!(x: (x + y) * (x + y)), 2_f64 * (x + y));
assert_eq!(autodiff!(x: (x + y) * (x + y)), autodiff!(y: (x + y) * (x + y)));
}

#[test]
fn test_chain_rule() {
let (x, y) = (1_f64, 2_f64);

assert_eq!(autodiff!(x: y * (x + y)), 2.0);
assert_eq!(autodiff!(y: y * (x + y)), 5.0);
assert_eq!(autodiff!(x: (x + y) * y), 2.0);
assert_eq!(autodiff!(y: (x + y) * y), 5.0);
}

#[test]
fn test_trig() {
let x: f64 = 2.0;
assert_eq!(autodiff!(x: x.cos()), -x.sin());
assert_eq!(autodiff!(x: x.sin()), x.cos());
assert_eq!(autodiff!(x: x.tan()), x.cos().square().recip());
}

#[test]
fn test_log() {
let x: f64 = 2.0;

assert_eq!(autodiff!(x: x.ln()), 2_f64.recip());
assert_eq!(autodiff!(x: (x + 1.0).ln()), 3_f64.recip());
}

#[test]
fn test_chained() {
let x: f64 = 2.0;
assert_abs_diff_eq!(autodiff!(x: x.sin() * x.cos()), 2_f64 * x.cos().square() - 1_f64, epsilon = 1e-8);
assert_eq!(autodiff!(x: x.sin().cos()), -x.cos() * x.sin().sin());
assert_eq!(autodiff!(x: x.ln().ln()), (x * x.ln()).recip());
}

#[test]
fn test_sigmoid() {
let x = 2_f64;
assert_eq!(autodiff!(x: 1.0 / (1.0 + (-x).exp())), sigmoid_prime(x));
assert_eq!(autodiff!(x: | x: f64 | 1.0 / (1.0 + (-x).exp())), sigmoid_prime(x));
assert_eq!(autodiff!(x: fn sigmoid(x: f64) -> f64 { 1_f64 / (1_f64 + (-x).exp()) }), sigmoid_prime(x));
}

// #[ignore = "Currently, support for function calls is not fully implemented"]
#[test]
fn test_function_call() {
let x = 2_f64;
assert_eq!(autodiff!(x: sigmoid::<f64>(x)), sigmoid_prime(x));
}

#[ignore = "Custom trait methods are not yet supported"]
#[test]
fn test_method() {
let (x, y) = (1_f64, 2_f64);
assert_eq!(autodiff!(x: x.mul(y)), 2.0);

assert_eq!(autodiff!(x: x.sigmoid()), sigmoid_prime(x));
}
3 changes: 2 additions & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ test = true

[dependencies]
anyhow.workspace = true
daggy = { features = ["serde-1"], version = "0.8" }
# daggy = { features = ["serde-1"], version = "0.8" }
lazy_static = "1"
num = "0.4"
petgraph = { features = ["serde-1"], version = "0.6" }
serde.workspace = true
serde_json.workspace = true
strum.workspace = true
Expand Down
Loading