DEV Community

tomomomomo
tomomomomo

Posted on

Rust Beginnings: Coding a Perceptron with Struggles and Hope

This is my first Rust code!

pub struct LogicGate {
    weights: Vec<f64>, //重み
    bias: f64,       //バイアス
    inputs: Vec<f64>, //入力
}


impl LogicGate {
    pub fn new(weights: Vec<f64>, bias: f64, inputs: Vec<f64>) -> Self {
        LogicGate { weights, bias, inputs }
    }
}


pub trait Gate {
    fn and(gate: &Self) -> f64;
    fn or(gate: &Self) -> f64;
    fn nand(gate: &Self) ->f64;
    fn xor(gate: &Self) -> f64;

}

impl Gate for LogicGate {
    fn and(gate: &Self) -> f64 {
        let sum: f64 = gate.inputs.iter().zip(gate.weights.iter())
            .map(|(x, w)| x * w).sum();

        if sum + gate.bias > 0.0 { 1.0 } else { 0.0 }
    }

    fn nand(gate: &Self) ->f64 {
        let sum: f64 = gate.inputs.iter().zip(gate.weights.iter())
            .map(|(x, w)| x * w).sum();

        if sum + gate.bias <= 0.0 { 1.0 } else { 0.0 }
    }

    fn or(gate: &Self) -> f64 {
        let sum: f64 = gate.inputs.iter().zip(gate.weights.iter())
            .map(|(x, w)| x * w).sum();

        if sum + gate.bias > 0.0 { 1.0 } else { 0.0 }
    }

    fn xor(gate: &Self) -> f64 {
        let nand_out = Self::nand(gate);
        let or_out = Self::or(gate);
        let and_inputs = vec![nand_out, or_out];
        let and_gate = LogicGate::new(vec![0.5, 0.5], 0.7, and_inputs);
        Self::and(&and_gate)

    }
}
Enter fullscreen mode Exit fullscreen mode

I faced tons of errors while writing it, but those errors actually helped me learn a lot.

I tried implementing a Perceptron.
The code doesn't use Generics or lifetime yet-honestly I haven't understood them so far.

When I use Laravel before, I only knew MVC and Controller was very messy.
This time, I tried to think about responsibilities and put this Rust code in an "entities" folder.
It feels like a big step forward for me!

There are still problems, though.
First, the inner product calculation is repeated in every function.

let sum: f64 = gate.inputs.iter().zip(gate.weights.iter())
            .map(|(x, w)| x * w).sum();
Enter fullscreen mode Exit fullscreen mode

Second, I made a struct with an initialization function, but the bias isn’t working as expected.

The code runs, but the logic gates don’t always give the right output.

I left it as is for now—it’s part of my learning journey.

By the way, I also implemented the same logic gates in Python first.

Python feels very intuitive to me—it’s so easy to write and test quickly.

After finishing the Python version, I rewrote it in Rust.

This workflow works really well for me.

Here's my Python code for the AND gate:

def AND(x1, x2):
    inputs = np.array([x1, x2])
    weight = np.array([0.5, 0.5])
    bias = -0.7
    sum = np.sum(weight * inputs) + bias
    if sum <= 0:
        return 0
    else: 
        return 1
Enter fullscreen mode Exit fullscreen mode

I love np.sum!!! It makes the math so simple and clean!

I’m still confused about &self vs Self in Rust.

I just bought "Programming Rust" (O’Reilly), so I’ll read it and write about what I learn next.

Thanks for reading!

Top comments (0)