123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- Rust Language Cheat Sheet - https://cheats.rs/
- Easy Rust - https://dighomon.github.io/easy_rust/
- A Gentle Introduction Rust - https://stevedonovan.github.io/rust-gentle-intro/
- Installation - https://doc.rust-lang.org/book/ch01-01-installation.html
- The standard library reference - https://doc.rust-lang.org/std/
- The rustc book - https://doc.rust-lang.org/stable/rustc/
- Cookin' with Rust - https://rust-lang-nursery.github.io/rust-cookbook/
- The Embedded Rust Book - https://docs.rust-embedded.org/book/intro/index.html
- Learn Rust with Entirely too many Linked Lists -
- https://rust-unofficial.github.io/too-many-lists/
- The Rust community's crate registry - https://crates.io/
- Are we learning yet? - https://www.arewelearningyet.com/
- Open-Source Rust crates for numerical simulation - https://www.dimforge.com/
- Module ndarray for NumPy users -
- https://docs.rs/ndarray/latest/ndarray/doc/ndarray_for_numpy_users/index.html
- From Python into Rust -
- https://github.com/rochachrumo/py2rs#getting-started-with-rust
- Rust quick reference - https://quickref.me/rust
- Programming Idioms with Go and Rust -
- https://programming-idioms.org/cheatsheet/Go/Rust
- Getting started with Programming in Rust -
- https://jesselawson.github.io/getting-started-with-rust/
- # to download Rustup and install Rust
- $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- Rust updates very frequently, if you have installed Rustup some time ago, chances
- are your Rust version is out of date. Get the latest version of Rust by running
- $ rustup update
- # version
- $ rustc --version
- Rust By Example
- $ git clone https://github.com/rust-lang/rust-by-example.git
- $ cd rust-by-example
- $ cargo install mdbook
- $ mdbook build
- $ mdbook serve
- # list of supported targets
- $ rustc --print target-list
- # Rust's package manager
- $ cargo --help
- # list of all avaliable commands
- $ cargo --list
- # list installed component
- $ rustup show
- # install component
- $ rustup component add clippy
- # create new project using cargo
- $ cargo new --lib <project> // create new package directory
- # create a new Cargo package in an existing directory
- $ cargo init // without args creates files in current location
- $ cargo init --bin // create a package with a binary target (src/main.rs)
- $ cargo init --lib // create a package with a library target (src/lib.rs)
- $ cargo init <project> // with <project name> as args acts like cargo new
- Ref: https://doc.rust-lang.org/cargo/commands/cargo-init.html
- # working on an existing Cargo package
- If you download an existing package that uses Cargo, it's really easy to get
- going. First, get the package, in this example, we'll use regex cloned from its
- repository on GitHub:
- $ git clone https://github.com/rust-lang/regex.git
- $ cd regex
- To build, use cargo build:
- $ cargo build
- Compiling regex v1.5.0 (file://path/to/package/regex)
- This will fetch all of the dependencies and then build them, along with the
- package.
- Ref: https://doc.rust-lang.org/cargo/guide/working-on-an-existing-project.html
- # rust formatting
- $ rustfmt program.rs
- $ rustfmt lib.rs program.rs
- # rust compile
- $ rustc program.rs
- $ rustc -O program.rs // optimized compile
- # adding dependencies using Cargo
- Cargo allow to add dependencies that your program needs to run. Adding a
- dependency is extremely easy with Cargo. Every Rust package includes a
- Cargo.toml file, which contains a list (empty by default) of dependencies. Open
- the file, find the [dependencies] section, and add the library you want to
- include in your package. For example, to add the rand library as your
- dependency.
- [dependencies]
- rand = "0.3.14"
- Try building your package to see what happens.
- $ cargo build
- New versions of libraries keep coming, and Cargo provides an easy way to update
- all of their dependencies using the update command:
- $ cargo update
- To update specific libraries using the -p flag followed by the package name:
- $ cargo update -p rand
- # create documnetation
- //! # it uses markdown notation
- //! - bullet
- //! - points
- # primitive types
- # integers
- signed integers: i8, i16, i32, i64, i128, isize
- unsigned integers: u8, u16, u32, u64, u128, usize
- isize and usize: number of bits on the machine (architecture)
- # science in rust lang
- ndarray - https://docs.rs/ndarray/latest/ndarray/index.html
- nalgebra - https://docs.rs/nalgebra/latest/nalgebra/index.html
- plotters - https://plotters-rs.github.io/home/#!/
- # don't array but vector
- don't pass a variable to a funtion and create an array of that variable size,
- instead pass a variable to a function and create a vector ot that variable size.
- Example:
- Not work:
- fn fibonacci(n: usize) -> usize {
- let mut f = [0; n]; // create an array of size n and assign 0 (int type)
- f[0] = 1; f[1] = 1; // the above line fails since size of n should be a
- // constant not a variable for an array creation
- for i in 1..n - 1 {
- f[i + 1] = f[i] + f[i - 1];
- }
- return f[n - 1];
- }
- Work well:
- fn fibonacci(n: usize) -> usize {
- let mut f = vec![0; n]; // create a vector of size n and assign 0 (int type)
- f[0] = 1; f[1] = 1;
- for i in 1..n - 1 {
- f[i + 1] = f[i] + f[i - 1];
- }
- return f[n - 1];
- }
- # comparison between Python and Rust
- Python Rust
- - interpreted - compiled
- - strongly, dynamically typed - strongly and statically typed
- - garbage collected - static memory management
- - structured, object-oriented, functional - structured, object-oriented, functional, concurrent
- - Exceptions - no exceptions
- - duck-typing, OO inheritance - no inheritance, uses traits
- - v3.0 stable since 2008 - stable since 2015
- 00. Hello world
- #!/usr/bin/env python
- "classic Hello World example in Python" //! classic Hello World example in Rust
- if __name__ == '__main__': fn main() {
- print("Hello World!") println!("Hello World!");
- }
- //! - module documentation string
- println! - a macro in rust (a function in python)
- # ecosystem
- Python Rust
- linter pylint, pep8 cargo clippy
- language server protocal python-language-server RLS, rust-analyzer
- code formatting black, yapf, autopep8 cargo fmt
- build binary setuptools, py2exe cargo build
- test unittest, pytest cargo test
- build environment virtualenv, pip, requirements.txt cargo new, cargo update, Cargo.toml
- documentation Sphinx based, doxygen cargo doc
- benchmark cProfile cargo bench, criterion.rs
- # factorial
- fn factorial(n: usize) -> usize {
- (1..n+1).product()
- }
- fn main() {
- const N: usize = 12;
- println!("{}", factorial(N));
- }
- # prime
- fn prime(number: i32) -> String {
- /* function to check prime */
- let sqrt_number = f64::sqrt(number.into());
- for i in 2..(sqrt_number as i32) + 1 {
- if number % i == 0 {
- return format!("{} is not a prime number", number);
- }
- }
- return format!("{} is a prime number", number);
- }
- fn main() {
- for n in 4..30 {
- println!("{}", prime(n));
- }
- }
- # vectors
- A vector Vec<T> is a resizable array of elements of type T, allocated on the
- heap. There are several ways to create vectors. The simplest is to use the vec!
- macro, which gives us a syntax for vectors that looks very much like an array
- literal:
- let mut primes = vec![2, 3, 5, 7]; // i32 type by default
- The vec! macro is equivalent to calling Vec::new to create a new, empty vector
- and then pushing the elements onto it, which is another idiom:
- let mut pal = Vec::new();
- pal.push("step");
- pal.push("on");
- pal.push("no");
- pal.push("pets");
- assert_eq!(pal, vec!["step", "on", "no", "pets"]);
- Another possibility is to build a vector from the values produced by an
- iterator:
- let v: Vec<i32> = (0..5).collect();
- assert_eq!(v, [0, 1, 2, 3, 4]);
- You'll often need to supply the type when using collect (as we've done here),
- because it can build many different sorts of collections, not just vectors. By
- specifying the type of v, we've made it unambiguous which sort of collection we
- want.
- The vector's len method returns the number of elements it contains now, its
- capacity method returns the number of elements it could hold without
- reallocation:
- let mut v = Vec::with_capacity(2);
- assert_eq!(v.len(), 0);
- assert_eq!(v.capacity(), 2);
- v.push(1);
- v.push(2);
- assert_eq!(v.len(), 2);
- assert_eq!(v.capacity(), 2);
- v.push(3);
- assert_eq!(v.len(), 3);
- println!("capacity is now {}", v.capacity()); // capacity is now 3
- You can insert and remove elements wherever you like in a vector, although these
- operations shift all the elements after the affected position forward or
- backward, so they may be slow if the vector is long:
- let mut v = vec![10, 20, 30, 40, 50];
- // make the element at index 3 be 35
- v.insert(3, 35);
- assert_eq!(v, [10, 20, 30, 35, 40, 50]);
- // remove the element at index 1
- v.remove(1);
- assert_eq!(v, [10, 30, 35, 40, 50]);
- You can use the pop method to remove the last element and return it. More
- precisely, popping a value from a Vec<T> returns an Option<T>: None if the
- vector was already empty, or Some(v) if its last element had been v:
- let mut v = vec!["Snow Puff", "Glass Gem"];
- assert_eq!(v.pop(), Some("Glass Gem"));
- assert_eq!(v.pop(), Some("Snow Puff"));
- assert_eq!(v.pop(), None);
- # adding all elements in a container
- let mut primes = vec![2, 3, 5, 7];
- assert_eq!(primes.iter().sum::<i32>(), 17);
- primes.push(11);
- primes.push(13);
- assert_eq!(primes.iter().sum::<i32>(), 41);
- # multiply all elements in a container
- let mut primes = vec![2, 3, 5, 7];
- assert_eq!(primes.iter().product::<i32>(), 210);
- primes.push(11);
- primes.push(13);
- assert_eq!(primes.iter().product::<i32>(), 30030);
- # floating-point types
- The types f32 and f64 have associated constants for the IEEE-required special
- values like INFINITY, NEG_INFINITY (negative infinity), NAN (the not-a-number
- value), and MIN and MAX (the largest and smallest finite values):
- assert!((-1. / f32::INFINITY).is_sign_negative());
- assert_eq!(-f32::MIN, f32::MAX);
- The f32 and f64 types provide a full complement of methods for mathematical
- calculations; for example, 2f64.sqrt() is the double-precision square root of
- two. Some examples:
- assert_eq!(5f32.sqrt() * 5f32.sqrt(), 5); // exactly 5.0, per IEEEE
- assert_eq!((-1.01f64).floor(), -2.0);
- As with integers, you usually won't need to write out type suffixes on
- floating-point literals in real code, but when you do, putting a type on either
- the literal or the function will suffice.
- println!("{}", (2.0_f64).sqrt());
- println!("{}", f64::sqrt(2.0));
- # math constants
- std::f64::consts::PI
- # Expressions
- Expression type Example Related traits
- Addition n + 1 Add
- Subtraction n - 1 Sub
- Multiplication n * 2 Mul
- Division n / 2 Div
- Remainder (modulus) n % 2 Rem
- Less than n < 1 std::cmp::PartialOrd
- Less than or equal n <= 1 std::cmp::PartialOrd
- Greater than n > 1 std::cmp::PartialOrd
- Greater than or equal n >= 1 std::cmp::PartialOrd
- Equal n == 1 std::cmp::PartialEq
- Not equal n != 1 std::cmp::PartialEq
- Assignment x = val
- Compound assignment x += 1 AddAssign
- x -= 1 SubAssign
- x *= 1 MulAssign
- x /= 1 DivAssign
- x %= 1 RemAssign
- x <<= 1 ShlAssign
- x >>= 1 ShrAssign
- x &= 1 BitAndAssign
- x ^= 1 BitXorAssign
- x != 1 BitOrAssign
- # ndarray - numpy equivalents
- import numpy as np # import numpy library in python
- use ndarray::prelude::*; / use the ndarray library in rust
- Array creation:
- np.array([[1.,2.,3.], [4.,5.,6.]]) # 2x3 floating-point array literal
- array![[1.,2.,3.], [4.,5.,6.]] / 2x3 floating-point array literal
- arr2(& [[1.,2.,3.], [4.,5.,6.]]) / 2x3 floating-point array literal
- np.arange(0., 10., 0.5) # create a 1-D array with values 0., 0.5, ..., 9.5
- np.r_[:10.:0.5] # create a 1-D array with values 0., 0.5, ..., 9.5
- Array::range(0., 10., 0.5) / create a 1-D array with values 0., 0.5, ..., 9.5
- np.linspace(0., 10., 11) # create a 1-D array with 11 elements with values 0., ..., 10.
- np.r_[:10.:11] # create a 1-D array with 11 elements with values 0., ..., 10.
- Array::linspace(0., 10., 11) / create a 1-D array with 11 elements with values 0., ..., 10.
- np.logspace(2.0, 3.0, num=4, base=10.0) # create a 1-D array with 4 elements with values 100., 215.4, 464.1, 1000.
- Array::logspace(10.0, 2.0, 3.0, 4) / create a 1-D array with 4 elements with values 100., 215.4, 464.1, 1000.
- np.geomspace(1., 1000., num=4) # create a 1-D array with 4 elements with values 1., 10., 100., 1000.
- Array::geomspace(1e0, 1e3, 4) / create a 1-D array with 4 elements with values 1., 10., 100., 1000.
- np.ones((3, 4, 5)) # create a 3x4x5 array filled with ones (inferring the element type)
- Array::ones((3, 4, 5)) / create a 3x4x5 array filled with ones (inferring the element type)
- np.zeros((3, 4, 5)) # create a 3x4x5 array filled with zeros (inferring the element type)
- Array::zeros((3, 4, 5)) / create a 3x4x5 array filled with zeros (inferring the element type)
- np.zeros((3, 4, 5), order='F') # create a 3x4x5 array with Fortran (column-major) memory layout filled with zeros (inferring the element type)
- Array::zeros((3, 4, 5).f()) / create a 3x4x5 array with Fortran (column-major) memory layout filled with zeros (inferring the element type)
- np.zeros_like(a, order='C') # create an array of zeros of the shape as a, with row-major
- Array::zeros(a.raw_dim()) # memory layout (unlike NumPy, this infers the element type from
- # context instead of duplicating a's element type)
- np.full((3, 4), 7.) # create a 3x4 array filled with the value 7.
- Array::from_elem((3, 4), 7.) / create a 3x4 array filled with the value 7.
- np.eye(3) # create a 3x3 identity matrix (inferring the element type)
- Array::eye(3) / create a 3x3 identity matrix (inferring the element type)
- np.diag(np.array([1, 2, 3])) # create a 3x3 matrix with [1, 2, 3] as diagonal and zeros elsewhere (inferring the element type)
- Array2::from_diag(&arr1(&[1, 2, 3])) / create a 3x3 matrix with [1, 2, 3] as diagonal and zeros elsewhere (inferring the element type)
- np.array([1, 2, 3, 4]).reshape((2, 2)) # create a 2x2 array from the elements in the list/Vec
- Array::from_shape_vec((2, 2), vec![1, 2, 3, 4])? / create a 2x2 array from the elements in the list/Vec
- np.array([1, 2, 3, 4]).reshape((2, 2), order='F') # create a 2x2 array from the elements in the list/Vec using Fortran (column-major) order
- Array::from_shape_vec((2, 2).f(), vec![1, 2, 3, 4])? / create a 2x2 array from the elements in the list/Vec using Fortran (column-major) order
- np.random # create arrays of random numbers
- Indexing and slicing
- a[-1] # access the last element in 1-D array a
- a[a.len() - 1] / access the last element in 1-D array a
- a[1, 4] # access the element in row 1, column 4
- a[[1, 4]] / access the element in row 1, column 4
- a[1] # get a 2-D subview of a 3-D array at index 1 of axis 0
- a[1, :, :] # get a 2-D subview of a 3-D array at index 1 of axis 0
- a.slice(s![1, .., ..]) / get a 2-D subview of a 3-D array at index 1 of axis 0
- a.index_axis(Axis(0), 1) / get a 2-D subview of a 3-D array at index 1 of axis 0
- a[:5] # get the first 5 rows of a 2-D array
- a[0:5] # get the first 5 rows of a 2-D array
- a[0:5, :] # get the first 5 rows of a 2-D array
- a.slice(s![..5, ..] / get the first 5 rows of a 2-D array
- a.slice(s![0..5, ..]) / get the first 5 rows of a 2-D array
- a.slice_axis(Axis(0), Slice::from(0..5)) / get the first 5 rows of a 2-D array
- a[-5:] # get the last 5 rows of a 2-D array
- a[-5:, :] # get the last 5 rows of a 2-D array
- a.slice(s![-5.., ..]) / get the last 5 rows of a 2-D array
- a.slice_axis(Axis(0), Slice::from(-5..)) / get the last 5 rows of a 2-D array
- a[:3, 4:9] # columns 4, 5, 6, 7, and 8 of the first 3 rows
- a.slice(s![..3, 4..9]) / columns 4, 5, 6, 7, and 8 of the first 3 rows
- a[1:4:2, ::-1] # rows 1 and 3 with the columns in reverse onder
- a.slice(s![1..4;2, ..;-1] / rows 1 and 3 with the columns in reverse onder
- Shape and strides
- np.ndim(a) # get the number of dimensions of array a
- a.ndim # get the number of dimensions of array a
- a.ndim() / get the number of dimensions of array a
- np.size(a) # get the number of elements in array a
- a.size # get the number of elements in array a
- a.len() / get the number of elements in array a
- np.shape(a) # get the shape of array a
- a.shape # get the shape of array a
- a.shape() / get the shape of array a
- a.dim() / get the shape of array a
- a.shape[axis] # get the length of an axis
- a.len_of(Axis(axis)) / get the length of an axis
- a.strides # get the strides of array a
- a.strides() / get the strides of array a
- np.size(a) == 0 # check if the array has zero elements
- a.size == 0 # check if the array has zero elements
- a.is_empty() / check if the array has zero elements
- Mathematics
- a.transpose() # transpose of array a
- a.T # transpose of array a
- a.t() / transpose of array a
- a.reversed_axes() / transpose of array a
- mat1.dot(mat2) # 2-D matrix multiply
- mat1.dot(&mat2) / 2-D matrix multiply
- mat.dot(vec) # 2-D matrix dot 1-D column vector
- mat.dot(&vec) / 2-D matrix dot 1-D column vector
- vec.dot(mat) # 1-D row vector dot 2-D matrix
- vec.dot(&mat) / 1-D row vector dot 2-D matrix
- vec1.dot(vec2) # vector dot product
- vec1.dot(&vec2) / vector dot product
- a * b, a + b, etc. # element-wise arithmetic operations
- a * b, a + b, etc. / element-wise arithmetic operations
- a**3 # element-wise power of 3
- a.mapv(|a| a.powi(3)) / element-wise power of 3
- np.sqrt(a) # element-wise square root for f64 array
- a.mapv(f64::sqrt) / element-wise square root for f64 array
- (a > 0.5) # array of bools of same shape as a with true where a > 0.5 and false elsewhere
- a.mapv(|a| a > 0.5) / array of bools of same shape as a with true where a > 0.5 and false elsewhere
- np.sum(a) # sum the elements in a
- a.sum() # sum the elements in a
- a.sum() / sum the elements in a
- np.sum(a, axis=2) # sum the elements in a along azis 2
- a.sum(axis=2) # sum the elements in a along azis 2
- a.sum_axis(Axis(2)) / sum the elements in a along azis 2
- np.mean(a) # calculate the mean of the elements in f64 array a
- a.mean() # calculate the mean of the elements in f64 array a
- a.mean().unwrap() / calculate the mean of the elements in f64 array a
- np.mean(a, axis=2) # calculate the mean of the elements in a along axis 2
- a.mean(axis=2) # calculate the mean of the elements in a along axis 2
- a.mean_axis(Axis(2)) / calculate the mean of the elements in a along axis 2
- np.allclose(a, b, atol=1e-8) # check if the arrays' elementwise differences
- are within an absolute tolerance (it requires
- the approx feature-flag)
- a.abs_diff_eq(&b, 1e-8) / check if the arrays' elementwise differences
- are within an absolute tolerance (it requires
- the approx feature-flag)
- np.diag(a) # view the diagonal of a
- a.diag() / view the diagonal of a
- np.linalg # linear algebra (matrix inverse, solving decompositions, etc.)
- Array manipulation
- a[:] = 3. # set all array elements to the same scalar value
- a.fill(3.) / set all array elements to the same scalar value
- a[:] = b # copy the data from array b into array a
- a.assign(&b) / copy the data from array b into array a
- np.concatenate((a,b), axis=1) # concatenate arrays a and b along axis 1
- concatenate![Axis(1), a, b] # concatenate arrays a and b along axis 1
- concatenate(Axis(1), &[a.view(), b.view()]) / concatenate arrays a and b along axis 1
- np.stack((a,b), axis=1) # stack arrays a and b along axis 1
- stack![Axis(1), a, b] / stack arrays a and b along axis 1
- stack(Axis(1), vec![a.view(), b.view()]) / stack arrays a and b along axis 1
- a[:,np.newaxis] # create an view of 1-D array a, inserting a new axis 1
- np.expand_dims(a, axis=1) # create an view of 1-D array a, inserting a new axis 1
- a.slice(s![.., NewAxis]) / create an view of 1-D array a, inserting a new axis 1
- a.insert_axis(Axis(1)) / create an view of 1-D array a, inserting a new axis 1
- a.transpose() # transpose of array a
- a.T # transpose of array a
- a.t() / transpose of array a
- a.reversed_axes() / transpose of array a
- np.diag(a) # view the diagonal of a
- a.diag() / view the diagonal of a
- a.flatten() # create a 1-D array by flattening a
- use std::iter::FromIterator;
- Array::from_iter(a.iter().cloned()) / create a 1-D array by flattening a
- Iteration
- a.flat # iterator over the array elements in logical order
- a.iter() / iterator over the array elements in logical order
- np.ndenumerate(a) # flat iterator yielding the index along with each element reference
- a.indexed_iter() / flat iterator yielding the index along with each element reference
- iter(a) # iterator over the first (outermost) axis, yielding each subview
- a.outer_iter() / iterator over the first (outermost) axis, yielding each subview
- a.axis_iter(Axis(0)) / iterator over the first (outermost) axis, yielding each subview
- Type conversions
- a.astype(np.float32) / convert u8 array infallibly to f32 array with
- a.mapv(|x| f32::from(x)) / std::convert::From, generally recommended
- a.astype(np.int32) / upcast u8 array to i32 array wit std::convert::From, preferable
- a.mapv(|x| i32::from(x)) / over as because it ensures at compile-time that the conversion is lossless
- a.astype(np.uint8) / try to convert i8 array to u8 array, panic if any value cannot
- a.mapv(|x| u8::try_from(x).unwrap()) / be converted lossless at runtime (e.g. negative value)
- a.astype(np.int32) / convert f32 array to i32 array with "saturating" conversion; care needed because
- a.mapv(|x| x as i32) / it can be a lossy conversion or result in non-finite values!
- Convenience methods for 2-D arrays
- len(a) or a.shape[0] # get the number of rows in a 2-D array
- a.nrows() / get the number of rows in a 2-D array
- a.shape[1] # get the number of columns in a 2-D array
- a.ncols() / get the number of columns in a 2-D array
- a[1] or a[1,:] # view (or mutable view) of row 1 in a 2-D array
- a.row(1) or a.row_mut(1) / view (or mutable view) of row 1 in a 2-D array
- a[:,4] # view (or mutable view) of columns 4 in a 2-D array
- a.column(4) or a.column_mut(4) / view (or mutable view) of columns 4 in a 2-D array
- a.shape[0] == a.shape[1] # check if the array is square
- a.is_square() / check if the array is square
- Reference: https://docs.rs/ndarray/latest/ndarray/doc/ndarray_for_numpy_users/index.html
|