From 4f50a5325d4e6954f1a01f78baa2ed592ca75534 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:23:30 +0200 Subject: [PATCH 01/16] Linalg solver --- src/lib.cairo | 177 +++++++++++++++++++++++++++++++++++++ src/operators/matrix.cairo | 128 ++++++++++++++++++++++++++- 2 files changed, 304 insertions(+), 1 deletion(-) diff --git a/src/lib.cairo b/src/lib.cairo index 2a8a99208..957490268 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -2,3 +2,180 @@ mod operators; mod numbers; mod utils; mod test_helper; + +use core::debug::PrintTrait; +use core::array::ArrayTrait; +use core::option::OptionTrait; +use orion::numbers::NumberTrait; +use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; +use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; + +fn test_matrix(ref X: MutMatrix) { + // Print X by columns + let mut c = 0; + loop { + if c == X.cols { + break (); + } + let mut r = 0; + loop { + if r == X.rows { + break; + } + let mut val = X.get(r, c).unwrap(); + val.print(); + r += 1; + }; + c += 1; + }; + } + +fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { + + let n = X.rows; + let mut row: u32 = 0; + let mut col: u32 = 0; + let mut i = 0; + + loop { + if row == n { + break; + } + + // Find the row number and max row number for X + i = row + 1; + let mut max_row = row; + loop { + if i == n { + break; + } + if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { + max_row = i; + } + i += 1; + }; + + let mut X_row = MutMatrixImpl::new(1, X.cols); + let mut X_max_row = MutMatrixImpl::new(1, X.cols); + let mut y_row = y.get(row, 0).unwrap(); + let mut y_max_row = y.get(max_row, 0).unwrap(); + + // Store X_row and X_max_row + i = 0; + loop { + if i == n { + break; + } + + X_row.set(0, i, X.get(row, i).unwrap()); + X_max_row.set(0, i, X.get(max_row, i).unwrap()); + + i += 1; + }; + + // Interchange X_row with X_max_row, y_row with y_max_row + i = 0; + loop { + if i == n { + break; + } + + X.set(row, i, X_max_row.get(0, i).unwrap()); + X.set(max_row, i, X_row.get(0, i).unwrap()); + + i += 1; + }; + y.set(max_row, 0, y_row); + y.set(row, 0, y_max_row); + + // Perform forward elimination + i = row + 1; + loop { + if i == n { + break; + } + let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); + let mut j = row; + loop { + if j == n { + break; + } + let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); + X.set(i, j, X_new_val); + + j += 1; + }; + let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); + y.set(i, 0, y_new_val); + + i += 1; + }; + + row += 1; + }; + + // Perform back substitution + let mut S = MutMatrixImpl::new(X.rows, 1); + i = 0; + loop { + if i == n { + break; + } + S.set(i, 1, FP16x16 { mag: 0, sign: false }); + i += 1; + }; + + i = n; + loop { + if i == 0 { + break; + } + let mut X_i = y.get(i - 1, 0).unwrap(); + let mut j = i; + loop { + if j == n { + break; + } + X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); + + j += 1; + }; + X_i /= X.get(i - 1, i - 1).unwrap(); + S.set(i - 1, 0, X_i); + + i -= 1; + }; + + return S; + } + +fn main(){ + + // Test linalg solver + let mut X_data = VecTrait::::new(); + X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 + X_data.push(FP16x16 { mag: 196608, sign: true }); // -3 + X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 + X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 + X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 + + let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; + + let mut y_data = VecTrait::::new(); + y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 + y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 + y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 + + let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; + + let mut S = linalg_solve(ref X, ref y); + test_matrix(ref S); + + // Solution is [2, 3, -1] in FP16x16 format! + + } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 0d19a7a4d..60a1d6433 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -1,8 +1,8 @@ use core::array::ArrayTrait; use core::option::OptionTrait; - use orion::numbers::NumberTrait; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16}; struct MutMatrix { data: NullableVec, @@ -340,4 +340,130 @@ impl MutMatrixImpl< result } + + // fn linalg_solve<+Mul, +Add, +Sub, +Div>( + // ref X: MutMatrix, ref y: MutMatrix + // ) -> MutMatrix { + + // let n = X.rows; + // let mut row: u32 = 0; + // let mut col: u32 = 0; + // let mut i = 0; + + + // // Forward elimination + // loop { + // if row == n { + // break; + // } + + // let mut max_row = row; + // i = row + 1; + + // loop { + // if i == n { + // break; + // } + + // if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { + // max_row = i; + // } + + // i += 1; + // }; + + // // Get the row max row and set that to the current row + // let mut X_row = MutMatrixImpl::new(1, X.cols); + // let mut X_max_row = MutMatrixImpl::new(1, X.cols); + // let mut y_row = y.get(row, 1).unwrap(); + // let mut y_max_row = y.get(max_row, 1).unwrap(); + + // i = 0; + // loop { + // if i == n { + // break; + // } + + // X_row.set(1, i, X.get(row, i).unwrap()); + // X_max_row.set(1, i, X.get(max_row, i).unwrap()); + + // i += 1; + // }; + + // i = 0; + // loop { + // if i == n { + // break; + // } + + // X.set(row, i, X_max_row.get(1, i).unwrap()); + // X.set(max_row, i, X_row.get(1, i).unwrap()); + + // i += 1; + // }; + + // y.set(max_row, 1, y_row); + // y.set(row, 1, y_max_row); + + // i = row + 1; + // loop { + // if i == n { + // break; + // } + // let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); + // let mut j = row; + // loop { + // if j == n { + // break; + // } + // let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); + // X.set(i, j, X_new_val); + + // j += 1; + // }; + // let mut y_new_val = y.get(i, 1).unwrap(); + // y.set(i, 1, y_new_val); + + // i += 1; + // }; + + // row += 1; + // }; + + // // Back Substitution + // let mut S = MutMatrixImpl::new(X.rows, 1); + // i = 0; + // loop { + // if i == n { + // break; + // } + // S.set(i, 1, FP16x16 { mag: 0, sign: true }); + // i += 1; + // }; + + // i = n; + // loop { + // if i == 0 { + // break; + // } + // let mut X_i = y.get(i - 1, 1).unwrap(); + // let mut j = i; + // loop { + // if j == n { + // break; + // } + // X_i -= X.get(i - 1, j).unwrap() * S.get(j, 1).unwrap(); + + // j += 1; + // }; + // X_i /= X.get(i - 1, i - 1).unwrap(); + // S.set(i - 1, 1, X_i); + + // i -= 1; + // }; + + // return S; + // } + + } From 6bee41917813a8d7b1c5d41d773b048039fc08a8 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Mon, 29 Jan 2024 19:11:04 +0200 Subject: [PATCH 02/16] linalg solver --- src/lib.cairo | 8 +- src/operators/matrix.cairo | 224 +++++++++++++++--------------- tests/operators/linalg_test.cairo | 67 +++++++++ 3 files changed, 184 insertions(+), 115 deletions(-) create mode 100644 tests/operators/linalg_test.cairo diff --git a/src/lib.cairo b/src/lib.cairo index 957490268..d7d934a30 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -7,6 +7,7 @@ use core::debug::PrintTrait; use core::array::ArrayTrait; use core::option::OptionTrait; use orion::numbers::NumberTrait; +use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; @@ -89,6 +90,9 @@ fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatr y.set(max_row, 0, y_row); y.set(row, 0, y_max_row); + // Check for singularity + assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); + // Perform forward elimination i = row + 1; loop { @@ -174,8 +178,8 @@ fn main(){ let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; let mut S = linalg_solve(ref X, ref y); - test_matrix(ref S); + // test_matrix(ref S); // Solution is [2, 3, -1] in FP16x16 format! - + } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 60a1d6433..cb697d938 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -2,7 +2,7 @@ use core::array::ArrayTrait; use core::option::OptionTrait; use orion::numbers::NumberTrait; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; -use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; struct MutMatrix { data: NullableVec, @@ -341,129 +341,127 @@ impl MutMatrixImpl< result } - // fn linalg_solve<+Mul, +Add, +Sub, +Div>( - // ref X: MutMatrix, ref y: MutMatrix - // ) -> MutMatrix { + fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { - // let n = X.rows; - // let mut row: u32 = 0; - // let mut col: u32 = 0; - // let mut i = 0; + let n = X.rows; + let mut row: u32 = 0; + let mut col: u32 = 0; + let mut i = 0; - - // // Forward elimination - // loop { - // if row == n { - // break; - // } - - // let mut max_row = row; - // i = row + 1; - - // loop { - // if i == n { - // break; - // } - - // if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { - // max_row = i; - // } - - // i += 1; - // }; - - // // Get the row max row and set that to the current row - // let mut X_row = MutMatrixImpl::new(1, X.cols); - // let mut X_max_row = MutMatrixImpl::new(1, X.cols); - // let mut y_row = y.get(row, 1).unwrap(); - // let mut y_max_row = y.get(max_row, 1).unwrap(); + loop { + if row == n { + break; + } - // i = 0; - // loop { - // if i == n { - // break; - // } - - // X_row.set(1, i, X.get(row, i).unwrap()); - // X_max_row.set(1, i, X.get(max_row, i).unwrap()); + // Find the row number and max row number for X + i = row + 1; + let mut max_row = row; + loop { + if i == n { + break; + } + if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { + max_row = i; + } + i += 1; + }; - // i += 1; - // }; + let mut X_row = MutMatrixImpl::new(1, X.cols); + let mut X_max_row = MutMatrixImpl::new(1, X.cols); + let mut y_row = y.get(row, 0).unwrap(); + let mut y_max_row = y.get(max_row, 0).unwrap(); - // i = 0; - // loop { - // if i == n { - // break; - // } + // Store X_row and X_max_row + i = 0; + loop { + if i == n { + break; + } + + X_row.set(0, i, X.get(row, i).unwrap()); + X_max_row.set(0, i, X.get(max_row, i).unwrap()); + + i += 1; + }; + + // Interchange X_row with X_max_row, y_row with y_max_row + i = 0; + loop { + if i == n { + break; + } - // X.set(row, i, X_max_row.get(1, i).unwrap()); - // X.set(max_row, i, X_row.get(1, i).unwrap()); + X.set(row, i, X_max_row.get(0, i).unwrap()); + X.set(max_row, i, X_row.get(0, i).unwrap()); - // i += 1; - // }; - - // y.set(max_row, 1, y_row); - // y.set(row, 1, y_max_row); - - // i = row + 1; - // loop { - // if i == n { - // break; - // } - // let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); - // let mut j = row; - // loop { - // if j == n { - // break; - // } - // let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); - // X.set(i, j, X_new_val); - - // j += 1; - // }; - // let mut y_new_val = y.get(i, 1).unwrap(); - // y.set(i, 1, y_new_val); - - // i += 1; - // }; + i += 1; + }; + y.set(max_row, 0, y_row); + y.set(row, 0, y_max_row); + + // Check for singularity + assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); + + // Perform forward elimination + i = row + 1; + loop { + if i == n { + break; + } + let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); + let mut j = row; + loop { + if j == n { + break; + } + let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); + X.set(i, j, X_new_val); + + j += 1; + }; + let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); + y.set(i, 0, y_new_val); + + i += 1; + }; - // row += 1; - // }; - - // // Back Substitution - // let mut S = MutMatrixImpl::new(X.rows, 1); - // i = 0; - // loop { - // if i == n { - // break; - // } - // S.set(i, 1, FP16x16 { mag: 0, sign: true }); - // i += 1; - // }; - - // i = n; - // loop { - // if i == 0 { - // break; - // } - // let mut X_i = y.get(i - 1, 1).unwrap(); - // let mut j = i; - // loop { - // if j == n { - // break; - // } - // X_i -= X.get(i - 1, j).unwrap() * S.get(j, 1).unwrap(); + row += 1; + }; + + // Perform back substitution + let mut S = MutMatrixImpl::new(X.rows, 1); + i = 0; + loop { + if i == n { + break; + } + S.set(i, 1, FP16x16 { mag: 0, sign: false }); + i += 1; + }; + + i = n; + loop { + if i == 0 { + break; + } + let mut X_i = y.get(i - 1, 0).unwrap(); + let mut j = i; + loop { + if j == n { + break; + } + X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); - // j += 1; - // }; - // X_i /= X.get(i - 1, i - 1).unwrap(); - // S.set(i - 1, 1, X_i); + j += 1; + }; + X_i /= X.get(i - 1, i - 1).unwrap(); + S.set(i - 1, 0, X_i); - // i -= 1; - // }; + i -= 1; + }; - // return S; - // } + return S; + } } diff --git a/tests/operators/linalg_test.cairo b/tests/operators/linalg_test.cairo new file mode 100644 index 000000000..7261d3c9d --- /dev/null +++ b/tests/operators/linalg_test.cairo @@ -0,0 +1,67 @@ +use core::array::{ArrayTrait, SpanTrait}; +use core::debug::PrintTrait; +use core::option::OptionTrait; +use orion::numbers::NumberTrait; +use orion::numbers::fixed_point::implementations::fp16x16::math::core::{abs}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; +use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; +use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; + +fn test_matrix(ref X: MutMatrix) { + // Print X by columns + let mut c = 0; + loop { + if c == X.cols { + break (); + } + let mut r = 0; + loop { + if r == X.rows { + break; + } + let mut val = X.get(r, c).unwrap(); + val.print(); + r += 1; + }; + c += 1; + }; + } + +#[test] +#[available_gas(99999999999999999)] +fn linalg_test() { + let mut X = MutMatrixTrait::::new(rows: 3, cols: 3); + X.set(0, 0, FP16x16 { mag: 131072, sign: false }); // 2 + X.set(0, 1, FP16x16 { mag: 65536, sign: false }); // 1 + X.set(0, 2, FP16x16 { mag: 65536, sign: true }); // -1 + X.set(1, 0, FP16x16 { mag: 196608, sign: true }); // -3 + X.set(1, 1, FP16x16 { mag: 65536, sign: true }); // -1 + X.set(1, 2, FP16x16 { mag: 131072, sign: false }); // 2 + X.set(2, 0, FP16x16 { mag: 131072, sign: true }); // -2 + X.set(2, 1, FP16x16 { mag: 65536, sign: false }); // 1 + X.set(2, 2, FP16x16 { mag: 131072, sign: false }); // 1 + + let mut y = MutMatrixTrait::::new(rows: 3, cols: 1); + y.set(0, 0, FP16x16 { mag: 524288, sign: false }); // 8 + y.set(0, 1, FP16x16 { mag: 720896, sign: true }); // -11 + y.set(0, 2, FP16x16 { mag: 196608, sign: true }); // -3 + + let mut S = linalg_solve(ref X, ref y); + // S = [2, 3, -1] + + assert(S.rows == X.rows, 'Wrong num of rows'); + assert(S.cols == 1, 'Wrong num of cols'); + + // Check mags + let threshold = FP16x16 {mag: 100, sign: false}; // ~0.00153 error threshold + assert(abs(S.get(0, 0).unwrap() - FP16x16 {mag: 131072, sign: false}) <= threshold , 'S_0 mag is wrong'); + assert(abs(S.get(1, 0).unwrap() - FP16x16 {mag: 196608, sign: false}) <= threshold, 'S_1 mag is wrong'); + assert(abs(S.get(2, 0).unwrap() - FP16x16 {mag: 65536, sign: true}) <= threshold, 'S_2 mag is wrong'); + + // Check signs + assert(S.get(0, 0).unwrap().sign == false, 'S_1 sign is wrong'); + assert(S.get(1, 0).unwrap().sign == false, 'S_2 sign is wrong'); + assert(S.get(2, 0).unwrap().sign == true, 'S_3 sign is wrong'); + +} \ No newline at end of file From 47abc02fa90cf67379016982d2d7fe474d208182 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:51:10 +0200 Subject: [PATCH 03/16] mean function --- src/lib.cairo | 182 +++++++++++++++++++++++++++++++++++-- src/operators/matrix.cairo | 21 +++++ 2 files changed, 197 insertions(+), 6 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index d7d934a30..1ba14b795 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -10,7 +10,7 @@ use orion::numbers::NumberTrait; use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; -use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; fn test_matrix(ref X: MutMatrix) { // Print X by columns @@ -154,9 +154,143 @@ fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatr return S; } +// fn weights(lambda_unscaled: u32, l: u32) -> MutMatrix { +// let mut lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); +// let mut weights = MutMatrixImpl::new(l, 1); +// let mut i: u32 = 0; +// loop { +// if i == l { +// break (); +// } +// let mut i_fp = FixedTrait::::new_unscaled(i, false); +// let mut x = (FixedTrait::::new_unscaled(1, false) - lambda) * (lambda.pow(i_fp)); +// weights.set(i, 0, x); +// i += 1; +// }; + +// return weights; +// } + +fn mean(ref X: MutMatrix, weights: Option>, axis: Option) -> MutMatrix { + let mut i = 0; + + // Assume by default that the weights are a column vector + match weights { + Option::None => { + let mut weights = MutMatrixImpl:new() + }, + Option::Some(x) => { + assert(weights.rows == X.rows & weights.cols == 1, 'Wrong shape weights'); + }, + } + + // Vector average + match axis { + Option::None => { + assert(X.rows == 1 || X.cols == 1, 'Wrong shape'); + + if X.cols == 1 & X.rows != 1 { + let mut X = X.transpose(); + } + + let mut result = MutMatrixImpl::new(1, 1); + let mut num = FixedTrait::new_unscaled(0, false); + let l = FixedTrait::new_unscaled(mag: X.data.len(), sign: false); + loop { + if i == X.rows { + break; + } + if weights == Option::None { + num += X.get(i, 0); + } + else { + num += X.get(i, 0) * Option::Some(weights).get(i, 0); + } + i += 1; + }; + result.set(0, 0, num / l); + }, + + // Matrix average along specified axis + Option::Some(x) => { + assert(axis == 0 || axis == 1, 'Wrong axis'); + + // Average along rows + if axis == 0 { + let mut result = MutMatrixImpl::new(X.rows, 1); + let l = FixedTrait::new_unscaled(mag: X.data.len() / X.rows, sign: false); + loop { + if i == X.rows { + break; + } + let mut num = FixedTrait::new_unscaled(0, false); + let mut j = 0; + loop { + if j == X.cols { + break; + } + + if weights == Option::None { + num += X.get(i, j); + } + else { + // Assert weights are a row vector + num += X.get(i, j) * Option::Some(weights).get(j, 0); // Need to assert shape correctly + } + + j += 1; + }; + result.set(i, 0, num / l); + + i += 1; + }; + } + + // Average along columns + else { + let mut result = MutMatrixImpl::new(1, X.cols); + let l = FixedTrait::new_unscaled(mag: X.data.len() / X.cols, sign: false); + loop { + if i == X.cols { + break; + } + let mut num = FixedTrait::new_unscaled(0, false); + let mut j = 0; + loop { + if j == X.rows { + break; + } + + if weights == Option::None { + num += X.get(j, i); + } + else { + num += X.get(j, i) * Option::Some(weights).get(j, 0); + } + + j += 1; + }; + result.set(0, i, num / l); + + i += 1; + }; + } + }, + } + + return result; +} + +// fn cov(X: MutMatrix, weights: MutMatrix) -> MutMatrix { +// 0 +// } + +// fn diag(X: MutMatrix) -> MutMatrix { +// 0 +// } + fn main(){ - // Test linalg solver let mut X_data = VecTrait::::new(); X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 @@ -167,19 +301,55 @@ fn main(){ X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 - let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; let mut y_data = VecTrait::::new(); y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; - let mut S = linalg_solve(ref X, ref y); + // Linalg test + // let mut S = linalg_solve(ref X, ref y); // test_matrix(ref S); - // Solution is [2, 3, -1] in FP16x16 format! + + // Exp weights test + let mut weights_data = VecTrait::::new(); + weights_data.push(FP16x16 { mag: 22453, sign: false }); // ~0.34 + weights_data.push(FP16x16 { mag: 16731, sign: false }); // ~0.26 + weights_data.push(FP16x16 { mag: 26352, sign: false }); // ~0.40 + let mut W = MutMatrix { data: weights_data, rows: 3, cols: 1}; + let mut W_bad = MutMatrix { data: weights_data, rows: 1, cols: 3}; + + let mut Y_data = VecTrait::::new(); + Y_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + Y_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + Y_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + let mut Y = MutMatrix { data: Y_data, rows: 3, cols: 1}; + + // Mean test (1D) + let Y_simple_avg = mean(ref Y, (), ()); // Should return 3_fp16x16 + // let Y_weighted_avg = mean(ref Y, weights=Option(W)); + // let Y_weighted_avg_bad = mean(ref Y, weights=Option(W_bad)); // should error out + // 'Y smpl avg:'.print(); + // test_matrix(ref Y_simple_avg); + // 'Y wtd avg:'.print(); + // test_matrix(ref Y_weighted_avg); + + // // Mean test (2D) + // let Y_simple_avg_axis_0 = mean(ref X, axis=Option(0)); + // let Y_weighted_avg_axis_0 = mean(ref X, weights=Option(W), axis=Option(0)); + // let Y_simple_avg_axis_1 = mean(ref X, axis=Option(1)); + // let Y_weighted_avg_axis_1 = mean(ref X, weights=Option(W), axis=Option(1)); + // 'Y smpl avg ax=0:'.print(); + // test_matrix(ref Y_simple_avg_axis_0); + // 'Y wtd avg ax=0:'.print(); + // test_matrix(ref Y_weighted_avg_axis_0); + // 'Y smpl avg ax=1:'.print(); + // test_matrix(ref Y_simple_avg_axis_1); + // 'Y wtd avg ax=1:'.print(); + // test_matrix(ref Y_weighted_avg_axis_1); + } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index cb697d938..9131a7b04 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -47,6 +47,27 @@ impl MutMatrixImpl< (self.rows, self.cols) } + /// Transposes the matrix + fn transpose(ref self: MutMatrix) -> MutMatrix { + let mut result = MutMatrixImpl::new(rows: self.cols, cols: self.rows); + let mut row = 0; + loop { + if row == self.rows { + break; + } + let mut col = 0; + loop { + if col == self.cols { + break; + } + result.set(row, col, self.get(col, row)); + col += 1; + }; + row += 1; + }; + return result; + } + /// Returns the index of the maximum value along the specified axis fn argmax(ref self: MutMatrix, axis: usize) -> Span { assert(axis < 2, 'Invalid axis'); From 202dcfb19a38d3fc618c30431f63778d5c6ebcec Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Mon, 19 Feb 2024 07:33:30 +0200 Subject: [PATCH 04/16] updates --- src/lib.cairo | 83 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index 1ba14b795..e5cae3945 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -182,7 +182,7 @@ fn mean(ref X: MutMatrix, weights: Option>, axis: Op Option::Some(x) => { assert(weights.rows == X.rows & weights.cols == 1, 'Wrong shape weights'); }, - } + }; // Vector average match axis { @@ -281,9 +281,84 @@ fn mean(ref X: MutMatrix, weights: Option>, axis: Op return result; } -// fn cov(X: MutMatrix, weights: MutMatrix) -> MutMatrix { -// 0 -// } + fn covariance(X: MutMatrix, weights: MutMatrix) -> MutMatrix { + // Assert weights are a row vector + assert(weights.rows == X.rows && weights.cols == 1, 'Wrong weights shape'); + + // Get shape of array + let m = X.rows; // num rows + let n = X.cols; // num columns + let l = weights.rows; // length of weight vector + assert(m == l, 'Data/weight length mismatch'); + + // Transform weights vector into (l,l) diagonal matrix + let mut W = diagonalize(weights); // TODO - write this function + + // Take dot product of W and X and center it + // X_weighted = np.dot(W, X), shape = (m,n) + let mut X_weighted = W.matmul(@X); // TODO - write this function + + // mean_weighted = (np.dot(weights, X) / np.sum(weights)), shape = (n,1) + let mut X_mean = mean(X, W). + + // let mut weights_T = weights.reshape(target_shape: array![1, *weights.shape.at(0)].span()); // TODO: write this function + // let mut weights_dot_X = weights_T.matmul(@X); + // let mut weights_sum = *weights.reduce_sum(0, false).data.at(0); + // let mut mean_weighted_shape = ArrayTrait::::new(); + // mean_weighted_shape.append(*weights_dot_X.shape.at(1)); + // let mut mean_weighted_data = ArrayTrait::::new(); + // let mut i: u32 = 0; + // loop { + // if i == *weights_dot_X.shape.at(1) { + // break (); + // } + // mean_weighted_data.append(*weights_dot_X.data.at(i) / weights_sum); + // i += 1; + // }; + + // let mean_weighted = TensorTrait::::new(mean_weighted_shape.span(), mean_weighted_data.span(), Option::Some(extra)); + + // X_centered = X_weighted - mean_weighted, shape = (n,n) + let mut X_centered_shape = ArrayTrait::::new(); + X_centered_shape.append(n); + X_centered_shape.append(n); + let mut X_centered_data = ArrayTrait::::new(); + let mut row: u32 = 0; + loop { + if row == n { + break (); + } + let mut row_i: u32 = 0; + loop { + if row_i == n { + break (); + } + X_centered_data.append(*X_weighted.data.at(row_i) - *mean_weighted.data.at(row)); + row_i += 1; + }; + row += 1; + }; + let X_centered = TensorTrait::::new(X_centered_shape.span(), X_centered_data.span(), Option::Some(extra)); + + // Calculate covariance matrix + // covariance_matrix = centered_data.T.dot(centered_data) / (np.sum(weights) - 1) + let mut X_centered_T = X_centered.transpose(axes: array![1, 0].span()); + let mut Cov_X_num = X_centered_T.matmul(@X_centered); + let mut Cov_X_den = *weights.reduce_sum(0, false).data.at(0) - FixedTrait::new_unscaled(1, false); + let mut Cov_X_shape = Cov_X_num.shape; + let mut Cov_X_data = ArrayTrait::::new(); + i = 0; + loop { + if (i == *Cov_X_shape.at(0) * Cov_X_shape.len()) { + break (); + } + Cov_X_data.append(*Cov_X_num.data.at(i) / Cov_X_den); + i += 1; + }; + + let Cov_X = TensorTrait::::new(Cov_X_shape, Cov_X_data.span(), Option::Some(extra)); + return Cov_X; + } // fn diag(X: MutMatrix) -> MutMatrix { // 0 From 2c6bedaa1f0f8c8bc4882ab82fd49687e02ad630 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:23:07 +0200 Subject: [PATCH 05/16] Updates 2/20 --- src/lib.cairo | 529 ++++++++++++++++++++++--------------- src/operators/matrix.cairo | 91 ++++++- 2 files changed, 392 insertions(+), 228 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index e5cae3945..e814dbd1f 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -154,217 +154,281 @@ fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatr return S; } -// fn weights(lambda_unscaled: u32, l: u32) -> MutMatrix { -// let mut lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); -// let mut weights = MutMatrixImpl::new(l, 1); -// let mut i: u32 = 0; -// loop { -// if i == l { -// break (); -// } -// let mut i_fp = FixedTrait::::new_unscaled(i, false); -// let mut x = (FixedTrait::::new_unscaled(1, false) - lambda) * (lambda.pow(i_fp)); -// weights.set(i, 0, x); -// i += 1; -// }; - -// return weights; -// } - -fn mean(ref X: MutMatrix, weights: Option>, axis: Option) -> MutMatrix { +// fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { +// let mut lambda = FixedTrait::::new_unscaled(lambda_unscaled, false); +// lambda = lambda / FixedTrait::::new_unscaled(100, false); +// let mut weights = MutMatrixImpl::::new(l, 1); +// let mut i = 0; +// loop { +// if i == l { +// break (); +// } +// let mut l_i = FixedTrait::::new_unscaled(i, false); +// let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * (lambda.pow(@l_i)); +// weights.set(i, 0, w_i); +// i += 1; +// }; + +// return weights; +// } + +fn diagonalize(ref X: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols == 1, 'X not row vector'); + let mut i = 0; - - // Assume by default that the weights are a column vector - match weights { - Option::None => { - let mut weights = MutMatrixImpl:new() - }, - Option::Some(x) => { - assert(weights.rows == X.rows & weights.cols == 1, 'Wrong shape weights'); - }, + let mut result = MutMatrixImpl::::new(X.rows, X.rows); + loop { + if i == X.rows { + break; + } + let mut j = 0; + loop { + if j == X.rows { + break; + } + if i == j { + result.set(i, j, X.get(i, 0).unwrap()); + } + else { + result.set(i, j, FixedTrait::::new(0, false)); + } + j += 1; + }; + i += 1; }; + return result; +} + +fn mean(ref X: MutMatrix) -> MutMatrix { + // Simple average case for a vector + // Returns a matrix with shape (1,1) - // Vector average - match axis { - Option::None => { - assert(X.rows == 1 || X.cols == 1, 'Wrong shape'); + assert(X.cols == 1, 'Wrong shape'); - if X.cols == 1 & X.rows != 1 { - let mut X = X.transpose(); + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; + + let l = FixedTrait::::new_unscaled(X.data.len(), false); + + if X.rows == 1 { + result.set(0, 0, X.get(0, 0).unwrap()); + return result; + } + else { + loop { + if i == X.rows { + break; } + num += X.get(i, 0).unwrap(); + i += 1; + }; + result.set(0, 0, num / l); + return result; + } +} + +fn mean_matrix(ref X: MutMatrix, axis: u32) -> MutMatrix { + // Simple average case for a matrix along specified axis + // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 + + assert(axis == 0 || axis == 1, 'Wrong axis'); + + // Average along rows + if axis == 0 { + let mut result = MutMatrixImpl::::new(X.rows, 1); + let l = FixedTrait::::new_unscaled(X.cols, false); + let mut row = 0; - let mut result = MutMatrixImpl::new(1, 1); - let mut num = FixedTrait::new_unscaled(0, false); - let l = FixedTrait::new_unscaled(mag: X.data.len(), sign: false); + loop { + if row == X.rows { + break; + } + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; loop { - if i == X.rows { + if col == X.cols { break; } - if weights == Option::None { - num += X.get(i, 0); - } - else { - num += X.get(i, 0) * Option::Some(weights).get(i, 0); - } - i += 1; + row_num += X.get(row, col).unwrap(); + col += 1; }; - result.set(0, 0, num / l); - }, - - // Matrix average along specified axis - Option::Some(x) => { - assert(axis == 0 || axis == 1, 'Wrong axis'); - - // Average along rows - if axis == 0 { - let mut result = MutMatrixImpl::new(X.rows, 1); - let l = FixedTrait::new_unscaled(mag: X.data.len() / X.rows, sign: false); - loop { - if i == X.rows { - break; - } - let mut num = FixedTrait::new_unscaled(0, false); - let mut j = 0; - loop { - if j == X.cols { - break; - } - - if weights == Option::None { - num += X.get(i, j); - } - else { - // Assert weights are a row vector - num += X.get(i, j) * Option::Some(weights).get(j, 0); // Need to assert shape correctly - } - - j += 1; - }; - result.set(i, 0, num / l); - - i += 1; - }; - } + result.set(row, 0, row_num / l); + row += 1; + }; - // Average along columns - else { - let mut result = MutMatrixImpl::new(1, X.cols); - let l = FixedTrait::new_unscaled(mag: X.data.len() / X.cols, sign: false); - loop { - if i == X.cols { - break; - } - let mut num = FixedTrait::new_unscaled(0, false); - let mut j = 0; - loop { - if j == X.rows { - break; - } - - if weights == Option::None { - num += X.get(j, i); - } - else { - num += X.get(j, i) * Option::Some(weights).get(j, 0); - } - - j += 1; - }; - result.set(0, i, num / l); - - i += 1; - }; - } - }, + return result; } - return result; -} + // Average along columns + else { + let mut result = MutMatrixImpl::::new(1, X.cols); + let l = FixedTrait::::new_unscaled(X.rows, false); + let mut col = 0; - fn covariance(X: MutMatrix, weights: MutMatrix) -> MutMatrix { - // Assert weights are a row vector - assert(weights.rows == X.rows && weights.cols == 1, 'Wrong weights shape'); - - // Get shape of array - let m = X.rows; // num rows - let n = X.cols; // num columns - let l = weights.rows; // length of weight vector - assert(m == l, 'Data/weight length mismatch'); - - // Transform weights vector into (l,l) diagonal matrix - let mut W = diagonalize(weights); // TODO - write this function - - // Take dot product of W and X and center it - // X_weighted = np.dot(W, X), shape = (m,n) - let mut X_weighted = W.matmul(@X); // TODO - write this function - - // mean_weighted = (np.dot(weights, X) / np.sum(weights)), shape = (n,1) - let mut X_mean = mean(X, W). - - // let mut weights_T = weights.reshape(target_shape: array![1, *weights.shape.at(0)].span()); // TODO: write this function - // let mut weights_dot_X = weights_T.matmul(@X); - // let mut weights_sum = *weights.reduce_sum(0, false).data.at(0); - // let mut mean_weighted_shape = ArrayTrait::::new(); - // mean_weighted_shape.append(*weights_dot_X.shape.at(1)); - // let mut mean_weighted_data = ArrayTrait::::new(); - // let mut i: u32 = 0; - // loop { - // if i == *weights_dot_X.shape.at(1) { - // break (); - // } - // mean_weighted_data.append(*weights_dot_X.data.at(i) / weights_sum); - // i += 1; - // }; - - // let mean_weighted = TensorTrait::::new(mean_weighted_shape.span(), mean_weighted_data.span(), Option::Some(extra)); - - // X_centered = X_weighted - mean_weighted, shape = (n,n) - let mut X_centered_shape = ArrayTrait::::new(); - X_centered_shape.append(n); - X_centered_shape.append(n); - let mut X_centered_data = ArrayTrait::::new(); - let mut row: u32 = 0; loop { - if row == n { - break (); - } - let mut row_i: u32 = 0; + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; loop { - if row_i == n { - break (); + if row == X.rows { + break; } - X_centered_data.append(*X_weighted.data.at(row_i) - *mean_weighted.data.at(row)); - row_i += 1; + col_num += X.get(row, col).unwrap(); + row += 1; }; - row += 1; + result.set(0, col, col_num / l); + col += 1; }; - let X_centered = TensorTrait::::new(X_centered_shape.span(), X_centered_data.span(), Option::Some(extra)); - - // Calculate covariance matrix - // covariance_matrix = centered_data.T.dot(centered_data) / (np.sum(weights) - 1) - let mut X_centered_T = X_centered.transpose(axes: array![1, 0].span()); - let mut Cov_X_num = X_centered_T.matmul(@X_centered); - let mut Cov_X_den = *weights.reduce_sum(0, false).data.at(0) - FixedTrait::new_unscaled(1, false); - let mut Cov_X_shape = Cov_X_num.shape; - let mut Cov_X_data = ArrayTrait::::new(); - i = 0; + + return result; + } +} + +fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix { + // Weighted average + // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 + + // Weight assertions + assert(weights.rows == X.rows, 'Weights shape mismatch'); + assert(weights.cols == 1, 'Weights not row vector'); + + // Vector case + if X.rows == 1 || X.cols == 1 { + + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; + + let l = FixedTrait::::new_unscaled(X.data.len(), false); loop { - if (i == *Cov_X_shape.at(0) * Cov_X_shape.len()) { - break (); + if i == X.rows { + break; + } + if X.rows != 1 { + num += X.get(i, 0).unwrap() * weights.get(i, 0).unwrap(); + } + else { + result.set(0, 0, X.get(0, 0).unwrap()); + break; } - Cov_X_data.append(*Cov_X_num.data.at(i) / Cov_X_den); i += 1; }; + result.set(0, 0, num / l); - let Cov_X = TensorTrait::::new(Cov_X_shape, Cov_X_data.span(), Option::Some(extra)); - return Cov_X; + return result; } -// fn diag(X: MutMatrix) -> MutMatrix { -// 0 + // Matrix case + else { + assert(axis == 0 || axis == 1, 'Wrong axis'); + + // Average along rows + if axis == 0 { + + let mut result = MutMatrixImpl::::new(X.rows, 1); + let l = FixedTrait::::new_unscaled(X.cols, false); + let mut row = 0; + + loop { + if row == X.rows { + break; + } + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; + loop { + if col == X.cols { + break; + } + row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); + col += 1; + }; + result.set(row, 0, row_num / l); + row += 1; + }; + + return result; + } + + // Average along columns + else { + let mut result = MutMatrixImpl::::new(1, X.cols); + let l = FixedTrait::::new_unscaled(X.rows, false); + let mut col = 0; + + loop { + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; + loop { + if row == X.rows { + break; + } + col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); + row += 1; + }; + result.set(0, col, col_num / l); + col += 1; + }; + + return result; + } + } +} + +// fn covariance(X: MutMatrix, weights: MutMatrix) -> MutMatrix { +// // Weight assertions +// assert(weights.rows == X.rows, 'Weights shape mismatch'); +// assert(weights.cols == 1, 'Weights not row vector'); + +// // Get shape of array +// // let m = X.rows; // num rows +// // let n = X.cols; // num columns +// // let l = weights.rows; // length of weight vector + +// // Transform weights vector into (l,l) diagonal matrix +// let mut W = diagonalize(weights); + +// // Take dot product of W and X and center it +// // X_weighted = np.dot(W, X), shape = (m,n) +// // let mut X_weighted = W.matmul(@X); // TODO - write this function + +// // mean_weighted = (np.dot(weights, X) / np.sum(weights)), shape = (n,1) +// let mut X_mean = mean_weighted(X, W, 0) + +// // let mut weights_T = weights.reshape(target_shape: array![1, *weights.shape.at(0)].span()); // TODO: write this function +// // let mut weights_dot_X = weights_T.matmul(@X); +// // let mut weights_sum = *weights.reduce_sum(0, false).data.at(0); +// // let mut mean_weighted_shape = ArrayTrait::::new(); +// // mean_weighted_shape.append(*weights_dot_X.shape.at(1)); +// // let mut mean_weighted_data = ArrayTrait::::new(); +// // let mut i: u32 = 0; +// // loop { +// // if i == *weights_dot_X.shape.at(1) { +// // break (); +// // } +// // mean_weighted_data.append(*weights_dot_X.data.at(i) / weights_sum); +// // i += 1; +// // }; + +// // let mean_weighted = TensorTrait::::new(mean_weighted_shape.span(), mean_weighted_data.span(), Option::Some(extra)); + +// // X_centered = X_weighted - mean_weighted, shape = (n,n) + +// // Calculate covariance matrix +// // covariance_matrix = centered_data.T.dot(centered_data) / (np.sum(weights) - 1) + +// return Cov_X; // } -fn main(){ + + + +fn main() { let mut X_data = VecTrait::::new(); X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 @@ -389,42 +453,71 @@ fn main(){ // test_matrix(ref S); // Solution is [2, 3, -1] in FP16x16 format! - // Exp weights test - + let mut Y1_data = VecTrait::::new(); + Y1_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + Y1_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + Y1_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + let mut Y1 = MutMatrix { data: Y1_data, rows: 3, cols: 1}; + + let mut Y2_data = VecTrait::::new(); + Y2_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + Y2_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + Y2_data.push(FP16x16 { mag: 196608, sign: false }); // 3 + Y2_data.push(FP16x16 { mag: 262144, sign: false }); // 4 + Y2_data.push(FP16x16 { mag: 327680, sign: false }); // 5 + Y2_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + Y2_data.push(FP16x16 { mag: 458752, sign: false }); // 7 + Y2_data.push(FP16x16 { mag: 524288, sign: false }); // 8 + Y2_data.push(FP16x16 { mag: 589824, sign: false }); // 9 + let mut Y2 = MutMatrix { data: Y2_data, rows: 3, cols: 3}; + let mut weights_data = VecTrait::::new(); - weights_data.push(FP16x16 { mag: 22453, sign: false }); // ~0.34 - weights_data.push(FP16x16 { mag: 16731, sign: false }); // ~0.26 - weights_data.push(FP16x16 { mag: 26352, sign: false }); // ~0.40 + weights_data.push(FP16x16 { mag: 13017, sign: false }); // 0.2 + weights_data.push(FP16x16 { mag: 19661, sign: false }); // 0.3 + weights_data.push(FP16x16 { mag: 32768, sign: false }); // 0.5 let mut W = MutMatrix { data: weights_data, rows: 3, cols: 1}; - let mut W_bad = MutMatrix { data: weights_data, rows: 1, cols: 3}; - - let mut Y_data = VecTrait::::new(); - Y_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - Y_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - Y_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - let mut Y = MutMatrix { data: Y_data, rows: 3, cols: 1}; - - // Mean test (1D) - let Y_simple_avg = mean(ref Y, (), ()); // Should return 3_fp16x16 - // let Y_weighted_avg = mean(ref Y, weights=Option(W)); - // let Y_weighted_avg_bad = mean(ref Y, weights=Option(W_bad)); // should error out - // 'Y smpl avg:'.print(); - // test_matrix(ref Y_simple_avg); - // 'Y wtd avg:'.print(); - // test_matrix(ref Y_weighted_avg); - - // // Mean test (2D) - // let Y_simple_avg_axis_0 = mean(ref X, axis=Option(0)); - // let Y_weighted_avg_axis_0 = mean(ref X, weights=Option(W), axis=Option(0)); - // let Y_simple_avg_axis_1 = mean(ref X, axis=Option(1)); - // let Y_weighted_avg_axis_1 = mean(ref X, weights=Option(W), axis=Option(1)); - // 'Y smpl avg ax=0:'.print(); - // test_matrix(ref Y_simple_avg_axis_0); - // 'Y wtd avg ax=0:'.print(); - // test_matrix(ref Y_weighted_avg_axis_0); - // 'Y smpl avg ax=1:'.print(); - // test_matrix(ref Y_simple_avg_axis_1); - // 'Y wtd avg ax=1:'.print(); - // test_matrix(ref Y_weighted_avg_axis_1); + + // Mean tests + // let mut Y1_mean = mean(ref Y1); + // let mut Y2_mean_rows = mean_matrix(ref Y2, 0); + // let mut Y2_mean_cols = mean_matrix(ref Y2, 1); + // 'Y1_mean:'.print(); + // test_matrix(ref Y1_mean); + // 'Y2_mean_rows:'.print(); + // test_matrix(ref Y2_mean_rows); + // 'Y2_mean_cols:'.print(); + // test_matrix(ref Y2_mean_cols); + + // let mut Y1_mean_weighted = mean_weighted(ref Y1, ref W, 0); + // let mut Y2_mean_weighted_rows = mean_weighted(ref Y2, ref W, 0); + // let mut Y2_mean_weighted_cols = mean_weighted(ref Y2, ref W, 1); + // 'Y1_mean_weighted:'.print(); + // test_matrix(ref Y1_mean_weighted); + // 'Y2_mean_weighted_rows:'.print(); + // test_matrix(ref Y2_mean_weighted_rows); + // 'Y2_mean_weighted_cols:'.print(); + // test_matrix(ref Y2_mean_weighted_cols); + + // let mut W_diag = diagonalize(ref W); + // test_matrix(ref W_diag); + + let mut Y3_data = VecTrait::::new(); + Y3_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + Y3_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + Y3_data.push(FP16x16 { mag: 196608, sign: false }); // 3 + Y3_data.push(FP16x16 { mag: 262144, sign: false }); // 4 + let mut Y3 = MutMatrix { data: Y3_data, rows: 2, cols: 2}; + + let mut Y4_data = VecTrait::::new(); + Y4_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + Y4_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + Y4_data.push(FP16x16 { mag: 196608, sign: false }); // 3 + Y4_data.push(FP16x16 { mag: 262144, sign: false }); // 4 + Y4_data.push(FP16x16 { mag: 327680, sign: false }); // 5 + Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; + + let mut Y3x4 = Y3.matmul(ref Y4); + test_matrix(ref Y3x4); } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 9131a7b04..27c1f42c5 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -3,6 +3,8 @@ use core::option::OptionTrait; use orion::numbers::NumberTrait; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; +use orion::operators::tensor::{TensorTrait, Tensor}; struct MutMatrix { data: NullableVec, @@ -47,23 +49,92 @@ impl MutMatrixImpl< (self.rows, self.cols) } - /// Transposes the matrix - fn transpose(ref self: MutMatrix) -> MutMatrix { - let mut result = MutMatrixImpl::new(rows: self.cols, cols: self.rows); - let mut row = 0; + /// Returns the reshaped matrix + fn reshape(ref self: MutMatrix, target_shape: Span) -> MutMatrix { + let mut t = self.to_tensor(); + let mut result = t.reshape(target_shape); + return result.from_tensor(); + } + + /// Returns the transposed matrix + fn transpose(ref self: MutMatrix, axes: Span) -> MutMatrix { + let mut t = self.to_tensor(); + let mut result = t.transpose(axes); + return result.from_tensor(); + } + + /// Returns the sum + fn reduce_sum(ref self: MutMatrix, axis: usize, keepdims: bool) -> MutMatrix { + let mut t = self.to_tensor(); + let mut result = t.reduce_sum(axis, keepdims); + return result.from_tensor(); + } + + /// Returns the matrix power + fn pow(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { + let mut t1 = self.to_tensor(); + let mut t2 = other.to_tensor(); + let mut result = t1.pow(@t2); + return result.from_tensor(); + } + + /// Returns the product of two matrices + fn matmul(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { + let mut t1 = self.to_tensor(); + let mut t2 = other.to_tensor(); + let mut result = t1.matmul(@t2); + return result.from_tensor(); + } + + /// Transforms a MutMatrix into a Tensor + fn to_tensor(ref self: MutMatrix) -> Tensor { + let mut result_shape = ArrayTrait::::new(); + result_shape.append(self.rows); + result_shape.append(self.cols); + + let mut result_data = ArrayTrait::::new(); + + let mut i = 0; loop { - if row == self.rows { + if i == self.rows { break; } - let mut col = 0; + let mut j = 0; loop { - if col == self.cols { + if j == self.cols { break; } - result.set(row, col, self.get(col, row)); - col += 1; + result_data.append(self.get(i, j).unwrap()); + j += 1; }; - row += 1; + i += 1; + }; + + let result = TensorTrait::new(result_shape.span(), result_data.span()); + return result; + } + + /// Transforms a Tensor to a MutMatrix + fn from_tensor(ref self: Tensor) -> MutMatrix { + let mut result_rows = *self.shape.at(0); + let mut result_cols = *self.shape.at(1); + let mut result: MutMatrix = MutMatrixTrait::::new(result_rows, result_cols); + + let mut i = 0; + loop { + if i == result_rows { + break; + } + let mut j = 0; + loop { + if j == result_cols { + break; + } + let mut val = self.at(array![i, j].span()); + result.set(i, j, val); + j += 1; + }; + i += 1; }; return result; } From c14359b280e5545e3e638d2a2a2be09f139dc31b Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Wed, 21 Feb 2024 22:38:33 +0200 Subject: [PATCH 06/16] Updates 2/21 --- src/lib.cairo | 132 +++++++++++++++++++++---------------- src/operators/matrix.cairo | 16 ++--- 2 files changed, 82 insertions(+), 66 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index e814dbd1f..f98e4a074 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -11,6 +11,8 @@ use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, ab use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::tensor::{TensorTrait, Tensor}; +use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; fn test_matrix(ref X: MutMatrix) { // Print X by columns @@ -430,52 +432,52 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi fn main() { - let mut X_data = VecTrait::::new(); - X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 - X_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 - X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 - X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 - let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; - - let mut y_data = VecTrait::::new(); - y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 - y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 - y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; + // let mut X_data = VecTrait::::new(); + // X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + // X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + // X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 + // X_data.push(FP16x16 { mag: 196608, sign: true }); // -3 + // X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 + // X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + // X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 + // X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + // X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 + // let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; + + // let mut y_data = VecTrait::::new(); + // y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 + // y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 + // y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 + // let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; // Linalg test // let mut S = linalg_solve(ref X, ref y); // test_matrix(ref S); // Solution is [2, 3, -1] in FP16x16 format! - let mut Y1_data = VecTrait::::new(); - Y1_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - Y1_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - Y1_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - let mut Y1 = MutMatrix { data: Y1_data, rows: 3, cols: 1}; - - let mut Y2_data = VecTrait::::new(); - Y2_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - Y2_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - Y2_data.push(FP16x16 { mag: 196608, sign: false }); // 3 - Y2_data.push(FP16x16 { mag: 262144, sign: false }); // 4 - Y2_data.push(FP16x16 { mag: 327680, sign: false }); // 5 - Y2_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - Y2_data.push(FP16x16 { mag: 458752, sign: false }); // 7 - Y2_data.push(FP16x16 { mag: 524288, sign: false }); // 8 - Y2_data.push(FP16x16 { mag: 589824, sign: false }); // 9 - let mut Y2 = MutMatrix { data: Y2_data, rows: 3, cols: 3}; - - let mut weights_data = VecTrait::::new(); - weights_data.push(FP16x16 { mag: 13017, sign: false }); // 0.2 - weights_data.push(FP16x16 { mag: 19661, sign: false }); // 0.3 - weights_data.push(FP16x16 { mag: 32768, sign: false }); // 0.5 - let mut W = MutMatrix { data: weights_data, rows: 3, cols: 1}; + // let mut Y1_data = VecTrait::::new(); + // Y1_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + // Y1_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + // Y1_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + // let mut Y1 = MutMatrix { data: Y1_data, rows: 3, cols: 1}; + + // let mut Y2_data = VecTrait::::new(); + // Y2_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + // Y2_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + // Y2_data.push(FP16x16 { mag: 196608, sign: false }); // 3 + // Y2_data.push(FP16x16 { mag: 262144, sign: false }); // 4 + // Y2_data.push(FP16x16 { mag: 327680, sign: false }); // 5 + // Y2_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + // Y2_data.push(FP16x16 { mag: 458752, sign: false }); // 7 + // Y2_data.push(FP16x16 { mag: 524288, sign: false }); // 8 + // Y2_data.push(FP16x16 { mag: 589824, sign: false }); // 9 + // let mut Y2 = MutMatrix { data: Y2_data, rows: 3, cols: 3}; + + // let mut weights_data = VecTrait::::new(); + // weights_data.push(FP16x16 { mag: 13017, sign: false }); // 0.2 + // weights_data.push(FP16x16 { mag: 19661, sign: false }); // 0.3 + // weights_data.push(FP16x16 { mag: 32768, sign: false }); // 0.5 + // let mut W = MutMatrix { data: weights_data, rows: 3, cols: 1}; // Mean tests // let mut Y1_mean = mean(ref Y1); @@ -501,23 +503,37 @@ fn main() { // let mut W_diag = diagonalize(ref W); // test_matrix(ref W_diag); - let mut Y3_data = VecTrait::::new(); - Y3_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - Y3_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - Y3_data.push(FP16x16 { mag: 196608, sign: false }); // 3 - Y3_data.push(FP16x16 { mag: 262144, sign: false }); // 4 - let mut Y3 = MutMatrix { data: Y3_data, rows: 2, cols: 2}; - - let mut Y4_data = VecTrait::::new(); - Y4_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - Y4_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - Y4_data.push(FP16x16 { mag: 196608, sign: false }); // 3 - Y4_data.push(FP16x16 { mag: 262144, sign: false }); // 4 - Y4_data.push(FP16x16 { mag: 327680, sign: false }); // 5 - Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; - - let mut Y3x4 = Y3.matmul(ref Y4); - test_matrix(ref Y3x4); + // let mut Y3_data = VecTrait::::new(); + // Y3_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + // Y3_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + // Y3_data.push(FP16x16 { mag: 196608, sign: false }); // 3 + // Y3_data.push(FP16x16 { mag: 262144, sign: false }); // 4 + // let mut Y3 = MutMatrix { data: Y3_data, rows: 2, cols: 2}; + + // let mut Y4_data = VecTrait::::new(); + // Y4_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + // Y4_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + // Y4_data.push(FP16x16 { mag: 196608, sign: false }); // 3 + // Y4_data.push(FP16x16 { mag: 262144, sign: false }); // 4 + // Y4_data.push(FP16x16 { mag: 327680, sign: false }); // 5 + // Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 + // let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; + + let mut X = MutMatrixImpl::::new(2,2); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(0, 1, FixedTrait::::new_unscaled(2, false)); + X.set(1, 0, FixedTrait::::new_unscaled(3, false)); + X.set(1, 1, FixedTrait::::new_unscaled(4, false)); + + let mut Y = MutMatrixImpl::::new(2,3); + Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); + Y.set(0, 1, FixedTrait::::new_unscaled(2, false)); + Y.set(0, 2, FixedTrait::::new_unscaled(3, false)); + Y.set(1, 0, FixedTrait::::new_unscaled(4, false)); + Y.set(1, 1, FixedTrait::::new_unscaled(5, false)); + Y.set(1, 2, FixedTrait::::new_unscaled(6, false)); + + let mut XY = X.matmul(ref Y); + test_matrix(ref XY); } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 27c1f42c5..44ba9f35d 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -50,28 +50,28 @@ impl MutMatrixImpl< } /// Returns the reshaped matrix - fn reshape(ref self: MutMatrix, target_shape: Span) -> MutMatrix { + fn reshape<+TensorTrait>(ref self: MutMatrix, target_shape: Span) -> MutMatrix { let mut t = self.to_tensor(); let mut result = t.reshape(target_shape); return result.from_tensor(); } /// Returns the transposed matrix - fn transpose(ref self: MutMatrix, axes: Span) -> MutMatrix { + fn transpose<+TensorTrait>(ref self: MutMatrix, axes: Span) -> MutMatrix { let mut t = self.to_tensor(); let mut result = t.transpose(axes); return result.from_tensor(); } /// Returns the sum - fn reduce_sum(ref self: MutMatrix, axis: usize, keepdims: bool) -> MutMatrix { + fn reduce_sum<+TensorTrait>(ref self: MutMatrix, axis: usize, keepdims: bool) -> MutMatrix { let mut t = self.to_tensor(); let mut result = t.reduce_sum(axis, keepdims); return result.from_tensor(); } /// Returns the matrix power - fn pow(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { + fn pow<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { let mut t1 = self.to_tensor(); let mut t2 = other.to_tensor(); let mut result = t1.pow(@t2); @@ -79,7 +79,7 @@ impl MutMatrixImpl< } /// Returns the product of two matrices - fn matmul(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { + fn matmul<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { let mut t1 = self.to_tensor(); let mut t2 = other.to_tensor(); let mut result = t1.matmul(@t2); @@ -87,7 +87,7 @@ impl MutMatrixImpl< } /// Transforms a MutMatrix into a Tensor - fn to_tensor(ref self: MutMatrix) -> Tensor { + fn to_tensor<+TensorTrait>(ref self: MutMatrix) -> Tensor { let mut result_shape = ArrayTrait::::new(); result_shape.append(self.rows); result_shape.append(self.cols); @@ -110,12 +110,12 @@ impl MutMatrixImpl< i += 1; }; - let result = TensorTrait::new(result_shape.span(), result_data.span()); + let mut result = TensorTrait::new(result_shape.span(), result_data.span()); return result; } /// Transforms a Tensor to a MutMatrix - fn from_tensor(ref self: Tensor) -> MutMatrix { + fn from_tensor<+TensorTrait>(ref self: Tensor) -> MutMatrix { let mut result_rows = *self.shape.at(0); let mut result_cols = *self.shape.at(1); let mut result: MutMatrix = MutMatrixTrait::::new(result_rows, result_cols); From b3d0d1ee4cbeb2a7e43c53cfde27e4a47a951f02 Mon Sep 17 00:00:00 2001 From: Benjamin Shmulevsky Date: Thu, 22 Feb 2024 18:47:29 +0200 Subject: [PATCH 07/16] Updates 2/22 --- .tool-versions | 2 +- src/lib.cairo | 218 +++++++++++++++++++------------------ src/operators/matrix.cairo | 26 ++++- 3 files changed, 135 insertions(+), 111 deletions(-) diff --git a/.tool-versions b/.tool-versions index 21cfc8077..cd721c52f 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.4.0 +scarb 2.5.1 diff --git a/src/lib.cairo b/src/lib.cairo index f98e4a074..06ee766f1 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -156,23 +156,22 @@ fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatr return S; } -// fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { -// let mut lambda = FixedTrait::::new_unscaled(lambda_unscaled, false); -// lambda = lambda / FixedTrait::::new_unscaled(100, false); -// let mut weights = MutMatrixImpl::::new(l, 1); -// let mut i = 0; -// loop { -// if i == l { -// break (); -// } -// let mut l_i = FixedTrait::::new_unscaled(i, false); -// let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * (lambda.pow(@l_i)); -// weights.set(i, 0, w_i); -// i += 1; -// }; - -// return weights; -// } +fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { + let lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); + let mut weights = MutMatrixImpl::::new(l, 1); + let mut i = 0; + loop { + if i == l { + break; + } + let mut l_i = FixedTrait::::new_unscaled(i, false); + let mut l_pow = FixedTrait::pow(lambda, l_i); + let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * l_pow; + weights.set(i, 0, w_i); + i += 1; + }; + return weights; +} fn diagonalize(ref X: MutMatrix) -> MutMatrix { assert(X.rows > 1 && X.cols == 1, 'X not row vector'); @@ -230,61 +229,99 @@ fn mean(ref X: MutMatrix) -> MutMatrix { } } -fn mean_matrix(ref X: MutMatrix, axis: u32) -> MutMatrix { +fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { // Simple average case for a matrix along specified axis // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 assert(axis == 0 || axis == 1, 'Wrong axis'); - // Average along rows - if axis == 0 { - let mut result = MutMatrixImpl::::new(X.rows, 1); - let l = FixedTrait::::new_unscaled(X.cols, false); - let mut row = 0; + // Simple average case for a vector + // Returns a matrix with shape (1,1) + if X.cols == 1 || X.rows == 1 { - loop { - if row == X.rows { - break; - } - let mut row_num = FixedTrait::::new_unscaled(0, false); - let mut col = 0; + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; + + let l = FixedTrait::::new_unscaled(X.data.len(), false); + + if X.rows == 1 { + result.set(0, 0, X.get(0, 0).unwrap()); + return result; + } + else { loop { - if col == X.cols { + if i == X.rows { break; } - row_num += X.get(row, col).unwrap(); - col += 1; + let mut num_i = if (X.cols == 1) { + X.get(i, 0).unwrap() + } + else { + X.get(0, i).unwrap() + }; + num += num_i + i += 1; }; - result.set(row, 0, row_num / l); - row += 1; - }; + result.set(0, 0, num / l); + } return result; } - // Average along columns + // Matrix average along specified axis + // Returns a vector with shape=(X.rows, 1) if axis == 0 or shape=(1, X.cols) if axis == 1 else { - let mut result = MutMatrixImpl::::new(1, X.cols); - let l = FixedTrait::::new_unscaled(X.rows, false); - let mut col = 0; - - loop { - if col == X.cols { - break; - } - let mut col_num = FixedTrait::::new_unscaled(0, false); + // Average along rows + if axis == 0 { + let mut result = MutMatrixImpl::::new(X.rows, 1); + let l = FixedTrait::::new_unscaled(X.cols, false); let mut row = 0; + loop { if row == X.rows { break; - } - col_num += X.get(row, col).unwrap(); + } + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; + loop { + if col == X.cols { + break; + } + row_num += X.get(row, col).unwrap(); + col += 1; + }; + result.set(row, 0, row_num / l); row += 1; }; - result.set(0, col, col_num / l); - col += 1; - }; + return result; + } + + // Average along columns + else { + let mut result = MutMatrixImpl::::new(1, X.cols); + let l = FixedTrait::::new_unscaled(X.rows, false); + let mut col = 0; + + loop { + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; + loop { + if row == X.rows { + break; + } + col_num += X.get(row, col).unwrap(); + row += 1; + }; + result.set(0, col, col_num / l); + col += 1; + }; + } + return result; } } @@ -382,54 +419,6 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi } } -// fn covariance(X: MutMatrix, weights: MutMatrix) -> MutMatrix { -// // Weight assertions -// assert(weights.rows == X.rows, 'Weights shape mismatch'); -// assert(weights.cols == 1, 'Weights not row vector'); - -// // Get shape of array -// // let m = X.rows; // num rows -// // let n = X.cols; // num columns -// // let l = weights.rows; // length of weight vector - -// // Transform weights vector into (l,l) diagonal matrix -// let mut W = diagonalize(weights); - -// // Take dot product of W and X and center it -// // X_weighted = np.dot(W, X), shape = (m,n) -// // let mut X_weighted = W.matmul(@X); // TODO - write this function - -// // mean_weighted = (np.dot(weights, X) / np.sum(weights)), shape = (n,1) -// let mut X_mean = mean_weighted(X, W, 0) - -// // let mut weights_T = weights.reshape(target_shape: array![1, *weights.shape.at(0)].span()); // TODO: write this function -// // let mut weights_dot_X = weights_T.matmul(@X); -// // let mut weights_sum = *weights.reduce_sum(0, false).data.at(0); -// // let mut mean_weighted_shape = ArrayTrait::::new(); -// // mean_weighted_shape.append(*weights_dot_X.shape.at(1)); -// // let mut mean_weighted_data = ArrayTrait::::new(); -// // let mut i: u32 = 0; -// // loop { -// // if i == *weights_dot_X.shape.at(1) { -// // break (); -// // } -// // mean_weighted_data.append(*weights_dot_X.data.at(i) / weights_sum); -// // i += 1; -// // }; - -// // let mean_weighted = TensorTrait::::new(mean_weighted_shape.span(), mean_weighted_data.span(), Option::Some(extra)); - -// // X_centered = X_weighted - mean_weighted, shape = (n,n) - -// // Calculate covariance matrix -// // covariance_matrix = centered_data.T.dot(centered_data) / (np.sum(weights) - 1) - -// return Cov_X; -// } - - - - fn main() { // let mut X_data = VecTrait::::new(); @@ -519,21 +508,36 @@ fn main() { // Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 // let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; - let mut X = MutMatrixImpl::::new(2,2); + let mut X = MutMatrixImpl::::new(1,3); X.set(0, 0, FixedTrait::::new_unscaled(1, false)); X.set(0, 1, FixedTrait::::new_unscaled(2, false)); - X.set(1, 0, FixedTrait::::new_unscaled(3, false)); - X.set(1, 1, FixedTrait::::new_unscaled(4, false)); + X.set(0, 2, FixedTrait::::new_unscaled(3, false)); - let mut Y = MutMatrixImpl::::new(2,3); + let mut Y = MutMatrixImpl::::new(1,3); Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); Y.set(0, 1, FixedTrait::::new_unscaled(2, false)); Y.set(0, 2, FixedTrait::::new_unscaled(3, false)); - Y.set(1, 0, FixedTrait::::new_unscaled(4, false)); - Y.set(1, 1, FixedTrait::::new_unscaled(5, false)); - Y.set(1, 2, FixedTrait::::new_unscaled(6, false)); + // Y.set(1, 1, FixedTrait::::new_unscaled(4, false)); + // Y.set(2, 0, FixedTrait::::new_unscaled(5, false)); + // Y.set(2, 1, FixedTrait::::new_unscaled(6, false)); - let mut XY = X.matmul(ref Y); - test_matrix(ref XY); + // let mut Z = exponential_weights(97, 3); + let mut Y_T = Y.transpose(array![0,1].span()); + let mut Z = X.matmul(ref Y_T); + + test_matrix(ref Z); + + // let result_rows = *Z.shape.at(0); + // let result_cols = if (Z.shape.len() != 1) { + // *Z.shape.at(1) + // } + // else { + // 1 + // }; + // result_rows.print(); + // result_cols.print(); + // let val = Z.at(array![0].span()); + // val.print(); + } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 44ba9f35d..5c417d6f3 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -5,6 +5,7 @@ use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; use orion::operators::tensor::{TensorTrait, Tensor}; +use core::debug::PrintTrait; struct MutMatrix { data: NullableVec, @@ -70,6 +71,13 @@ impl MutMatrixImpl< return result.from_tensor(); } + // /// Returns the sum + // fn reduce_sum<+TensorTrait>(ref self: MutMatrix, axis: usize, keepdims: bool) -> Tensor { + // let mut t = self.to_tensor(); + // let mut result = t.reduce_sum(axis, keepdims); + // return result; + // } + /// Returns the matrix power fn pow<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { let mut t1 = self.to_tensor(); @@ -116,8 +124,15 @@ impl MutMatrixImpl< /// Transforms a Tensor to a MutMatrix fn from_tensor<+TensorTrait>(ref self: Tensor) -> MutMatrix { - let mut result_rows = *self.shape.at(0); - let mut result_cols = *self.shape.at(1); + let dim = self.shape.len(); + let result_rows = *self.shape.at(0); + let result_cols = if (dim == 1) { + 1 + } + else { + *self.shape.at(1) + }; + let mut result: MutMatrix = MutMatrixTrait::::new(result_rows, result_cols); let mut i = 0; @@ -130,7 +145,12 @@ impl MutMatrixImpl< if j == result_cols { break; } - let mut val = self.at(array![i, j].span()); + let mut val = if (dim == 1) { + self.at(array![i].span()) + } + else { + self.at(array![i, j].span()) + }; result.set(i, j, val); j += 1; }; From 67787e3dbc198b9ec2564dfd114220976a482b90 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Sun, 25 Feb 2024 10:34:59 +0200 Subject: [PATCH 08/16] 2/24 --- .tool-versions | 2 +- src/lib.cairo | 175 +++++++++++++++++++++++++++---------------------- 2 files changed, 98 insertions(+), 79 deletions(-) diff --git a/.tool-versions b/.tool-versions index cd721c52f..21cfc8077 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.5.1 +scarb 2.4.0 diff --git a/src/lib.cairo b/src/lib.cairo index 06ee766f1..f717a5fa8 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -200,35 +200,6 @@ fn diagonalize(ref X: MutMatrix) -> MutMatrix { return result; } -fn mean(ref X: MutMatrix) -> MutMatrix { - // Simple average case for a vector - // Returns a matrix with shape (1,1) - - assert(X.cols == 1, 'Wrong shape'); - - let mut result = MutMatrixImpl::::new(1, 1); - let mut num = FixedTrait::::new_unscaled(0, false); - let mut i = 0; - - let l = FixedTrait::::new_unscaled(X.data.len(), false); - - if X.rows == 1 { - result.set(0, 0, X.get(0, 0).unwrap()); - return result; - } - else { - loop { - if i == X.rows { - break; - } - num += X.get(i, 0).unwrap(); - i += 1; - }; - result.set(0, 0, num / l); - return result; - } -} - fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { // Simple average case for a matrix along specified axis // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 @@ -243,27 +214,33 @@ fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { let mut num = FixedTrait::::new_unscaled(0, false); let mut i = 0; - let l = FixedTrait::::new_unscaled(X.data.len(), false); + let den = FixedTrait::::new_unscaled(X.data.len(), false); - if X.rows == 1 { + if X.cols == 1 && X.rows == 1 { result.set(0, 0, X.get(0, 0).unwrap()); return result; } else { + let l = if (X.rows > 1) { + X.rows + } + else { + X.cols + }; loop { - if i == X.rows { + if i == l { break; } - let mut num_i = if (X.cols == 1) { + let mut num_i = if (X.rows > 1) { X.get(i, 0).unwrap() } else { X.get(0, i).unwrap() }; - num += num_i + num += num_i; i += 1; }; - result.set(0, 0, num / l); + result.set(0, 0, num / den); } return result; @@ -275,7 +252,7 @@ fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { // Average along rows if axis == 0 { let mut result = MutMatrixImpl::::new(X.rows, 1); - let l = FixedTrait::::new_unscaled(X.cols, false); + let den = FixedTrait::::new_unscaled(X.cols, false); let mut row = 0; loop { @@ -291,7 +268,7 @@ fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { row_num += X.get(row, col).unwrap(); col += 1; }; - result.set(row, 0, row_num / l); + result.set(row, 0, row_num / den); row += 1; }; @@ -301,7 +278,7 @@ fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { // Average along columns else { let mut result = MutMatrixImpl::::new(1, X.cols); - let l = FixedTrait::::new_unscaled(X.rows, false); + let den = FixedTrait::::new_unscaled(X.rows, false); let mut col = 0; loop { @@ -317,12 +294,12 @@ fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { col_num += X.get(row, col).unwrap(); row += 1; }; - result.set(0, col, col_num / l); + result.set(0, col, col_num / den); col += 1; }; - } - return result; + return result; + } } } @@ -331,31 +308,45 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 // Weight assertions - assert(weights.rows == X.rows, 'Weights shape mismatch'); - assert(weights.cols == 1, 'Weights not row vector'); + if X.rows > 1 { + assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); + } + else { + assert(weights.cols == X.cols && weights.rows == 1, 'Weights shape mismatch'); + } // Vector case if X.rows == 1 || X.cols == 1 { + + assert(X.rows != X.cols, '1 element input'); let mut result = MutMatrixImpl::::new(1, 1); let mut num = FixedTrait::::new_unscaled(0, false); let mut i = 0; - let l = FixedTrait::::new_unscaled(X.data.len(), false); + let den = FixedTrait::::new_unscaled(X.data.len(), false); + + let l = if (X.rows > 1) { + X.rows + } + else { + X.cols + }; + loop { - if i == X.rows { + if i == l { break; } - if X.rows != 1 { - num += X.get(i, 0).unwrap() * weights.get(i, 0).unwrap(); + let mut num_i = if (X.rows > 1) { + X.get(i, 0).unwrap() * weights.get(i, 0).unwrap() } else { - result.set(0, 0, X.get(0, 0).unwrap()); - break; - } + X.get(0, i).unwrap() * weights.get(0, i).unwrap() + }; + num += num_i; i += 1; }; - result.set(0, 0, num / l); + result.set(0, 0, num / den); return result; } @@ -368,7 +359,7 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi if axis == 0 { let mut result = MutMatrixImpl::::new(X.rows, 1); - let l = FixedTrait::::new_unscaled(X.cols, false); + let den = FixedTrait::::new_unscaled(X.cols, false); let mut row = 0; loop { @@ -384,7 +375,7 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); col += 1; }; - result.set(row, 0, row_num / l); + result.set(row, 0, row_num / den); row += 1; }; @@ -394,7 +385,7 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi // Average along columns else { let mut result = MutMatrixImpl::::new(1, X.cols); - let l = FixedTrait::::new_unscaled(X.rows, false); + let den = FixedTrait::::new_unscaled(X.rows, false); let mut col = 0; loop { @@ -410,7 +401,7 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); row += 1; }; - result.set(0, col, col_num / l); + result.set(0, col, col_num / den); col += 1; }; @@ -419,6 +410,42 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi } } +fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { + assert(X.rows == weights.rows, 'Data/weight length mismatch'); + + // Transform weights vector into (l,l) diagonal matrix + let mut W = diagonalize(ref weights); + + // Take dot product of W and X and center it + // X_weighted = np.dot(W, X), shape = (m,n) + let mut X_weighted = W.matmul(ref X); + + // mean_weighted = (np.dot(weights, X) / np.sum(weights)), shape = (n,1) + let mut mean_weighted_num = weights.matmul(ref X); + let mut mean_weighted_den = weights.reduce_sum(0, false); + // let mut mean_weighted = weights.matmul(ref X) / weights.reduce_sum(0, false); + 'w_max_x'.print(); + test_matrix(ref mean_weighted_num); + 'w_sum'.print(); + test_matrix(ref mean_weighted_den); + + return W; + + // let mut mean_weighted = mean_weighted_num / mean_weighted_den; + + // // X_centered = X_weighted - mean_weighted, shape = (n,n) + // let mut X_centered = X_weighted - mean_weighted; + + // // covariance_matrix = centered_data.T.dot(centered_data) / (np.sum(weights) - 1) + // let mut X_centered_T: MutMatrix = X_centered.transpose(array![0,1].span()); + // let mut one = MutMatrixImpl::::new(1,1); + // one.set(0, 0, FixedTrait::::new_unscaled(1, false)); + // let mut den = weights.reduce_sum(0, false) - one; + // let mut Cov_X = X_centered_T.matmul(ref X_centered) / den; + + // return Cov_X; +} + fn main() { // let mut X_data = VecTrait::::new(); @@ -508,36 +535,28 @@ fn main() { // Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 // let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; - let mut X = MutMatrixImpl::::new(1,3); + let mut X = MutMatrixImpl::::new(3,1); X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(0, 1, FixedTrait::::new_unscaled(2, false)); - X.set(0, 2, FixedTrait::::new_unscaled(3, false)); - - let mut Y = MutMatrixImpl::::new(1,3); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(3, false)); + X.set(2, 1, FixedTrait::::new_unscaled(2, false)); + X.set(0, 2, FixedTrait::::new_unscaled(4, false)); + X.set(1, 2, FixedTrait::::new_unscaled(1, false)); + X.set(2, 2, FixedTrait::::new_unscaled(7, false)); + + let mut Y = MutMatrixImpl::::new(3,1); Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); - Y.set(0, 1, FixedTrait::::new_unscaled(2, false)); - Y.set(0, 2, FixedTrait::::new_unscaled(3, false)); + Y.set(1, 0, FixedTrait::::new_unscaled(1, false)); + Y.set(2, 0, FixedTrait::::new_unscaled(1, false)); // Y.set(1, 1, FixedTrait::::new_unscaled(4, false)); // Y.set(2, 0, FixedTrait::::new_unscaled(5, false)); // Y.set(2, 1, FixedTrait::::new_unscaled(6, false)); // let mut Z = exponential_weights(97, 3); - - let mut Y_T = Y.transpose(array![0,1].span()); - let mut Z = X.matmul(ref Y_T); - test_matrix(ref Z); - - // let result_rows = *Z.shape.at(0); - // let result_cols = if (Z.shape.len() != 1) { - // *Z.shape.at(1) - // } - // else { - // 1 - // }; - // result_rows.print(); - // result_cols.print(); - // let val = Z.at(array![0].span()); - // val.print(); + let mut sigma2 = covariance_weighted(ref X, ref Y); + // test_matrix(ref sigma2); } \ No newline at end of file From 107c281f81fed00be85808051dc1bfac8f493542 Mon Sep 17 00:00:00 2001 From: Benjamin Shmulevsky Date: Sun, 25 Feb 2024 17:27:35 +0200 Subject: [PATCH 09/16] Updates --- .tool-versions | 2 +- src/lib.cairo | 169 ++++++++++++++++++++++++++----------- src/operators/matrix.cairo | 7 -- 3 files changed, 121 insertions(+), 57 deletions(-) diff --git a/.tool-versions b/.tool-versions index 21cfc8077..9e7be0075 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.4.0 +scarb 2.5.1 \ No newline at end of file diff --git a/src/lib.cairo b/src/lib.cairo index f717a5fa8..87721b446 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -359,7 +359,6 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi if axis == 0 { let mut result = MutMatrixImpl::::new(X.rows, 1); - let den = FixedTrait::::new_unscaled(X.cols, false); let mut row = 0; loop { @@ -375,7 +374,7 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); col += 1; }; - result.set(row, 0, row_num / den); + result.set(row, 0, row_num); row += 1; }; @@ -385,7 +384,6 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi // Average along columns else { let mut result = MutMatrixImpl::::new(1, X.cols); - let den = FixedTrait::::new_unscaled(X.rows, false); let mut col = 0; loop { @@ -401,7 +399,7 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); row += 1; }; - result.set(0, col, col_num / den); + result.set(0, col, col_num); col += 1; }; @@ -410,40 +408,106 @@ fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axi } } -fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { - assert(X.rows == weights.rows, 'Data/weight length mismatch'); +fn covariance(ref X: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); - // Transform weights vector into (l,l) diagonal matrix - let mut W = diagonalize(ref weights); + let m = X.rows; // Num observations + let n = X.cols; // Num variables + let mut Cov_X = MutMatrixImpl::::new(n, n); + let mut Mean_X = mean(ref X, 1); - // Take dot product of W and X and center it - // X_weighted = np.dot(W, X), shape = (m,n) - let mut X_weighted = W.matmul(ref X); + let mut i = 0; + loop { + if i == n { + break; + } + let mut j = 0; + loop { + if j == n { + break; + } + let mut k = 0; + let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + loop { + if k == m { + break; + } + Cov_X_i_j += ((X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); + k += 1; + }; + Cov_X_i_j /= FixedTrait::::new_unscaled(m - 1, false); + Cov_X.set(i, j, Cov_X_i_j); + Cov_X.set(j, i, Cov_X_i_j); + j += 1; + }; + i += 1; + }; - // mean_weighted = (np.dot(weights, X) / np.sum(weights)), shape = (n,1) - let mut mean_weighted_num = weights.matmul(ref X); - let mut mean_weighted_den = weights.reduce_sum(0, false); - // let mut mean_weighted = weights.matmul(ref X) / weights.reduce_sum(0, false); - 'w_max_x'.print(); - test_matrix(ref mean_weighted_num); - 'w_sum'.print(); - test_matrix(ref mean_weighted_den); + return Cov_X; +} - return W; +fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); + assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); - // let mut mean_weighted = mean_weighted_num / mean_weighted_den; + // Normalize weights + let mut normalized_weights = MutMatrixImpl::::new(weights.rows, 1); + let mut total_weight = weights.reduce_sum(0, false); + let mut i = 0; + loop { + if i == weights.rows { + break; + } + let w_i = weights.get(i, 0).unwrap(); + normalized_weights.set(i, 0, w_i / total_weight.get(0, 0).unwrap()); + i += 1; + }; - // // X_centered = X_weighted - mean_weighted, shape = (n,n) - // let mut X_centered = X_weighted - mean_weighted; + let m = X.rows; // Num observations + let n = X.cols; // Num variables + let mut Cov_X = MutMatrixImpl::::new(n, n); + let mut Mean_X = mean_weighted(ref X, ref weights, 1); - // // covariance_matrix = centered_data.T.dot(centered_data) / (np.sum(weights) - 1) - // let mut X_centered_T: MutMatrix = X_centered.transpose(array![0,1].span()); - // let mut one = MutMatrixImpl::::new(1,1); - // one.set(0, 0, FixedTrait::::new_unscaled(1, false)); - // let mut den = weights.reduce_sum(0, false) - one; - // let mut Cov_X = X_centered_T.matmul(ref X_centered) / den; + let mut adj_weight_sum = FixedTrait::::new_unscaled(0, false); + i = 0; + loop { + if i == normalized_weights.rows { + break; + } + let mut w_i = normalized_weights.get(i, 0).unwrap(); + adj_weight_sum += (w_i * w_i); + i += 1; + }; - // return Cov_X; + i = 0; + loop { + if i == n { + break; + } + let mut j = 0; + loop { + if j == n { + break; + } + let mut k = 0; + let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + loop { + if k == m { + break; + } + Cov_X_i_j += (normalized_weights.get(k, 0).unwrap() * (X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); + k += 1; + }; + let mut den = FixedTrait::::new_unscaled(1, false) - adj_weight_sum; + Cov_X_i_j /= den; + Cov_X.set(i, j, Cov_X_i_j); + Cov_X.set(j, i, Cov_X_i_j); + j += 1; + }; + i += 1; + }; + + return Cov_X; } fn main() { @@ -535,28 +599,35 @@ fn main() { // Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 // let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; - let mut X = MutMatrixImpl::::new(3,1); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(3, false)); - X.set(2, 1, FixedTrait::::new_unscaled(2, false)); - X.set(0, 2, FixedTrait::::new_unscaled(4, false)); - X.set(1, 2, FixedTrait::::new_unscaled(1, false)); - X.set(2, 2, FixedTrait::::new_unscaled(7, false)); - - let mut Y = MutMatrixImpl::::new(3,1); - Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); - Y.set(1, 0, FixedTrait::::new_unscaled(1, false)); - Y.set(2, 0, FixedTrait::::new_unscaled(1, false)); + // let mut Y = MutMatrixImpl::::new(3,1); + // Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); + // Y.set(1, 0, FixedTrait::::new_unscaled(1, false)); + // Y.set(2, 0, FixedTrait::::new_unscaled(1, false)); // Y.set(1, 1, FixedTrait::::new_unscaled(4, false)); // Y.set(2, 0, FixedTrait::::new_unscaled(5, false)); // Y.set(2, 1, FixedTrait::::new_unscaled(6, false)); - // let mut Z = exponential_weights(97, 3); - - let mut sigma2 = covariance_weighted(ref X, ref Y); - // test_matrix(ref sigma2); + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixImpl::::new(4, 1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 + weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + + let mut sigma2 = covariance_weighted(ref X, ref weights); + test_matrix(ref sigma2); } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 5c417d6f3..5f81b4b81 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -71,13 +71,6 @@ impl MutMatrixImpl< return result.from_tensor(); } - // /// Returns the sum - // fn reduce_sum<+TensorTrait>(ref self: MutMatrix, axis: usize, keepdims: bool) -> Tensor { - // let mut t = self.to_tensor(); - // let mut result = t.reduce_sum(axis, keepdims); - // return result; - // } - /// Returns the matrix power fn pow<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { let mut t1 = self.to_tensor(); From d7b7cc0ede1dc5fb20cbf3cc67cfdda29f7bef13 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Sun, 25 Feb 2024 20:36:53 +0200 Subject: [PATCH 10/16] Updates 2/25 --- .tool-versions | 2 +- src/lib.cairo | 56 +- src/operators/matrix.cairo | 573 +----------------- src/operators/matrix/matrix.cairo | 440 ++++++++++++++ src/operators/matrix/matrix_linalg.cairo | 158 +++++ src/operators/matrix/matrix_statistics.cairo | 337 ++++++++++ .../tree_ensemble_classifier.cairo | 4 +- .../tree_ensemble_regressor.cairo | 4 +- src/operators/tensor/manipulation/split.cairo | 2 +- tests/operators/linalg_test.cairo | 67 -- .../operators/matrix/matrix_linalg_test.cairo | 54 ++ .../matrix/matrix_statistics_test.cairo | 229 +++++++ 12 files changed, 1259 insertions(+), 667 deletions(-) create mode 100644 src/operators/matrix/matrix.cairo create mode 100644 src/operators/matrix/matrix_linalg.cairo create mode 100644 src/operators/matrix/matrix_statistics.cairo delete mode 100644 tests/operators/linalg_test.cairo create mode 100644 tests/operators/matrix/matrix_linalg_test.cairo create mode 100644 tests/operators/matrix/matrix_statistics_test.cairo diff --git a/.tool-versions b/.tool-versions index 9e7be0075..ff8bf3eb2 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.5.1 \ No newline at end of file +scarb 2.4.0 \ No newline at end of file diff --git a/src/lib.cairo b/src/lib.cairo index 87721b446..efc3821cd 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -8,7 +8,7 @@ use core::array::ArrayTrait; use core::option::OptionTrait; use orion::numbers::NumberTrait; use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; -use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; use orion::operators::tensor::{TensorTrait, Tensor}; @@ -512,27 +512,27 @@ fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix::new(); - // X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - // X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - // X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 - // X_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - // X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 - // X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - // X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 - // X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - // X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 - // let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; - - // let mut y_data = VecTrait::::new(); - // y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 - // y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 - // y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - // let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; + let mut X_data = VecTrait::::new(); + X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 + X_data.push(FP16x16 { mag: 196608, sign: true }); // -3 + X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 + X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 + X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 + X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 + X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 + let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; + + let mut y_data = VecTrait::::new(); + y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 + y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 + y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 + let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; // Linalg test - // let mut S = linalg_solve(ref X, ref y); - // test_matrix(ref S); + let mut S = linalg_solve(ref X, ref y); + test_matrix(ref S); // Solution is [2, 3, -1] in FP16x16 format! // let mut Y1_data = VecTrait::::new(); @@ -627,7 +627,19 @@ fn main() { weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 - let mut sigma2 = covariance_weighted(ref X, ref weights); - test_matrix(ref sigma2); + // let mut mean_X = mean_weighted(ref X, ref weights, 1); + // let mut cov_X = covariance_weighted(ref X, ref weights); + // 'shape'.print(); + // cov_X.rows.print(); + // cov_X.cols.print(); + // test_matrix(ref cov_X); + // let mut X = exponential_weights(97, 3); + // 'shape='.print(); + // X.rows.print(); + // X.cols.print(); + // test_matrix(ref X); + + 'S_1 sign incorrect'.print(); + } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 5f81b4b81..6c2401df9 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -1,572 +1 @@ -use core::array::ArrayTrait; -use core::option::OptionTrait; -use orion::numbers::NumberTrait; -use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; -use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; -use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; -use orion::operators::tensor::{TensorTrait, Tensor}; -use core::debug::PrintTrait; - -struct MutMatrix { - data: NullableVec, - rows: usize, - cols: usize, -} - -impl MutMatrixDestruct> of Destruct> { - fn destruct(self: MutMatrix) nopanic { - self.data.destruct() - } -} - -#[generate_trait] -impl MutMatrixImpl< - T, MAG, +Drop, +Copy, +NumberTrait, +PartialOrd -> of MutMatrixTrait { - /// Constructor for the Matrix - fn new(rows: usize, cols: usize) -> MutMatrix { - MutMatrix { data: NullableVecImpl::new(), rows: rows, cols: cols } - } - - /// Get the value at (row, col) - fn get(ref self: MutMatrix, row: usize, col: usize) -> Option { - if row >= self.rows || col >= self.cols { - Option::None - } else { - self.data.get(row * self.cols + col) - } - } - - /// Set the value at (row, col) - fn set(ref self: MutMatrix, row: usize, col: usize, value: T) { - if row < self.rows && col < self.cols { - let index = row * self.cols + col; - self.data.set(index, value) - } - } - - /// Returns the shape of the matrix as (rows, cols) - fn shape(self: MutMatrix) -> (usize, usize) { - (self.rows, self.cols) - } - - /// Returns the reshaped matrix - fn reshape<+TensorTrait>(ref self: MutMatrix, target_shape: Span) -> MutMatrix { - let mut t = self.to_tensor(); - let mut result = t.reshape(target_shape); - return result.from_tensor(); - } - - /// Returns the transposed matrix - fn transpose<+TensorTrait>(ref self: MutMatrix, axes: Span) -> MutMatrix { - let mut t = self.to_tensor(); - let mut result = t.transpose(axes); - return result.from_tensor(); - } - - /// Returns the sum - fn reduce_sum<+TensorTrait>(ref self: MutMatrix, axis: usize, keepdims: bool) -> MutMatrix { - let mut t = self.to_tensor(); - let mut result = t.reduce_sum(axis, keepdims); - return result.from_tensor(); - } - - /// Returns the matrix power - fn pow<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { - let mut t1 = self.to_tensor(); - let mut t2 = other.to_tensor(); - let mut result = t1.pow(@t2); - return result.from_tensor(); - } - - /// Returns the product of two matrices - fn matmul<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { - let mut t1 = self.to_tensor(); - let mut t2 = other.to_tensor(); - let mut result = t1.matmul(@t2); - return result.from_tensor(); - } - - /// Transforms a MutMatrix into a Tensor - fn to_tensor<+TensorTrait>(ref self: MutMatrix) -> Tensor { - let mut result_shape = ArrayTrait::::new(); - result_shape.append(self.rows); - result_shape.append(self.cols); - - let mut result_data = ArrayTrait::::new(); - - let mut i = 0; - loop { - if i == self.rows { - break; - } - let mut j = 0; - loop { - if j == self.cols { - break; - } - result_data.append(self.get(i, j).unwrap()); - j += 1; - }; - i += 1; - }; - - let mut result = TensorTrait::new(result_shape.span(), result_data.span()); - return result; - } - - /// Transforms a Tensor to a MutMatrix - fn from_tensor<+TensorTrait>(ref self: Tensor) -> MutMatrix { - let dim = self.shape.len(); - let result_rows = *self.shape.at(0); - let result_cols = if (dim == 1) { - 1 - } - else { - *self.shape.at(1) - }; - - let mut result: MutMatrix = MutMatrixTrait::::new(result_rows, result_cols); - - let mut i = 0; - loop { - if i == result_rows { - break; - } - let mut j = 0; - loop { - if j == result_cols { - break; - } - let mut val = if (dim == 1) { - self.at(array![i].span()) - } - else { - self.at(array![i, j].span()) - }; - result.set(i, j, val); - j += 1; - }; - i += 1; - }; - return result; - } - - /// Returns the index of the maximum value along the specified axis - fn argmax(ref self: MutMatrix, axis: usize) -> Span { - assert(axis < 2, 'Invalid axis'); - - let mut result: Array = ArrayTrait::new(); - if axis == 0 { - let mut col: usize = 0; - loop { - if col == self.cols { - break; - } - - let mut max_value = self.get(0, col); - let mut max_value = match max_value { - Option::Some => { max_value.unwrap() }, - Option::None => { NumberTrait::min_value() } - }; - let mut max_index = 0; - - let mut row: usize = 1; - loop { - if row == self.rows { - break; - } - - let mut value = self.get(row, col); - let mut value = match value { - Option::Some => { value.unwrap() }, - Option::None => { NumberTrait::min_value() } - }; - if value > max_value { - max_value = value; - max_index = row; - } - - row += 1; - }; - - result.append(max_index); - - col += 1; - }; - - return result.span(); - } - - let mut row: usize = 0; - loop { - if row == self.rows { - break; - } - - let mut max_value = self.get(row, 0); - let mut max_value = match max_value { - Option::Some => { max_value.unwrap() }, - Option::None => { NumberTrait::min_value() } - }; - let mut max_index = 0; - - let mut col: usize = 1; - loop { - if col == self.cols { - break; - } - - let mut value = self.get(row, col); - let mut value = match value { - Option::Some => { value.unwrap() }, - Option::None => { NumberTrait::min_value() } - }; - if value > max_value { - max_value = value; - max_index = col; - } - - col += 1; - }; - - result.append(max_index); - - row += 1; - }; - - return result.span(); - } - - /// Apply softmax to the matrix along the specified axis - fn softmax<+AddEq, +Div>(ref self: MutMatrix, axis: usize) -> MutMatrix { - assert(axis < 2, 'Invalid axis'); - - let mut result = MutMatrixImpl::new(self.rows, self.cols); - - if axis == 0 { - let mut col: usize = 0; - loop { - if col == self.cols { - break; - } - - let mut sum_exp = NumberTrait::zero(); - let mut row: usize = 0; - loop { - if row == self.rows { - break; - } - - let value = self.get(row, col).unwrap().into(); - sum_exp += value.exp(); - - row += 1; - }; - - row = 0; - loop { - if row == self.rows { - break; - } - - let value = self.get(row, col).unwrap().into(); - let softmax_value = (value.exp() / sum_exp).into(); - result.set(row, col, softmax_value); - - row += 1; - }; - - col += 1; - }; - } else { - let mut row: usize = 0; - loop { - if row == self.rows { - break; - } - - let mut sum_exp = NumberTrait::zero(); - let mut col: usize = 0; - loop { - if col == self.cols { - break; - } - - let value = self.get(row, col).unwrap().into(); - sum_exp += value.exp(); - - col += 1; - }; - - col = 0; - loop { - if col == self.cols { - break; - } - - let value = self.get(row, col).unwrap().into(); - let softmax_value = (value.exp() / sum_exp).into(); - result.set(row, col, softmax_value); - - col += 1; - }; - - row += 1; - }; - } - - result - } - - /// Apply softmax to the matrix along the specified axis, treating zeros as neutral - fn softmax_zero<+AddEq, +Div, +PartialEq>( - ref self: MutMatrix, axis: usize - ) -> MutMatrix { - assert(axis < 2, 'Invalid axis'); - - let mut result = MutMatrixImpl::new(self.rows, self.cols); - - if axis == 0 { - let mut col: usize = 0; - loop { - if col == self.cols { - break; - } - - let mut sum_exp = NumberTrait::zero(); - let mut row: usize = 0; - loop { - if row == self.rows { - break; - } - - let value = self.get(row, col).unwrap().into(); - if value != NumberTrait::zero() { - sum_exp += value.exp(); - } - row += 1; - }; - - row = 0; - loop { - if row == self.rows { - break; - } - - let value = self.get(row, col).unwrap().into(); - if value != NumberTrait::zero() { - let softmax_value = (value.exp() / sum_exp).into(); - result.set(row, col, softmax_value); - } else { - result.set(row, col, NumberTrait::zero()); - } - - row += 1; - }; - - col += 1; - }; - } else { - let mut row: usize = 0; - loop { - if row == self.rows { - break; - } - - let mut sum_exp = NumberTrait::zero(); - let mut col: usize = 0; - loop { - if col == self.cols { - break; - } - - let value = self.get(row, col).unwrap().into(); - if value != NumberTrait::zero() { - sum_exp += value.exp(); - } - col += 1; - }; - - col = 0; - loop { - if col == self.cols { - break; - } - - let value = self.get(row, col).unwrap().into(); - - if value != NumberTrait::zero() { - let softmax_value = (value.exp() / sum_exp).into(); - result.set(row, col, softmax_value); - } else { - result.set(row, col, NumberTrait::zero()); - } - - col += 1; - }; - - row += 1; - }; - } - - result - } - - /// Apply the sigmoid function to each element of the matrix - fn sigmoid<+Mul, +Add, +Div>(ref self: MutMatrix) -> MutMatrix { - let mut result = MutMatrixImpl::new(self.rows, self.cols); - - let mut row: usize = 0; - loop { - if row == self.rows { - break; - } - - let mut col: usize = 0; - loop { - if col == self.cols { - break; - } - - let value = self.get(row, col); - if value.is_some() { - let value = NumberTrait::one() - / (NumberTrait::one() + (value.unwrap() * NumberTrait::neg_one()).exp()); - - result.set(row, col, value); - } - - col += 1; - }; - - row += 1; - }; - - result - } - - fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { - - let n = X.rows; - let mut row: u32 = 0; - let mut col: u32 = 0; - let mut i = 0; - - loop { - if row == n { - break; - } - - // Find the row number and max row number for X - i = row + 1; - let mut max_row = row; - loop { - if i == n { - break; - } - if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { - max_row = i; - } - i += 1; - }; - - let mut X_row = MutMatrixImpl::new(1, X.cols); - let mut X_max_row = MutMatrixImpl::new(1, X.cols); - let mut y_row = y.get(row, 0).unwrap(); - let mut y_max_row = y.get(max_row, 0).unwrap(); - - // Store X_row and X_max_row - i = 0; - loop { - if i == n { - break; - } - - X_row.set(0, i, X.get(row, i).unwrap()); - X_max_row.set(0, i, X.get(max_row, i).unwrap()); - - i += 1; - }; - - // Interchange X_row with X_max_row, y_row with y_max_row - i = 0; - loop { - if i == n { - break; - } - - X.set(row, i, X_max_row.get(0, i).unwrap()); - X.set(max_row, i, X_row.get(0, i).unwrap()); - - i += 1; - }; - y.set(max_row, 0, y_row); - y.set(row, 0, y_max_row); - - // Check for singularity - assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); - - // Perform forward elimination - i = row + 1; - loop { - if i == n { - break; - } - let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); - let mut j = row; - loop { - if j == n { - break; - } - let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); - X.set(i, j, X_new_val); - - j += 1; - }; - let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); - y.set(i, 0, y_new_val); - - i += 1; - }; - - row += 1; - }; - - // Perform back substitution - let mut S = MutMatrixImpl::new(X.rows, 1); - i = 0; - loop { - if i == n { - break; - } - S.set(i, 1, FP16x16 { mag: 0, sign: false }); - i += 1; - }; - - i = n; - loop { - if i == 0 { - break; - } - let mut X_i = y.get(i - 1, 0).unwrap(); - let mut j = i; - loop { - if j == n { - break; - } - X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); - - j += 1; - }; - X_i /= X.get(i - 1, i - 1).unwrap(); - S.set(i - 1, 0, X_i); - - i -= 1; - }; - - return S; - } - - -} +mod matrix; \ No newline at end of file diff --git a/src/operators/matrix/matrix.cairo b/src/operators/matrix/matrix.cairo new file mode 100644 index 000000000..055fe73ae --- /dev/null +++ b/src/operators/matrix/matrix.cairo @@ -0,0 +1,440 @@ +use core::array::ArrayTrait; +use core::option::OptionTrait; +use orion::numbers::NumberTrait; +use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; +use orion::operators::tensor::{TensorTrait, Tensor}; + +struct MutMatrix { + data: NullableVec, + rows: usize, + cols: usize, +} + +impl MutMatrixDestruct> of Destruct> { + fn destruct(self: MutMatrix) nopanic { + self.data.destruct() + } +} + +#[generate_trait] +impl MutMatrixImpl< + T, MAG, +Drop, +Copy, +NumberTrait, +PartialOrd +> of MutMatrixTrait { + /// Constructor for the Matrix + fn new(rows: usize, cols: usize) -> MutMatrix { + MutMatrix { data: NullableVecImpl::new(), rows: rows, cols: cols } + } + + /// Get the value at (row, col) + fn get(ref self: MutMatrix, row: usize, col: usize) -> Option { + if row >= self.rows || col >= self.cols { + Option::None + } else { + self.data.get(row * self.cols + col) + } + } + + /// Set the value at (row, col) + fn set(ref self: MutMatrix, row: usize, col: usize, value: T) { + if row < self.rows && col < self.cols { + let index = row * self.cols + col; + self.data.set(index, value) + } + } + + /// Returns the shape of the matrix as (rows, cols) + fn shape(self: MutMatrix) -> (usize, usize) { + (self.rows, self.cols) + } + + /// Returns the reshaped matrix + fn reshape<+TensorTrait>(ref self: MutMatrix, target_shape: Span) -> MutMatrix { + let mut t = self.to_tensor(); + let mut result = t.reshape(target_shape); + return result.from_tensor(); + } + + /// Returns the transposed matrix + fn transpose<+TensorTrait>(ref self: MutMatrix, axes: Span) -> MutMatrix { + let mut t = self.to_tensor(); + let mut result = t.transpose(axes); + return result.from_tensor(); + } + + /// Returns the sum + fn reduce_sum<+TensorTrait>(ref self: MutMatrix, axis: usize, keepdims: bool) -> MutMatrix { + let mut t = self.to_tensor(); + let mut result = t.reduce_sum(axis, keepdims); + return result.from_tensor(); + } + + /// Returns the product of two matrices + fn matmul<+TensorTrait>(ref self: MutMatrix, ref other: MutMatrix) -> MutMatrix { + let mut t1 = self.to_tensor(); + let mut t2 = other.to_tensor(); + let mut result = t1.matmul(@t2); + return result.from_tensor(); + } + + /// Transforms a MutMatrix into a Tensor + fn to_tensor<+TensorTrait>(ref self: MutMatrix) -> Tensor { + let mut result_shape = ArrayTrait::::new(); + result_shape.append(self.rows); + result_shape.append(self.cols); + + let mut result_data = ArrayTrait::::new(); + + let mut i = 0; + loop { + if i == self.rows { + break; + } + let mut j = 0; + loop { + if j == self.cols { + break; + } + result_data.append(self.get(i, j).unwrap()); + j += 1; + }; + i += 1; + }; + + let mut result = TensorTrait::new(result_shape.span(), result_data.span()); + return result; + } + + /// Transforms a Tensor to a MutMatrix + fn from_tensor<+TensorTrait>(ref self: Tensor) -> MutMatrix { + let dim = self.shape.len(); + let result_rows = *self.shape.at(0); + let result_cols = if (dim == 1) { + 1 + } + else { + *self.shape.at(1) + }; + + let mut result: MutMatrix = MutMatrixTrait::::new(result_rows, result_cols); + + let mut i = 0; + loop { + if i == result_rows { + break; + } + let mut j = 0; + loop { + if j == result_cols { + break; + } + let mut val = if (dim == 1) { + self.at(array![i].span()) + } + else { + self.at(array![i, j].span()) + }; + result.set(i, j, val); + j += 1; + }; + i += 1; + }; + return result; + } + + /// Returns the index of the maximum value along the specified axis + fn argmax(ref self: MutMatrix, axis: usize) -> Span { + assert(axis < 2, 'Invalid axis'); + + let mut result: Array = ArrayTrait::new(); + if axis == 0 { + let mut col: usize = 0; + loop { + if col == self.cols { + break; + } + + let mut max_value = self.get(0, col); + let mut max_value = match max_value { + Option::Some => { max_value.unwrap() }, + Option::None => { NumberTrait::min_value() } + }; + let mut max_index = 0; + + let mut row: usize = 1; + loop { + if row == self.rows { + break; + } + + let mut value = self.get(row, col); + let mut value = match value { + Option::Some => { value.unwrap() }, + Option::None => { NumberTrait::min_value() } + }; + if value > max_value { + max_value = value; + max_index = row; + } + + row += 1; + }; + + result.append(max_index); + + col += 1; + }; + + return result.span(); + } + + let mut row: usize = 0; + loop { + if row == self.rows { + break; + } + + let mut max_value = self.get(row, 0); + let mut max_value = match max_value { + Option::Some => { max_value.unwrap() }, + Option::None => { NumberTrait::min_value() } + }; + let mut max_index = 0; + + let mut col: usize = 1; + loop { + if col == self.cols { + break; + } + + let mut value = self.get(row, col); + let mut value = match value { + Option::Some => { value.unwrap() }, + Option::None => { NumberTrait::min_value() } + }; + if value > max_value { + max_value = value; + max_index = col; + } + + col += 1; + }; + + result.append(max_index); + + row += 1; + }; + + return result.span(); + } + + /// Apply softmax to the matrix along the specified axis + fn softmax<+AddEq, +Div>(ref self: MutMatrix, axis: usize) -> MutMatrix { + assert(axis < 2, 'Invalid axis'); + + let mut result = MutMatrixImpl::new(self.rows, self.cols); + + if axis == 0 { + let mut col: usize = 0; + loop { + if col == self.cols { + break; + } + + let mut sum_exp = NumberTrait::zero(); + let mut row: usize = 0; + loop { + if row == self.rows { + break; + } + + let value = self.get(row, col).unwrap().into(); + sum_exp += value.exp(); + + row += 1; + }; + + row = 0; + loop { + if row == self.rows { + break; + } + + let value = self.get(row, col).unwrap().into(); + let softmax_value = (value.exp() / sum_exp).into(); + result.set(row, col, softmax_value); + + row += 1; + }; + + col += 1; + }; + } else { + let mut row: usize = 0; + loop { + if row == self.rows { + break; + } + + let mut sum_exp = NumberTrait::zero(); + let mut col: usize = 0; + loop { + if col == self.cols { + break; + } + + let value = self.get(row, col).unwrap().into(); + sum_exp += value.exp(); + + col += 1; + }; + + col = 0; + loop { + if col == self.cols { + break; + } + + let value = self.get(row, col).unwrap().into(); + let softmax_value = (value.exp() / sum_exp).into(); + result.set(row, col, softmax_value); + + col += 1; + }; + + row += 1; + }; + } + + result + } + + /// Apply softmax to the matrix along the specified axis, treating zeros as neutral + fn softmax_zero<+AddEq, +Div, +PartialEq>( + ref self: MutMatrix, axis: usize + ) -> MutMatrix { + assert(axis < 2, 'Invalid axis'); + + let mut result = MutMatrixImpl::new(self.rows, self.cols); + + if axis == 0 { + let mut col: usize = 0; + loop { + if col == self.cols { + break; + } + + let mut sum_exp = NumberTrait::zero(); + let mut row: usize = 0; + loop { + if row == self.rows { + break; + } + + let value = self.get(row, col).unwrap().into(); + if value != NumberTrait::zero() { + sum_exp += value.exp(); + } + row += 1; + }; + + row = 0; + loop { + if row == self.rows { + break; + } + + let value = self.get(row, col).unwrap().into(); + if value != NumberTrait::zero() { + let softmax_value = (value.exp() / sum_exp).into(); + result.set(row, col, softmax_value); + } else { + result.set(row, col, NumberTrait::zero()); + } + + row += 1; + }; + + col += 1; + }; + } else { + let mut row: usize = 0; + loop { + if row == self.rows { + break; + } + + let mut sum_exp = NumberTrait::zero(); + let mut col: usize = 0; + loop { + if col == self.cols { + break; + } + + let value = self.get(row, col).unwrap().into(); + if value != NumberTrait::zero() { + sum_exp += value.exp(); + } + col += 1; + }; + + col = 0; + loop { + if col == self.cols { + break; + } + + let value = self.get(row, col).unwrap().into(); + + if value != NumberTrait::zero() { + let softmax_value = (value.exp() / sum_exp).into(); + result.set(row, col, softmax_value); + } else { + result.set(row, col, NumberTrait::zero()); + } + + col += 1; + }; + + row += 1; + }; + } + + result + } + + /// Apply the sigmoid function to each element of the matrix + fn sigmoid<+Mul, +Add, +Div>(ref self: MutMatrix) -> MutMatrix { + let mut result = MutMatrixImpl::new(self.rows, self.cols); + + let mut row: usize = 0; + loop { + if row == self.rows { + break; + } + + let mut col: usize = 0; + loop { + if col == self.cols { + break; + } + + let value = self.get(row, col); + if value.is_some() { + let value = NumberTrait::one() + / (NumberTrait::one() + (value.unwrap() * NumberTrait::neg_one()).exp()); + + result.set(row, col, value); + } + + col += 1; + }; + + row += 1; + }; + + result + } + +} diff --git a/src/operators/matrix/matrix_linalg.cairo b/src/operators/matrix/matrix_linalg.cairo new file mode 100644 index 000000000..ff66c7262 --- /dev/null +++ b/src/operators/matrix/matrix_linalg.cairo @@ -0,0 +1,158 @@ +use core::array::ArrayTrait; +use core::option::OptionTrait; +use orion::numbers::NumberTrait; +use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; +use orion::operators::tensor::{TensorTrait, Tensor}; +use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; + +fn diagonalize(ref X: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols == 1, 'X not row vector'); + + let mut i = 0; + let mut result = MutMatrixImpl::::new(X.rows, X.rows); + loop { + if i == X.rows { + break; + } + let mut j = 0; + loop { + if j == X.rows { + break; + } + if i == j { + result.set(i, j, X.get(i, 0).unwrap()); + } + else { + result.set(i, j, FixedTrait::::new(0, false)); + } + j += 1; + }; + i += 1; + }; + return result; +} + +fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { + + let n = X.rows; + let mut row: u32 = 0; + let mut col: u32 = 0; + let mut i = 0; + + loop { + if row == n { + break; + } + + // Find the row number and max row number for X + i = row + 1; + let mut max_row = row; + loop { + if i == n { + break; + } + if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { + max_row = i; + } + i += 1; + }; + + let mut X_row = MutMatrixImpl::new(1, X.cols); + let mut X_max_row = MutMatrixImpl::new(1, X.cols); + let mut y_row = y.get(row, 0).unwrap(); + let mut y_max_row = y.get(max_row, 0).unwrap(); + + // Store X_row and X_max_row + i = 0; + loop { + if i == n { + break; + } + + X_row.set(0, i, X.get(row, i).unwrap()); + X_max_row.set(0, i, X.get(max_row, i).unwrap()); + + i += 1; + }; + + // Interchange X_row with X_max_row, y_row with y_max_row + i = 0; + loop { + if i == n { + break; + } + + X.set(row, i, X_max_row.get(0, i).unwrap()); + X.set(max_row, i, X_row.get(0, i).unwrap()); + + i += 1; + }; + y.set(max_row, 0, y_row); + y.set(row, 0, y_max_row); + + // Check for singularity + assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); + + // Perform forward elimination + i = row + 1; + loop { + if i == n { + break; + } + let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); + let mut j = row; + loop { + if j == n { + break; + } + let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); + X.set(i, j, X_new_val); + + j += 1; + }; + let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); + y.set(i, 0, y_new_val); + + i += 1; + }; + + row += 1; + }; + + // Perform back substitution + let mut S = MutMatrixImpl::new(X.rows, 1); + i = 0; + loop { + if i == n { + break; + } + S.set(i, 1, FP16x16 { mag: 0, sign: false }); + i += 1; + }; + + i = n; + loop { + if i == 0 { + break; + } + let mut X_i = y.get(i - 1, 0).unwrap(); + let mut j = i; + loop { + if j == n { + break; + } + X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); + + j += 1; + }; + X_i /= X.get(i - 1, i - 1).unwrap(); + S.set(i - 1, 0, X_i); + + i -= 1; + }; + + return S; + } \ No newline at end of file diff --git a/src/operators/matrix/matrix_statistics.cairo b/src/operators/matrix/matrix_statistics.cairo new file mode 100644 index 000000000..1c15c32dd --- /dev/null +++ b/src/operators/matrix/matrix_statistics.cairo @@ -0,0 +1,337 @@ +use core::array::ArrayTrait; +use core::option::OptionTrait; +use orion::numbers::NumberTrait; +use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; +use orion::operators::tensor::{TensorTrait, Tensor}; +use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; + +fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { + let lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); + let mut weights = MutMatrixImpl::::new(l, 1); + let mut i = 0; + loop { + if i == l { + break; + } + let mut l_i = FixedTrait::::new_unscaled(i, false); + let mut l_pow = FixedTrait::pow(lambda, l_i); + let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * l_pow; + weights.set(i, 0, w_i); + i += 1; + }; + return weights; +} + +fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { + // Simple average case for a matrix along specified axis + // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 + + assert(axis == 0 || axis == 1, 'Wrong axis'); + + // Simple average case for a vector + // Returns a matrix with shape (1,1) + if X.cols == 1 || X.rows == 1 { + + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; + + let den = FixedTrait::::new_unscaled(X.data.len(), false); + + if X.cols == 1 && X.rows == 1 { + result.set(0, 0, X.get(0, 0).unwrap()); + return result; + } + else { + let l = if (X.rows > 1) { + X.rows + } + else { + X.cols + }; + loop { + if i == l { + break; + } + let mut num_i = if (X.rows > 1) { + X.get(i, 0).unwrap() + } + else { + X.get(0, i).unwrap() + }; + num += num_i; + i += 1; + }; + result.set(0, 0, num / den); + } + + return result; + } + + // Matrix average along specified axis + // Returns a vector with shape=(X.rows, 1) if axis == 0 or shape=(1, X.cols) if axis == 1 + else { + // Average along rows + if axis == 0 { + let mut result = MutMatrixImpl::::new(X.rows, 1); + let den = FixedTrait::::new_unscaled(X.cols, false); + let mut row = 0; + + loop { + if row == X.rows { + break; + } + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; + loop { + if col == X.cols { + break; + } + row_num += X.get(row, col).unwrap(); + col += 1; + }; + result.set(row, 0, row_num / den); + row += 1; + }; + + return result; + } + + // Average along columns + else { + let mut result = MutMatrixImpl::::new(1, X.cols); + let den = FixedTrait::::new_unscaled(X.rows, false); + let mut col = 0; + + loop { + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; + loop { + if row == X.rows { + break; + } + col_num += X.get(row, col).unwrap(); + row += 1; + }; + result.set(0, col, col_num / den); + col += 1; + }; + + return result; + } + } +} + +fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix { + // Weighted average + // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 + + // Weight assertions + if X.rows > 1 { + assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); + } + else { + assert(weights.cols == X.cols && weights.rows == 1, 'Weights shape mismatch'); + } + + // Vector case + if X.rows == 1 || X.cols == 1 { + + assert(X.rows != X.cols, '1 element input'); + + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; + + let den = FixedTrait::::new_unscaled(X.data.len(), false); + + let l = if (X.rows > 1) { + X.rows + } + else { + X.cols + }; + + loop { + if i == l { + break; + } + let mut num_i = if (X.rows > 1) { + X.get(i, 0).unwrap() * weights.get(i, 0).unwrap() + } + else { + X.get(0, i).unwrap() * weights.get(0, i).unwrap() + }; + num += num_i; + i += 1; + }; + result.set(0, 0, num / den); + + return result; + } + + // Matrix case + else { + assert(axis == 0 || axis == 1, 'Wrong axis'); + + // Average along rows + if axis == 0 { + + let mut result = MutMatrixImpl::::new(X.rows, 1); + let mut row = 0; + + loop { + if row == X.rows { + break; + } + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; + loop { + if col == X.cols { + break; + } + row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); + col += 1; + }; + result.set(row, 0, row_num); + row += 1; + }; + + return result; + } + + // Average along columns + else { + let mut result = MutMatrixImpl::::new(1, X.cols); + let mut col = 0; + + loop { + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; + loop { + if row == X.rows { + break; + } + col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); + row += 1; + }; + result.set(0, col, col_num); + col += 1; + }; + + return result; + } + } +} + +fn covariance(ref X: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); + + let m = X.rows; // Num observations + let n = X.cols; // Num variables + let mut Cov_X = MutMatrixImpl::::new(n, n); + let mut Mean_X = mean(ref X, 1); + + let mut i = 0; + loop { + if i == n { + break; + } + let mut j = 0; + loop { + if j == n { + break; + } + let mut k = 0; + let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + loop { + if k == m { + break; + } + Cov_X_i_j += ((X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); + k += 1; + }; + Cov_X_i_j /= FixedTrait::::new_unscaled(m - 1, false); + Cov_X.set(i, j, Cov_X_i_j); + Cov_X.set(j, i, Cov_X_i_j); + j += 1; + }; + i += 1; + }; + + return Cov_X; +} + +fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); + assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); + + // Normalize weights + let mut normalized_weights = MutMatrixImpl::::new(weights.rows, 1); + let mut total_weight = weights.reduce_sum(0, false); + let mut i = 0; + loop { + if i == weights.rows { + break; + } + let w_i = weights.get(i, 0).unwrap(); + normalized_weights.set(i, 0, w_i / total_weight.get(0, 0).unwrap()); + i += 1; + }; + + let m = X.rows; // Num observations + let n = X.cols; // Num variables + let mut Cov_X = MutMatrixImpl::::new(n, n); + let mut Mean_X = mean_weighted(ref X, ref weights, 1); + + let mut adj_weight_sum = FixedTrait::::new_unscaled(0, false); + i = 0; + loop { + if i == normalized_weights.rows { + break; + } + let mut w_i = normalized_weights.get(i, 0).unwrap(); + adj_weight_sum += (w_i * w_i); + i += 1; + }; + + i = 0; + loop { + if i == n { + break; + } + let mut j = 0; + loop { + if j == n { + break; + } + let mut k = 0; + let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + loop { + if k == m { + break; + } + Cov_X_i_j += (normalized_weights.get(k, 0).unwrap() * (X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); + k += 1; + }; + let mut den = FixedTrait::::new_unscaled(1, false) - adj_weight_sum; + Cov_X_i_j /= den; + Cov_X.set(i, j, Cov_X_i_j); + Cov_X.set(j, i, Cov_X_i_j); + j += 1; + }; + i += 1; + }; + + return Cov_X; +} + diff --git a/src/operators/ml/tree_ensemble/tree_ensemble_classifier.cairo b/src/operators/ml/tree_ensemble/tree_ensemble_classifier.cairo index 051965260..b199e07e9 100644 --- a/src/operators/ml/tree_ensemble/tree_ensemble_classifier.cairo +++ b/src/operators/ml/tree_ensemble/tree_ensemble_classifier.cairo @@ -3,7 +3,7 @@ use core::clone::Clone; use core::box::BoxTrait; use core::traits::Into; use core::option::OptionTrait; -use orion::operators::matrix::MutMatrixTrait; +use orion::operators::matrix::matrix::MutMatrixTrait; use core::array::SpanTrait; use core::nullable::NullableTrait; use core::dict::Felt252DictTrait; @@ -18,7 +18,7 @@ use orion::utils::get_row; use alexandria_merkle_tree::merkle_tree::{pedersen::PedersenHasherImpl}; use alexandria_data_structures::array_ext::{SpanTraitExt}; -use orion::operators::matrix::{MutMatrix, MutMatrixImpl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixImpl}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use core::debug::PrintTrait; diff --git a/src/operators/ml/tree_ensemble/tree_ensemble_regressor.cairo b/src/operators/ml/tree_ensemble/tree_ensemble_regressor.cairo index 9848efd9e..f24120673 100644 --- a/src/operators/ml/tree_ensemble/tree_ensemble_regressor.cairo +++ b/src/operators/ml/tree_ensemble/tree_ensemble_regressor.cairo @@ -3,7 +3,7 @@ use core::clone::Clone; use core::box::BoxTrait; use core::traits::Into; use core::option::OptionTrait; -use orion::operators::matrix::MutMatrixTrait; +use orion::operators::matrix::matrix::MutMatrixTrait; use core::array::SpanTrait; use core::nullable::NullableTrait; use core::dict::Felt252DictTrait; @@ -19,7 +19,7 @@ use orion::utils::get_row; use alexandria_merkle_tree::merkle_tree::{pedersen::PedersenHasherImpl}; use alexandria_data_structures::array_ext::{SpanTraitExt}; -use orion::operators::matrix::{MutMatrix, MutMatrixImpl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixImpl}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use core::debug::PrintTrait; diff --git a/src/operators/tensor/manipulation/split.cairo b/src/operators/tensor/manipulation/split.cairo index bf0274aec..59f1f6501 100644 --- a/src/operators/tensor/manipulation/split.cairo +++ b/src/operators/tensor/manipulation/split.cairo @@ -1,7 +1,7 @@ use orion::operators::tensor::{Tensor, TensorTrait, U32Tensor}; use core::array::{ArrayTrait, SpanTrait}; use core::option::OptionTrait; -use orion::operators::matrix::{MutMatrixTrait, MutMatrix, MutMatrixImpl}; +use orion::operators::matrix::matrix::{MutMatrixTrait, MutMatrix, MutMatrixImpl}; /// Cf: NNTrait::split docstring fn split< diff --git a/tests/operators/linalg_test.cairo b/tests/operators/linalg_test.cairo deleted file mode 100644 index 7261d3c9d..000000000 --- a/tests/operators/linalg_test.cairo +++ /dev/null @@ -1,67 +0,0 @@ -use core::array::{ArrayTrait, SpanTrait}; -use core::debug::PrintTrait; -use core::option::OptionTrait; -use orion::numbers::NumberTrait; -use orion::numbers::fixed_point::implementations::fp16x16::math::core::{abs}; -use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; -use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; -use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; -use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; - -fn test_matrix(ref X: MutMatrix) { - // Print X by columns - let mut c = 0; - loop { - if c == X.cols { - break (); - } - let mut r = 0; - loop { - if r == X.rows { - break; - } - let mut val = X.get(r, c).unwrap(); - val.print(); - r += 1; - }; - c += 1; - }; - } - -#[test] -#[available_gas(99999999999999999)] -fn linalg_test() { - let mut X = MutMatrixTrait::::new(rows: 3, cols: 3); - X.set(0, 0, FP16x16 { mag: 131072, sign: false }); // 2 - X.set(0, 1, FP16x16 { mag: 65536, sign: false }); // 1 - X.set(0, 2, FP16x16 { mag: 65536, sign: true }); // -1 - X.set(1, 0, FP16x16 { mag: 196608, sign: true }); // -3 - X.set(1, 1, FP16x16 { mag: 65536, sign: true }); // -1 - X.set(1, 2, FP16x16 { mag: 131072, sign: false }); // 2 - X.set(2, 0, FP16x16 { mag: 131072, sign: true }); // -2 - X.set(2, 1, FP16x16 { mag: 65536, sign: false }); // 1 - X.set(2, 2, FP16x16 { mag: 131072, sign: false }); // 1 - - let mut y = MutMatrixTrait::::new(rows: 3, cols: 1); - y.set(0, 0, FP16x16 { mag: 524288, sign: false }); // 8 - y.set(0, 1, FP16x16 { mag: 720896, sign: true }); // -11 - y.set(0, 2, FP16x16 { mag: 196608, sign: true }); // -3 - - let mut S = linalg_solve(ref X, ref y); - // S = [2, 3, -1] - - assert(S.rows == X.rows, 'Wrong num of rows'); - assert(S.cols == 1, 'Wrong num of cols'); - - // Check mags - let threshold = FP16x16 {mag: 100, sign: false}; // ~0.00153 error threshold - assert(abs(S.get(0, 0).unwrap() - FP16x16 {mag: 131072, sign: false}) <= threshold , 'S_0 mag is wrong'); - assert(abs(S.get(1, 0).unwrap() - FP16x16 {mag: 196608, sign: false}) <= threshold, 'S_1 mag is wrong'); - assert(abs(S.get(2, 0).unwrap() - FP16x16 {mag: 65536, sign: true}) <= threshold, 'S_2 mag is wrong'); - - // Check signs - assert(S.get(0, 0).unwrap().sign == false, 'S_1 sign is wrong'); - assert(S.get(1, 0).unwrap().sign == false, 'S_2 sign is wrong'); - assert(S.get(2, 0).unwrap().sign == true, 'S_3 sign is wrong'); - -} \ No newline at end of file diff --git a/tests/operators/matrix/matrix_linalg_test.cairo b/tests/operators/matrix/matrix_linalg_test.cairo new file mode 100644 index 000000000..93b499633 --- /dev/null +++ b/tests/operators/matrix/matrix_linalg_test.cairo @@ -0,0 +1,54 @@ +#[cfg(test)] +mod matrix_linalg { + + use core::array::{ArrayTrait, SpanTrait}; + use core::option::OptionTrait; + use orion::numbers::NumberTrait; + use orion::numbers::fixed_point::implementations::fp16x16::math::core::{abs}; + use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; + use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; + use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; + use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; + use orion::operators::matrix::matrix_linalg::linalg_solve; + + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + + #[test] + #[available_gas(99999999999999999)] + fn matrix_linalg_test() { + let mut X = MutMatrixTrait::::new(3, 3); + X.set(0, 0, FixedTrait::::new_unscaled(2, false)); + X.set(0, 1, FixedTrait::::new_unscaled(1, false)); + X.set(0, 2, FixedTrait::::new_unscaled(1, true)); + X.set(1, 0, FixedTrait::::new_unscaled(3, true)); + X.set(1, 1, FixedTrait::::new_unscaled(1, true)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(2, true)); + X.set(2, 1, FixedTrait::::new_unscaled(1, false)); + X.set(2, 2, FixedTrait::::new_unscaled(1, false)); + + let mut Y = MutMatrixTrait::::new(3, 1); + Y.set(0, 0, FixedTrait::::new_unscaled(8, false)); + Y.set(0, 1, FixedTrait::::new_unscaled(11, true)); + Y.set(0, 2, FixedTrait::::new_unscaled(3, true)); + + let mut S = linalg_solve(ref X, ref Y); + + // Solution = [2, 3, -1] + + assert(S.rows == X.rows, 'Wrong num of rows'); + assert(S.cols == 1, 'Wrong num of cols'); + + // Check mags + assert(FixedTrait::abs(S.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'S_1 mag incorrect'); // ~2 + assert(FixedTrait::abs(S.get(1, 0).unwrap() - FixedTrait::::new_unscaled(3, false)) < ERROR_THRESHOLD, 'S_2 mag incorrect'); // ~3 + assert(FixedTrait::abs(S.get(2, 0).unwrap() - FixedTrait::::new_unscaled(1, true)) < ERROR_THRESHOLD, 'S_3 mag incorrect'); // ~-1 + + // Check signs + assert(S.get(0, 0).unwrap().sign == false, 'S_1 sign incorrect'); + assert(S.get(1, 0).unwrap().sign == false, 'S_2 sign incorrect'); + assert(S.get(2, 0).unwrap().sign == true, 'S_3 sign incorrect'); + + } + +} \ No newline at end of file diff --git a/tests/operators/matrix/matrix_statistics_test.cairo b/tests/operators/matrix/matrix_statistics_test.cairo new file mode 100644 index 000000000..983c11cb7 --- /dev/null +++ b/tests/operators/matrix/matrix_statistics_test.cairo @@ -0,0 +1,229 @@ +#[cfg(test)] +mod matrix_statistics { + use core::array::ArrayTrait; + use core::option::OptionTrait; + use orion::numbers::NumberTrait; + use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; + use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; + use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; + use orion::operators::tensor::{TensorTrait, Tensor}; + use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; + use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; + use orion::operators::matrix::matrix_statistics::{exponential_weights, mean, mean_weighted, covariance, covariance_weighted}; + + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + + #[test] + #[available_gas(2000000000)] + fn exponential_weights_test { + let mut X = exponential_weights(97, 3); + + assert(X.rows == 3 && X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1967, false)) < ERROR_THRESHOLD, 'X_1 incorrect'); // ~0.300 + assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1907, false)) < ERROR_THRESHOLD, 'X_2 incorrect'); // ~0.029 + assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1850, false)) < ERROR_THRESHOLD, 'X_3 incorrect'); // ~0.028 + } + + #[test] + #[available_gas(2000000000)] + fn 1D_mean_test { + + let mut X = MutMatrixImpl::::new(3,1); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(1, false)); + X.set(2, 0, FixedTrait::::new_unscaled(1, false)); + + let mut mu_X = mean(ref X, 0); + + assert(mu_X.rows == 1 & mu_X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'mean_X incorrect'); + } + + #[test] + #[available_gas(2000000000)] + fn 2D_mean_test_i { + + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut mu_X = mean(ref X, 0); + + assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(174762, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.67 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(218453, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~3.33 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(305834, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.67 + assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(349525, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~5.33 + } + + #[test] + #[available_gas(2000000000)] + fn 2D_mean_test_ii { + + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut mu_X = mean(ref X, 1); + + assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 + } + + #[test] + #[available_gas(2000000000)] + fn 2D_mean_weighted_test_i { + + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixImpl::::new(4,1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.7 + + let mut mu_X = mean_weighted(ref X, ref weights, 0); + + assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163839, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(183500, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~2.8 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(294911, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.5 + assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(314572, false)) < ERROR_THRESHOLD, 'mean_X_4 incorrect'); // ~4.8 + } + + #[test] + #[available_gas(2000000000)] + fn 2D_mean_weighted_test_ii { + + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixImpl::::new(4,1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 + weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + + let mut mu_X = mean_weighted(ref X, ref weights, 1); + + assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 + } + + #[test] + #[available_gas(2000000000)] + fn covariance_test { + + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut sigma2_X = covariance(ref X); + + assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 + } + + #[test] + #[available_gas(2000000000)] + fn covariance_weighted_test { + + let mut X = MutMatrixImpl::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixImpl::::new(4,1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 + weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + + let mut sigma2_X = covariance_weighted(ref X, ref weights); + + assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 + } + +} \ No newline at end of file From 49e7ba8d882abe53f1d9e29577871479d569669a Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Sun, 25 Feb 2024 23:59:17 +0200 Subject: [PATCH 11/16] Updates --- src/lib.cairo | 2 - src/operators/matrix.cairo | 4 +- src/operators/matrix/matrix_linalg.cairo | 306 +++++++++++------- tests/ml/tree_ensemble_classifier.cairo | 2 +- tests/ml/tree_ensemble_regressor.cairo | 2 +- tests/operators.cairo | 2 + .../operators/matrix/matrix_linalg_test.cairo | 54 ---- .../matrix/matrix_statistics_test.cairo | 229 ------------- tests/operators/matrix_linalg_test.cairo | 44 +++ tests/operators/matrix_statistics_test.cairo | 226 +++++++++++++ 10 files changed, 475 insertions(+), 396 deletions(-) delete mode 100644 tests/operators/matrix/matrix_linalg_test.cairo delete mode 100644 tests/operators/matrix/matrix_statistics_test.cairo create mode 100644 tests/operators/matrix_linalg_test.cairo create mode 100644 tests/operators/matrix_statistics_test.cairo diff --git a/src/lib.cairo b/src/lib.cairo index efc3821cd..a44be4aee 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -640,6 +640,4 @@ fn main() { // X.cols.print(); // test_matrix(ref X); - 'S_1 sign incorrect'.print(); - } \ No newline at end of file diff --git a/src/operators/matrix.cairo b/src/operators/matrix.cairo index 6c2401df9..d64a31baf 100644 --- a/src/operators/matrix.cairo +++ b/src/operators/matrix.cairo @@ -1 +1,3 @@ -mod matrix; \ No newline at end of file +mod matrix; +mod matrix_linalg; +mod matrix_statistics; \ No newline at end of file diff --git a/src/operators/matrix/matrix_linalg.cairo b/src/operators/matrix/matrix_linalg.cairo index ff66c7262..51bd94428 100644 --- a/src/operators/matrix/matrix_linalg.cairo +++ b/src/operators/matrix/matrix_linalg.cairo @@ -8,151 +8,241 @@ use orion::operators::tensor::{TensorTrait, Tensor}; use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; -fn diagonalize(ref X: MutMatrix) -> MutMatrix { - assert(X.rows > 1 && X.cols == 1, 'X not row vector'); - - let mut i = 0; - let mut result = MutMatrixImpl::::new(X.rows, X.rows); - loop { - if i == X.rows { - break; - } - let mut j = 0; - loop { - if j == X.rows { - break; - } - if i == j { - result.set(i, j, X.get(i, 0).unwrap()); - } - else { - result.set(i, j, FixedTrait::::new(0, false)); - } - j += 1; - }; - i += 1; - }; - return result; +/// Trait +trait MatrixLinalgTrait { + /// # MatrixLinalgTrait::diagonalize + /// + /// ```rust + /// fn diagonalize(ref X: MutMatrix) -> MutMatrix; + /// ``` + /// + /// ## Args + /// + /// * `X`: Input 1D vector + /// + /// ## Returns + /// + /// * 2D diagonal matrix. + /// + /// ## Type Constraints + /// + /// X must be FP16x16 valued. + /// + /// ## Examples + /// let mut X = MutMatrixImpl::::new(3, 1); + /// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + /// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + /// let mut diag_X = diagonalize(ref X); + /// Output: + /// [[FP16x16 { mag: 65536, sign: false }, 0, 0], [0, FP16x16 { mag: 13107, sign: false }, 0], [0, 0, FP16x16 { mag: 196608, sign: false }]] + + fn diagonalize(ref X: MutMatrix) -> MutMatrix; + + /// # MatrixLinalgTrait::linalg_solve + /// + /// ```rust + /// fn(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix; + /// ``` + /// + /// ## Args + /// + /// * `X`: Input 2D MutMatrix + /// * `y`: Input 1D vector + /// + /// ## Returns + /// + /// * 1D solution vector + /// + /// ## Type Constraints + /// + /// X, y must be FP16x16 valued. + /// + /// ## Examples + /// let mut X = MutMatrixTrait::::new(3, 3); + /// X.set(0, 0, FixedTrait::::new_unscaled(2, false)); + /// X.set(0, 1, FixedTrait::::new_unscaled(1, false)); + /// X.set(0, 2, FixedTrait::::new_unscaled(1, true)); + /// X.set(1, 0, FixedTrait::::new_unscaled(3, true)); + /// X.set(1, 1, FixedTrait::::new_unscaled(1, true)); + /// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 0, FixedTrait::::new_unscaled(2, true)); + /// X.set(2, 1, FixedTrait::::new_unscaled(1, false)); + /// X.set(2, 2, FixedTrait::::new_unscaled(1, false)); + /// let mut Y = MutMatrixTrait::::new(3, 1); + /// Y.set(0, 0, FixedTrait::::new_unscaled(8, false)); + /// Y.set(0, 1, FixedTrait::::new_unscaled(11, true)); + /// Y.set(0, 2, FixedTrait::::new_unscaled(3, true)); + /// let mut S = linalg_solve(ref X, ref Y); + /// Output: + /// [FP16x16 { mag: 131072, sign: false }, FP16x16 { mag: 196608, sign: false }, FP16x16 { mag: 65536, sign: true }] + + fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix; } -fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { - - let n = X.rows; - let mut row: u32 = 0; - let mut col: u32 = 0; - let mut i = 0; +impl MatrixLinalgImpl< + FP16x16, + MAG, + +Drop, + +Copy, + +NumberTrait, + +PartialOrd, + +FixedTrait, + +MutMatrix, + +Add, + +AddEq, + +Sub, + +SubEq, + +Mul, + +MulEq, + +Div, + +DivEq> of MatrixLinalgTrait { + fn diagonalize(ref X: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols == 1, 'X not row vector'); + let mut i = 0; + let mut result = MutMatrixImpl::::new(X.rows, X.rows); loop { - if row == n { + if i == X.rows { break; } - - // Find the row number and max row number for X - i = row + 1; - let mut max_row = row; + let mut j = 0; loop { - if i == n { + if j == X.rows { break; } - if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { - max_row = i; + if i == j { + result.set(i, j, X.get(i, 0).unwrap()); } - i += 1; + else { + result.set(i, j, FixedTrait::new(0, false)); + } + j += 1; }; + i += 1; + }; + return result; + } - let mut X_row = MutMatrixImpl::new(1, X.cols); - let mut X_max_row = MutMatrixImpl::new(1, X.cols); - let mut y_row = y.get(row, 0).unwrap(); - let mut y_max_row = y.get(max_row, 0).unwrap(); + fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { + + let n = X.rows; + let mut row: u32 = 0; + let mut col: u32 = 0; + let mut i = 0; - // Store X_row and X_max_row - i = 0; loop { - if i == n { + if row == n { break; } + + // Find the row number and max row number for X + i = row + 1; + let mut max_row = row; + loop { + if i == n { + break; + } + if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { + max_row = i; + } + i += 1; + }; - X_row.set(0, i, X.get(row, i).unwrap()); - X_max_row.set(0, i, X.get(max_row, i).unwrap()); + let mut X_row = MutMatrixImpl::new(1, X.cols); + let mut X_max_row = MutMatrixImpl::new(1, X.cols); + let mut y_row = y.get(row, 0).unwrap(); + let mut y_max_row = y.get(max_row, 0).unwrap(); - i += 1; + // Store X_row and X_max_row + i = 0; + loop { + if i == n { + break; + } + + X_row.set(0, i, X.get(row, i).unwrap()); + X_max_row.set(0, i, X.get(max_row, i).unwrap()); + + i += 1; + }; + + // Interchange X_row with X_max_row, y_row with y_max_row + i = 0; + loop { + if i == n { + break; + } + + X.set(row, i, X_max_row.get(0, i).unwrap()); + X.set(max_row, i, X_row.get(0, i).unwrap()); + + i += 1; + }; + y.set(max_row, 0, y_row); + y.set(row, 0, y_max_row); + + // Check for singularity + assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); + + // Perform forward elimination + i = row + 1; + loop { + if i == n { + break; + } + let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); + let mut j = row; + loop { + if j == n { + break; + } + let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); + X.set(i, j, X_new_val); + + j += 1; + }; + let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); + y.set(i, 0, y_new_val); + + i += 1; + }; + + row += 1; }; - // Interchange X_row with X_max_row, y_row with y_max_row + // Perform back substitution + let mut S = MutMatrixImpl::new(X.rows, 1); i = 0; loop { if i == n { break; } - - X.set(row, i, X_max_row.get(0, i).unwrap()); - X.set(max_row, i, X_row.get(0, i).unwrap()); - + S.set(i, 1, FP16x16 { mag: 0, sign: false }); i += 1; }; - y.set(max_row, 0, y_row); - y.set(row, 0, y_max_row); - - // Check for singularity - assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); - // Perform forward elimination - i = row + 1; + i = n; loop { - if i == n { + if i == 0 { break; } - let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); - let mut j = row; + let mut X_i = y.get(i - 1, 0).unwrap(); + let mut j = i; loop { if j == n { break; } - let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); - X.set(i, j, X_new_val); - + X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); + j += 1; }; - let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); - y.set(i, 0, y_new_val); + X_i /= X.get(i - 1, i - 1).unwrap(); + S.set(i - 1, 0, X_i); - i += 1; + i -= 1; }; - - row += 1; - }; - // Perform back substitution - let mut S = MutMatrixImpl::new(X.rows, 1); - i = 0; - loop { - if i == n { - break; - } - S.set(i, 1, FP16x16 { mag: 0, sign: false }); - i += 1; - }; - - i = n; - loop { - if i == 0 { - break; - } - let mut X_i = y.get(i - 1, 0).unwrap(); - let mut j = i; - loop { - if j == n { - break; - } - X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); - - j += 1; - }; - X_i /= X.get(i - 1, i - 1).unwrap(); - S.set(i - 1, 0, X_i); - - i -= 1; - }; - - return S; - } \ No newline at end of file + return S; + } +} \ No newline at end of file diff --git a/tests/ml/tree_ensemble_classifier.cairo b/tests/ml/tree_ensemble_classifier.cairo index 441aabb34..5d3460a2a 100644 --- a/tests/ml/tree_ensemble_classifier.cairo +++ b/tests/ml/tree_ensemble_classifier.cairo @@ -5,7 +5,7 @@ use orion::operators::ml::tree_ensemble::tree_ensemble_classifier::{ TreeEnsembleClassifier, POST_TRANSFORM, TreeEnsembleClassifierTrait }; use orion::operators::tensor::implementations::tensor_fp16x16::relative_eq; -use orion::operators::matrix::{MutMatrix, MutMatrixImpl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixImpl}; #[test] #[available_gas(200000000000)] diff --git a/tests/ml/tree_ensemble_regressor.cairo b/tests/ml/tree_ensemble_regressor.cairo index 2ee505774..ba1bbc9cb 100644 --- a/tests/ml/tree_ensemble_regressor.cairo +++ b/tests/ml/tree_ensemble_regressor.cairo @@ -4,7 +4,7 @@ use orion::operators::ml::tree_ensemble::core::{NODE_MODES, TreeEnsembleAttribut use orion::operators::ml::tree_ensemble::tree_ensemble_regressor::{ TreeEnsembleRegressor, POST_TRANSFORM, TreeEnsembleRegressorTrait, AGGREGATE_FUNCTION }; -use orion::operators::matrix::{MutMatrix, MutMatrixImpl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixImpl}; use orion::operators::tensor::implementations::tensor_fp16x16::relative_eq; use core::debug::PrintTrait; diff --git a/tests/operators.cairo b/tests/operators.cairo index d02bf25a4..d4b81ff27 100644 --- a/tests/operators.cairo +++ b/tests/operators.cairo @@ -4,3 +4,5 @@ mod qlinear_concat_test; mod qlinear_add_test; mod constant_of_shape_test; mod qlinear_leakyrelu_test; +mod matrix_linalg_test; +mod matrix_statistics_test; \ No newline at end of file diff --git a/tests/operators/matrix/matrix_linalg_test.cairo b/tests/operators/matrix/matrix_linalg_test.cairo deleted file mode 100644 index 93b499633..000000000 --- a/tests/operators/matrix/matrix_linalg_test.cairo +++ /dev/null @@ -1,54 +0,0 @@ -#[cfg(test)] -mod matrix_linalg { - - use core::array::{ArrayTrait, SpanTrait}; - use core::option::OptionTrait; - use orion::numbers::NumberTrait; - use orion::numbers::fixed_point::implementations::fp16x16::math::core::{abs}; - use orion::numbers::fixed_point::implementations::fp16x16::core::{FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; - use orion::operators::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; - use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; - use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; - use orion::operators::matrix::matrix_linalg::linalg_solve; - - let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold - - #[test] - #[available_gas(99999999999999999)] - fn matrix_linalg_test() { - let mut X = MutMatrixTrait::::new(3, 3); - X.set(0, 0, FixedTrait::::new_unscaled(2, false)); - X.set(0, 1, FixedTrait::::new_unscaled(1, false)); - X.set(0, 2, FixedTrait::::new_unscaled(1, true)); - X.set(1, 0, FixedTrait::::new_unscaled(3, true)); - X.set(1, 1, FixedTrait::::new_unscaled(1, true)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(2, true)); - X.set(2, 1, FixedTrait::::new_unscaled(1, false)); - X.set(2, 2, FixedTrait::::new_unscaled(1, false)); - - let mut Y = MutMatrixTrait::::new(3, 1); - Y.set(0, 0, FixedTrait::::new_unscaled(8, false)); - Y.set(0, 1, FixedTrait::::new_unscaled(11, true)); - Y.set(0, 2, FixedTrait::::new_unscaled(3, true)); - - let mut S = linalg_solve(ref X, ref Y); - - // Solution = [2, 3, -1] - - assert(S.rows == X.rows, 'Wrong num of rows'); - assert(S.cols == 1, 'Wrong num of cols'); - - // Check mags - assert(FixedTrait::abs(S.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'S_1 mag incorrect'); // ~2 - assert(FixedTrait::abs(S.get(1, 0).unwrap() - FixedTrait::::new_unscaled(3, false)) < ERROR_THRESHOLD, 'S_2 mag incorrect'); // ~3 - assert(FixedTrait::abs(S.get(2, 0).unwrap() - FixedTrait::::new_unscaled(1, true)) < ERROR_THRESHOLD, 'S_3 mag incorrect'); // ~-1 - - // Check signs - assert(S.get(0, 0).unwrap().sign == false, 'S_1 sign incorrect'); - assert(S.get(1, 0).unwrap().sign == false, 'S_2 sign incorrect'); - assert(S.get(2, 0).unwrap().sign == true, 'S_3 sign incorrect'); - - } - -} \ No newline at end of file diff --git a/tests/operators/matrix/matrix_statistics_test.cairo b/tests/operators/matrix/matrix_statistics_test.cairo deleted file mode 100644 index 983c11cb7..000000000 --- a/tests/operators/matrix/matrix_statistics_test.cairo +++ /dev/null @@ -1,229 +0,0 @@ -#[cfg(test)] -mod matrix_statistics { - use core::array::ArrayTrait; - use core::option::OptionTrait; - use orion::numbers::NumberTrait; - use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; - use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; - use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; - use orion::operators::tensor::{TensorTrait, Tensor}; - use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; - use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; - use orion::operators::matrix::matrix_statistics::{exponential_weights, mean, mean_weighted, covariance, covariance_weighted}; - - let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold - - #[test] - #[available_gas(2000000000)] - fn exponential_weights_test { - let mut X = exponential_weights(97, 3); - - assert(X.rows == 3 && X.cols == 1, 'Shape incorrect'); - assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1967, false)) < ERROR_THRESHOLD, 'X_1 incorrect'); // ~0.300 - assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1907, false)) < ERROR_THRESHOLD, 'X_2 incorrect'); // ~0.029 - assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1850, false)) < ERROR_THRESHOLD, 'X_3 incorrect'); // ~0.028 - } - - #[test] - #[available_gas(2000000000)] - fn 1D_mean_test { - - let mut X = MutMatrixImpl::::new(3,1); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(1, false)); - X.set(2, 0, FixedTrait::::new_unscaled(1, false)); - - let mut mu_X = mean(ref X, 0); - - assert(mu_X.rows == 1 & mu_X.cols == 1, 'Shape incorrect'); - assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'mean_X incorrect'); - } - - #[test] - #[available_gas(2000000000)] - fn 2D_mean_test_i { - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut mu_X = mean(ref X, 0); - - assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); - assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(174762, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.67 - assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(218453, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~3.33 - assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(305834, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.67 - assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(349525, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~5.33 - } - - #[test] - #[available_gas(2000000000)] - fn 2D_mean_test_ii { - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut mu_X = mean(ref X, 1); - - assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); - assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 - assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 - assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 - } - - #[test] - #[available_gas(2000000000)] - fn 2D_mean_weighted_test_i { - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut weights = MutMatrixImpl::::new(4,1); - weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 - weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 - weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.7 - - let mut mu_X = mean_weighted(ref X, ref weights, 0); - - assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); - assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163839, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 - assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(183500, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~2.8 - assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(294911, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.5 - assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(314572, false)) < ERROR_THRESHOLD, 'mean_X_4 incorrect'); // ~4.8 - } - - #[test] - #[available_gas(2000000000)] - fn 2D_mean_weighted_test_ii { - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut weights = MutMatrixImpl::::new(4,1); - weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 - weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 - weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 - weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 - - let mut mu_X = mean_weighted(ref X, ref weights, 1); - - assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); - assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 - assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 - assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 - } - - #[test] - #[available_gas(2000000000)] - fn covariance_test { - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut sigma2_X = covariance(ref X); - - assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 - } - - #[test] - #[available_gas(2000000000)] - fn covariance_weighted_test { - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut weights = MutMatrixImpl::::new(4,1); - weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 - weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 - weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 - weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 - - let mut sigma2_X = covariance_weighted(ref X, ref weights); - - assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 - } - -} \ No newline at end of file diff --git a/tests/operators/matrix_linalg_test.cairo b/tests/operators/matrix_linalg_test.cairo new file mode 100644 index 000000000..d79f42eee --- /dev/null +++ b/tests/operators/matrix_linalg_test.cairo @@ -0,0 +1,44 @@ +use core::option::OptionTrait; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; +use orion::operators::matrix::matrix_linalg::MatrixLinalgTrait; + +#[test] +#[available_gas(99999999999999999)] +fn matrix_linalg_test() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + + let mut X = MutMatrixTrait::::new(3, 3); + X.set(0, 0, FixedTrait::::new_unscaled(2, false)); + X.set(0, 1, FixedTrait::::new_unscaled(1, false)); + X.set(0, 2, FixedTrait::::new_unscaled(1, true)); + X.set(1, 0, FixedTrait::::new_unscaled(3, true)); + X.set(1, 1, FixedTrait::::new_unscaled(1, true)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(2, true)); + X.set(2, 1, FixedTrait::::new_unscaled(1, false)); + X.set(2, 2, FixedTrait::::new_unscaled(1, false)); + + let mut Y = MutMatrixTrait::::new(3, 1); + Y.set(0, 0, FixedTrait::::new_unscaled(8, false)); + Y.set(0, 1, FixedTrait::::new_unscaled(11, true)); + Y.set(0, 2, FixedTrait::::new_unscaled(3, true)); + + let mut S = MatrixLinalgTrait::::linalg_solve(ref X, ref Y); + + // Solution = [2, 3, -1] + + assert(S.rows == X.rows, 'Wrong num of rows'); + assert(S.cols == 1, 'Wrong num of cols'); + + // Check mags + assert(FixedTrait::abs(S.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'S_1 mag incorrect'); // ~2 + assert(FixedTrait::abs(S.get(1, 0).unwrap() - FixedTrait::::new_unscaled(3, false)) < ERROR_THRESHOLD, 'S_2 mag incorrect'); // ~3 + assert(FixedTrait::abs(S.get(2, 0).unwrap() - FixedTrait::::new_unscaled(1, true)) < ERROR_THRESHOLD, 'S_3 mag incorrect'); // ~-1 + + // Check signs + assert(S.get(0, 0).unwrap().sign == false, 'S_1 sign incorrect'); + assert(S.get(1, 0).unwrap().sign == false, 'S_2 sign incorrect'); + assert(S.get(2, 0).unwrap().sign == true, 'S_3 sign incorrect'); + +} \ No newline at end of file diff --git a/tests/operators/matrix_statistics_test.cairo b/tests/operators/matrix_statistics_test.cairo new file mode 100644 index 000000000..630e96c4f --- /dev/null +++ b/tests/operators/matrix_statistics_test.cairo @@ -0,0 +1,226 @@ +// use core::option::OptionTrait; +// use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +// use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; +// use orion::operators::matrix::matrix_statistics::{exponential_weights, mean, mean_weighted, covariance, covariance_weighted}; + +// #[test] +// #[available_gas(2000000000)] +// fn exponential_weights_test() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = exponential_weights(97, 3); + +// assert(X.rows == 3 && X.cols == 1, 'Shape incorrect'); +// assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1967, false)) < ERROR_THRESHOLD, 'X_1 incorrect'); // ~0.300 +// assert(FixedTrait::abs(X.get(1, 0).unwrap() - FixedTrait::::new(1907, false)) < ERROR_THRESHOLD, 'X_2 incorrect'); // ~0.029 +// assert(FixedTrait::abs(X.get(2, 0).unwrap() - FixedTrait::::new(1850, false)) < ERROR_THRESHOLD, 'X_3 incorrect'); // ~0.028 +// } + +// #[test] +// #[available_gas(2000000000)] +// fn mean_test_1D() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(3,1); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(1, false)); + +// let mut mu_X = mean(ref X, 0); + +// assert(mu_X.rows == 1 & mu_X.cols == 1, 'Shape incorrect'); +// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'mean_X incorrect'); +// } + +// #[test] +// #[available_gas(2000000000)] +// fn mean_test_2D_i() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(4,3); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); +// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); +// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); +// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); +// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); +// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); +// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); +// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + +// let mut mu_X = mean(ref X, 0); + +// assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); +// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(174762, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.67 +// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(218453, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~3.33 +// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(305834, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.67 +// assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(349525, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~5.33 +// } + +// #[test] +// #[available_gas(2000000000)] +// fn mean_test_2D_ii() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(4,3); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); +// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); +// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); +// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); +// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); +// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); +// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); +// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + +// let mut mu_X = mean(ref X, 1); + +// assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); +// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 +// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 +// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 +// } + +// #[test] +// #[available_gas(2000000000)] +// fn mean_weighted_test_i() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(4,3); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); +// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); +// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); +// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); +// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); +// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); +// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); +// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + +// let mut weights = MutMatrixTrait::::new(4,1); +// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 +// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 +// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.7 + +// let mut mu_X = mean_weighted(ref X, ref weights, 0); + +// assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); +// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163839, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 +// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(183500, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~2.8 +// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(294911, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.5 +// assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(314572, false)) < ERROR_THRESHOLD, 'mean_X_4 incorrect'); // ~4.8 +// } + +// #[test] +// #[available_gas(2000000000)] +// fn mean_weighted_test_ii() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(4,3); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); +// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); +// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); +// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); +// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); +// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); +// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); +// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + +// let mut weights = MutMatrixTrait::::new(4,1); +// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 +// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 +// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 +// weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + +// let mut mu_X = mean_weighted(ref X, ref weights, 1); + +// assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); +// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 +// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 +// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 +// } + +// #[test] +// #[available_gas(2000000000)] +// fn covariance_test() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(4,3); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); +// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); +// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); +// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); +// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); +// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); +// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); +// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + +// let mut sigma2_X = covariance(ref X); + +// assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); +// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 +// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 +// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 +// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 +// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 +// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 +// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 +// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 +// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 +// } + +// #[test] +// #[available_gas(2000000000)] +// fn covariance_weighted_test() { +// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + +// let mut X = MutMatrixTrait::::new(4,3); +// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); +// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); +// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); +// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); +// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); +// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); +// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); +// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + +// let mut weights = MutMatrixTrait::::new(4,1); +// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 +// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 +// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 +// weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + +// let mut sigma2_X = covariance_weighted(ref X, ref weights); + +// assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); +// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 +// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 +// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 +// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 +// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 +// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 +// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 +// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 +// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 +// } \ No newline at end of file From 5ec5b1011bb436dbf4d4aa5145b44bb178727158 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Mon, 26 Feb 2024 00:33:04 +0200 Subject: [PATCH 12/16] Updates --- src/operators/matrix/matrix_linalg.cairo | 2 + src/operators/matrix/matrix_statistics.cairo | 741 ++++++++++++------- 2 files changed, 494 insertions(+), 249 deletions(-) diff --git a/src/operators/matrix/matrix_linalg.cairo b/src/operators/matrix/matrix_linalg.cairo index 51bd94428..d7736acc2 100644 --- a/src/operators/matrix/matrix_linalg.cairo +++ b/src/operators/matrix/matrix_linalg.cairo @@ -29,6 +29,7 @@ trait MatrixLinalgTrait { /// X must be FP16x16 valued. /// /// ## Examples + /// /// let mut X = MutMatrixImpl::::new(3, 1); /// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); /// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); @@ -59,6 +60,7 @@ trait MatrixLinalgTrait { /// X, y must be FP16x16 valued. /// /// ## Examples + /// /// let mut X = MutMatrixTrait::::new(3, 3); /// X.set(0, 0, FixedTrait::::new_unscaled(2, false)); /// X.set(0, 1, FixedTrait::::new_unscaled(1, false)); diff --git a/src/operators/matrix/matrix_statistics.cairo b/src/operators/matrix/matrix_statistics.cairo index 1c15c32dd..31c17bd72 100644 --- a/src/operators/matrix/matrix_statistics.cairo +++ b/src/operators/matrix/matrix_statistics.cairo @@ -8,330 +8,573 @@ use orion::operators::tensor::{TensorTrait, Tensor}; use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; -fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { - let lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); - let mut weights = MutMatrixImpl::::new(l, 1); - let mut i = 0; - loop { - if i == l { - break; - } - let mut l_i = FixedTrait::::new_unscaled(i, false); - let mut l_pow = FixedTrait::pow(lambda, l_i); - let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * l_pow; - weights.set(i, 0, w_i); - i += 1; - }; - return weights; +/// Trait +trait MatrixStatisticsTrait { + /// # MatrixStatisticsTrait::exponential_weights + /// + /// ```rust + /// fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix + /// ``` + /// + /// ## Args + /// + /// * `lambda_unscaled`: Input u32 number from 0 to 100 + /// * `l`: length of output vector + /// + /// ## Returns + /// + /// * Output vector of length l + /// + /// ## Examples + /// let mut X = exponential_weights(97, 3); + /// Output: + /// [FP16x16 { mag: 1967, sign: false }, FP16x16 { mag: 1907, sign: false }, FP16x16 { mag: 1850, sign: false }] + + fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix ; + + /// # MatrixStatisticsTrait::mean + /// + /// ```rust + /// fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix + /// ``` + /// + /// ## Args + /// + /// * `X`: Input 1D vector or 2D matrix + /// * `axis`: 0 for rows, 1 for columns + /// + /// ## Returns + /// + /// * Simple mean for a vector input, vector of means for a matrix input along specified axis. + /// + /// ## Type Constraints + /// + /// X must be FP16x16 valued. + /// + /// ## Examples + /// + /// let mut Y = MutMatrixTrait::::new(3,1); + /// Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); + /// Y.set(1, 0, FixedTrait::::new_unscaled(2, false)); + /// Y.set(2, 0, FixedTrait::::new_unscaled(3, false)); + /// let mut mu_Y = mean(ref Y, 0); + /// + /// let mut X = MutMatrixTrait::::new(4,3); + /// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + /// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + /// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + /// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + /// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + /// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + /// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + /// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + /// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + /// let mut mu1_X = mean(ref X, 0); + /// let mut mu2_X = mean(ref X, 1); + /// + /// Output: + /// mu_Y: [FP16x16 { mag: 13107, sign: false }] + /// mu1_X: [FP16x16 { mag: 174762, sign: false }, FP16x16 { mag: 218453, sign: false }, FP16x16 { mag: 305834, sign: false }, FP16x16 { mag: 349525, sign: false }] + /// mu2_X: [FP16x16 { mag: 163840, sign: false }, FP16x16 { mag: 425984, sign: false }, FP16x16 { mag: 196608, sign: false }] + + fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix; + + /// # MatrixStatisticsTrait::mean_weighted + /// + /// ```rust + /// fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix + /// ``` + /// + /// ## Args + /// + /// * `X`: Input 1D vector or 2D matrix + /// * `weights`: Input 1D row vector of weights + /// * `axis`: 0 for rows, 1 for columns + /// + /// ## Returns + /// + /// * Weighted mean for a vector input, vector of weighted means for a matrix input along specified axis. + /// + /// ## Type Constraints + /// + /// X must be FP16x16 valued + /// weights must be FP16x16 valued and a row vector + /// + /// ## Examples + /// let mut weights = MutMatrixTrait::::new(4,1); + /// weights.set(0, 0, FixedTrait::::new(6554, false)); + /// weights.set(1, 0, FixedTrait::::new(13107, false)); + /// weights.set(2, 0, FixedTrait::::new(19661, false)); + /// + /// let mut weights2 = MutMatrixTrait::::new(4,1); + /// weights2.set(0, 0, FixedTrait::::new(6554, false)); + /// weights2.set(1, 0, FixedTrait::::new(13107, false)); + /// weights2.set(2, 0, FixedTrait::::new(19661, false)); + /// weights2.set(3, 0, FixedTrait::::new(26214, false)); + /// + /// let mut X = MutMatrixTrait::::new(4,3); + /// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + /// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + /// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + /// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + /// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + /// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + /// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + /// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + /// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + /// let mut mu1_X = mean(ref X, ref weights, 0); + /// let mut mu2_X = mean(ref X, ref weights2, 1); + /// + /// Output: + /// mu1_X: [FP16x16 { mag: 163839, sign: false }, FP16x16 { mag: 183500, sign: false }, FP16x16 { mag: 294911, sign: false }, FP16x16 { mag: 314572, sign: false }] + /// mu2_X: [FP16x16 { mag: 196607, sign: false }, FP16x16 { mag: 458751, sign: false }, FP16x16 { mag: 222822, sign: false }] + + fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix; + + /// # MatrixStatisticsTrait::covariance + /// + /// ```rust + /// fn covariance(ref X: MutMatrix) -> MutMatrix; + /// ``` + /// + /// ## Args + /// + /// * `X`: Input 1D vector or 2D matrix + /// + /// ## Returns + /// + /// * (n,n) covariance matrix for (m,n) matrix input. + /// + /// ## Type Constraints + /// + /// X must be FP16x16 valued. + /// Assumes columns are variables and rows are observations + /// + /// ## Examples + /// + /// let mut X = MutMatrixTrait::::new(4,3); + /// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + /// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + /// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + /// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + /// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + /// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + /// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + /// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + /// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + /// + /// let mut sigma2_X = covariance(ref X); + /// + /// Output: + /// [[FP16x16 { mag: 109226, sign: false }, FP16x16 { mag: 109226, sign: false }, FixedTrait::::new(87381, false)], + /// [FP16x16 { mag: 109226, sign: false }, FP16x16 { mag: 109226, sign: false }, FixedTrait::::new(87381, false)], + /// [FP16x16 { mag: 87381, sign: false }, FP16x16 { mag: 87381, sign: false }, FixedTrait::::new(87381, false)]] + + fn covariance(ref X: MutMatrix) -> MutMatrix; + + /// # MatrixStatisticsTrait::covariance_weighted + /// + /// ```rust + /// fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix; + /// ``` + /// + /// ## Args + /// + /// * `X`: Input 1D vector or 2D matrix + /// * `weights`: Input 1D row vector of weights + /// + /// ## Returns + /// + /// * (n,n) weighted covariance matrix for (m,n) matrix input and (m, 1) weights input. + /// + /// ## Type Constraints + /// + /// X and weights must be FP16x16 valued. + /// Assumes columns are variables and rows are observations. + /// + /// ## Examples + /// + /// let mut X = MutMatrixTrait::::new(4,3); + /// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + /// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + /// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + /// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + /// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + /// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + /// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + /// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + /// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + /// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + /// + /// let mut weights = MutMatrixTrait::::new(4,1); + /// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + /// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + /// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 + /// weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + /// + /// let mut sigma2_X = covariance(ref X, ref weights); + /// + /// Output: + /// [[FP16x16 { mag: 93613, sign: false }, FP16x16 { mag: 93613, sign: false }, FixedTrait::::new(74889, false)], + /// [FP16x16 { mag: 93613, sign: false }, FP16x16 { mag: 93613, sign: false }, FixedTrait::::new(74889, false)], + /// [FP16x16 { mag: 74889, sign: false }, FP16x16 { mag: 74889, sign: false }, FixedTrait::::new(78632, false)],] + + fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix; } -fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { - // Simple average case for a matrix along specified axis - // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 +impl MatrixStatisticsImpl< + FP16x16, + MAG, + +Drop, + +Copy, + +NumberTrait, + +PartialOrd, + +FixedTrait, + +MutMatrix, + +Add, + +AddEq, + +Sub, + +SubEq, + +Mul, + +MulEq, + +Div, + +DivEq> of MatrixStatisticsTrait { + fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { + let lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); + let mut weights = MutMatrixImpl::::new(l, 1); + let mut i = 0; + loop { + if i == l { + break; + } + let mut l_i = FixedTrait::::new_unscaled(i, false); + let mut l_pow = FixedTrait::pow(lambda, l_i); + let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * l_pow; + weights.set(i, 0, w_i); + i += 1; + }; + return weights; + } - assert(axis == 0 || axis == 1, 'Wrong axis'); + fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { + // Simple average case for a matrix along specified axis + // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 - // Simple average case for a vector - // Returns a matrix with shape (1,1) - if X.cols == 1 || X.rows == 1 { + assert(axis == 0 || axis == 1, 'Wrong axis'); - let mut result = MutMatrixImpl::::new(1, 1); - let mut num = FixedTrait::::new_unscaled(0, false); - let mut i = 0; + // Simple average case for a vector + // Returns a matrix with shape (1,1) + if X.cols == 1 || X.rows == 1 { - let den = FixedTrait::::new_unscaled(X.data.len(), false); + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; - if X.cols == 1 && X.rows == 1 { - result.set(0, 0, X.get(0, 0).unwrap()); - return result; - } - else { - let l = if (X.rows > 1) { - X.rows + let den = FixedTrait::::new_unscaled(X.data.len(), false); + + if X.cols == 1 && X.rows == 1 { + result.set(0, 0, X.get(0, 0).unwrap()); + return result; } else { - X.cols - }; - loop { - if i == l { - break; - } - let mut num_i = if (X.rows > 1) { - X.get(i, 0).unwrap() + let l = if (X.rows > 1) { + X.rows } else { - X.get(0, i).unwrap() + X.cols }; - num += num_i; - i += 1; - }; - result.set(0, 0, num / den); - } - - return result; - } - - // Matrix average along specified axis - // Returns a vector with shape=(X.rows, 1) if axis == 0 or shape=(1, X.cols) if axis == 1 - else { - // Average along rows - if axis == 0 { - let mut result = MutMatrixImpl::::new(X.rows, 1); - let den = FixedTrait::::new_unscaled(X.cols, false); - let mut row = 0; - - loop { - if row == X.rows { - break; - } - let mut row_num = FixedTrait::::new_unscaled(0, false); - let mut col = 0; loop { - if col == X.cols { + if i == l { break; } - row_num += X.get(row, col).unwrap(); - col += 1; + let mut num_i = if (X.rows > 1) { + X.get(i, 0).unwrap() + } + else { + X.get(0, i).unwrap() + }; + num += num_i; + i += 1; }; - result.set(row, 0, row_num / den); - row += 1; - }; + result.set(0, 0, num / den); + } return result; } - // Average along columns + // Matrix average along specified axis + // Returns a vector with shape=(X.rows, 1) if axis == 0 or shape=(1, X.cols) if axis == 1 else { - let mut result = MutMatrixImpl::::new(1, X.cols); - let den = FixedTrait::::new_unscaled(X.rows, false); - let mut col = 0; - - loop { - if col == X.cols { - break; - } - let mut col_num = FixedTrait::::new_unscaled(0, false); + // Average along rows + if axis == 0 { + let mut result = MutMatrixImpl::::new(X.rows, 1); + let den = FixedTrait::::new_unscaled(X.cols, false); let mut row = 0; + loop { if row == X.rows { break; - } - col_num += X.get(row, col).unwrap(); + } + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; + loop { + if col == X.cols { + break; + } + row_num += X.get(row, col).unwrap(); + col += 1; + }; + result.set(row, 0, row_num / den); row += 1; }; - result.set(0, col, col_num / den); - col += 1; - }; - - return result; - } - } -} - -fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix { - // Weighted average - // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 - - // Weight assertions - if X.rows > 1 { - assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); - } - else { - assert(weights.cols == X.cols && weights.rows == 1, 'Weights shape mismatch'); - } - - // Vector case - if X.rows == 1 || X.cols == 1 { - - assert(X.rows != X.cols, '1 element input'); - - let mut result = MutMatrixImpl::::new(1, 1); - let mut num = FixedTrait::::new_unscaled(0, false); - let mut i = 0; - let den = FixedTrait::::new_unscaled(X.data.len(), false); - - let l = if (X.rows > 1) { - X.rows + return result; } + + // Average along columns else { - X.cols - }; - - loop { - if i == l { - break; - } - let mut num_i = if (X.rows > 1) { - X.get(i, 0).unwrap() * weights.get(i, 0).unwrap() + let mut result = MutMatrixImpl::::new(1, X.cols); + let den = FixedTrait::::new_unscaled(X.rows, false); + let mut col = 0; + + loop { + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; + loop { + if row == X.rows { + break; + } + col_num += X.get(row, col).unwrap(); + row += 1; + }; + result.set(0, col, col_num / den); + col += 1; + }; + + return result; } - else { - X.get(0, i).unwrap() * weights.get(0, i).unwrap() - }; - num += num_i; - i += 1; - }; - result.set(0, 0, num / den); - - return result; + } } - // Matrix case - else { - assert(axis == 0 || axis == 1, 'Wrong axis'); + fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix { + // Weighted average + // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 + + // Weight assertions + if X.rows > 1 { + assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); + } + else { + assert(weights.cols == X.cols && weights.rows == 1, 'Weights shape mismatch'); + } - // Average along rows - if axis == 0 { + // Vector case + if X.rows == 1 || X.cols == 1 { - let mut result = MutMatrixImpl::::new(X.rows, 1); - let mut row = 0; + assert(X.rows != X.cols, '1 element input'); + + let mut result = MutMatrixImpl::::new(1, 1); + let mut num = FixedTrait::::new_unscaled(0, false); + let mut i = 0; + let den = FixedTrait::::new_unscaled(X.data.len(), false); + + let l = if (X.rows > 1) { + X.rows + } + else { + X.cols + }; + loop { - if row == X.rows { + if i == l { break; } - let mut row_num = FixedTrait::::new_unscaled(0, false); - let mut col = 0; - loop { - if col == X.cols { - break; - } - row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); - col += 1; + let mut num_i = if (X.rows > 1) { + X.get(i, 0).unwrap() * weights.get(i, 0).unwrap() + } + else { + X.get(0, i).unwrap() * weights.get(0, i).unwrap() }; - result.set(row, 0, row_num); - row += 1; + num += num_i; + i += 1; }; - + result.set(0, 0, num / den); + return result; } - // Average along columns + // Matrix case else { - let mut result = MutMatrixImpl::::new(1, X.cols); - let mut col = 0; + assert(axis == 0 || axis == 1, 'Wrong axis'); - loop { - if col == X.cols { - break; - } - let mut col_num = FixedTrait::::new_unscaled(0, false); + // Average along rows + if axis == 0 { + + let mut result = MutMatrixImpl::::new(X.rows, 1); let mut row = 0; + loop { if row == X.rows { break; } - col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); + let mut row_num = FixedTrait::::new_unscaled(0, false); + let mut col = 0; + loop { + if col == X.cols { + break; + } + row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); + col += 1; + }; + result.set(row, 0, row_num); row += 1; }; - result.set(0, col, col_num); - col += 1; - }; - return result; + return result; + } + + // Average along columns + else { + let mut result = MutMatrixImpl::::new(1, X.cols); + let mut col = 0; + + loop { + if col == X.cols { + break; + } + let mut col_num = FixedTrait::::new_unscaled(0, false); + let mut row = 0; + loop { + if row == X.rows { + break; + } + col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); + row += 1; + }; + result.set(0, col, col_num); + col += 1; + }; + + return result; + } } } -} -fn covariance(ref X: MutMatrix) -> MutMatrix { - assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); - - let m = X.rows; // Num observations - let n = X.cols; // Num variables - let mut Cov_X = MutMatrixImpl::::new(n, n); - let mut Mean_X = mean(ref X, 1); - - let mut i = 0; - loop { - if i == n { - break; - } - let mut j = 0; + fn covariance(ref X: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); + + let m = X.rows; // Num observations + let n = X.cols; // Num variables + let mut Cov_X = MutMatrixImpl::::new(n, n); + let mut Mean_X = mean(ref X, 1); + + let mut i = 0; loop { - if j == n { + if i == n { break; } - let mut k = 0; - let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + let mut j = 0; loop { - if k == m { + if j == n { break; } - Cov_X_i_j += ((X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); - k += 1; + let mut k = 0; + let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + loop { + if k == m { + break; + } + Cov_X_i_j += ((X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); + k += 1; + }; + Cov_X_i_j /= FixedTrait::::new_unscaled(m - 1, false); + Cov_X.set(i, j, Cov_X_i_j); + Cov_X.set(j, i, Cov_X_i_j); + j += 1; }; - Cov_X_i_j /= FixedTrait::::new_unscaled(m - 1, false); - Cov_X.set(i, j, Cov_X_i_j); - Cov_X.set(j, i, Cov_X_i_j); - j += 1; + i += 1; }; - i += 1; - }; - return Cov_X; -} + return Cov_X; + } -fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { - assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); - assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); - - // Normalize weights - let mut normalized_weights = MutMatrixImpl::::new(weights.rows, 1); - let mut total_weight = weights.reduce_sum(0, false); - let mut i = 0; - loop { - if i == weights.rows { - break; - } - let w_i = weights.get(i, 0).unwrap(); - normalized_weights.set(i, 0, w_i / total_weight.get(0, 0).unwrap()); - i += 1; - }; - - let m = X.rows; // Num observations - let n = X.cols; // Num variables - let mut Cov_X = MutMatrixImpl::::new(n, n); - let mut Mean_X = mean_weighted(ref X, ref weights, 1); - - let mut adj_weight_sum = FixedTrait::::new_unscaled(0, false); - i = 0; - loop { - if i == normalized_weights.rows { - break; - } - let mut w_i = normalized_weights.get(i, 0).unwrap(); - adj_weight_sum += (w_i * w_i); - i += 1; - }; - - i = 0; - loop { - if i == n { - break; - } - let mut j = 0; + fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { + assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); + assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); + + // Normalize weights + let mut normalized_weights = MutMatrixImpl::::new(weights.rows, 1); + let mut total_weight = weights.reduce_sum(0, false); + let mut i = 0; + loop { + if i == weights.rows { + break; + } + let w_i = weights.get(i, 0).unwrap(); + normalized_weights.set(i, 0, w_i / total_weight.get(0, 0).unwrap()); + i += 1; + }; + + let m = X.rows; // Num observations + let n = X.cols; // Num variables + let mut Cov_X = MutMatrixImpl::::new(n, n); + let mut Mean_X = mean_weighted(ref X, ref weights, 1); + + let mut adj_weight_sum = FixedTrait::::new_unscaled(0, false); + i = 0; + loop { + if i == normalized_weights.rows { + break; + } + let mut w_i = normalized_weights.get(i, 0).unwrap(); + adj_weight_sum += (w_i * w_i); + i += 1; + }; + + i = 0; loop { - if j == n { + if i == n { break; } - let mut k = 0; - let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + let mut j = 0; loop { - if k == m { + if j == n { break; } - Cov_X_i_j += (normalized_weights.get(k, 0).unwrap() * (X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); - k += 1; + let mut k = 0; + let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); + loop { + if k == m { + break; + } + Cov_X_i_j += (normalized_weights.get(k, 0).unwrap() * (X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); + k += 1; + }; + let mut den = FixedTrait::::new_unscaled(1, false) - adj_weight_sum; + Cov_X_i_j /= den; + Cov_X.set(i, j, Cov_X_i_j); + Cov_X.set(j, i, Cov_X_i_j); + j += 1; }; - let mut den = FixedTrait::::new_unscaled(1, false) - adj_weight_sum; - Cov_X_i_j /= den; - Cov_X.set(i, j, Cov_X_i_j); - Cov_X.set(j, i, Cov_X_i_j); - j += 1; + i += 1; }; - i += 1; - }; - return Cov_X; + return Cov_X; + } } From cea033149766cccc42c5c564d0c9bf083d778f01 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Mon, 26 Feb 2024 00:34:20 +0200 Subject: [PATCH 13/16] Updates --- tests/operators/matrix_statistics_test.cairo | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/operators/matrix_statistics_test.cairo b/tests/operators/matrix_statistics_test.cairo index 630e96c4f..c17540af2 100644 --- a/tests/operators/matrix_statistics_test.cairo +++ b/tests/operators/matrix_statistics_test.cairo @@ -1,7 +1,7 @@ // use core::option::OptionTrait; // use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; // use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; -// use orion::operators::matrix::matrix_statistics::{exponential_weights, mean, mean_weighted, covariance, covariance_weighted}; +// use orion::operators::matrix::matrix_statistics::MatrixStatisticsTrait; // #[test] // #[available_gas(2000000000)] @@ -23,8 +23,8 @@ // let mut X = MutMatrixTrait::::new(3,1); // X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(1, false)); +// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); +// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); // let mut mu_X = mean(ref X, 0); From 8d404b1cba199e7212ae3178b8834b5881b6ed52 Mon Sep 17 00:00:00 2001 From: bshmu <35515851+bshmu@users.noreply.github.com> Date: Mon, 26 Feb 2024 00:37:22 +0200 Subject: [PATCH 14/16] Updates --- tests/operators/matrix_statistics_test.cairo | 440 +++++++++---------- 1 file changed, 220 insertions(+), 220 deletions(-) diff --git a/tests/operators/matrix_statistics_test.cairo b/tests/operators/matrix_statistics_test.cairo index c17540af2..a6ce76a38 100644 --- a/tests/operators/matrix_statistics_test.cairo +++ b/tests/operators/matrix_statistics_test.cairo @@ -1,226 +1,226 @@ -// use core::option::OptionTrait; -// use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; -// use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; -// use orion::operators::matrix::matrix_statistics::MatrixStatisticsTrait; - -// #[test] -// #[available_gas(2000000000)] -// fn exponential_weights_test() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold - -// let mut X = exponential_weights(97, 3); - -// assert(X.rows == 3 && X.cols == 1, 'Shape incorrect'); -// assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1967, false)) < ERROR_THRESHOLD, 'X_1 incorrect'); // ~0.300 -// assert(FixedTrait::abs(X.get(1, 0).unwrap() - FixedTrait::::new(1907, false)) < ERROR_THRESHOLD, 'X_2 incorrect'); // ~0.029 -// assert(FixedTrait::abs(X.get(2, 0).unwrap() - FixedTrait::::new(1850, false)) < ERROR_THRESHOLD, 'X_3 incorrect'); // ~0.028 -// } - -// #[test] -// #[available_gas(2000000000)] -// fn mean_test_1D() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold - -// let mut X = MutMatrixTrait::::new(3,1); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - -// let mut mu_X = mean(ref X, 0); - -// assert(mu_X.rows == 1 & mu_X.cols == 1, 'Shape incorrect'); -// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'mean_X incorrect'); -// } - -// #[test] -// #[available_gas(2000000000)] -// fn mean_test_2D_i() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold +use core::option::OptionTrait; +use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; +use orion::operators::matrix::matrix_statistics::MatrixStatisticsTrait; + +#[test] +#[available_gas(2000000000)] +fn exponential_weights_test() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + + let mut X = MatrixStatisticsTrait::::exponential_weights(97, 3); + + assert(X.rows == 3 && X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(X.get(0, 0).unwrap() - FixedTrait::::new(1967, false)) < ERROR_THRESHOLD, 'X_1 incorrect'); // ~0.300 + assert(FixedTrait::abs(X.get(1, 0).unwrap() - FixedTrait::::new(1907, false)) < ERROR_THRESHOLD, 'X_2 incorrect'); // ~0.029 + assert(FixedTrait::abs(X.get(2, 0).unwrap() - FixedTrait::::new(1850, false)) < ERROR_THRESHOLD, 'X_3 incorrect'); // ~0.028 +} + +#[test] +#[available_gas(2000000000)] +fn mean_test_1D() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + + let mut X = MutMatrixTrait::::new(3,1); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + + let mut mu_X = MatrixStatisticsTrait::::mean(ref X, 0); + + assert(mu_X.rows == 1 & mu_X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'mean_X incorrect'); +} + +#[test] +#[available_gas(2000000000)] +fn mean_test_2D_i() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold -// let mut X = MutMatrixTrait::::new(4,3); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); -// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); -// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); -// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); -// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); -// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); -// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); -// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - -// let mut mu_X = mean(ref X, 0); - -// assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); -// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(174762, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.67 -// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(218453, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~3.33 -// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(305834, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.67 -// assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(349525, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~5.33 -// } - -// #[test] -// #[available_gas(2000000000)] -// fn mean_test_2D_ii() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + let mut X = MutMatrixTrait::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut mu_X = MatrixStatisticsTrait::::mean(ref X, 0); + + assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(174762, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.67 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(218453, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~3.33 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(305834, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.67 + assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(349525, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~5.33 +} + +#[test] +#[available_gas(2000000000)] +fn mean_test_2D_ii() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold -// let mut X = MutMatrixTrait::::new(4,3); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); -// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); -// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); -// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); -// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); -// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); -// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); -// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - -// let mut mu_X = mean(ref X, 1); - -// assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); -// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 -// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 -// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 -// } - -// #[test] -// #[available_gas(2000000000)] -// fn mean_weighted_test_i() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + let mut X = MutMatrixTrait::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut mu_X = MatrixStatisticsTrait::::mean(ref X, 1); + + assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 +} + +#[test] +#[available_gas(2000000000)] +fn mean_weighted_test_i() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold -// let mut X = MutMatrixTrait::::new(4,3); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); -// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); -// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); -// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); -// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); -// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); -// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); -// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - -// let mut weights = MutMatrixTrait::::new(4,1); -// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 -// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 -// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.7 - -// let mut mu_X = mean_weighted(ref X, ref weights, 0); - -// assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); -// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163839, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 -// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(183500, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~2.8 -// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(294911, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.5 -// assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(314572, false)) < ERROR_THRESHOLD, 'mean_X_4 incorrect'); // ~4.8 -// } - -// #[test] -// #[available_gas(2000000000)] -// fn mean_weighted_test_ii() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + let mut X = MutMatrixTrait::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixTrait::::new(4,1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.7 + + let mut mu_X = MatrixStatisticsTrait::::mean_weighted(ref X, ref weights, 0); + + assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163839, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(183500, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~2.8 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(294911, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.5 + assert(FixedTrait::abs(mu_X.get(3, 0).unwrap() - FixedTrait::::new(314572, false)) < ERROR_THRESHOLD, 'mean_X_4 incorrect'); // ~4.8 +} + +#[test] +#[available_gas(2000000000)] +fn mean_weighted_test_ii() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold -// let mut X = MutMatrixTrait::::new(4,3); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); -// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); -// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); -// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); -// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); -// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); -// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); -// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - -// let mut weights = MutMatrixTrait::::new(4,1); -// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 -// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 -// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 -// weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 - -// let mut mu_X = mean_weighted(ref X, ref weights, 1); - -// assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); -// assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 -// assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 -// assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 -// } - -// #[test] -// #[available_gas(2000000000)] -// fn covariance_test() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + let mut X = MutMatrixTrait::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixTrait::::new(4,1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 + weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + + let mut mu_X = MatrixStatisticsTrait::::mean_weighted(ref X, ref weights, 1); + + assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 + assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 + assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 +} + +#[test] +#[available_gas(2000000000)] +fn covariance_test() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold -// let mut X = MutMatrixTrait::::new(4,3); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); -// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); -// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); -// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); -// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); -// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); -// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); -// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - -// let mut sigma2_X = covariance(ref X); - -// assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); -// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 -// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 -// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 -// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 -// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 -// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 -// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 -// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 -// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 -// } - -// #[test] -// #[available_gas(2000000000)] -// fn covariance_weighted_test() { -// let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold + let mut X = MutMatrixTrait::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut sigma2_X = MatrixStatisticsTrait::::covariance(ref X); + + assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 +} + +#[test] +#[available_gas(2000000000)] +fn covariance_weighted_test() { + let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold -// let mut X = MutMatrixTrait::::new(4,3); -// X.set(0, 0, FixedTrait::::new_unscaled(1, false)); -// X.set(1, 0, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 0, FixedTrait::::new_unscaled(3, false)); -// X.set(3, 0, FixedTrait::::new_unscaled(4, false)); -// X.set(0, 1, FixedTrait::::new_unscaled(5, false)); -// X.set(1, 1, FixedTrait::::new_unscaled(6, false)); -// X.set(2, 1, FixedTrait::::new_unscaled(7, false)); -// X.set(3, 1, FixedTrait::::new_unscaled(8, false)); -// X.set(0, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(1, 2, FixedTrait::::new_unscaled(2, false)); -// X.set(2, 2, FixedTrait::::new_unscaled(4, false)); -// X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - -// let mut weights = MutMatrixTrait::::new(4,1); -// weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 -// weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 -// weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 -// weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 - -// let mut sigma2_X = covariance_weighted(ref X, ref weights); - -// assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); -// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 -// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 -// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 -// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 -// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 -// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 -// assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 -// assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 -// assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 -// } \ No newline at end of file + let mut X = MutMatrixTrait::::new(4,3); + X.set(0, 0, FixedTrait::::new_unscaled(1, false)); + X.set(1, 0, FixedTrait::::new_unscaled(2, false)); + X.set(2, 0, FixedTrait::::new_unscaled(3, false)); + X.set(3, 0, FixedTrait::::new_unscaled(4, false)); + X.set(0, 1, FixedTrait::::new_unscaled(5, false)); + X.set(1, 1, FixedTrait::::new_unscaled(6, false)); + X.set(2, 1, FixedTrait::::new_unscaled(7, false)); + X.set(3, 1, FixedTrait::::new_unscaled(8, false)); + X.set(0, 2, FixedTrait::::new_unscaled(2, false)); + X.set(1, 2, FixedTrait::::new_unscaled(2, false)); + X.set(2, 2, FixedTrait::::new_unscaled(4, false)); + X.set(3, 2, FixedTrait::::new_unscaled(4, false)); + + let mut weights = MutMatrixTrait::::new(4,1); + weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 + weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 + weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 + weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 + + let mut sigma2_X = MatrixStatisticsTrait::::covariance_weighted(ref X, ref weights); + + assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 +} \ No newline at end of file From e3b838071447d49d32bcf4cc681fccf2e5ee6e3f Mon Sep 17 00:00:00 2001 From: Benjamin Shmulevsky Date: Mon, 26 Feb 2024 11:37:12 +0200 Subject: [PATCH 15/16] Updates --- .tool-versions | 2 +- src/operators/matrix/matrix_linalg.cairo | 216 +++++++++---------- src/operators/matrix/matrix_statistics.cairo | 34 +-- tests/operators/matrix_statistics_test.cairo | 30 +-- 4 files changed, 125 insertions(+), 157 deletions(-) diff --git a/.tool-versions b/.tool-versions index ff8bf3eb2..9e7be0075 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.4.0 \ No newline at end of file +scarb 2.5.1 \ No newline at end of file diff --git a/src/operators/matrix/matrix_linalg.cairo b/src/operators/matrix/matrix_linalg.cairo index d7736acc2..b3781b6b7 100644 --- a/src/operators/matrix/matrix_linalg.cairo +++ b/src/operators/matrix/matrix_linalg.cairo @@ -2,14 +2,16 @@ use core::array::ArrayTrait; use core::option::OptionTrait; use orion::numbers::NumberTrait; use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; -use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; +use orion::numbers::fixed_point::implementations::fp16x16::core::{ + FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl +}; use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; use orion::operators::tensor::{TensorTrait, Tensor}; use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; /// Trait -trait MatrixLinalgTrait { +trait MatrixLinalgTrait { /// # MatrixLinalgTrait::diagonalize /// /// ```rust @@ -37,9 +39,9 @@ trait MatrixLinalgTrait { /// let mut diag_X = diagonalize(ref X); /// Output: /// [[FP16x16 { mag: 65536, sign: false }, 0, 0], [0, FP16x16 { mag: 13107, sign: false }, 0], [0, 0, FP16x16 { mag: 196608, sign: false }]] - - fn diagonalize(ref X: MutMatrix) -> MutMatrix; - + + fn diagonalize(ref X: MutMatrix) -> MutMatrix; + /// # MatrixLinalgTrait::linalg_solve /// /// ```rust @@ -79,26 +81,10 @@ trait MatrixLinalgTrait { /// Output: /// [FP16x16 { mag: 131072, sign: false }, FP16x16 { mag: 196608, sign: false }, FP16x16 { mag: 65536, sign: true }] - fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix; + fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix; } -impl MatrixLinalgImpl< - FP16x16, - MAG, - +Drop, - +Copy, - +NumberTrait, - +PartialOrd, - +FixedTrait, - +MutMatrix, - +Add, - +AddEq, - +Sub, - +SubEq, - +Mul, - +MulEq, - +Div, - +DivEq> of MatrixLinalgTrait { +impl FP16x16MatrixLinalgImpl of MatrixLinalgTrait { fn diagonalize(ref X: MutMatrix) -> MutMatrix { assert(X.rows > 1 && X.cols == 1, 'X not row vector'); @@ -115,8 +101,7 @@ impl MatrixLinalgImpl< } if i == j { result.set(i, j, X.get(i, 0).unwrap()); - } - else { + } else { result.set(i, j, FixedTrait::new(0, false)); } j += 1; @@ -127,124 +112,123 @@ impl MatrixLinalgImpl< } fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { - - let n = X.rows; - let mut row: u32 = 0; - let mut col: u32 = 0; - let mut i = 0; + let n = X.rows; + let mut row: u32 = 0; + let mut col: u32 = 0; + let mut i = 0; + loop { + if row == n { + break; + } + + // Find the row number and max row number for X + i = row + 1; + let mut max_row = row; loop { - if row == n { + if i == n { break; } - - // Find the row number and max row number for X - i = row + 1; - let mut max_row = row; - loop { - if i == n { - break; - } - if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { - max_row = i; - } - i += 1; - }; - - let mut X_row = MutMatrixImpl::new(1, X.cols); - let mut X_max_row = MutMatrixImpl::new(1, X.cols); - let mut y_row = y.get(row, 0).unwrap(); - let mut y_max_row = y.get(max_row, 0).unwrap(); - - // Store X_row and X_max_row - i = 0; - loop { - if i == n { - break; - } - - X_row.set(0, i, X.get(row, i).unwrap()); - X_max_row.set(0, i, X.get(max_row, i).unwrap()); + if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { + max_row = i; + } + i += 1; + }; - i += 1; - }; + let mut X_row = MutMatrixImpl::new(1, X.cols); + let mut X_max_row = MutMatrixImpl::new(1, X.cols); + let mut y_row = y.get(row, 0).unwrap(); + let mut y_max_row = y.get(max_row, 0).unwrap(); - // Interchange X_row with X_max_row, y_row with y_max_row - i = 0; - loop { - if i == n { - break; - } - - X.set(row, i, X_max_row.get(0, i).unwrap()); - X.set(max_row, i, X_row.get(0, i).unwrap()); - - i += 1; - }; - y.set(max_row, 0, y_row); - y.set(row, 0, y_max_row); + // Store X_row and X_max_row + i = 0; + loop { + if i == n { + break; + } - // Check for singularity - assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); + X_row.set(0, i, X.get(row, i).unwrap()); + X_max_row.set(0, i, X.get(max_row, i).unwrap()); - // Perform forward elimination - i = row + 1; - loop { - if i == n { - break; - } - let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); - let mut j = row; - loop { - if j == n { - break; - } - let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); - X.set(i, j, X_new_val); - - j += 1; - }; - let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); - y.set(i, 0, y_new_val); - - i += 1; - }; - - row += 1; + i += 1; }; - // Perform back substitution - let mut S = MutMatrixImpl::new(X.rows, 1); + // Interchange X_row with X_max_row, y_row with y_max_row i = 0; loop { if i == n { break; } - S.set(i, 1, FP16x16 { mag: 0, sign: false }); + + X.set(row, i, X_max_row.get(0, i).unwrap()); + X.set(max_row, i, X_row.get(0, i).unwrap()); + i += 1; }; + y.set(max_row, 0, y_row); + y.set(row, 0, y_max_row); - i = n; + // Check for singularity + assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); + + // Perform forward elimination + i = row + 1; loop { - if i == 0 { + if i == n { break; } - let mut X_i = y.get(i - 1, 0).unwrap(); - let mut j = i; + let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); + let mut j = row; loop { if j == n { break; } - X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); - + let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); + X.set(i, j, X_new_val); + j += 1; }; - X_i /= X.get(i - 1, i - 1).unwrap(); - S.set(i - 1, 0, X_i); + let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); + y.set(i, 0, y_new_val); - i -= 1; + i += 1; }; - return S; - } -} \ No newline at end of file + row += 1; + }; + + // Perform back substitution + let mut S = MutMatrixImpl::new(X.rows, 1); + i = 0; + loop { + if i == n { + break; + } + S.set(i, 1, FP16x16 { mag: 0, sign: false }); + i += 1; + }; + + i = n; + loop { + if i == 0 { + break; + } + let mut X_i = y.get(i - 1, 0).unwrap(); + let mut j = i; + loop { + if j == n { + break; + } + X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); + + j += 1; + }; + X_i /= X.get(i - 1, i - 1).unwrap(); + S.set(i - 1, 0, X_i); + + i -= 1; + }; + + return S; + } +} diff --git a/src/operators/matrix/matrix_statistics.cairo b/src/operators/matrix/matrix_statistics.cairo index 31c17bd72..f32a19577 100644 --- a/src/operators/matrix/matrix_statistics.cairo +++ b/src/operators/matrix/matrix_statistics.cairo @@ -9,7 +9,7 @@ use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; /// Trait -trait MatrixStatisticsTrait { +trait MatrixStatisticsTrait { /// # MatrixStatisticsTrait::exponential_weights /// /// ```rust @@ -30,7 +30,7 @@ trait MatrixStatisticsTrait { /// Output: /// [FP16x16 { mag: 1967, sign: false }, FP16x16 { mag: 1907, sign: false }, FP16x16 { mag: 1850, sign: false }] - fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix ; + fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix ; /// # MatrixStatisticsTrait::mean /// @@ -80,7 +80,7 @@ trait MatrixStatisticsTrait { /// mu1_X: [FP16x16 { mag: 174762, sign: false }, FP16x16 { mag: 218453, sign: false }, FP16x16 { mag: 305834, sign: false }, FP16x16 { mag: 349525, sign: false }] /// mu2_X: [FP16x16 { mag: 163840, sign: false }, FP16x16 { mag: 425984, sign: false }, FP16x16 { mag: 196608, sign: false }] - fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix; + fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix; /// # MatrixStatisticsTrait::mean_weighted /// @@ -135,7 +135,7 @@ trait MatrixStatisticsTrait { /// mu1_X: [FP16x16 { mag: 163839, sign: false }, FP16x16 { mag: 183500, sign: false }, FP16x16 { mag: 294911, sign: false }, FP16x16 { mag: 314572, sign: false }] /// mu2_X: [FP16x16 { mag: 196607, sign: false }, FP16x16 { mag: 458751, sign: false }, FP16x16 { mag: 222822, sign: false }] - fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix; + fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix; /// # MatrixStatisticsTrait::covariance /// @@ -179,7 +179,7 @@ trait MatrixStatisticsTrait { /// [FP16x16 { mag: 109226, sign: false }, FP16x16 { mag: 109226, sign: false }, FixedTrait::::new(87381, false)], /// [FP16x16 { mag: 87381, sign: false }, FP16x16 { mag: 87381, sign: false }, FixedTrait::::new(87381, false)]] - fn covariance(ref X: MutMatrix) -> MutMatrix; + fn covariance(ref X: MutMatrix) -> MutMatrix; /// # MatrixStatisticsTrait::covariance_weighted /// @@ -230,26 +230,10 @@ trait MatrixStatisticsTrait { /// [FP16x16 { mag: 93613, sign: false }, FP16x16 { mag: 93613, sign: false }, FixedTrait::::new(74889, false)], /// [FP16x16 { mag: 74889, sign: false }, FP16x16 { mag: 74889, sign: false }, FixedTrait::::new(78632, false)],] - fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix; + fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix; } -impl MatrixStatisticsImpl< - FP16x16, - MAG, - +Drop, - +Copy, - +NumberTrait, - +PartialOrd, - +FixedTrait, - +MutMatrix, - +Add, - +AddEq, - +Sub, - +SubEq, - +Mul, - +MulEq, - +Div, - +DivEq> of MatrixStatisticsTrait { +impl MatrixStatisticsImpl of MatrixStatisticsTrait { fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { let lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); let mut weights = MutMatrixImpl::::new(l, 1); @@ -481,7 +465,7 @@ impl MatrixStatisticsImpl< let m = X.rows; // Num observations let n = X.cols; // Num variables let mut Cov_X = MutMatrixImpl::::new(n, n); - let mut Mean_X = mean(ref X, 1); + let mut Mean_X = MatrixStatisticsImpl::mean(ref X, 1); let mut i = 0; loop { @@ -533,7 +517,7 @@ impl MatrixStatisticsImpl< let m = X.rows; // Num observations let n = X.cols; // Num variables let mut Cov_X = MutMatrixImpl::::new(n, n); - let mut Mean_X = mean_weighted(ref X, ref weights, 1); + let mut Mean_X = MatrixStatisticsImpl::mean_weighted(ref X, ref weights, 1); let mut adj_weight_sum = FixedTrait::::new_unscaled(0, false); i = 0; diff --git a/tests/operators/matrix_statistics_test.cairo b/tests/operators/matrix_statistics_test.cairo index a6ce76a38..9944d8a65 100644 --- a/tests/operators/matrix_statistics_test.cairo +++ b/tests/operators/matrix_statistics_test.cairo @@ -4,7 +4,7 @@ use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl} use orion::operators::matrix::matrix_statistics::MatrixStatisticsTrait; #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn exponential_weights_test() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -17,7 +17,7 @@ fn exponential_weights_test() { } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn mean_test_1D() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -28,12 +28,12 @@ fn mean_test_1D() { let mut mu_X = MatrixStatisticsTrait::::mean(ref X, 0); - assert(mu_X.rows == 1 & mu_X.cols == 1, 'Shape incorrect'); + assert(mu_X.rows == 1 && mu_X.cols == 1, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new_unscaled(2, false)) < ERROR_THRESHOLD, 'mean_X incorrect'); } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn mean_test_2D_i() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -53,7 +53,7 @@ fn mean_test_2D_i() { let mut mu_X = MatrixStatisticsTrait::::mean(ref X, 0); - assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); + assert(mu_X.rows == 4 && mu_X.cols == 1, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(174762, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.67 assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(218453, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~3.33 assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(305834, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.67 @@ -61,7 +61,7 @@ fn mean_test_2D_i() { } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn mean_test_2D_ii() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -81,14 +81,14 @@ fn mean_test_2D_ii() { let mut mu_X = MatrixStatisticsTrait::::mean(ref X, 1); - assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); + assert(mu_X.rows == 1 && mu_X.cols == 3, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn mean_weighted_test_i() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -113,7 +113,7 @@ fn mean_weighted_test_i() { let mut mu_X = MatrixStatisticsTrait::::mean_weighted(ref X, ref weights, 0); - assert(mu_X.rows == 4 & mu_X.cols == 1, 'Shape incorrect'); + assert(mu_X.rows == 4 && mu_X.cols == 1, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163839, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(183500, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~2.8 assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(294911, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~4.5 @@ -121,7 +121,7 @@ fn mean_weighted_test_i() { } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn mean_weighted_test_ii() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -147,14 +147,14 @@ fn mean_weighted_test_ii() { let mut mu_X = MatrixStatisticsTrait::::mean_weighted(ref X, ref weights, 1); - assert(mu_X.rows == 1 & mu_X.cols == 3, 'Shape incorrect'); + assert(mu_X.rows == 1 && mu_X.cols == 3, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn covariance_test() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -174,7 +174,7 @@ fn covariance_test() { let mut sigma2_X = MatrixStatisticsTrait::::covariance(ref X); - assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); + assert(sigma2_X.rows == 3 && sigma2_X.cols == 3, 'Shape incorrect'); assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 @@ -187,7 +187,7 @@ fn covariance_test() { } #[test] -#[available_gas(2000000000)] +#[available_gas(200000000000)] fn covariance_weighted_test() { let ERROR_THRESHOLD = FixedTrait::::new_unscaled(100, false); // ~0.00153 error threshold @@ -213,7 +213,7 @@ fn covariance_weighted_test() { let mut sigma2_X = MatrixStatisticsTrait::::covariance_weighted(ref X, ref weights); - assert(sigma2_X.rows == 3 & sigma2_X.cols == 3, 'Shape incorrect'); + assert(sigma2_X.rows == 3 && sigma2_X.cols == 3, 'Shape incorrect'); assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 From 35d51a55933e9be3961556fdc6a3009047f92123 Mon Sep 17 00:00:00 2001 From: Benjamin Shmulevsky Date: Mon, 26 Feb 2024 13:11:44 +0200 Subject: [PATCH 16/16] Final updates --- .tool-versions | 2 +- src/lib.cairo | 641 +------------------ tests/operators/matrix_linalg_test.cairo | 4 +- tests/operators/matrix_statistics_test.cairo | 32 +- 4 files changed, 20 insertions(+), 659 deletions(-) diff --git a/.tool-versions b/.tool-versions index 9e7be0075..ff8bf3eb2 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.5.1 \ No newline at end of file +scarb 2.4.0 \ No newline at end of file diff --git a/src/lib.cairo b/src/lib.cairo index a44be4aee..c824e3701 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,643 +1,4 @@ mod operators; mod numbers; mod utils; -mod test_helper; - -use core::debug::PrintTrait; -use core::array::ArrayTrait; -use core::option::OptionTrait; -use orion::numbers::NumberTrait; -use orion::numbers::fixed_point::implementations::fp16x16::math::core::{ceil, abs}; -use orion::operators::matrix::matrix::{MutMatrix, MutMatrixTrait, MutMatrixImpl}; -use orion::operators::vec::{VecTrait, NullableVec, NullableVecImpl}; -use orion::numbers::fixed_point::implementations::fp16x16::core::{FixedTrait, FP16x16, FP16x16Add, FP16x16Div, FP16x16Mul, FP16x16Sub, FP16x16Impl}; -use orion::operators::tensor::{TensorTrait, Tensor}; -use orion::operators::tensor::implementations::tensor_fp16x16::FP16x16Tensor; - -fn test_matrix(ref X: MutMatrix) { - // Print X by columns - let mut c = 0; - loop { - if c == X.cols { - break (); - } - let mut r = 0; - loop { - if r == X.rows { - break; - } - let mut val = X.get(r, c).unwrap(); - val.print(); - r += 1; - }; - c += 1; - }; - } - -fn linalg_solve(ref X: MutMatrix, ref y: MutMatrix) -> MutMatrix { - - let n = X.rows; - let mut row: u32 = 0; - let mut col: u32 = 0; - let mut i = 0; - - loop { - if row == n { - break; - } - - // Find the row number and max row number for X - i = row + 1; - let mut max_row = row; - loop { - if i == n { - break; - } - if X.get(i, row).unwrap().mag > X.get(max_row, row).unwrap().mag { - max_row = i; - } - i += 1; - }; - - let mut X_row = MutMatrixImpl::new(1, X.cols); - let mut X_max_row = MutMatrixImpl::new(1, X.cols); - let mut y_row = y.get(row, 0).unwrap(); - let mut y_max_row = y.get(max_row, 0).unwrap(); - - // Store X_row and X_max_row - i = 0; - loop { - if i == n { - break; - } - - X_row.set(0, i, X.get(row, i).unwrap()); - X_max_row.set(0, i, X.get(max_row, i).unwrap()); - - i += 1; - }; - - // Interchange X_row with X_max_row, y_row with y_max_row - i = 0; - loop { - if i == n { - break; - } - - X.set(row, i, X_max_row.get(0, i).unwrap()); - X.set(max_row, i, X_row.get(0, i).unwrap()); - - i += 1; - }; - y.set(max_row, 0, y_row); - y.set(row, 0, y_max_row); - - // Check for singularity - assert(X.get(row, row).unwrap().mag != 0, 'Singular matrix error'); - - // Perform forward elimination - i = row + 1; - loop { - if i == n { - break; - } - let mut factor = X.get(i, row).unwrap() / X.get(row, row).unwrap(); - let mut j = row; - loop { - if j == n { - break; - } - let mut X_new_val = X.get(i, j).unwrap() - factor * X.get(row, j).unwrap(); - X.set(i, j, X_new_val); - - j += 1; - }; - let mut y_new_val = y.get(i, 0).unwrap() - factor * y.get(row, 0).unwrap(); - y.set(i, 0, y_new_val); - - i += 1; - }; - - row += 1; - }; - - // Perform back substitution - let mut S = MutMatrixImpl::new(X.rows, 1); - i = 0; - loop { - if i == n { - break; - } - S.set(i, 1, FP16x16 { mag: 0, sign: false }); - i += 1; - }; - - i = n; - loop { - if i == 0 { - break; - } - let mut X_i = y.get(i - 1, 0).unwrap(); - let mut j = i; - loop { - if j == n { - break; - } - X_i -= X.get(i - 1, j).unwrap() * S.get(j, 0).unwrap(); - - j += 1; - }; - X_i /= X.get(i - 1, i - 1).unwrap(); - S.set(i - 1, 0, X_i); - - i -= 1; - }; - - return S; - } - -fn exponential_weights(lambda_unscaled: u32, l: u32) -> MutMatrix { - let lambda = FixedTrait::::new_unscaled(lambda_unscaled, false) / FixedTrait::::new_unscaled(100, false); - let mut weights = MutMatrixImpl::::new(l, 1); - let mut i = 0; - loop { - if i == l { - break; - } - let mut l_i = FixedTrait::::new_unscaled(i, false); - let mut l_pow = FixedTrait::pow(lambda, l_i); - let mut w_i = (FixedTrait::::new_unscaled(1, false) - lambda) * l_pow; - weights.set(i, 0, w_i); - i += 1; - }; - return weights; -} - -fn diagonalize(ref X: MutMatrix) -> MutMatrix { - assert(X.rows > 1 && X.cols == 1, 'X not row vector'); - - let mut i = 0; - let mut result = MutMatrixImpl::::new(X.rows, X.rows); - loop { - if i == X.rows { - break; - } - let mut j = 0; - loop { - if j == X.rows { - break; - } - if i == j { - result.set(i, j, X.get(i, 0).unwrap()); - } - else { - result.set(i, j, FixedTrait::::new(0, false)); - } - j += 1; - }; - i += 1; - }; - return result; -} - -fn mean(ref X: MutMatrix, axis: u32) -> MutMatrix { - // Simple average case for a matrix along specified axis - // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 - - assert(axis == 0 || axis == 1, 'Wrong axis'); - - // Simple average case for a vector - // Returns a matrix with shape (1,1) - if X.cols == 1 || X.rows == 1 { - - let mut result = MutMatrixImpl::::new(1, 1); - let mut num = FixedTrait::::new_unscaled(0, false); - let mut i = 0; - - let den = FixedTrait::::new_unscaled(X.data.len(), false); - - if X.cols == 1 && X.rows == 1 { - result.set(0, 0, X.get(0, 0).unwrap()); - return result; - } - else { - let l = if (X.rows > 1) { - X.rows - } - else { - X.cols - }; - loop { - if i == l { - break; - } - let mut num_i = if (X.rows > 1) { - X.get(i, 0).unwrap() - } - else { - X.get(0, i).unwrap() - }; - num += num_i; - i += 1; - }; - result.set(0, 0, num / den); - } - - return result; - } - - // Matrix average along specified axis - // Returns a vector with shape=(X.rows, 1) if axis == 0 or shape=(1, X.cols) if axis == 1 - else { - // Average along rows - if axis == 0 { - let mut result = MutMatrixImpl::::new(X.rows, 1); - let den = FixedTrait::::new_unscaled(X.cols, false); - let mut row = 0; - - loop { - if row == X.rows { - break; - } - let mut row_num = FixedTrait::::new_unscaled(0, false); - let mut col = 0; - loop { - if col == X.cols { - break; - } - row_num += X.get(row, col).unwrap(); - col += 1; - }; - result.set(row, 0, row_num / den); - row += 1; - }; - - return result; - } - - // Average along columns - else { - let mut result = MutMatrixImpl::::new(1, X.cols); - let den = FixedTrait::::new_unscaled(X.rows, false); - let mut col = 0; - - loop { - if col == X.cols { - break; - } - let mut col_num = FixedTrait::::new_unscaled(0, false); - let mut row = 0; - loop { - if row == X.rows { - break; - } - col_num += X.get(row, col).unwrap(); - row += 1; - }; - result.set(0, col, col_num / den); - col += 1; - }; - - return result; - } - } -} - -fn mean_weighted(ref X: MutMatrix, ref weights: MutMatrix, axis: u32) -> MutMatrix { - // Weighted average - // Returns a matrix with shape (X.rows, 1) if axis == 0 or (1, X.cols) if axis == 1 - - // Weight assertions - if X.rows > 1 { - assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); - } - else { - assert(weights.cols == X.cols && weights.rows == 1, 'Weights shape mismatch'); - } - - // Vector case - if X.rows == 1 || X.cols == 1 { - - assert(X.rows != X.cols, '1 element input'); - - let mut result = MutMatrixImpl::::new(1, 1); - let mut num = FixedTrait::::new_unscaled(0, false); - let mut i = 0; - - let den = FixedTrait::::new_unscaled(X.data.len(), false); - - let l = if (X.rows > 1) { - X.rows - } - else { - X.cols - }; - - loop { - if i == l { - break; - } - let mut num_i = if (X.rows > 1) { - X.get(i, 0).unwrap() * weights.get(i, 0).unwrap() - } - else { - X.get(0, i).unwrap() * weights.get(0, i).unwrap() - }; - num += num_i; - i += 1; - }; - result.set(0, 0, num / den); - - return result; - } - - // Matrix case - else { - assert(axis == 0 || axis == 1, 'Wrong axis'); - - // Average along rows - if axis == 0 { - - let mut result = MutMatrixImpl::::new(X.rows, 1); - let mut row = 0; - - loop { - if row == X.rows { - break; - } - let mut row_num = FixedTrait::::new_unscaled(0, false); - let mut col = 0; - loop { - if col == X.cols { - break; - } - row_num += X.get(row, col).unwrap() * weights.get(col, 0).unwrap(); - col += 1; - }; - result.set(row, 0, row_num); - row += 1; - }; - - return result; - } - - // Average along columns - else { - let mut result = MutMatrixImpl::::new(1, X.cols); - let mut col = 0; - - loop { - if col == X.cols { - break; - } - let mut col_num = FixedTrait::::new_unscaled(0, false); - let mut row = 0; - loop { - if row == X.rows { - break; - } - col_num += X.get(row, col).unwrap() * weights.get(row, 0).unwrap(); - row += 1; - }; - result.set(0, col, col_num); - col += 1; - }; - - return result; - } - } -} - -fn covariance(ref X: MutMatrix) -> MutMatrix { - assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); - - let m = X.rows; // Num observations - let n = X.cols; // Num variables - let mut Cov_X = MutMatrixImpl::::new(n, n); - let mut Mean_X = mean(ref X, 1); - - let mut i = 0; - loop { - if i == n { - break; - } - let mut j = 0; - loop { - if j == n { - break; - } - let mut k = 0; - let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); - loop { - if k == m { - break; - } - Cov_X_i_j += ((X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); - k += 1; - }; - Cov_X_i_j /= FixedTrait::::new_unscaled(m - 1, false); - Cov_X.set(i, j, Cov_X_i_j); - Cov_X.set(j, i, Cov_X_i_j); - j += 1; - }; - i += 1; - }; - - return Cov_X; -} - -fn covariance_weighted(ref X: MutMatrix, ref weights: MutMatrix) -> MutMatrix { - assert(X.rows > 1 && X.cols > 1, 'Not enough obs'); - assert(weights.rows == X.rows && weights.cols == 1, 'Weights shape mismatch'); - - // Normalize weights - let mut normalized_weights = MutMatrixImpl::::new(weights.rows, 1); - let mut total_weight = weights.reduce_sum(0, false); - let mut i = 0; - loop { - if i == weights.rows { - break; - } - let w_i = weights.get(i, 0).unwrap(); - normalized_weights.set(i, 0, w_i / total_weight.get(0, 0).unwrap()); - i += 1; - }; - - let m = X.rows; // Num observations - let n = X.cols; // Num variables - let mut Cov_X = MutMatrixImpl::::new(n, n); - let mut Mean_X = mean_weighted(ref X, ref weights, 1); - - let mut adj_weight_sum = FixedTrait::::new_unscaled(0, false); - i = 0; - loop { - if i == normalized_weights.rows { - break; - } - let mut w_i = normalized_weights.get(i, 0).unwrap(); - adj_weight_sum += (w_i * w_i); - i += 1; - }; - - i = 0; - loop { - if i == n { - break; - } - let mut j = 0; - loop { - if j == n { - break; - } - let mut k = 0; - let mut Cov_X_i_j = FixedTrait::::new_unscaled(0, false); - loop { - if k == m { - break; - } - Cov_X_i_j += (normalized_weights.get(k, 0).unwrap() * (X.get(k, i).unwrap() - Mean_X.get(0, i).unwrap()) * (X.get(k, j).unwrap() - Mean_X.get(0, j).unwrap())); - k += 1; - }; - let mut den = FixedTrait::::new_unscaled(1, false) - adj_weight_sum; - Cov_X_i_j /= den; - Cov_X.set(i, j, Cov_X_i_j); - Cov_X.set(j, i, Cov_X_i_j); - j += 1; - }; - i += 1; - }; - - return Cov_X; -} - -fn main() { - - let mut X_data = VecTrait::::new(); - X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 - X_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - X_data.push(FP16x16 { mag: 65536, sign: true }); // -1 - X_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - X_data.push(FP16x16 { mag: 131072, sign: true }); // -2 - X_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - X_data.push(FP16x16 { mag: 131072, sign: false }); // 1 - let mut X = MutMatrix { data: X_data, rows: 3, cols: 3}; - - let mut y_data = VecTrait::::new(); - y_data.push(FP16x16 { mag: 524288, sign: false }); // 8 - y_data.push(FP16x16 { mag: 720896, sign: true }); // -11 - y_data.push(FP16x16 { mag: 196608, sign: true }); // -3 - let mut y = MutMatrix { data: y_data, rows: 3, cols: 1}; - - // Linalg test - let mut S = linalg_solve(ref X, ref y); - test_matrix(ref S); - // Solution is [2, 3, -1] in FP16x16 format! - - // let mut Y1_data = VecTrait::::new(); - // Y1_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - // Y1_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - // Y1_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - // let mut Y1 = MutMatrix { data: Y1_data, rows: 3, cols: 1}; - - // let mut Y2_data = VecTrait::::new(); - // Y2_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - // Y2_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - // Y2_data.push(FP16x16 { mag: 196608, sign: false }); // 3 - // Y2_data.push(FP16x16 { mag: 262144, sign: false }); // 4 - // Y2_data.push(FP16x16 { mag: 327680, sign: false }); // 5 - // Y2_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - // Y2_data.push(FP16x16 { mag: 458752, sign: false }); // 7 - // Y2_data.push(FP16x16 { mag: 524288, sign: false }); // 8 - // Y2_data.push(FP16x16 { mag: 589824, sign: false }); // 9 - // let mut Y2 = MutMatrix { data: Y2_data, rows: 3, cols: 3}; - - // let mut weights_data = VecTrait::::new(); - // weights_data.push(FP16x16 { mag: 13017, sign: false }); // 0.2 - // weights_data.push(FP16x16 { mag: 19661, sign: false }); // 0.3 - // weights_data.push(FP16x16 { mag: 32768, sign: false }); // 0.5 - // let mut W = MutMatrix { data: weights_data, rows: 3, cols: 1}; - - // Mean tests - // let mut Y1_mean = mean(ref Y1); - // let mut Y2_mean_rows = mean_matrix(ref Y2, 0); - // let mut Y2_mean_cols = mean_matrix(ref Y2, 1); - // 'Y1_mean:'.print(); - // test_matrix(ref Y1_mean); - // 'Y2_mean_rows:'.print(); - // test_matrix(ref Y2_mean_rows); - // 'Y2_mean_cols:'.print(); - // test_matrix(ref Y2_mean_cols); - - // let mut Y1_mean_weighted = mean_weighted(ref Y1, ref W, 0); - // let mut Y2_mean_weighted_rows = mean_weighted(ref Y2, ref W, 0); - // let mut Y2_mean_weighted_cols = mean_weighted(ref Y2, ref W, 1); - // 'Y1_mean_weighted:'.print(); - // test_matrix(ref Y1_mean_weighted); - // 'Y2_mean_weighted_rows:'.print(); - // test_matrix(ref Y2_mean_weighted_rows); - // 'Y2_mean_weighted_cols:'.print(); - // test_matrix(ref Y2_mean_weighted_cols); - - // let mut W_diag = diagonalize(ref W); - // test_matrix(ref W_diag); - - // let mut Y3_data = VecTrait::::new(); - // Y3_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - // Y3_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - // Y3_data.push(FP16x16 { mag: 196608, sign: false }); // 3 - // Y3_data.push(FP16x16 { mag: 262144, sign: false }); // 4 - // let mut Y3 = MutMatrix { data: Y3_data, rows: 2, cols: 2}; - - // let mut Y4_data = VecTrait::::new(); - // Y4_data.push(FP16x16 { mag: 65536, sign: false }); // 1 - // Y4_data.push(FP16x16 { mag: 131072, sign: false }); // 2 - // Y4_data.push(FP16x16 { mag: 196608, sign: false }); // 3 - // Y4_data.push(FP16x16 { mag: 262144, sign: false }); // 4 - // Y4_data.push(FP16x16 { mag: 327680, sign: false }); // 5 - // Y4_data.push(FP16x16 { mag: 393216, sign: false }); // 6 - // let mut Y4 = MutMatrix { data: Y4_data, rows: 2, cols: 3}; - - // let mut Y = MutMatrixImpl::::new(3,1); - // Y.set(0, 0, FixedTrait::::new_unscaled(1, false)); - // Y.set(1, 0, FixedTrait::::new_unscaled(1, false)); - // Y.set(2, 0, FixedTrait::::new_unscaled(1, false)); - // Y.set(1, 1, FixedTrait::::new_unscaled(4, false)); - // Y.set(2, 0, FixedTrait::::new_unscaled(5, false)); - // Y.set(2, 1, FixedTrait::::new_unscaled(6, false)); - - let mut X = MutMatrixImpl::::new(4,3); - X.set(0, 0, FixedTrait::::new_unscaled(1, false)); - X.set(1, 0, FixedTrait::::new_unscaled(2, false)); - X.set(2, 0, FixedTrait::::new_unscaled(3, false)); - X.set(3, 0, FixedTrait::::new_unscaled(4, false)); - X.set(0, 1, FixedTrait::::new_unscaled(5, false)); - X.set(1, 1, FixedTrait::::new_unscaled(6, false)); - X.set(2, 1, FixedTrait::::new_unscaled(7, false)); - X.set(3, 1, FixedTrait::::new_unscaled(8, false)); - X.set(0, 2, FixedTrait::::new_unscaled(2, false)); - X.set(1, 2, FixedTrait::::new_unscaled(2, false)); - X.set(2, 2, FixedTrait::::new_unscaled(4, false)); - X.set(3, 2, FixedTrait::::new_unscaled(4, false)); - - let mut weights = MutMatrixImpl::::new(4, 1); - weights.set(0, 0, FixedTrait::::new(6554, false)); // 0.1 - weights.set(1, 0, FixedTrait::::new(13107, false)); // 0.2 - weights.set(2, 0, FixedTrait::::new(19661, false)); // 0.3 - weights.set(3, 0, FixedTrait::::new(26214, false)); // 0.4 - - // let mut mean_X = mean_weighted(ref X, ref weights, 1); - // let mut cov_X = covariance_weighted(ref X, ref weights); - // 'shape'.print(); - // cov_X.rows.print(); - // cov_X.cols.print(); - // test_matrix(ref cov_X); - - // let mut X = exponential_weights(97, 3); - // 'shape='.print(); - // X.rows.print(); - // X.cols.print(); - // test_matrix(ref X); - - } \ No newline at end of file +mod test_helper; \ No newline at end of file diff --git a/tests/operators/matrix_linalg_test.cairo b/tests/operators/matrix_linalg_test.cairo index d79f42eee..bc4914a09 100644 --- a/tests/operators/matrix_linalg_test.cairo +++ b/tests/operators/matrix_linalg_test.cairo @@ -21,8 +21,8 @@ fn matrix_linalg_test() { let mut Y = MutMatrixTrait::::new(3, 1); Y.set(0, 0, FixedTrait::::new_unscaled(8, false)); - Y.set(0, 1, FixedTrait::::new_unscaled(11, true)); - Y.set(0, 2, FixedTrait::::new_unscaled(3, true)); + Y.set(1, 0, FixedTrait::::new_unscaled(11, true)); + Y.set(2, 0, FixedTrait::::new_unscaled(3, true)); let mut S = MatrixLinalgTrait::::linalg_solve(ref X, ref Y); diff --git a/tests/operators/matrix_statistics_test.cairo b/tests/operators/matrix_statistics_test.cairo index 9944d8a65..f3a5b6105 100644 --- a/tests/operators/matrix_statistics_test.cairo +++ b/tests/operators/matrix_statistics_test.cairo @@ -83,8 +83,8 @@ fn mean_test_2D_ii() { assert(mu_X.rows == 1 && mu_X.cols == 3, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(163840, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~2.5 - assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 - assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 + assert(FixedTrait::abs(mu_X.get(0, 1).unwrap() - FixedTrait::::new(425984, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~6.5 + assert(FixedTrait::abs(mu_X.get(0, 2).unwrap() - FixedTrait::::new(196608, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3 } #[test] @@ -149,8 +149,8 @@ fn mean_weighted_test_ii() { assert(mu_X.rows == 1 && mu_X.cols == 3, 'Shape incorrect'); assert(FixedTrait::abs(mu_X.get(0, 0).unwrap() - FixedTrait::::new(196607, false)) < ERROR_THRESHOLD, 'mean_X_1 incorrect'); // ~3.0 - assert(FixedTrait::abs(mu_X.get(1, 0).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 - assert(FixedTrait::abs(mu_X.get(2, 0).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 + assert(FixedTrait::abs(mu_X.get(0, 1).unwrap() - FixedTrait::::new(458751, false)) < ERROR_THRESHOLD, 'mean_X_2 incorrect'); // ~7.0 + assert(FixedTrait::abs(mu_X.get(0, 2).unwrap() - FixedTrait::::new(222822, false)) < ERROR_THRESHOLD, 'mean_X_3 incorrect'); // ~3.4 } #[test] @@ -178,12 +178,12 @@ fn covariance_test() { assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.67 assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.67 assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(0, 1).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(1, 1).unwrap() - FixedTrait::::new(109226, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.67 + assert(FixedTrait::abs(sigma2_X.get(2, 1).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(0, 2).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(1, 2).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.33 + assert(FixedTrait::abs(sigma2_X.get(2, 2).unwrap() - FixedTrait::::new(87381, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.33 } #[test] @@ -217,10 +217,10 @@ fn covariance_weighted_test() { assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_11 incorrect'); // ~1.43 assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_21 incorrect'); // ~1.43 assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_31 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(0, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(1, 0).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 - assert(FixedTrait::abs(sigma2_X.get(2, 0).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 + assert(FixedTrait::abs(sigma2_X.get(0, 1).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_12 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(1, 1).unwrap() - FixedTrait::::new(93613, false)) < ERROR_THRESHOLD, 'sigma2_X_22 incorrect'); // ~1.43 + assert(FixedTrait::abs(sigma2_X.get(2, 1).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_32 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(0, 2).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_13 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(1, 2).unwrap() - FixedTrait::::new(74889, false)) < ERROR_THRESHOLD, 'sigma2_X_23 incorrect'); // ~1.14 + assert(FixedTrait::abs(sigma2_X.get(2, 2).unwrap() - FixedTrait::::new(78632, false)) < ERROR_THRESHOLD, 'sigma2_X_33 incorrect'); // ~1.20 } \ No newline at end of file