/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package automenta.spacenet.run.old.bio; import automenta.spacenet.plugin.neural.brainz.AbstractNeuron; import automenta.spacenet.plugin.neural.brainz.Brain; import automenta.spacenet.plugin.neural.brainz.BrainBuilder; import automenta.spacenet.plugin.neural.brainz.BrainGraph; import automenta.spacenet.plugin.neural.brainz.InterNeuron; import automenta.spacenet.plugin.neural.brainz.SenseNeuron; import automenta.spacenet.run.ArdorSpacetime; import automenta.spacenet.run.old.DefaultGraphBuilder; import automenta.spacenet.space.Repeat; import automenta.spacenet.space.Space; import automenta.spacenet.space.control.Zoomable; import automenta.spacenet.space.geom.Box; import automenta.spacenet.space.geom.Box.BoxShape; import automenta.spacenet.space.geom.ProcessBox; import automenta.spacenet.space.geom.Rect; import automenta.spacenet.space.geom.Rect.RectShape; import automenta.spacenet.space.geom.graph.GraphBox; import automenta.spacenet.space.geom.graph.GraphBoxBuilder; import automenta.spacenet.space.geom.graph.arrange.forcedirect.ForceDirecting; import automenta.spacenet.space.geom.graph.arrange.forcedirect.ForceDirecting.ForceDirectedParameters; import automenta.spacenet.space.geom.physics.PhyBox; import automenta.spacenet.space.geom.physics.PhySpace; import automenta.spacenet.space.geom.physics.PhySpaceBox; import automenta.spacenet.var.Maths; import automenta.spacenet.var.physical.Color; import automenta.spacenet.var.vector.V3; import com.ardor3d.math.Vector3; import com.ardor3d.math.type.ReadOnlyVector3; import com.ardor3d.renderer.state.BlendState; import com.ardor3d.renderer.state.BlendState.DestinationFunction; import com.ardor3d.renderer.state.BlendState.SourceFunction; import com.ardor3d.scenegraph.Spatial; import com.bulletphysics.collision.dispatch.CollisionWorld; import com.bulletphysics.collision.dispatch.CollisionWorld.ClosestRayResultCallback; import com.bulletphysics.dynamics.RigidBody; import com.bulletphysics.dynamics.constraintsolver.Generic6DofConstraint; import com.bulletphysics.dynamics.constraintsolver.HingeConstraint; import com.bulletphysics.dynamics.constraintsolver.Point2PointConstraint; import com.bulletphysics.dynamics.constraintsolver.TranslationalLimitMotor; import com.bulletphysics.linearmath.Transform; import java.util.LinkedList; import java.util.List; import javax.vecmath.Vector3f; /** * * @author seh */ public class DemoCell extends ProcessBox { //TODO fix inter-cell mapping, its broken and one-directional i think double neuralDensity = 620.0; //neurons per cubic volume unit float maxStretch = 0.25f; float motorStep = 0.1f; double motorPeriod = 0.0; int cellPositionInputs = 6; int cellMotorNeurons = 3; int intercellNeurons = 4; //int cellInternalNeurons = 32; int cellRandomInputs = 1; double randomInputMomentum = 0.95; //closer to zero is faster, closer to 1 is slower float motorRestitution = 0.8f; //how quickly the motor returns to zero length (1.0 = never, so use < 1.0) double randomPeriod = 1.0; protected PhySpaceBox phy; double neuronBoxUpdatePeriod = 0.1; double neuralPeriod = 0.0; public class Retina { private final V3 pos; private final V3 normal; private Box box; public Retina(V3 pos, V3 normal) { this.pos = pos; this.normal = normal; } Vector3f retinaCenter = new Vector3f(); Vector3f rayTo = new Vector3f(); float pickDist = 200.0f; public Space seenObject(ReadOnlyVector3 absolutePos, ReadOnlyVector3 direction, PhySpace physics) { rayTo.set(direction.getXf(), direction.getYf(), direction.getZf()); rayTo.scale(pickDist); retinaCenter.set((float) absolutePos.getX(), (float) absolutePos.getY(), (float) absolutePos.getZ()); ClosestRayResultCallback rayCallback = new CollisionWorld.ClosestRayResultCallback(retinaCenter, rayTo); physics.dynamicsWorld.rayTest(retinaCenter, rayTo, rayCallback); RigidBody pickedBody = null; Space pickedSpace = null; if (rayCallback.hasHit()) { RigidBody body = RigidBody.upcast(rayCallback.collisionObject); if (body != null) { // other exclusions? //if (!(body.isStaticObject() || body.isKinematicObject())) { pickedBody = body; pickedSpace = physics.getSpace(pickedBody); //} } } return pickedSpace; } public Color getColor(ReadOnlyVector3 worldTranslation, ReadOnlyVector3 normal, PhySpace p) { Color c; Space pickedSpace = seenObject(worldTranslation, normal, p); if (pickedSpace != null) { c = Color.White.alpha(0.5); } else { c = Color.Black.alpha(0.5); } box.color(c); return c; } private void setBox(Box rb) { this.box = rb; } } public class BoxCell extends PhyBox implements Zoomable { private double[] nextOutputs; private final Brain b; private final BrainGraph bGraph; private final List<Retina> retinas; private BoxCell(V3 pos, V3 size, float mass, double neuralDensity, List<Retina> retinas) { super(pos, size, mass); color(Color.White.alpha(0.3)); if (retinas == null) { retinas = new LinkedList(); //empty } this.retinas = retinas; for (Retina r : retinas) { Box rb = new Box(BoxShape.Spheroid); rb.move(r.pos); r.setBox(rb); add(rb); } int cellInternalNeurons = (int) (neuralDensity * size.getVolume()); int cellInternalMinSynapses = cellInternalNeurons / 6; int cellInternalMaxSynapses = cellInternalNeurons / 3; /** * inputs = (intercell input, random, position, retina cells[r,g,b]) * */ b = new BrainBuilder(cellRandomInputs + intercellNeurons + cellPositionInputs + retinas.size() * 3, intercellNeurons + cellMotorNeurons).newBrain(cellInternalNeurons, cellInternalMinSynapses, cellInternalMaxSynapses); bGraph = new BrainGraph(b); V3 boundsMax = new V3(2, 2, 2); ForceDirectedParameters par = new ForceDirectedParameters(boundsMax, 0.01, 0.001, 1.0); double updatePeriod = 0.1; double interpSpeed = 0.3; int substeps = 4; ForceDirecting arr = new ForceDirecting(par, updatePeriod, substeps, interpSpeed); add(new GraphBox(bGraph, getGraphBuilder(), arr)); add(new Repeat(randomPeriod) { @Override protected void update(double t, double dt, Spatial parent) { updateRandomInputs(); } }); add(new Repeat(neuralPeriod, true) { @Override protected void update(double t, double dt, Spatial parent) { updateInputs(); b.forward(); updateOutputs(); } }); } protected void updateOutputs() { // outputRect.removeAll(); // // // Rect[] o = new Rect[b.getMotor().size()]; // // int j = 0; // for (MotorNeuron m : b.getMotor()) { // double bo = m.getOutput(); // Color c; // if (bo < 0.5) { // c = Color.Blue; // } else { // c = Color.Red; // } // Rect re = new Rect(RectShape.Ellipse); // re.color(c); // o[j++] = re; // } // // outputRect.add(new ColRect(0.01, o)); } public void updateRandomInputs() { if (nextOutputs == null) { nextOutputs = new double[cellRandomInputs]; } for (int i = 0; i < cellRandomInputs; i++) { nextOutputs[i] = Maths.random(-1, 1); } } public void updateInputs() { int randomOffset = intercellNeurons; for (int i = 0; i < cellRandomInputs; i++) { SenseNeuron s = b.getSense().get(i + randomOffset); s.senseInput = (randomInputMomentum * s.senseInput) + ((1.0 - randomInputMomentum) * nextOutputs[i++]); } int positionOffset = intercellNeurons + cellRandomInputs; for (int i = 0; i < cellPositionInputs; i++) { SenseNeuron s = b.getSense().get(i + positionOffset); if (i % 3 == 0) { //cos(X) s.senseInput = Math.cos(getPosition().getXf()); } else if (i % 3 == 1) { //cos(Y) s.senseInput = Math.cos(getPosition().getYf()); } else { //cos(Z) s.senseInput = Math.cos(getPosition().getZf()); } } int retinaOffset = intercellNeurons + cellRandomInputs + cellPositionInputs; int r = 0; for (int i = 0; i < retinas.size(); i++) { Retina x = retinas.get(i); Vector3[] axes = new Vector3[3]; getOrientation().toAxes(axes); Color c = x.getColor(getWorldTranslation(), axes[0], phy.physics); b.getSense().get(retinaOffset + (r++)).senseInput = c.getRed(); b.getSense().get(retinaOffset + (r++)).senseInput = c.getGreen(); b.getSense().get(retinaOffset + (r++)).senseInput = c.getBlue(); } } @Override public void onZoomStart() { } @Override public void onZoomStop() { } @Override public boolean isZoomable() { return true; } @Override public boolean isTangible() { return true; } double minNeuronScale = 0.01; double neuronScale = 0.05; public GraphBoxBuilder getGraphBuilder() { return new DefaultGraphBuilder() { @Override public Box newNodeSpace(Object node) { final Box b = new Box(BoxShape.Empty); if (node instanceof AbstractNeuron) { final AbstractNeuron i = (AbstractNeuron) node; final Rect r = b.add(new Rect(node instanceof InterNeuron ? RectShape.Rect : RectShape.Ellipse)); b.add(new Repeat(neuronBoxUpdatePeriod) { @Override protected void update(double t, double dt, Spatial parent) { double o = i.getOutput(); double p = o; if (i instanceof InterNeuron) { p = ((InterNeuron) i).getPotential(); } else if (i instanceof SenseNeuron) { p = ((SenseNeuron) i).senseInput; } r.color(getNeuronColor(o, p)); double s = 0.1 + (Math.abs(p)) * 0.2; r.scale(s); } }); } b.scale(minNeuronScale); return b; } @Override public Space newEdgeSpace(Object edge, Box pa, Box pb) { return new Box(BoxShape.Empty); } }; } private double getOutput(int i) { return b.getMotor().get(i).getOutput(); } private void setInput(int i, double d) { b.getSense().get(i).senseInput = d; } } /** a physical pipe of capsules */ public /*static*/ class Snake { Vector3f tmp = new Vector3f(); public Snake(PhySpaceBox b, int numSegments, double segmentLength, double radius, double snakeHeadFactor) { super(); double density = 1.0; BoxCell segment[] = new BoxCell[numSegments]; for (int s = 0; s < numSegments; s++) { double l = segmentLength * Maths.random(0.75, 1.25); double w = radius; double h = radius; List<Retina> retinas = null; if (s == 0) { l *= snakeHeadFactor; w *= snakeHeadFactor; h *= snakeHeadFactor; retinas = new LinkedList(); retinas.add(new Retina(new V3(1, 0, 0), new V3(1, 0, 0))); } float mass = (float) ((l * w * h) * density); BoxCell pb = new BoxCell(new V3(), new V3(l, w, h), mass, neuralDensity, retinas); b.add(pb); segment[s] = pb; pb.getBody().setDamping(0.05f, 0.85f); pb.getBody().setDeactivationTime(0.8f); pb.getBody().setSleepingThresholds(1.6f, 2.5f); if (s > 0) { bind(segment[s - 1], segment[s]); } } } protected void bind6DoF(final BoxCell a, final BoxCell b) { final Generic6DofConstraint joint6DOF; Transform localA = new Transform(), localB = new Transform(); boolean useLinearReferenceFrameA = false; localA.setIdentity(); localB.setIdentity(); localA.origin.set((float) (-a.getSize().getX() / 2.0) * 1.1f, 0, 0); localB.origin.set((float) (b.getSize().getX() / 2.0) * 1.1f, 0, 0); joint6DOF = new Generic6DofConstraint(a.getBody(), b.getBody(), localA, localB, useLinearReferenceFrameA); //joint6DOF.setLimit(0, -0.5f, 0.5f); tmp.set(-3.10f, -3.1f, -3.1f); joint6DOF.setAngularLowerLimit(tmp); tmp.set(3.1f, 3.1f, 3.1f); joint6DOF.setAngularUpperLimit(tmp); phy.addConstraint(joint6DOF, false); add(new Repeat(motorPeriod) { Vector3f pivA = new Vector3f(); Vector3f pivB = new Vector3f(); double icAB[] = new double[intercellNeurons]; double icBA[] = new double[intercellNeurons]; @Override protected void update(double t, double dt, Spatial parent) { TranslationalLimitMotor m = joint6DOF.getTranslationalLimitMotor(); float length = m.upperLimit.x; double expand = 0; for (int x = 0; x < cellMotorNeurons; x++) { expand += a.getOutput(x); } if (expand > 0) { //m.accumulatedImpulse.x += motorStep; length += motorStep; length = Math.min(length, maxStretch); } else { length = length * motorRestitution; } //System.out.println(expand + " " + length + " " + m.accumulatedImpulse); m.lowerLimit.set(length / 2.0f, 0, 0); m.upperLimit.set(length, 0, 0); //transfer a->b & b->a for (int i = 0; i < intercellNeurons; i++) { icAB[i] = a.getOutput(i + cellMotorNeurons); icBA[i] = b.getOutput(i + cellMotorNeurons); a.setInput(i, icBA[i]); b.setInput(i, icAB[i]); //System.out.print(icAB[i] + "/" + icBA[i]); } //System.out.println(); } }); } protected void bind(BoxCell a, BoxCell b) { //bindPoint2Point(a, b); //bindHinge(a, b); bind6DoF(a, b); } // protected void bindHinge(PhyBox a, PhyBox b) { HingeConstraint j; Transform localA = new Transform(), localB = new Transform(); boolean useLinearReferenceFrameA = true; localA.setIdentity(); localB.setIdentity(); localA.origin.set(-0.07f, 0, 0f); localB.origin.set(0.07f, 0, 0f); j = new HingeConstraint(a.getBody(), b.getBody(), localA, localB); j.setLimit(-1.0f, 1.0f); //j.setLimit( -0.5f, 0.5f, 0.9f, 0.3f, 1.0f );; j.enableAngularMotor(true, 0.3f, 0.5f); phy.addConstraint(j, false); } } @Override protected void start() { BlendState bs = new BlendState(); bs.setBlendEnabled(true); bs.setSourceFunction(SourceFunction.SourceAlpha); bs.setDestinationFunction(DestinationFunction.OneMinusSourceAlpha); bs.setEnabled(true); setRenderState(bs); phy = add(new PhySpaceBox(20)); phy.physics.getTimeScale().set(1.0); phy.physics.getGravity().set(0, -9.5, 0); PhyBox ground = phy.add(new PhyBox(new V3(0, -2, 0), new V3(15, 0.5, 15), 0f)); //walls double wallHeight = 1.5; phy.add(new PhyBox(new V3(-7.5, -wallHeight, 0), new V3(0.5, wallHeight, 15), 0f)); phy.add(new PhyBox(new V3(7.5, -wallHeight, 0), new V3(0.5, wallHeight, 15), 0f)); phy.add(new PhyBox(new V3(0, -wallHeight, -7.5), new V3(15, wallHeight, 0.5), 0f)); phy.add(new PhyBox(new V3(0, -wallHeight, 7.5), new V3(15, wallHeight, 0.5), 0f)); //ground.rotate(0.1, 0.1, 0.1); //Obstacles and Toys phy.add(new PhyBox(new V3(), new V3(0.5, 0.5, 0.5), 0.5f, BoxShape.Spheroid)).color(Color.Orange); phy.add(new PhyBox(new V3(0, -2.5, 0), new V3(6.5, 2.5, 6.5), 0f, BoxShape.Spheroid)).color(Color.Gray); new Snake(phy, 9, 0.45, 0.25, 1.1); //new Snake(phy, 12, 0.15, 0.25); } public static Color getNeuronColor(double a, double b) { a = (a + 1.0) * 0.5; b = (b + 1.0) * 0.5; return new Color(a, 0, b); } public static void main(String[] args) { ArdorSpacetime.newWindow(new DemoCell()); } }