Science tools borrow Rust

Hi! I'm Hanneli
- Computer Engineer
- Programming
- Electronics
- Math <3 <3
- Physics
- Lego
- Meetups
- Animals
- Coffee
- GIFs

This presentation is about rewriting frequently used code from Octave in Rust
Bonus: transforming math concepts into code (searching for an expressive way to do it)
DISCLAIMER
Some slides contain code drafts (do not try to run them)
Architecture opinions are on my own
Some math
Some GIFs
Agenda
- About trending tools in science
- Octave, Data Analysis and Machine Learning
- Linear Algebra intro
- Rust and basic Matrices discussion
- Functions involving complex numbers and Rust
- Lessons learned on types, safety and Rust Language
Topics from traditional Academia accessible to everyone




Topics that became popular
Machine Learning

Big Data
Data Analysis
I was talking to some students about these topics


"We use some tools to help us with math"
Tools - Octave

I was talking to some students about these topics


Do you like it?
Yes, but it is hard to express math with C or C++
I was talking to some students about these topics


Have you tried Rust?
No, what is Rust?
I was talking to some students about these topics


I think I can _borrow_ you some knowledge
Is it safe?
(Please laugh)
(Thanks)
Agenda
- About trending tools in science
- Octave, Data Analysis and Machine Learning
- Linear Algebra intro
- Rust and basic Matrices discussion
- Functions involving complex numbers and Rust
- Lessons learned on types, safety and Rust Language
Octave is very useful for Machine Learning and Data analysis
Normalising the data
Operations with Matrices
Plotting charts
Statistics
Octave is Open Source
https://www.gnu.org/software/octave/download.html

Open Source <3
Agenda
- About trending tools in science √
- Octave, Data Analysis and Machine Learning
- Linear Algebra intro
- Rust and basic Matrices discussion
- Functions involving complex numbers and Rust
- Lessons learned on types, safety and Rust Language
"Cool, I'll build a lib for Octave"
People can expand the codebase and add features
Octave external packages

When we work with data, this is a frequent structure:

Agenda
- About trending tools in science √
- Octave, Data Analysis and Machine Learning√
- Linear Algebra intro
- Rust and basic Matrices discussion
- Functions involving complex numbers and Rust
- Lessons learned on types, safety and Rust Language
Matrices
Why are matrices so important?
Do you remember high school times? Physics lectures:

Electronic circuits and Ohm's Law (U = R x I)

The circuits can be more sophisticated:


Va
R4

R5

Vb



R1
R2
R3

The circuits can be more sophisticated:


Va
R4

R5

Vb



R1
R2
R3

V1
V2
i1
i2
i4
i2
i3
i5

