Rust Beginnings: Coding a Perceptron with Struggles and Hope

This is my first Rust code! pub struct LogicGate { weights: Vec, //重み bias: f64, //バイアス inputs: Vec, //入力 } impl LogicGate { pub fn new(weights: Vec, bias: f64, inputs: Vec) -> 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 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) } } 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(); 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

Mar 9, 2025 - 21:12
 0
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)

    }
}

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();

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

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!