Skip to content

Commit

Permalink
added brain stuff (probably all garbage)
Browse files Browse the repository at this point in the history
  • Loading branch information
i-make-robots committed May 14, 2024
1 parent febc60a commit f1ad08e
Show file tree
Hide file tree
Showing 11 changed files with 483 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.ro3.node.nodes.odenode.brain.BrainManager;
import com.marginallyclever.ro3.node.nodes.odenode.odebody.ODEBody;
import com.marginallyclever.ro3.physics.CollisionListener;
import org.ode4j.ode.DContact;
Expand All @@ -24,7 +25,7 @@
public class CreatureController extends ODENode implements CollisionListener {
private final List<ODEHinge> hinges = new ArrayList<>();
private final List<ODEBody> bodies = new ArrayList<>();
private final Brain brain = new Brain();
private final BrainManager brainManager = new BrainManager();
// max experienced during simulation
private double maxForce = 0;
// max experienced during simulation
Expand Down Expand Up @@ -106,7 +107,7 @@ protected void onFirstUpdate() {
hinges.addAll(findHinges());
bodies.clear();
bodies.addAll(findBodies());
brain.setNumInputs(bodies.size()+hinges.size()+1);
brainManager.setNumInputs(bodies.size()+hinges.size()+1);

// add feedback to hinges
for(ODEHinge h : hinges) {
Expand All @@ -121,7 +122,7 @@ public void update(double dt) {
sendSensoryInputToBrain(dt);

// perform magic
brain.update(dt);
brainManager.update(dt);

sendBrainOutputToHinges();

Expand All @@ -148,15 +149,15 @@ private void sendSensoryInputToBrain(double dt) {
t.scale(0.1);
m.setTranslation(t);
// set to brain
brain.setMatrix(i++, m);
brainManager.setMatrix(i++, m);
}

// any bodies that are marked isTouching must be because onCollision says so.
// onCollision happens before update, so this is the right place to check the flag.
// add the isTouching flag to the brain sensory input
i=0;
for (ODEBody b : bodies) {
brain.setTouching(i++,b.isTouchingSomething());
brainManager.setTouching(i++,b.isTouchingSomething());
}

// add the hinge feedback to the brain sensory input
Expand All @@ -168,11 +169,11 @@ private void sendSensoryInputToBrain(double dt) {
} else {
convertHingeFeedbackToMatrix(internalHinge.getFeedback(),hm);
}
brain.setMatrix(i++,hm);
brainManager.setMatrix(i++,hm);
}

// add the torso matrix. Good for world up, world north, height above flat ground.
brain.setMatrix(i,torsoMatrix);
brainManager.setMatrix(i,torsoMatrix);

//System.out.println("f"+fmax+" t"+tmax);
}
Expand Down Expand Up @@ -206,7 +207,7 @@ private void sendBrainOutputToHinges() {
// I want the system to output torque values for each hinge.
int i=0;
for (ODEHinge h : hinges) {
var force = brain.getOutput(i++);
var force = brainManager.getOutput(i++);
//System.out.print(force+"\t");
h.addTorque(force * maxTorque); // 2.5e5 = 250k
}
Expand All @@ -220,7 +221,7 @@ public List<ODEBody> getBodies() {
return bodies;
}

public Brain getBrain() {
return brain;
public BrainManager getBrain() {
return brainManager;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.marginallyclever.ro3.node.nodes.odenode;
package com.marginallyclever.ro3.node.nodes.odenode.brain;

import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.nodes.odenode.brain.v2.Brain;

import javax.vecmath.Matrix4d;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

public class Brain {
public class BrainManager {
// build a list of all body pose matrices, relative to the world
private final List<Matrix4d> matrices = new ArrayList<>();
// build a list of contacts for each body
Expand All @@ -17,11 +18,11 @@ public class Brain {
public static int MEMORY_SECONDS = 3;
private final static int MEMORY_FRAMES = FPS * MEMORY_SECONDS; // fps * seconds
private int k=0;
private Brain brain;

private final List<Neuron> neurons = new ArrayList<>();
private BufferedImage image;

public Brain() {
public BrainManager() {
// create a list of neurons
// create a list of synapses
}
Expand Down Expand Up @@ -63,18 +64,16 @@ public double getOutput(int i) {
return 0;
}

void update(double dt) {
public void update(double dt) {
if(Registry.getPhysics().isPaused()) return;

// move every row of the image down one.
updateImage();
// write new data to the top row.
writeInputsToTopLineOfImage();
/*
// run the neural network
for(Neuron n : neurons) {
n.update(dt);
}*/

// update brain

}

private void writeInputsToTopLineOfImage() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.marginallyclever.ro3.node.nodes.odenode.brain;

/**
* A neuron in a brain.
* The neuron does not know how many inputs it has.
* The neuron knows how many outputs it has.
* An output might go to nothing.
* An output might go to a synapse.
* The synapse have bindings to "good" and "bad" feelings.
*/
public class Neuron {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.marginallyclever.ro3.node.nodes.odenode.brain.v2;

import java.util.ArrayList;
import java.util.List;

public class Brain {
private List<Neuron> inputNeurons = new ArrayList<>();
private List<Neuron> outputNeurons = new ArrayList<>();
private List<Neuron> hiddenNeurons = new ArrayList<>();
private List<Connection> connections = new ArrayList<>();
private final DopamineSimulator dopamineSimulator;
private final CortisolSimulator cortisolSimulator;

public Brain(int numInputs, int numOutputs, DopamineSimulator dopamineSimulator, CortisolSimulator cortisolSimulator) {
super();
this.dopamineSimulator = dopamineSimulator;
this.cortisolSimulator = cortisolSimulator;

// Initialize input neurons on the x=0 plane
for (int i = 0; i < numInputs; i++) {
inputNeurons.add(new Neuron(0, i, 0));
}

// Initialize output neurons on the y=0 plane
for (int i = 0; i < numOutputs; i++) {
outputNeurons.add(new Neuron(i, 0, 0));
}

// Create initial connections between input and output neurons
for (Neuron inputNeuron : inputNeurons) {
for (Neuron outputNeuron : outputNeurons) {
Connection connection = new Connection(inputNeuron, outputNeuron, Math.random() * 0.2 - 0.1);
addConnection(connection);
}
}
}

public void setInputs(List<Double> inputs) {
if(inputs.size() != inputNeurons.size()) {
throw new IllegalArgumentException("Number of inputs must match the number of input neurons");
}
// Feed the input through the network
for (int i = 0; i < inputs.size(); i++) {
inputNeurons.get(i).setInputValue(inputs.get(i));
}
}

/**
* Train the network with a set of inputs and expected outputs
* @param inputs List of input values
* @param expectedOutputs List of expected output values
*/
public void train(List<Double> inputs, List<Double> expectedOutputs) {
setInputs(inputs);

propagate();

if(expectedOutputs.size() != outputNeurons.size()) {
throw new IllegalArgumentException("Number of expected outputs must match the number of output neurons");
}
double[] output = getOutputs();
for (int i = 0; i < expectedOutputs.size(); i++) {
double d = outputNeurons.get(i).getOutputValue();
double error = expectedOutputs.get(i) - d;

// what happens here?
}
}

private void propagate() {
// Activate input neurons
for (Neuron neuron : inputNeurons) {
neuron.activate();
}
// Activate hidden and output neurons
for (Neuron neuron : hiddenNeurons) {
neuron.activate();
}
for (Neuron neuron : outputNeurons) {
neuron.activate();
}
}

public double[] getOutputs() {
// Evaluate the network's output based on the input
double[] output = new double[outputNeurons.size()];
for (int i = 0; i < outputNeurons.size(); i++) {
output[i] = outputNeurons.get(i).getOutputValue();
}
return output;
}

public List<Connection> findActiveConnections() {
List<Connection> activeConnections = new ArrayList<>();
for (Connection connection : connections) {
if (connection.isActive()) {
activeConnections.add(connection);
}
}
return activeConnections;
}

public void resetNetwork() {
for (Neuron neuron : inputNeurons) {
neuron.reset();
}
for (Neuron neuron : hiddenNeurons) {
neuron.reset();
}
for (Neuron neuron : outputNeurons) {
neuron.reset();
}
for (Connection connection : connections) {
connection.reset();
}
}

public void addNeuron(Neuron neuron) {
hiddenNeurons.add(neuron);
}

public void addConnection(Connection connection) {
connections.add(connection);
connection.getFromNeuron().addOutgoingConnection(connection);
}

public List<Neuron> getInputNeurons() {
return inputNeurons;
}

public List<Neuron> getOutputNeurons() {
return outputNeurons;
}

public List<Connection> getConnections() {
return connections;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.marginallyclever.ro3.node.nodes.odenode.brain.v2;

/**
* Positive weights will act as excitatory connections.
* Negative weights will act as inhibitory connections.
*/
public class Connection {
private Neuron fromNeuron;
private Neuron toNeuron;
private double weight;
private boolean active;

public Connection(Neuron fromNeuron, Neuron toNeuron, double weight) {
this.fromNeuron = fromNeuron;
this.toNeuron = toNeuron;
this.weight = weight;
this.active = false;
}

public void propagate() {
double propagatedValue = fromNeuron.getOutputValue() * weight;
toNeuron.addInputValue(propagatedValue);
active = true;
}

public void reset() {
active = false;
}

public boolean isActive() {
return active;
}

public Neuron getFromNeuron() {
return fromNeuron;
}

public Neuron getToNeuron() {
return toNeuron;
}

public void addWeight(double amount) {
// Example: Increase the weight by a small factor
weight += amount;
//weight = Math.max(-1.0, Math.min(1.0, weight));
}

public void scaleWeight(double scale) {
// Example: Decrease the weight by a small factor
weight *= scale;
//weight = Math.max(-1.0, Math.min(1.0, weight));
}

public double getWeight() {
return weight;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.marginallyclever.ro3.node.nodes.odenode.brain.v2;

import java.util.List;

public class CortisolSimulator {
double changeAmount = 1.0 - .01;
public void releaseCortisol(List<Connection> activeConnections) {
for (Connection connection : activeConnections) {
// Weaken or prune the connection
connection.scaleWeight(changeAmount);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.marginallyclever.ro3.node.nodes.odenode.brain.v2;

import java.util.List;

public class DopamineSimulator {
double changeAmount = 1.0 + .01;

public void releaseDopamine(List<Connection> activeConnections) {
for (Connection connection : activeConnections) {
// Strengthen the connection or add neurons along the pathway
connection.scaleWeight(changeAmount);
}
// Optionally, add new neurons to reinforce successful pathways
}
}
Loading

0 comments on commit f1ad08e

Please sign in to comment.