We can describe the system with some equations:
i1 - i2 - i4 = 0
i2 - i3 - i5 = 0
{
{
(Kirchoff Laws!)
Kirchoff Laws are an example of Linear Systems
There is a different way to represent these systems
{
Expanding the system (lots of Algebraic work):

{
Expanding the system (lots of Algebraic work):
{
We can represent the expanded system as a Matrix!

Matrix representation
We can apply several extra rules and properties with matrices
Understanting and resolving such systems is a big topic in Linear Algebra
Agenda
- About trending tools in science√
- Octave, Data Analysis and Machine Learning√
- Linear Algebra intro√
- Rust and basic Matrices discussion
- Functions involving complex numbers and Rust
- Lessons learned on types, safety and Rust Language
We have matrices in Octave:
template <class T>
Array<T>::Array (int n, const T& val)
{
//code
}
template <class T>
Array<T>&
Array<T>::operator = (const Array<T>& a)
{
if (this != &a && rep != a.rep)
{
if (--rep->count <= 0)
delete rep;
rep = a.rep;
rep->count++;
}
// code
return *this;
}
// more code
Building a simple matrix in Rust
pub struct Matrix<T> {
rows: usize,
cols: usize,
elements: Vec<T>,
}
There is a rule to multiply matrices
[
3 5 8
1 1 9
]
x
[
7 9 1 0
5 3 7 9
1 1 0 4
]
Rows: 2
Cols: 3
Rows: 3
Cols: 4
[
3 5 8
1 1 9
]
x
[
7 9 1 0
5 3 7 9
1 1 0 4
]
Rows: 2
Cols: 3
Rows: 3
Cols: 4
pub struct Matrix<T> {
rows: 2,
cols: 3,
elements: Vec<T>,
}
pub struct Matrix<T> {
rows: 3,
cols: 4,
elements: Vec<T>,
}
Explicit Matrix1.cols == Matrix2.rows
pub struct Matrix<T> {
rows: usize,
cols: usize,
elements: Vec<T>,
}

pub trait Dimension {
// we have a behaviour set
// for Dimensions
}
impl Dimension for Matrix {
}
We can also describe the matrix elements in terms of a type:
impl<E, D> Matrix<E, D>
where E: PhantomData,
D: Dimension
{
// better
}
*PhantomData: "PhantomData<T> allows you to describe that a type acts as if it stores a value of type T, even though it does not." https://doc.rust-lang.org/std/marker/struct.PhantomData.html
Inspiration: http://jadpole.github.io/rust/typechecked-matrix
Extra: Can you think of a code to represent square matrices?
[
3 5
1 1
]
Rows == Cols == 2
Agenda
- About trending tools in science√
- Octave, Data Analysis and Machine Learning√
- Linear Algebra intro√
- Rust and basic Matrices discussion√
- Functions involving complex numbers and Rust
- Lessons learned on types, safety and Rust Language
Another important structure: complex numbers
They are used for electrical engineering, for quantum computer and for signal processing
(Why?)
Off topic moment of this lecture:
Integer
+
Integer
=
Integer
1
+
1
=
2
Adding integers will always result in another integer.
This is not true for division
Integer
/
Integer
=
May not be an Integer

Think about Real Numbers set


ALL TEH NUMBERZ! (?)
Real
/
Real
=
Real
Real
-
Real
=
Real
Real
x
Real
=
Real
Real
+
Real
=
Real
Is there any operation within real numbers that does not result in a real number?

Yes

√Real
=
May not be Real
√-4
=
Not a Real number
Complex Numbers are important because they output complex numbers for all the common algebraic operations
Complex numbers are closed for the most common algebraic operations
Can we express this property with code?
Let's try with Rust
pub struct ComplexNumber<T> {
real: T,
imaginary: T,
}
All the mathematical operation functions should return
-> ComplexNumber<T>
pub fn pow(&self, exp: T) -> ComplexNumber<T> {
// stay inside the Complex number set
}
Why is this important?
You can create a trait with this idea
trait ClosedSet
You can add the trait to existing types
And make sure they will output the same input type for a certain scope!
Note: Complex<T> is included in num[*]
[*] https://github.com/rust-num/num
Agenda
- About trending tools in science√
- Octave, Data Analysis and Machine Learning√
- Linear Algebra intro√
- Rust and basic Matrices discussion√
- Functions involving complex numbers and Rust√
- Lessons learned on types, safety and Rust Language
Lessons Learned
- There are great tools to help us with science and engineering, but sometimes the existing code is verbose.
- Or it is sad to handle with dangling pointers and memory allocation problems.
- It is also non trivial how to express the types
- Converting from mathematics to code is not always trivial.
- Rust can be helpful to resolve most of these points.
- Rust compiler can help to prevent runtime errors (clients of traits are fully-typed checked).
Rust compiler can help to prevent runtime errors
Imagine running a long script in Octave and get a runtime error after several minutes of processing: it can be frustrating.
We can delegate this code to Rust.
Last, bust not least:
These concepts or mindset can be applied to other areas, not only scientific projects.
Example: wouldn't the idea of closed sets be useful for payments?
The idea of creating a trait for specific abstractions, like the Matrix Dimension, could be good as well.
Some epic failures
unsafe
pub unsafe fn from_vector(d: Dimension, v: Vec<A>) -> Matrix<T>
{
// at some point calls slice::get_unchecked
}

NOOOOO
It is okay to have an unsafe constructor, but wrap it into a safe structure.
fn from_safe_vec_impl(d: Dimension, v: Vec<A>)
-> Result<Matrix<T>, ConversionError>
{
if d.size_checked() != Some(v.len()) {
return
Err(error::incompatible_shapes(&v.len(),
&dim));
}
unsafe { Ok(Self::from_vector(dim, v)) }
}
}
mut (when you were not supposed to use it)
Fast Fourier Transform (FFT)
fn from_time(s: &mut Signal<Time>) -> Signal<Frequency>
fn from_frequency(s: &mut Signal<Frequency>) -> Signal<Time>
Once you have a measurement, it is immutable by definition! This code does not make sense!
Fast Fourier Transform (FFT)
fn from_time(s: Signal<Time>) -> Signal<Frequency>
fn from_frequency(s: Signal<Frequency>) -> Signal<Time>
(this is more appropriate!)
References
- https://github.com/servo/euclid
- https://github.com/bluss/rust-ndarray
- https://athemathmo.github.io/2016/03/23/linear-algebra-in-rust.html
- https://github.com/rust-num/num
- https://doc.rust-lang.org/reference.html
- http://pnkfelix.github.io/curry-on2015.html#/
- http://jadpole.github.io/rust/type-system
- http://rustbyexample.com/
- ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf
- https://killercup.github.io/trpl-ebook/nomicon-2016-06-02.a4.pdf
- https://blog.rust-lang.org/2015/05/11/traits.html
Special Thanks
- @skade and @bltavares
- Daniel Hahn, for being a great mentor
- B.C., for the constant review
- @lafp, @romulostorel and @pedrofelipee (GIFs)
- rust_br community :)





Thank you :)
Questions?
hannelita@gmail.com
@hannelita

RustFest
By Hanneli Tavante (hannelita)