#math #tensor #type #complex-numbers

rapl

一个使 Rust 数值脚本简单且愉快的 crate

5 个不稳定版本

0.3.0 2023年6月13日
0.2.1 2023年4月22日
0.2.0 2023年4月21日
0.1.1 2023年3月22日
0.1.0 2023年3月22日

#15 in #complex-numbers

42 每月下载次数

MIT 许可证

5MB
3.5K SLoC

rapl

Documentation Crate

注意: rapl 处于早期开发阶段,未针对性能优化,不建议用于生产应用。

rapl 是一个 Rust 库,提供了与 N 维数组简单操作的方式,并附带一系列用于操作它们的数学函数。它受到了 NumPy 和 APL 的启发,主要目标是实现最大的易用性和用户友好性,同时保持通用性。

我们的目标是使 Rust 脚本尽可能高效,使 Rust 成为数值计算和数据科学的一个真实选择。查看 示例

开箱即用的 rapl 提供了诸如 协同广播、秩类型检查、原生复数支持 等功能

use rapl::*;
fn main() {
    let a = Ndarr::from([1 + 1.i(), 2 + 1.i()]);
    let b = Ndarr::from([[1, 2], [3, 4]]);
    let r = a + b - 2;
    assert_eq!(r, Ndarr::from([[1.i(), 2 + 1.i()],[2 + 1.i(), 4 + 1.i()]]));
}

数组初始化

有多种方便的方法可以初始化 N 维数组(或 Ndarr)。

  • 从原生 Rust 数组到 Ndarr
let a = Ndarr::from(["a","b","c"]); 
let b = Ndarr::from([[1,2],[3,4]]);
  • 从范围。
let a = Ndarr::from(1..7).reshape(&[2,3])
  • &str
let chars = Ndarr::from("Hello rapl!"); //Ndarr<char,U1>
  • 其他
let ones: Ndarr<f32, 2> = Ndarr::ones(&[4,4]);
let zeros : Ndarr<i32, 3>= Ndarr::zeros(&[2,3,4]);
let letter_a = Ndarr::fill("a", &[5]);
let fold = Ndarr::new(data: &[0, 1, 2, 3], shape: [2, 2]).expect("Error initializing");
  • linspace, logspace, geomspace
    let linear = Ndarr::linspace(0, 9, 10);
    assert_eq!(linear,Ndarr::from(0..10));

    let logarithmic = Ndarr::logspace(0.,9., 10., 10);
    assert!(logarithmic.approx(&Ndarr::from([1.,1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9])));

    let geom = Ndarr::geomspace(1.,256., 9);
    assert!(geom.approx(&Ndarr::from([1., 2., 4., 8., 16., 32., 64., 128., 256.])));

随机数组创建

您可以轻松地创建任何形状的随机数组

//Normal distribution
let arr_norm = NdarrRand::normal(low: 0f32, high: 1f32, shape: [2, 2], Seed: Some(1234));
//Normal distribution
let arr_uniform = NdarrRand::uniform(low: 0f32, high: 1f32, shape: [10], Seed: None);
//Choose between values
let arr_choose = NdarrRand::choose(&[1, 2, 3, 4, 5], [3, 3], Some(1234));

逐元素操作

  • 与标量进行算术运算
let ones: Ndarr<i32, 2> = Ndarr::ones(&[4,4]);
let twos = ones + 1;
let sixes = twos * 3;
  • Ndarr 之间进行算术运算
let a = Ndarr::from([[1,2],[3,4]]);
let b = Ndarr::from([[1,2],[-3,-4]]);

assert_eq!(a + b, Ndarr::from([[2,4],[0,0]]))

注意:如果形状不相等,rapl 将自动将数组广播到兼容的形状(如果存在)并执行操作。

  • 包括三角函数和激活函数在内的数学运算。
let x = Ndarr::from([-1.0 , -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0]);
let sin_x = x.sin();
let cos_x = x.cos();
let tanh_x = x.tanh();

let abs_x = x.abs();
let relu_x = x.relu();
  • 映射函数
let a = Ndarr::from([[1,2],[3,4]]);
let mapped = a.map(|x| x*2-1);

单调张量操作

  • 转置
