Skip to content

Commit 3ef4b2c

Browse files
committed
ndarray-for-numpy-users examples
Created some examples for different ways to use rust-ndarray. It’s a first go at a few potentially common use cases. It should definitely be expanded down the road to include a larger number of useful examples. It also includes the same equivalent ndarray code written in Python using numpy.
1 parent 723ae8e commit 3ef4b2c

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#[macro_use]
2+
extern crate ndarray;
3+
4+
use ndarray::prelude::*;
5+
6+
fn main() {
7+
8+
//Creating an array of 3s
9+
let mut a = Array::from_elem((5,2), 3.0);
10+
//Here's just a simple example showing just one way to change a slice of our data.
11+
//I'm just assigning a new value to each set of our slice, but we could also apply a
12+
//scalar function to all of the values of the slice as well.
13+
a.slice_mut(s![..,0]).mapv_inplace(|_x| 1.0);
14+
//We can see here that the values did change.
15+
println!("\nA\n{:?}", a);
16+
17+
//If we want to work on a set of data that meets a logical set of conditions we have a couple of options available.
18+
//We could loop through the data by using a mutable iterator in conjunction with a filter.
19+
for i in a.iter_mut().filter(|x| **x < 3.0){
20+
*i = 4.0;
21+
}
22+
//If we want to avoid the for loop we could also do the following:
23+
a.mapv_inplace(|x| {if x < 3.0 {4.0}else{x}});
24+
25+
//We can now print our data and see that the values were modified based upon our logical condition.
26+
println!("\nA\n{:?}", a);
27+
28+
//Let's do a rotation example next using Bunge angles and then a simple passive rotation of our
29+
//coordinate system. The difference between a passive and active rotation can pretty much come
30+
//down to whether we want to rotate our coordinate system or simply the body itself. If we
31+
//are rotating the body then it's an active rotation. If we are rotating the coordinate
32+
//system it's a passive rotation. Also, the active and passive rotation matrices differ by a simple
33+
//transpose operation on the rotation matrix.
34+
35+
//We're going to be going row by row here, so it makes sense to keep the standard
36+
//row memory stride setup
37+
let bunge = Array2::<f64>::from_elem((3, 4), 1.0);
38+
39+
let s1:Array1<f64> = bunge.slice(s![0, ..]).iter().map(|&rho1| f64::sin(rho1)).collect();
40+
let c1:Array1<f64> = bunge.slice(s![0, ..]).iter().map(|&rho1| f64::cos(rho1)).collect();
41+
42+
let s2:Array1<f64> = bunge.slice(s![1, ..]).iter().map(|&phi1| f64::sin(phi1)).collect();
43+
let c2:Array1<f64> = bunge.slice(s![1, ..]).iter().map(|&phi1| f64::cos(phi1)).collect();
44+
45+
let s3:Array1<f64> = bunge.slice(s![2, ..]).iter().map(|&rho2| f64::sin(rho2)).collect();
46+
let c3:Array1<f64> = bunge.slice(s![2, ..]).iter().map(|&rho2| f64::cos(rho2)).collect();
47+
48+
let nelems = bunge.len_of(Axis(1));
49+
//We're going to make this a column memory stride setup, since we'll be using the
50+
//first two dimensions the most often.
51+
let mut rmat = Array3::<f64>::zeros((3, 3, nelems).set_f(true));
52+
53+
//We could also do this using iterators like seen above. However, we would be taking
54+
//a hit due to the fact that we aren't striding over memory instead of operating on
55+
//consecutive memory.
56+
//
57+
//Also, if we'd wanted to we could have also have just calculated the necessary sines and
58+
//cosines in this loop instead of doing it all at once like seen above.
59+
//However if we'd gone that route, then we'd would want to change the bunge array so that it was
60+
//using column strides for its memory layout.
61+
for i in 0..nelems{
62+
63+
rmat[(0, 0, i)] = c1[i] * c3[i] - s1[i] * s3[i] * c2[i];
64+
rmat[(0, 1, i)] = -c1[i] * s3[i] - s1[i] * c2[i] * c3[i];
65+
rmat[(0, 2, i)] = s1[i] * s2[i];
66+
67+
rmat[(1, 0, i)] = s1[i] * c3[i] + c1[i] * c2[i] * s3[i];
68+
rmat[(1, 1, i)] = -s1[i] * s3[i] + c1[i] * c2[i] * c3[i];
69+
rmat[(1, 2, i)] = -c1[i] * s2[i];
70+
71+
rmat[(2, 0, i)] = s2[i] * s3[i];
72+
rmat[(2, 1, i)] = s2[i] * c3[i];
73+
rmat[(2, 2, i)] = c2[i];
74+
75+
}
76+
77+
//Here we're just seeing what our rmat initially looks like.
78+
//We'll have another example down below that should be identical to this value.
79+
println!("\nrmat\n{:?}", rmat.slice(s![.., .., 0]));
80+
81+
let eye2d = Array2::<f64>::eye(3);
82+
83+
let mut mat_rot = Array3::<f64>::zeros((3, 3, nelems).set_f(true));
84+
85+
let mut crd_sys_rot = Array3::<f64>::zeros((3, 3, nelems).set_f(true));
86+
87+
//The below shows two examples:
88+
//The first example mat_rot shows how to apply a rotation to a tensor
89+
//In our example this will just return the identity matrix because R*I*R^T = R*R^T = I
90+
//The second example crd_sys_rot shows how to apply a rotatation to a coordinate
91+
//system or even a series of vectors.
92+
for i in 0..nelems{
93+
mat_rot.slice_mut(s![.., .., i]).assign({
94+
&rmat.slice(s![.., .., i]).dot({
95+
&eye2d.dot(&rmat.slice(s![.., .., i]).t())
96+
})
97+
});
98+
//Since we are just multiplying by identity here our
99+
//coordinate system is just equal to our rotation matrix
100+
crd_sys_rot.slice_mut(s![.., .., i]).assign({
101+
&rmat.slice(s![.., .., i]).dot(&eye2d)
102+
});
103+
104+
}
105+
106+
//Here we're going to just print off the first tensor/matrix and coordinate system
107+
//corresponding to our n_element 3D array of matrices and coordinate systems.
108+
//The rest of the tensors and coordinate systems will be exactly the same.
109+
println!("\ncrd_sys_rot\n{:?}", crd_sys_rot.slice(s![.., .., 0]));
110+
println!("\nmat_rot\n{:?}", mat_rot.slice(s![.., .., 0]));
111+
112+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
# -*- coding: utf-8 -*-
3+
4+
import numpy as np
5+
6+
a = 3.0 * np.ones((5, 2))
7+
a[:, 0] = 1.0
8+
print(a)
9+
10+
a[a < 3.0] = 4.0
11+
print(a)
12+
13+
'''
14+
Let's do a rotation example next using Bunge angles and then a simple passive rotation of our
15+
coordinate system. The difference between a passive and active rotation can pretty much come
16+
down to whether we want to rotate our coordinate system or simply the body itself. If we
17+
are rotating the body then it's an active rotation. If we are rotating the coordinate
18+
system it's a passive rotation. Also, the active and passive rotation matrices differ by a simple
19+
transpose operation on the rotation matrix.
20+
21+
We're going to be going row by row here, so it makes sense to keep the standard
22+
row memory stride setup
23+
'''
24+
bunge = np.ones((3, 4))
25+
26+
s1 = np.sin(bunge[0, :])
27+
c1 = np.cos(bunge[0, :])
28+
29+
s2 = np.sin(bunge[1, :])
30+
c2 = np.cos(bunge[1, :])
31+
32+
s3 = np.sin(bunge[2, :])
33+
c3 = np.cos(bunge[2, :])
34+
35+
nelems = bunge.shape[1]
36+
37+
#We're going to make this a column memory stride setup since we'll be using the
38+
#first two dimensions the most often.
39+
40+
rmat = np.zeros((3, 3, nelems), order='F')
41+
42+
'''
43+
We could also do this using iterators like seen above. However, we would be taking
44+
a hit due to the fact that we aren't striding over memory instead of operating on
45+
consecutive memory.
46+
47+
Also, if we'd wanted to we could have also have just calculated the necessary sines and
48+
cosines in this loop instead of doing it all at once like we did above.
49+
However if we'd gone that route, then we'd would want to change the bunge array so that it was
50+
using column strides for its memory layout.
51+
'''
52+
for i in range(nelems):
53+
54+
rmat[0, 0, i] = c1[i] * c3[i] - s1[i] * s3[i] * c2[i]
55+
rmat[0, 1, i] = -c1[i] * s3[i] - s1[i] * c2[i] * c3[i]
56+
rmat[0, 2, i] = s1[i] * s2[i]
57+
58+
rmat[1, 0, i] = s1[i] * c3[i] + c1[i] * c2[i] * s3[i]
59+
rmat[1, 1, i] = -s1[i] * s3[i] + c1[i] * c2[i] * c3[i]
60+
rmat[1, 2, i] = -c1[i] * s2[i]
61+
62+
rmat[2, 0, i] = s2[i] * s3[i]
63+
rmat[2, 1, i] = s2[i] * c3[i]
64+
rmat[2, 2, i] = c2[i]
65+
66+
print(rmat[:, :, 0])
67+
68+
eye2d = np.eye(3)
69+
70+
mat_rot = np.zeros((3, 3, nelems), order='F')
71+
crd_sys_rot = np.zeros((3, 3, nelems), order='F')
72+
73+
for i in range(nelems):
74+
mat_rot[:,:,i] = rmat[:,:,i].dot(eye2d.dot(rmat[:,:,i]).T)
75+
#Since we are just multiplying by identity here our
76+
#coordinate system is just equal to our rotation matrix
77+
crd_sys_rot[:,:,i] = rmat[:,:,i].dot(eye2d)
78+
79+
80+
print(crd_sys_rot[:,:,0])
81+
print(mat_rot[:,:,0])

0 commit comments

Comments
 (0)