Chinese test

pull/1/head
drinkjava2 5 years ago
parent b4865ab069
commit e26ce04039

@ -88,7 +88,8 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
2019-11-16 模式识别功能更新
上次提交有个大bug有多个字母出现时将不能区分这次提交更正过来。到此为止基本完成了模式识别的原理验证过程即如果字母的象素点与训练图片的重点合越多则听力区收到的反向红色光子数就越多这是一个简单、直观的模式识别方法以后可以通过将声音分成多个小区编码并统计每个区收到多少反向的光子总数来判断是哪个字母图像输入。原理验证比较枯燥但这个模式识别功能是无法绕过去的一旦原理被证实以后就可以有意地引导或者说设计青蛙向这个方向进化而不是由手工来搭建包含模式识别功能的脑模型因为一来要减少手工的干预,硬编码越少越好,尽量利用随机变异、生存竟争这个电脑工具,二来这个原理不光是模式识别要用到,其它信号处理(如快感、痛觉信号与行为信号之间的关联)都要用到类似的细胞级逻辑,因为我一直在强调“任意两个时间上相关的信号,大脑总会将它们关联起来,这是条件反射行为建立的基础”。
另外,这次更新加强了暂停功能,可以在脑图任一时刻暂停,并加上了脑图的剖面显示。所有脑图快捷键有: T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标操作:缩放旋转平移
![result6](https://gitee.com/drinkjava2/frog/raw/master/result6_letter.gif)
![result6](https://gitee.com/drinkjava2/frog/raw/master/result6_letter.gif)
2019-11-26 优化了一下程序用8个汉字来进行模式识别原理演示但容错性依然没有变形、变位后的文字识别率很差。以后要考虑借签算法中的侧抑制、卷积、分层等原理来提高它的容错性这方面算法已经很成熟了目前只需要拿来主义用图形化模拟的方式来实现。但总体上算法和图形化模拟是两条路算法通常可以用模拟的方式来表达但不是所有模拟都可以归纳成算法因为模拟(或者说软件本身)有时会非常复杂,不容易总结出规律。也就是说模拟的表现力比算法更强,但模拟的缺点是资源消耗大。
注意如果想要运行这个项目的以前码云版本可以结合gitk命令和参考"版本提交记录.md"的介绍用git reset命令回复到以前任一个版本例如用:
git reset --hard ae34b07e 可以转回到以前一个分组测试的找食版本。

@ -11,8 +11,8 @@ import javax.swing.JPanel;
import com.github.drinkjava2.frog.egg.Egg;
import com.github.drinkjava2.frog.egg.EggTool;
import com.github.drinkjava2.frog.objects.EnvObject;
import com.github.drinkjava2.frog.objects.LetterTester;
import com.github.drinkjava2.frog.objects.EnvObject;
import com.github.drinkjava2.frog.objects.Material;
import com.github.drinkjava2.frog.util.RandomUtils;
@ -41,7 +41,7 @@ public class Env extends JPanel {
/** Frog's brain size is a 3D array of Cell */ // 脑空间是个三维Cell数组为节约内存仅在用到数组元素时才去初始化这维按需分配内存
public static final int FROG_BRAIN_XSIZE = 30; // frog的脑在X方向长度
public static final int FROG_BRAIN_YSIZE = 20; // frog的脑在Y方向长度
public static final int FROG_BRAIN_ZSIZE = 25; // frog的脑在Z方向长度
public static final int FROG_BRAIN_ZSIZE = 20; // frog的脑在Z方向长度
/** SHOW first frog's brain structure */
public static boolean SHOW_FIRST_FROG_BRAIN = true; // 是否显示脑图在Env区的右侧
@ -56,10 +56,10 @@ public class Env extends JPanel {
public static final int ENV_HEIGHT = ENV_WIDTH; // 虚拟环境高度, 可调,通常取正方形
/** Frog's brain display width on screen, not important */
public static final int FROG_BRAIN_DISP_WIDTH = 500; // Frog的脑图在屏幕上的显示大小,可调
public static final int FROG_BRAIN_DISP_WIDTH = 600; // Frog的脑图在屏幕上的显示大小,可调
/** Steps of one test round */
public static final int STEPS_PER_ROUND = 500;// 每轮测试步数,可调
public static final int STEPS_PER_ROUND = LetterTester.STR.length() * 2 * LetterTester.TIME;// 每轮测试步数,可调
public static int step;// 当前测试步数
public static final int FOOD_QTY = 100; // 食物数量, 可调

@ -74,8 +74,8 @@ public class Frog {
this.alive = false;
return;
}
for (int i = 0; i < organs.size(); i++) {
organs.get(i).init(this, i);
for (int orgNo = 0; orgNo < organs.size(); orgNo++) {
organs.get(orgNo).init(this, orgNo);
}
}
@ -89,7 +89,7 @@ public class Frog {
}
/** Set with given activeValue */
public void setCuboidVales(Cuboid o, float active) {// 激活长方体区域内的所有脑区
public void setCuboidVales(Cuboid o, boolean active) {// 激活长方体区域内的所有脑区
if (!alive)
return;
for (int x = o.x; x < o.x + o.xe; x++)
@ -98,20 +98,10 @@ public class Frog {
if (cells[x][y] != null)
for (int z = o.z; z < o.z + o.ze; z++)
if (cells[x][y][z] != null)
getOrCreateCell(x, y, z).setEnergy(active);
getOrCreateCell(x, y, z).hasInput = active;
}
/** Calculate organ activity by add all organ cells' active value together */
public float getCuboidActiveTotalValue(Cuboid o) {// 遍历长方体区域所在cell将它们的激活值汇总返回
float activity = 0;
for (int x = o.x; x < o.x + o.xe; x++)
for (int y = o.y; y < o.y + o.ye; y++)
for (int z = o.z; z < o.z + o.ze; z++)
activity += this.getOrCreateCell(x, y, z).getEnergy();
return activity;
}
private int activeNo = 0;
private int activeNo = 0;// 每一帧光子只能走一步,用这个来作标记
public boolean active(Env v) {// 这个active方法在每一步循环都会被调用是脑思考的最小帧
activeNo++;
@ -133,25 +123,8 @@ public class Frog {
if (cells[i][j] != null)
for (int k = 0; k < Env.FROG_BRAIN_ZSIZE; k++) {
Cell cell = cells[i][j][k];
if (cell != null) {
if (cell.organs != null)
for (int orgNo : cell.organs)
CellActions.act(activeNo, organs.get(orgNo), cell, i, j, k); // 调用每个细胞的act方法
if (cell.photons != null) {
for (int ii = 0; ii < cell.photons.length; ii++) {
Photon p = cell.photons[ii];
if (p == null || p.activeNo == activeNo)// 同一轮新产生的光子或处理过的光子不再走了
continue;
p.activeNo = activeNo;
cell.removePhoton(ii);// 原来的位置的先清除去除它的Java对象引用
cell.photonWalk(this, p); // 让光子自已往下走
}
}
if (cell.holes != null)
for (Hole h : cell.holes) {// 洞的年龄增加,只有年龄很接近的洞才会产生绑定
h.age++;
}
}
if (cell != null)
CellActions.act(this, activeNo, cell); // 调用每个细胞的act方法
}
}
return alive;
@ -180,7 +153,7 @@ public class Frog {
cells[x][y] = new Cell[Env.FROG_BRAIN_ZSIZE];
Cell cell = cells[x][y][z];
if (cell == null) {
cell = new Cell();
cell = new Cell(x, y, z);
cells[x][y][z] = cell;
}
return cell;
@ -192,4 +165,56 @@ public class Frog {
|| z >= Env.FROG_BRAIN_ZSIZE;
}
/** Photon always walk */
public void addAndWalk(Photon p) { // 添加光子的同时让它沿光子方向自动走一格
p.x += p.mx;
p.y += p.my;
p.z += p.mz;
int rx = Math.round(p.x);
int ry = Math.round(p.y);
int rz = Math.round(p.z);
if (Frog.outBrainBound(rx, ry, rz))
return;// 出界直接扔掉
Cell cell = getCell(rx, ry, rz);
if (cell != null)
cell.addPhoton(p);
}
/** Photon always walk */
public void addAndWalkAndDig(Photon p) { // 添加光子的同时让它沿光子方向自动走一格
p.x += p.mx;
p.y += p.my;
p.z += p.mz;
int rx = Math.round(p.x);
int ry = Math.round(p.y);
int rz = Math.round(p.z);
if (Frog.outBrainBound(rx, ry, rz))
return;// 出界直接扔掉
Cell cell = getCell(rx, ry, rz);
if (cell != null) {
cell.addPhoton(p);
cell.digHole(p);
}
}
public void prepareNewTraining() {// for test purpose, reset some values for prepare next training.
for (int i = 0; i < Env.FROG_BRAIN_XSIZE; i++) {
if (cells[i] != null)
for (int j = 0; j < Env.FROG_BRAIN_YSIZE; j++)
if (cells[i][j] != null)
for (int k = 0; k < Env.FROG_BRAIN_ZSIZE; k++) {
Cell cell = cells[i][j][k];
if (cell != null) {
cell.deleteAllPhotons();
cell.hasInput = false;
cell.photonSum = 0;
if (cell.holes != null)
for (Hole h : cell.holes) {
h.age += 100;// 强迫洞的年龄增加,用这个方法来区分开不同批次的训练
}
}
}
}
}
}

@ -25,7 +25,8 @@ import com.github.drinkjava2.frog.util.ColorUtils;
* BrainPicture show first frog's brain structure, for debug purpose only
*
* 3
* tflr,x5
* tflr,x5
* MouseAction
*
* @author Yong Zhu
* @since 1.0
@ -42,8 +43,8 @@ public class BrainPicture extends JPanel {
float xAngle = d90 * .8f; // brain rotate on x axis
float yAngle = d90 / 4; // brain rotate on y axis
float zAngle = 0;// brain rotate on z axis
int xMask = 0;// x Mask
int yMask = 0;// y Mask
int xMask = -1;// x Mask
int yMask = -1;// y Mask
BufferedImage buffImg;
Graphics g;
String note;
@ -85,7 +86,7 @@ public class BrainPicture extends JPanel {
if (xMask > Env.FROG_BRAIN_XSIZE)
xMask = Env.FROG_BRAIN_XSIZE;
break;
case ' ':// 暂停切换
case ' ':// 暂停及继续
Application.pauseAction.actionPerformed(null);
break;
case 'T':// 顶视
@ -212,25 +213,11 @@ public class BrainPicture extends JPanel {
(int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
}
/** 画出cell的中心大点,通常用来显示器官的边界激活点 */
public void drawCellBigCenter(float x, float y, float z) {
/** 画出cell的中心点 */
public void drawCellCenter(float x, float y, float z, float diameter) {
if (x > 0 && (x < xMask || y < yMask))
return;
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, (int) Math.max(1, Math.round(scale * .7)));
}
/** 画出cell的中心小点通常用来显示光子 */
public void drawCellMiddleCenter(float x, float y, float z) {
if (x > 0 && (x < xMask || y < yMask))
return;
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, (int) Math.max(1, Math.round(scale * .45)));
}
/** 画出cell的中心小点通常用来显示光子 */
public void drawCellSmallCenter(float x, float y, float z) {
if (x > 0 && (x < xMask || y < yMask))
return;
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, (int) Math.max(1, Math.round(scale * .20)));
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, (int) Math.max(2, Math.round(scale * diameter)));
}
/** 画点固定以top视角的角度所以只需要在x1,y1位置画一个点 */
@ -289,21 +276,23 @@ public class BrainPicture extends JPanel {
if (f.cells[x][y] != null)
for (int z = 0; z < Env.FROG_BRAIN_ZSIZE; z++) {
Cell cell = f.getCell(x, y, z);
if (cell != null && cell.getEnergy() > 0) {// 只显示激活点
if (x == 0) {// 如果在左边,显示黑色大圆
if (cell != null) {// 只显示激活点
if (cell.hasInput && x == 0) {// 如果在左边,显示黑色大圆
setPicColor(Color.BLACK);
drawCellBigCenter(x, y, z);
} else if (z == Env.FROG_BRAIN_ZSIZE - 1) {// 如果在顶上边,显示兰色大圆
drawCellCenter(x, y, z, 0.6f);
} else if (z == Env.FROG_BRAIN_ZSIZE - 1 && cell.hasInput) {// 如果在顶上边,显示兰色大圆
setPicColor(Color.BLUE);
drawCellBigCenter(x, y, z);
drawCellCenter(x, y, z, 0.6f);
}
if (cell.getPhotonQty() > 0) {// 如果在内部只显示有光子的cell
setPicColor(ColorUtils.colorByCode(cell.getColor()));
if (cell.photonQty > 0) {// 如果在内部只显示有光子的cell
setPicColor(ColorUtils.colorByCode(cell.color));
float dia = 0.2f;
if (cell.color == 0)
dia = 0.3f;
if (x == xMask || y == yMask)
drawCellMiddleCenter(x, y, z);
else
drawCellSmallCenter(x, y, z);
dia = 0.5f;
drawCellCenter(x, y, z, dia);
}
}
}

@ -12,9 +12,8 @@ package com.github.drinkjava2.frog.brain;
import java.util.Arrays;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.util.ColorUtils;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
* Cell is the smallest unit of brain space, a Cell can have many actions and
@ -23,17 +22,30 @@ import com.github.drinkjava2.frog.util.ColorUtils;
* Cell(organs)(Photon)Hole)(Relation)frogcells
*
*
* ,hole)()
* (线)
* 沿线,
*
* CellCellActionsCell
*
* JellyMoveJelly,hole)
* ()(线)
* 沿线,
* hebb
*
*
* @author Yong Zhu
* @since 1.0
*/
public class Cell {
public int x;
public int y;
public int z;
public Cell(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
/** Active of current cell */
private float energy = 0; // 这个cell的激活能量允许是负值但暂时只用到正值),它反映了在这个cell里所有光子的能量汇总值
public boolean hasInput = false; // 这个细胞是否有外界信号(如光、声音)输入
public int[] organs = null; //// 每个Cell可以被多个Organ登记这里保存organ在蛋里的序号
@ -43,65 +55,58 @@ public class Cell {
public Relation[] relations = null;// 洞的关联关系
private int color;// Cell的颜色取最后一次被添加的光子的颜色颜色不重要但能方便观察
public int color;// Cell的颜色取最后一次被添加的光子的颜色颜色不重要但能方便观察
private int photonQty = 0;
public int photonQty = 0; // 这个细胞里当前包含的光子总数
public void regOrgan(int action) {// 每个Cell可以被多个Organ登记通常只在青蛙初始化器官时调用这个方法
public int photonSum = 0; // 这个细胞里曾经收到的光子总数
public void regOrgan(int orgNo) {// 每个Cell可以被多个Organ登记通常只在青蛙初始化器官时调用这个方法
if (organs == null)
organs = new int[] {};
organs = Arrays.copyOf(organs, organs.length + 1);
organs[organs.length - 1] = action;
organs[organs.length - 1] = orgNo;
}
public void addPhoton(Photon p) {// 每个cell可以存在多个光子
if (p == null)
return;
if (p.organNo == 0 && p.x < 3)
return;// 这是个临时限制,防止反向的光子落到视网膜上
if (p.organNo == 0 && p.z > Env.FROG_BRAIN_ZSIZE - 2)
return;// 这是个临时限制,防止反向的光子落到耳朵上
energy += 1000;
if (energy > 10000)
energy = 10000;
// //p.energy *= .7;
// if (p.energy < 0.1)
// return;
photonQty++;
photonSum++;
color = p.color; // Cell的颜色取最后一次被添加的光子的颜色
if (photons == null) {
photons = new Photon[] { p };// 创建数组
digHole(p);
return;
} else
for (int i = 0; i < photons.length; i++) { // 找空位插入,尽量重复利用内存
if (photons[i] == null || photons[i].energy < 0.1) {
if (photons[i] == null) {
photons[i] = p;
digHole(p);
return; // 如找到就插入,返回
}
}
photons = Arrays.copyOf(photons, photons.length + 1);// 否则追加新光子到未尾
photons[photons.length - 1] = p;
digHole(p);
}
public void digHole(Photon p) {// 根据光子来把洞挖大一点,同时,如果有洞和它年龄相近,将把它们绑定起来,如果已有绑定的洞,有可能在撞出的洞里撞出光子来
if (p == null || p.organNo == 0)// 反向的光子不参与挖坑
public void digHole(Photon p) {// 根据光子来把洞挖大一点,同时,如果有洞和它年龄相近,将把它们绑定起来,如果已有绑定的洞,有可能在绑定的洞里撞出光子来
if (p == null || p.isBackway())// 反向的光子不参与挖坑
return;
if (holes == null) {// 如果没有坑,就新挖一个
holes = new Hole[] { new Hole(p) }; // 新挖的坑不参与绑定
return;
}
if (energy > 90)
for (int i = 0; i < holes.length; i++) { // 这部分很关键,光子如果与坑同向或角度相近,会在与坑绑定的坑上撞出新的光子,注意只针对绑定的坑
Hole h = holes[i];
if (h != null && h.ifSimilarWay(p)) {
createBackPhoton(h);
if(RandomUtils.percent(2))
for (int i = 0; i < holes.length; i++) { // 这部分很关键,光子如果与坑同向或角度相近,会在与坑绑定的坑上撞出新的光子反向飞回,注意只针对绑定的坑
Hole h = holes[i];
if (h != null ) {
float r = h.angleCompare(p);
if(r<0.01) {
if(RandomUtils.percent(100-r*100))
createBackPhoton(h);
}
}
}
Hole found = null;
for (int i = 0; i < holes.length; i++) { // 先看看已存在的洞是不是与光子同向,是的话就把洞挖大一点
@ -111,13 +116,14 @@ public class Cell {
h.size *= 1.2f;
if (h.size > 10000)
h.size = 10000;
h.age = 0;
break;
}
}
if (found != null) { // 如果第二次扩洞,且光子和洞不是同一个器官产生的,这时可以把这个洞和其它洞关联起来了
for (Hole hole : holes) {
if (hole != found && found.organNo != hole.organNo && (Math.abs(found.age - hole.age) < 9)) {// TODO:不应用固定值
if (hole != found && found.organNo != hole.organNo && (Math.abs(found.age - hole.age) < 80)) {// TODO:不应用固定值
bind(found, hole);
}
}
@ -133,15 +139,13 @@ public class Cell {
if (relations == null)
return;
for (Relation r : relations) {
if (energy < 90)
return;
Hole f = null;
if (h.equals(r.h1))
f = r.h2;// h2与h是一对绑定的
else if (h.equals(r.h2))
f = r.h1; // h1与h是一对绑定的
if (f != null) {
Photon back = new Photon(0, ColorUtils.RED, f.x, f.y, f.z, -f.mx, -f.my, -f.mz, 90);// 生成反向的光子
Photon back = new Photon(-1, ColorUtils.RED, f.x, f.y, f.z, -f.mx, -f.my, -f.mz, 90);// 生成反向的光子
addPhoton(back);
// energy -= 90;
}
@ -172,47 +176,9 @@ public class Cell {
}
}
/** Photon always walk */
public void photonWalk(Frog f, Photon p) { // 光子自已会走到下一格,如果下一格为空,继续走,直到能量耗尽或出界
if (p.energy < 0.1)
return;// 能量小的光子直接扔掉
if (p.outBrainBound())
return; //// 出界的光子直接扔掉
p.x += p.mx;
p.y += p.my;
p.z += p.mz;
int rx = Math.round(p.x);
int ry = Math.round(p.y);
int rz = Math.round(p.z);
if (Frog.outBrainBound(rx, ry, rz))
return;// 出界直接扔掉
Cell cell = f.getCell(rx, ry, rz);
if (cell != null) {
cell.addPhoton(p);
} else {
// p.energy *= .6;// 真空中也要乘一个衰减系数,防止它走太远,占用计算资源
photonWalk(f, p);// 递归一直走下去直到遇到cell或出界
}
}
public float getEnergy() {// 获取cell的能量
return energy;
}
public void setEnergy(float energy) {// 设cell的能量
this.energy = energy;
}
public int getPhotonQty() {// 获取cell里的总光子数
return photonQty;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
public void deleteAllPhotons() {
photons = null;
photonQty = 0;
}
}

@ -10,6 +10,8 @@
*/
package com.github.drinkjava2.frog.brain;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -36,30 +38,78 @@ public class CellActions {
*
*
*/
public static void act(int activeNo, Organ o, Cell cell, int x, int y, int z) {
switch (o.type) { // 添加细胞的行为,这是硬编码
case Organ.EMPTY: // 如果是WALK细胞它的行为是让每个光子穿过这个细胞走到下一格保持直线运动不变
break;
case Organ.EYE: // 如果是视网膜细胞它的行为是将Cell的激活值转化为向右的多个光子发散出去模拟波源
if (cell.getEnergy() > 0 && RandomUtils.percent(100)) {
for (float yy = -0.3f; yy <= 0.3f; yy += 0.1) {// 形成一个扇面向右发送
for (float zz = -0.3f; zz <= 0.3f; zz += 0.1) {
cell.addPhoton(new Photon(o.organNo, o.color, x, y, z, 1.0f, yy, zz, 100f));
}
}
public static void act(Frog frog, int activeNo, Cell c) {
if (c.holes != null)
for (Hole h : c.holes) {// 洞的年龄增加,目的是让年龄越接近的洞之间,绑定的概率和强度越大
h.age++;
}
break;
case Organ.EAR: // 如果是听力细胞它的行为是将cell的激活能量转化为向下的多个光子发散出去模拟波源
if (cell.getEnergy() > 0 && RandomUtils.percent(100)) {
for (float xx = -0.3f; xx <= 0.3f; xx += 0.13) {// 形成一个扇面向下发送
for (float yy = -0.3f; yy <= 0.3f; yy += 0.13) {
cell.addPhoton(new Photon(o.organNo, o.color, x, y, z, xx, yy, -1, 100f));
if (c.organs != null)
for (int orgNo : c.organs) {
Organ o = frog.organs.get(orgNo);
switch (o.type) { // 添加细胞的行为,这是硬编码
case Organ.MOVE: // 如果是MOVE细胞它的行为是让每个光子穿过这个细胞走到下一格保持光子沿直线运动
if (c.x == 0 || c.z == Env.FROG_BRAIN_ZSIZE - 1) {// 但是对于输入区,将删除光子,并合计一共收到多少
if (c.photonQty > 0) {
c.photonSum += c.photonQty;
c.photons = null;
}
break;
}
if (c.photons != null) {
for (int ii = 0; ii < c.photons.length; ii++) {
Photon p = c.photons[ii];
if (p == null || p.activeNo == activeNo)// 同一轮新产生的光子或处理过的光子不再走了
continue;
p.activeNo = activeNo;
c.removePhoton(ii);
frog.addAndWalk(p); // 让光子自已往下走,并且还挖洞
}
}
break;
case Organ.MOVE_JELLY: // 如果是MOVE_JELLY细胞它让每个光子穿过这个细胞走到下一格并在下一个细胞上打出洞来
if (c.x == 0 || c.z == Env.FROG_BRAIN_ZSIZE - 1) {// 但是对于输入区,将删除光子,并合计一共收到多少
if (c.photonQty > 0) {
c.photonSum += c.photonQty;
c.photons = null;
}
break;
}
if (c.photons != null) {
for (int ii = 0; ii < c.photons.length; ii++) {
Photon p = c.photons[ii];
if (p == null || p.activeNo == activeNo)// 同一轮新产生的光子或处理过的光子不再走了
continue;
p.activeNo = activeNo;
c.removePhoton(ii);
frog.addAndWalkAndDig(p); // 让光子自已往下走,并且还挖洞
}
}
break;
case Organ.EYE: // 如果是视网膜细胞它的行为是将只要Cell有输入信号就产生向右的多个光子发散出去模拟波源
if (c.hasInput && RandomUtils.percent(40)) {// 随机数的作用是减少光子数,加快速度
for (float yy = -0.1f; yy <= 0.1f; yy += 0.03) {// 形成一个扇面向右发送
for (float zz = -0.1f; zz <= 0.1f; zz += 0.03) {
Photon p = new Photon(orgNo, o.color, c.x, c.y, c.z, 1.0f, yy, zz, 100f);
p.activeNo = activeNo; // 用这个activeNo防止一直被赶着走
frog.addAndWalk(p);// 光子不是直接添加,而是走一格后添加在相邻的细胞上
}
}
}
break;
case Organ.EAR: // 如果是听力细胞它的行为是将只要Cell有输入信号就产生向下的多个光子发散出去模拟波源
if (c.hasInput && RandomUtils.percent(40)) {// 随机数的作用是减少光子数,加快速度
for (float xx = -0.3f; xx <= 0.3f; xx += 0.15) {// 形成一个扇面向下发送
for (float yy = -1f; yy <= 1f; yy += 0.06) {
Photon p = new Photon(o.organNo, o.color, c.x, c.y, c.z, xx, yy, -1, 100f);
p.activeNo = activeNo;
frog.addAndWalk(p);// 光子不是直接添加,而是走一格后添加在相邻的细胞上
}
}
}
break;
default:
break;
}
}
break;
default:
break;
}
}
}

@ -59,10 +59,4 @@ public class Cone implements Shape {
// TODO 待添加Cone形器官播种脑细胞的代码
}
@Override
public void createCells(Frog f) {
// TODO 待添加Cone形器官createCells的代码
}
}

@ -59,13 +59,13 @@ public class Cuboid implements Shape {
}
@Override
public void createCellsRegOrgan(Frog f, int o) {// 创建Cell并登记Organ 先忽略密度分布等参数
public void createCellsRegOrgan(Frog f, int orgNo) {// 创建Cell并登记Organ 先忽略密度分布等参数
for (int i = x; i < x + xe; i++)
for (int j = y; j < y + ye; j++)
for (int k = z; k < z + ze; k++) {
Cell cell = f.getOrCreateCell(i, j, k);
if (cell != null)
cell.regOrgan(o);
cell.regOrgan(orgNo);
}
}

@ -25,7 +25,7 @@ public class Hole {
public float mx; // mx,my,mz分别是光子砸出这个洞时的光子每单元移动方向在三个轴上的投影
public float my;
public float mz;
public float size;// 洞的大小,同一个方向砸来的光子越多,能量越大,洞就越大
public float size = 1;// 洞的大小,同一个方向砸来的光子越多, 洞就越大
public int age;// 洞的年龄,一直在增长但当洞光子砸进来或被激活产生光子时洞的年龄就归0
public int organNo;// 这里记录第一个撞出来这个洞的产子是由哪个器官产生出来的
@ -36,7 +36,6 @@ public class Hole {
this.mx = p.mx;
this.my = p.my;
this.mz = p.mz;
this.size = p.energy;
this.organNo = p.organNo;
}

@ -55,12 +55,15 @@ public class Organ implements Serializable, Cloneable {// 因为要保存在蛋
// 以下是各种器官类型每个神经元都属于一个器官每个器官都有一个type类型参数
public static final int EMPTY = 0;// 空细胞,不处理光子
public static final int EYE = 1;// 眼细胞会根据cell激活度产生发散到各个方向的光子
public static final int EAR = 2;// 耳细胞,类似眼细胞,不同点是为了简化脑内听觉区和输入区混用一个区所以它也可吸收光子倒过来激活cell
public static final int DYNAMIC = 3; // 只有动态洞的细胞,它忽略静态洞参数
public static final int STATIC = 4; // 只有静态洞的细胞,它忽略动态洞参数
public static final int MIX = 5; // 同时具有静态和动态洞的细胞
public static final int TYPE_QTY = 6;// 所有的type都是预先写好在这里的自动生成的type也只能在写好的type里选一个
public static final int MOVE = 1;// 会让光子沿直线走一格
public static final int MOVE_JELLY = 2;// 会让光子沿直线走一格,并在下一个细胞上打洞
public static final int EYE = 3;// 眼细胞会根据cell激活度产生发散到各个方向的光子
public static final int EAR = 4;// 耳细胞,类似眼细胞,不同点是为了简化脑内听觉区和输入区混用一个区所以它也可吸收光子倒过来激活cell
public static final int JELLY = 5; // 光子在当前细胞上可以打出洞来
public static final int STATIC = 6; // 只有静态洞的细胞,它忽略动态洞参数
public static final int MIX = 7; // 同时具有静态和动态洞的细胞
public static final int TYPE_QTY = 8;// 所有的type都是预先写好在这里的自动生成的type也只能在写好的type里选一个
private static int organNoIndex = 1;
public int organNo = organNoIndex++; // 每个器官都有一个唯一的编号,作用是同一个编号的光子间将不产生绑定
@ -138,10 +141,10 @@ public class Organ implements Serializable, Cloneable {// 因为要保存在蛋
}
/** Only call once when frog created , Child class can override this method */
public void init(Frog f, int oIndex) { // 在青蛙生成时会调用这个方法,进行一些初始化,通常是根据参数来播种脑细胞
public void init(Frog f, int orgNo) { // 在青蛙生成时会调用这个方法,进行一些初始化,通常是根据参数来播种脑细胞
// 里是器官播种脑细胞的具体代码,对于手工生成的器官也可以重写这个方法对于自动生成的器官必须根据type和shape等来播种要写死在这里
if (shape != null)
shape.createCellsRegOrgan(f, oIndex); // 先均匀播种脑细胞试试
shape.createCellsRegOrgan(f, orgNo); // 先均匀播种脑细胞试试
}
/** each step will call Organ's active methodd */

@ -28,8 +28,7 @@ public class Photon {
public float mx;
public float my;
public float mz;
public float energy;
public int organNo;// 每个光子是由哪个器官产生的为0表示它不是器官而是由细胞动态生成的
public int organNo;// 每个光子是由哪个器官产生的,为-1表示它不是器官产生而是由细胞动态生成的反向光子信号
public int color;// 每个光子都有自已的颜色,由产生光子的器官的颜色来决定,颜色不重要,但能方便观察
public int activeNo;// 每一轮循环都有一个编号,光子走一格后就加上这个编号,同一个循环如果遇到相同编号的光子就跳过,防止光子被一直赶着走
@ -44,10 +43,13 @@ public class Photon {
this.my = my;
this.mz = mz;
this.organNo = organNo;
this.energy = energy;
this.color = color;
}
public boolean isBackway() {// 是反向光子? 通常反向传播的光子不再参与在果冻细胞上挖洞
return organNo < 0;
}
/** Check if x,y,z out of frog's brain bound */
public boolean outBrainBound() {// 检查指定坐标是否超出frog脑空间界限
return x < 0 || x >= Env.FROG_BRAIN_XSIZE || y < 0 || y >= Env.FROG_BRAIN_YSIZE || z < 0

@ -26,7 +26,5 @@ public interface Shape extends Serializable {
/* Draw self on brain picture */
public void drawOnBrainPicture(BrainPicture pic); // 把自己在脑图上画出来
public void createCellsRegOrgan(Frog f, int o); // 根据给定organ的参数在shape所代表的脑区内添加脑细胞并加入对应细胞的行为
public void createCells(Frog f); // 在organ所代表的脑区内仅创建空的Cell对象
public void createCellsRegOrgan(Frog f, int orgNo); // 在Shape所代表的脑区内找到或创建Cell对象并将器官号orgNo登记在cell里
}

@ -12,66 +12,56 @@ package com.github.drinkjava2.frog.brain.organ;
import com.github.drinkjava2.frog.Env;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.BrainPicture;
import com.github.drinkjava2.frog.brain.Cuboid;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.util.ColorUtils;
/**
* Ear can accept letter information input
* +Unicode
* Ear can accept sound input
*
*
*
* @author Yong Zhu
* @since 2.0.2
*/
@SuppressWarnings("all")
public class Ear extends Organ {// 耳朵也是长方体,我为什么要用也?
public class Ear extends Organ {// 耳朵位于脑的顶上,也是长方体
private static final long serialVersionUID = 1L;
public Cuboid a = new Cuboid(12, 10, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1);
public Cuboid b = new Cuboid(12, 15, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1);
public Cuboid c = new Cuboid(17, 10, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1);
public Cuboid d = new Cuboid(17, 15, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1);
public Ear() {
this.shape = new Cuboid(12, 10, Env.FROG_BRAIN_ZSIZE - 1, 8, 8, 1);// 手工固定耳区的大小
this.shape = new Cuboid(15, 5, Env.FROG_BRAIN_ZSIZE - 1, 1, 10, 1);// 手工固定耳区的大小
this.type = Organ.EAR;
this.organName = "ear";
this.organName = "Ear";
this.allowVary = false;// 不允许变异
this.allowBorrow = false;// 不允许借出
this.color = ColorUtils.BLUE;
}
public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来,子类可以重写这个方法
super.drawOnBrainPicture(f, pic); // 父类方法显示shape形状
pic.drawCuboid(a);// 显示abcd位置在脑图上
pic.drawCuboid(b);
pic.drawCuboid(c);
pic.drawCuboid(d);
public void hearSound(Frog f, int code) {
Cuboid c = (Cuboid) this.shape;
f.getOrCreateCell(c.x, c.y + code, c.z).hasInput = true;
}
/** 给这个耳朵听到一个字母,激活它的听觉输入区, 注意听觉输入区并不等于脑内虚拟听觉成像区,但是第一版...先共用一个区吧 */
public void hearSound(Frog f, String letter) {
f.setCuboidVales(getCuboidByStr(letter), 80);
public int readcode(Frog f) {//找出收取光子数最多的点
int temp = -10000;
int yPos = -1;
Cuboid c = (Cuboid) this.shape;
System.out.print("Ear received photons qty: ");
for (int y = 0; y < 10; y++) {
int sum = f.getOrCreateCell(c.x, c.y + y, c.z).photonSum;
System.out.print(sum + ",");
if (sum > temp) {
yPos = y;
temp = sum;
}
}
System.out.println();
return yPos;
}
/** 给这个耳朵听到一个字母,激活它的听觉输入区, 注意听觉输入区并不等于听觉成像区 */
public void hearNothing(Frog f) {
f.setCuboidVales(a, 0);
f.setCuboidVales(b, 0);
f.setCuboidVales(c, 0);
f.setCuboidVales(d, 0);
}
public Cuboid getCuboidByStr(String s) {
if ("A".equalsIgnoreCase(s))
return a;
if ("B".equalsIgnoreCase(s))
return b;
if ("C".equalsIgnoreCase(s))
return c;
if ("D".equalsIgnoreCase(s))
return d;
return null;
f.setCuboidVales((Cuboid) shape, false);
}
}

@ -14,6 +14,7 @@ import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Cuboid;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.util.ColorUtils;
import com.github.drinkjava2.frog.util.PixelsUtils;
/**
* Eye can only see env material
@ -24,9 +25,9 @@ public class Eye extends Organ {// 眼睛是长方体
private static final long serialVersionUID = 1L;
public Eye() {
this.shape = new Cuboid(0, 5, 5, 1, 13, 13);
this.shape = new Cuboid(0, 3, 2, 1, 13, 13);
this.type = Organ.EYE;
this.organName = "eye";
this.organName = "Eye";
this.allowVary = false;// 不允许变异
this.allowBorrow = false;// 不允许借出
this.color = ColorUtils.GRAY;
@ -34,7 +35,7 @@ public class Eye extends Organ {// 眼睛是长方体
/** Clear image on retina */
public void seeNothing(Frog f) {// 外界可以直接调用这个方法,清除视网膜图像
f.setCuboidVales((Cuboid) shape, 0);
f.setCuboidVales((Cuboid) shape, false);
}
/**
@ -53,6 +54,11 @@ public class Eye extends Organ {// 眼睛是长方体
for (int px = 0; px < w; px++)
for (int py = 0; py < h; py++)
if (pixels[px][py] > 0)
f.getOrCreateCell(0, c.y + c.ye - px - 1, c.z + py).setEnergy(100);
f.getOrCreateCell(0, c.y + c.ye - px - 1, c.z + py).hasInput = true;
}
public void seeImageWithOffset(Frog f, byte[][] pixels, int xOff, int yOff) {// 外界硬塞一个象素图到视网膜上,并给出偏移量
byte[][] newPixels = PixelsUtils.offset(pixels, xOff, yOff);
seeImage(f, newPixels);
}
}

@ -15,20 +15,20 @@ import com.github.drinkjava2.frog.brain.Cuboid;
import com.github.drinkjava2.frog.brain.Organ;
/**
* Empty is a special organ has no action, only used as media for photon
* Move is a special organ the action move photon go to next cell
*
* Emptycellcell
* MoveCell沿
*
* @author Yong Zhu
*/
public class Empty extends Organ {
public class MoveJelly extends Organ {
private static final long serialVersionUID = 1L;
public Empty() {
public MoveJelly() {
super();
this.shape = new Cuboid(6, 2, 2, Env.FROG_BRAIN_XSIZE-7, Env.FROG_BRAIN_YSIZE-3, Env.FROG_BRAIN_ZSIZE-4);
this.organName = "Empty";
this.type = Organ.EMPTY; // Empty这个器官并不播种cell,它存在的唯一目的只是充当光子媒介,否则光子会一直走下去消失
this.shape = new Cuboid(0, 0, 0, Env.FROG_BRAIN_XSIZE - 5, Env.FROG_BRAIN_YSIZE, Env.FROG_BRAIN_ZSIZE);
this.organName = "MoveJelly";
this.type = Organ.MOVE_JELLY; // Empty这个器官并不播种cell,它存在的唯一目的只是充当光子媒介,否则光子会一直走下去消失
this.allowVary = false;// 不允许变异
this.allowBorrow = false;// 不允许借出
}

@ -17,8 +17,8 @@ import java.util.List;
import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.Organ;
import com.github.drinkjava2.frog.brain.organ.Ear;
import com.github.drinkjava2.frog.brain.organ.Empty;
import com.github.drinkjava2.frog.brain.organ.Eye;
import com.github.drinkjava2.frog.brain.organ.MoveJelly;
import com.github.drinkjava2.frog.util.RandomUtils;
/**
@ -37,9 +37,9 @@ public class Egg implements Serializable {
public List<Organ> organs = new ArrayList<>();// NOSONAR
public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙
organs.add(new MoveJelly()); // MoveJelly即移动光子也是果冻记忆细胞本来可以分成两个器官的图省事
organs.add(new Eye()); // 眼是手工创建的,必有
organs.add(new Ear()); // 耳是手工创建的这个是用来测试ABCD字母识别的
organs.add(new Empty()); // Empty什么都不干只用来作光子媒介
}
/** Create egg from frog */

@ -15,22 +15,19 @@ import com.github.drinkjava2.frog.Frog;
import com.github.drinkjava2.frog.brain.BrainPicture;
import com.github.drinkjava2.frog.brain.organ.Ear;
import com.github.drinkjava2.frog.brain.organ.Eye;
import com.github.drinkjava2.frog.util.RandomUtils;
import com.github.drinkjava2.frog.util.StringPixelUtils;
/**
* LetterTester used to test A, B , C, D letter recognition
* ChineseTester used to test test recognition
*
* , AA
* BB(Ear+,)
* )
*
*
* @author Yong Zhu
* @since 1.0
*/
public class LetterTester implements EnvObject {
private static final String STR = "ABCD";
String letter;
public static final String STR = "对酒当歌人生几何";
public static final int TIME = 120;
@Override
public void build() { // do nothing
@ -42,42 +39,28 @@ public class LetterTester implements EnvObject {
@Override
public void active(int screen) {
if (Env.step == 0) { // 每当开始新一屏测试时,重选一个随机字符
letter = String.valueOf(STR.charAt(RandomUtils.nextInt(4)));
}
Frog frog = Env.frogs.get(screen * Env.FROG_PER_SCREEN); // 这个测试只针对每屏的第一只青蛙,因为脑图固定只显示第一只青蛙
Eye eye = frog.findOrganByName("eye");
Eye eye = frog.findOrganByName("Eye");
Ear ear = frog.findOrganByName("Ear");
Ear ear = frog.findOrganByName("ear");
int index = Env.step / TIME;
if (Env.step % TIME == 0)
frog.prepareNewTraining();
if (next50(1)) {
BrainPicture.setNote( "第1个字训练");
ear.hearSound(frog, "A");
eye.seeImage(frog, StringPixelUtils.getSanserif12Pixels("一"));
} else if (next50(50)) {
BrainPicture.setNote(" 第2个字训练");
ear.hearSound(frog, "C");
eye.seeImage(frog, StringPixelUtils.getSanserif12Pixels("二"));
} else if (next50(100)) {
BrainPicture.setNote("只看到第3个字");
eye.seeImage(frog, StringPixelUtils.getSanserif12Pixels("一"));
} else if (next50(150)) {
BrainPicture.setNote("只看到第4个字");
eye.seeImage(frog, StringPixelUtils.getSanserif12Pixels("二"));
} else if (next50(200)) {
BrainPicture.setNote("看到第5个字");
byte[][] pic = StringPixelUtils.getSanserif12Pixels("三");
eye.seeImage(frog, pic);
if (index < STR.length()) {
BrainPicture.setNote("第" + (index + 1) + "个字训练");
ear.hearSound(frog, index);
eye.seeImageWithOffset(frog, StringPixelUtils.getSanserif12Pixels(STR.substring(index, index + 1)),0,0);
} else {
BrainPicture.setNote(null);
ear.hearNothing(frog);
eye.seeNothing(frog);
int index2 = index % STR.length();
BrainPicture.setNote("第" + (index2 + 1) + "个字识别");
eye.seeImageWithOffset(frog, StringPixelUtils.getSanserif12Pixels(STR.substring(index2, index2 + 1)),0,0);
if (Env.step % TIME > (TIME - 2)) {
int result = ear.readcode(frog);
System.out.println("Max=" + result+", 即 '"+STR.substring(result, result+1)+"'");
frog.prepareNewTraining();
}
}
}
private static boolean next50(int i) {
return Env.step > i && Env.step < i + 25;
}
}

@ -44,7 +44,7 @@ public class RandomUtils {
}
public static boolean percent(float percent) {// 有百分这percent的机率为true
return rand.nextFloat() * 100 < percent;
return rand.nextInt(100) < percent;
}
/** Randomly create a Cuboid inside of brain space */

@ -29,6 +29,10 @@ import java.util.Map;
public class StringPixelUtils {
private static final Map<String, byte[][]> lettersMap = new HashMap<>();
public static byte[][] getSanserif10Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 10, s);
}
public static byte[][] getSanserif12Pixels(String s) {
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, s);
}

@ -11,10 +11,11 @@ LongFer
hl330
陈凯文
chanvictoire
目前收入总额:218.77元
Ad
目前收入总额:268.77元
支出(按时间顺序)
目前支出总额:0元
目前余额218.77元
目前余额268.77元

@ -184,3 +184,5 @@ git reset --hard ae34b07e 可以转回到2019-08-04提交的分组测试的找
另外,这次更新暂停功能加强了,可以在任意时刻暂停,并加上脑图的剖面显示,以方便调试,新增了空格、方向快捷键,现在汇总所有脑图快捷键如下:
T:顶视 F前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标操作:缩放旋转平移
### 2019-11-26 commit: Chinese test
这次更新用汉字"对酒当歌人生几何"来测试模式识别,优化了一下程序,目前这个图像识别基本没有容错性,图像像素多的会干拢像素少的文字的识别。下面考虑拉大听力信号间隔,以及引入侧抑制等机制(如果一个洞中砸进了光子,但是却和这个洞不同向,有可能产生负值的反向光子,这个负值与角度差有关),这和算法上的侧抑制很象,世界上的道理都是相通的。以后算法上的卷积、深度学习等现成的成果,也可以考虑融入进来,用图形化表示。反过来说,目前以算法进行的神经网络研究,如果借签这个项目的基本思路,把输入输出器官和适应环境进化做为重点,采用遗传淘汰的方式调整算法架构本身,尽量减少人为的设计,最后达到的行为表现可能和这个人工生命项目是一致的。我走图形化是没办法,因为基础差,但是精通算法的人如果明白我的意思,也可能很快做出表现比较复杂的人工生命来,毕竟算法研究已经到了很高的水平了,是现成的。

Loading…
Cancel
Save