let arr = Ndarr::from([[1,2,3],[4,5,6]]);	
assert_eq!(arr.shape(), [2,3]);
assert_eq!(arr.clone().t().shape, [3,2]); //transpose
  • 重塑
let a = Ndarr::from(1..7).reshape(&[2,3]).unwrap();
  • 切片
let arr = Ndarr::from([[1,2],[3,4]]);

assert_eq!(arr.slice_at(1)[0], Ndarr::from([1,3]))
  • 减少
let sum_axis = arr.clone().reduce(1, |x,y| x + y).unwrap();
assert_eq!(sum_axis, Ndarr::from([6, 15])); //sum reduction
  • 向右和向左扫描
 let s = Ndarr::from([1,2,3]);
 let cumsum = s.scanr( 0, |x,y| x + y);
 assert_eq!(cumsum, Ndarr::from([1,3,6]));
  • 滚动
let a = Ndarr::from([[1, 2], [3, 4]]);
assert_eq!(a.roll(1, 1), Ndarr::from([[2, 1], [4, 3]]))

动态张量操作

  • 兼容数组之间的一般矩阵乘法
use rapl::*
use rapl::ops::{mat_mul};
let a = Ndarr::from(1..7).reshape(&[2,3]).unwrap();
let b = Ndarr::from(1..7).reshape(&[3,2]).unwrap();
    
let matmul = mat_mul(a, b))
  • APL 启发的内积。
    let a = Ndarr::from(1..7).reshape(&[2,3]).unwrap();
    let b = Ndarr::from(1..7).reshape(&[3,2]).unwrap();
    
    let inner = rapl::ops::inner_product(|x,y| x*y, |x,y| x+y, a.clone(), b.clone());
    assert_eq!(inner, rapl::ops::mat_mul(a, b))

  • 外积。
    let suits = Ndarr::from(["","","",""]);
    let ranks = Ndarr::from(["2","3","4","5","6","7","8","9","10","J","Q","K","A"]);

    let add_str = |x: &str, y: &str| (x.to_owned() + y);

    let deck = ops::outer_product( add_str, ranks, suits).flatten(); //All cards in a deck

复数

您可以通过简单且干净的用户界面,在原生数值类型和复数类型 C<T> 之间进行操作。

use rapl::*;
// Complex sclars
    let z = 1 + 2.i();
    assert_eq!(z, C(1,2));
    assert_eq!(z - 3, -2 + 2.i());

无缝地与复数和复数张量一起工作。

use rapl::*;
// Complex tensors
let arr = Ndarr::from([1, 2, 3]);
let arr_z = arr + -1 + 2.i();
assert_eq!(arr_z, Ndarr::from([C(0,2), C(1,2), C(2,2)]));
assert_eq!(arr_z.im(), Ndarr::from([2,2,2]));

简单的 1D 和 2D FFT

    let signal = Ndarr::linspace(-10., 10., 100).sin();
    let signal_fft = signal.to_complex().fft();

图像到数组和数组到图像的转换

您可以轻松地处理几乎任何格式的图像。 rapl 提供了有用的函数来将图像作为 RGB 和亮度 Ndarr 打开,并将它们保存到您喜欢的格式。

use rapl::*;
use rapl::utils::rapl_img;

fn main() {
    //open RGB image as  Ndarr<u8,3>
    let img: Ndarr<u8,U3> = rapl_img::open_rgbu8(&"image_name.jpg").unwrap();
    //Split RGB channels by Slicing along 3'th axis.
    let channels: Vec<Ndarr<u8,U2>> = img.slice_at(2);
    //select blue channel and save it as black and white image.
    channels[2].save_as_luma(&"blue_channel.png", rapl_img::ImageFormat::Png);
}

开发中的功能

  • 移植到稳定的Rust
  • 支持复数。
  • 行间距和meshigrid初始化。
  • 随机数组创建。
  • 1D和2D FFT。
  • 矩阵求逆。
  • 图像到数组的转换。
  • 数组到图像的转换。
  • 受APL启发的旋转函数。
  • 常用的ML函数,如Relu、Softmax等。
  • 支持Rust中的现有绘图库。
  • 可变切片。
  • 其他线性代数功能:Eigen、LU、高斯-若尔当等。
  • 自动微分。

依赖项

~2.2–4.5MB
~80K SLoC