Update readme for history015_testinput3

This commit is contained in:
yong 2023-09-29 08:06:17 -06:00
parent 7c0674fb8b
commit 3410de3904
17 changed files with 685 additions and 176 deletions

View File

@ -24,7 +24,12 @@
这些全局参数是跟随青蛙终身的,一旦青蛙孵化出来就不再动了,在程序里把所有常量放在一个数组里用遗传算法来控制基本规则是小变动有大概率发生大变动有小概率发生。青蛙的参数分为两类一类是与空间位置相关的如脑细胞是否会出现在某个空间位置一类是与位置无关的如每个细胞激活后向其它细胞发送多少能量。前者要放到分裂算法里用一串8/4/2叉基因树来控制空间分布后者就没必要这么浪费了直接用一组全局数字表示即可并用遗传算法来随机变异和筛选它们。在给神经网络编程时如果碰到可以用全局常量来控制的参数尽量不要手工赋值而要用遗传算法来控制因为多变量的优化组合筛选靠人力是不可能做好的。就拿这个例子来说我压根不知道这些参数将会是多大是正还是负但是我知道应该有这些参数这就够了。人工生命项目编程不讲究精准思维模式要从传统的精细化编程转变为以概率、笼统、可能为导向的思维大方向人为确定细节交给电脑去算这和大自然用遗传算法来筛选出脑细胞的参数是一个道理。
从本次更新可以看到,青蛙是工作在一个连续的信息流下面,信息是以脉冲方式在细胞之间互相传递大小不等的能量,可以说是一个最简单的脉冲神经网络大脑了。这个实验不很实美,没有实现一个不漏地吃掉食物但是又不空咬这个目标,但是人生苦短,我不想继续和这三个细胞缠斗下去了,后面将转到多个视觉细胞和引入苦甜奖惩信号细胞来影响洞(权重)的大小,这个会更有趣、更智能,也更接近模式识别任务。我认为通用智能就是模式识别与行为输出结合起来的系统,如果奖罚细胞和行为输出细胞在一开始就做为这个模式识别系统的一个组成部分,并且由遗传算法来筛选参数,那通用人工智能就不远了。
2023-08-25 关于XOR逻辑及多个输入的测试
最近因为参数范围太大很难跑出结果想试试把忆细胞也简化掉直接视细胞在咬细胞上挖洞这样就成了单层神经网络问题变成传统的单层神经网络实现模式识别也就是说多个输入信号转化为更精简的输出信号。群里曾有人发过实现异或XOR逻辑需要一个中间层的图片这有点复杂我在网上搜了一下“实际脑细胞实现xor逻辑”发现一篇文章“大脑只需单个神经元就可进行XOR异或运算”按照它的原理想了一下在二个输入细胞、一个执行细胞且每个输出都有正负两种权重的情况下是可以实现所有正常逻辑操作的即AND、OR、XOR三个逻辑这里面的小窍门是把累加高于1的饱和信号削除掉。“正常”指的是排除掉输入全为0输出为1这种看着就没什么用的逻辑。
![result21](result21_input3.png)
本次更新在015_testinput3目录下只有一个TestInput3.java文件这是个临时测试类用穷举法来测试一个如果有三个视觉输入细胞、一个执行细胞的情况下能不能实现所有正常模式识别即输入有2的7次方=128种组合输出有0/1两种信号。实测发现这128种情况下有31种输入是无法通过调整权重来实现输出逻辑的也就是说31种情况下是无解的。类似地如果有4个输入在32768组合中有29987种情况是无解的。所以如果输入信号大于两个时必须改进结构增加层数或在水平方向平铺增加输入输出细胞。
目前有两个问题:一是用甜激素增加所有最近活跃的正权重、苦激素增加所有最近活跃的负权重这种方式能不能完全代替穷举法找到所有解;二是有没有办法只使用浅层神经网络实现模式识别?(人脑的皮层占了很大比重,顾名思义,皮层可能就是浅层的,而不是象深度学习一样是极深层的神经网络)这个模式识别不需要很精准能达到约15x15的分辨率就可以接近人脑的模式识别功能了因为人脑还会结合动眼和变焦两个功能来缩小需要进行模式识别信号的像素。这两个问题目前深度学习可能能找到答案但我不知道有没有人采用这种正负权重双通道输入的结构这种双通道输入结构实际上才是实际生物的神经网络构成。
## 运行方式 | Run

View File

@ -2,9 +2,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.drinkjava2</groupId>
<artifactId>frog014</artifactId>
<artifactId>frog015</artifactId>
<packaging>jar</packaging>
<version>14.0</version>
<version>15.0</version>
<name>frog</name>
<description>当前目标是用分裂算法来实现第一个具备模式识别功能的神经网络</description>

View File

@ -20,6 +20,7 @@ import java.util.ArrayList;
import javax.imageio.ImageIO;
import com.gitee.drinkjava2.frog.brain.Consts;
import com.gitee.drinkjava2.frog.brain.Genes;
import com.gitee.drinkjava2.frog.egg.Egg;
import com.gitee.drinkjava2.frog.objects.Material;
@ -49,8 +50,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>(); // 基因是多个数列有点象多条染色体每个数列都代表一个基因的分裂次序(8叉/4叉/2叉)
public static final int CONSTS_LENGTH = 8;
public int[] consts = new int[CONSTS_LENGTH]; //常量基因用来存放不参与分裂算法的全局常量这些常量也参与遗传算法筛选规则是有大概率小变异小概率大变异见constGenesMutation方法
public int[] consts = new int[Consts.CountsQTY]; //常量基因用来存放不参与分裂算法的全局常量这些常量也参与遗传算法筛选规则是有大概率小变异小概率大变异见constGenesMutation方法
/** brain cells每个细胞对应一个神经元long是64位所以目前一个细胞只能允许最多64个基因64个基因有些是8叉分裂有些是4叉分裂
* 如果今后要扩充到超过64个基因限制可以定义多个三维数组同一个细胞由多个三维数组相同坐标位置的基因共同表达
@ -100,13 +100,28 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步这个方法是在当前屏animal生成之后调用比方说有一千个青蛙分为500屏测试每屏只生成2个青蛙的脑细胞可以节约内存
GeneUtils.geneMutation(this); //有小概率基因突变
GeneUtils.constGenesMutation(this); //常量基因突变
Consts.constMutation(this);//常量基因突变
if (RandomUtils.percent(40))
for (ArrayList<Integer> gene : genes) //基因多也要适当小扣点分防止基因无限增长
fat -= gene.size();
GeneUtils.createCellsFromGene(this); //根据基因分裂生成脑细胞
}
public boolean active(int step) {// 这个active方法在每一步循环都会被调用是脑思考的最小帧step是当前屏的帧数
// 如果fat小于0出界与非食物的点重合则判死
if (!alive) {
return false;
}
if (fat <= 0 || Env.outsideEnv(xPos, yPos) || Env.bricks[xPos][yPos] >= Material.KILL_ANIMAL) {
kill();
return false;
}
holesReduce(); //所有细胞上的洞都随时间消逝即信息的遗忘旧的不去新的不来
Genes.active(this, step); //调用每个细胞的活动重要
return alive;
}
private static final int MIN_FAT_LIMIT = Integer.MIN_VALUE + 5000;
private static final int MAX_FAT_LIMIT = Integer.MAX_VALUE - 5000;
@ -122,31 +137,16 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
//没定各个等级的奖罚值目前是手工设定的常数
public void awardAAAA() { changeFat(2000);}
public void awardAAA() { changeFat(1000);}
public void awardAA() { changeFat(60);}
public void awardAA() { changeFat(100);}
public void awardA() { changeFat(10);}
public void penaltyAAAA() { changeFat(-2000);}
public void penaltyAAA() { changeFat(-1000);}
public void penaltyAA() { changeFat(-60);}
public void penaltyAA() { changeFat(-100);}
public void penaltyA() { changeFat(-10);}
public void kill() { this.alive = false; changeFat(-5000000); Env.clearMaterial(xPos, yPos, animalMaterial); } //kill是最大的惩罚
//@formatter:on
public boolean active(int step) {// 这个active方法在每一步循环都会被调用是脑思考的最小帧step是当前屏的帧数
// 如果fat小于0出界与非食物的点重合则判死
if (!alive) {
return false;
}
if (fat <= 0 || Env.outsideEnv(xPos, yPos) || Env.bricks[xPos][yPos] >= Material.KILL_ANIMAL) {
kill();
return false;
}
//holesReduce(); //TODO: 所有细胞上的洞都随时间消逝即信息的遗忘旧的不去新的不来
Genes.active(this, step); //调用每个细胞的活动重要
return alive;
}
public void show(Graphics g) {// 显示当前动物
if (!alive)
return;
@ -166,65 +166,79 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
return cells[x][y][z] > 0;
}
public void open(int x, int y, int z) { //打开指定的xyz坐标对应的cell能量值为极大
energys[x][y][z] = 99999f;
public void setEng1(int x, int y, int z) { //打开指定的xyz坐标对应的cell能量值为极大
energys[x][y][z] = 1;
}
public void open(int[] a) { //打开指定的a坐标对应的cell能量值为极大
energys[a[0]][a[1]][a[2]] = 99999f;
public void setEng1(int[] a) { //打开指定的a坐标对应的cell能量值为极大
energys[a[0]][a[1]][a[2]] =1;
}
public void close(int x, int y, int z) { //关闭指定的xyz坐标对应的cell能量值为0
public void setEng0(int x, int y, int z) { //关闭指定的xyz坐标对应的cell能量值为0
energys[x][y][z] = 0;
}
public void close(int[] a) {//关闭指定的a坐标对应的cell能量值为0
public void setEng0(int[] a) {//关闭指定的a坐标对应的cell能量值为0
energys[a[0]][a[1]][a[2]] = 0;
}
public void addEng(int[] a, float e) {//指定的a坐标对应的cell能量值加e
if (cells[a[0]][a[1]][a[2]] == 0)
return;
energys[a[0]][a[1]][a[2]] += e;
if (energys[a[0]][a[1]][a[2]] < 0)
energys[a[0]][a[1]][a[2]] = 0f;
if (energys[a[0]][a[1]][a[2]] > 10)
energys[a[0]][a[1]][a[2]] = 10f;
}
addEng(a[0], a[1], a[2], e);
}
public void addEng(int x, int y, int z, float e) {//指定的a坐标对应的cell能量值加e
if (cells[x][y][z] == 0)
return;
energys[x][y][z] += e;
}
float eng = energys[x][y][z] + e;
if (eng > 1) //如果饱和不再增加通过这个方法可以实现异或逻辑或更复杂的模式识别详见TestInput3测试
eng = 1;
if (eng < 0) //回到传统方式细胞不允许出现负能量但是权值即树突的正负两个通道中的负通道上可以出现负信号这个与实际细胞的抑制信号相似
eng = 0;
energys[x][y][z] = eng;
}
public float get(int x, int y, int z) {//返回指定的a坐标对应的cell能量值
public float getEng(int x, int y, int z) {//返回指定的a坐标对应的cell能量值
return energys[x][y][z];
}
static final int HOLE_MAX_SIZE = 1000 * 1000;
public void digHole(int sX, int sY, int sZ, int tX, int tY, int tZ, int holeSize) {//在t细胞上挖洞将洞的方向链接到源s如果洞已存在扩大洞, 新洞大小为1洞最大不超过100
public void digHole(int[] srcPos, int[] targetPos, int holeSize, int fresh) {
digHole(srcPos[0], srcPos[1], srcPos[2], targetPos[0], targetPos[1], targetPos[2], holeSize, fresh);
}
public void digHole(int sX, int sY, int sZ, int[] targetPos, int holeSize, int fresh) {
digHole(sX, sY, sZ, targetPos[0], targetPos[1], targetPos[2], holeSize, fresh);
}
public static final int HOLE_ARR_SIZE = 5; //洞由几个参数构成
//TODO: =================以下这些方法太复杂删除除或重新整理=================
public void digHole(int sX, int sY, int sZ, int tX, int tY, int tZ, int size, int fresh) {//在t细胞上挖洞将洞的方向链接到源s如果洞已存在扩大洞, 新洞大小为1洞最大不超过100
if (!hasGene(tX, tY, tZ))
return;
if (!Env.insideBrain(sX, sY, sZ))
return;
if (!Env.insideBrain(tX, tY, tZ))
return;
if (get(tX, tY, tZ) < 1) //要调整
if (getEng(tX, tY, tZ) < 1) //要调整
addEng(tX, tY, tZ, 1); //要调整
int[] cellHoles = holes[tX][tY][tZ];
if (cellHoles == null) { //洞不存在新建一个 洞参数是一个一维数组分别为源坐标X,Y,Z, 洞的大小洞的新鲜度(TODO:待加)
holes[tX][tY][tZ] = new int[]{sX, sY, sZ, holeSize};
if (cellHoles == null) { //洞不存在新建一个 洞参数是一个一维数组分别为源坐标X,Y,Z, 洞的大小洞的新鲜度
holes[tX][tY][tZ] = new int[]{sX, sY, sZ, size, fresh}; //
return;
} else {
int emptyPos = -1; //找指定源坐标已存在的洞如果不存在如发现空洞也可以占用
for (int i = 0; i < cellHoles.length / 4; i++) {
int n = i * 4;
for (int i = 0; i < cellHoles.length / HOLE_ARR_SIZE; i++) {
int n = i * HOLE_ARR_SIZE;
if (cellHoles[n] == sX && cellHoles[n + 1] == sY && cellHoles[n + 2] == sZ) {//找到已有的洞了
if (cellHoles[n + 3] < 1000) //要改成由基因调整
cellHoles[n + 3] += 100;
cellHoles[n + 3] += size;
if (cellHoles[n + 4] < 1000) //要改成由基因调整
cellHoles[n + 4] += fresh;
return;
}
if (emptyPos == -1 && cellHoles[n + 3] <= 1)//如发现空洞也可以先记下它的位置
@ -233,54 +247,62 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
if (emptyPos > -1) { //找到一个空洞
cellHoles[emptyPos] = sX;
cellHoles[emptyPos + 1] = sX;
cellHoles[emptyPos + 2] = sX;
cellHoles[emptyPos + 3] = holeSize; //要改成由基因调整
cellHoles[emptyPos + 1] = sY;
cellHoles[emptyPos + 2] = sZ;
if (cellHoles[emptyPos + 3] < 1000) //要改成由基因调整
cellHoles[emptyPos + 3] += size;
if (cellHoles[emptyPos + 4] < 1000) //要改成由基因调整
cellHoles[emptyPos + 4] += fresh;
return;
}
int length = cellHoles.length; //没找到已有的洞也没找到空洞新建一个并追加到原洞数组未尾
int[] newHoles = new int[length + 4];
int[] newHoles = new int[length + HOLE_ARR_SIZE];
System.arraycopy(cellHoles, 0, newHoles, 0, length);
newHoles[length] = sX;
newHoles[length + 1] = sY;
newHoles[length + 2] = sZ;
newHoles[length + 3] = holeSize; //要改成由基因调整
newHoles[length + 3] = size; //要改成由基因调整
newHoles[length + 4] = fresh; //要改成由基因调整
holes[tX][tY][tZ] = newHoles;
return;
}
}
public void holeSendEngery(int x, int y, int z, float le, float re) {//在当前细胞所有洞上反向发送能量光子)le是向左边的细胞发 re是向右边的细胞发
public void holeSendEngery(int[] pos, float e) {//在当前细胞所有洞上反向发送能量光子)le是向左边的细胞发 re是向右边的细胞发
holeSendEngery(pos[0], pos[1], pos[2], e);
}
public void holeSendEngery(int x, int y, int z, float e) {//在当前细胞所有洞上反向发送能量光子)le是向左边的细胞发 re是向右边的细胞发
int[] cellHoles = holes[x][y][z]; //cellHoles是单个细胞的所有洞(触突)4个一组前三个是洞的坐标后一个是洞的大小
if (cellHoles == null) //如洞不存在不发送能量
return;
for (int i = 0; i < cellHoles.length / 4; i++) {
int n = i * 4;
for (int i = 0; i < cellHoles.length / HOLE_ARR_SIZE; i++) {
int n = i * HOLE_ARR_SIZE;
float size = cellHoles[n + 3];
if (size > 1) {
int x2 = cellHoles[n];
if (x2 < x)
addEng(x2, cellHoles[n + 1], cellHoles[n + 2], le); //向左边的细胞反向发送常量大小的能量
else
addEng(x2, cellHoles[n + 1], cellHoles[n + 2], re); //向右边的细胞反向发送常量大小的能量
addEng(cellHoles[n], cellHoles[n + 1], cellHoles[n + 2], e + cellHoles[n + 3] + cellHoles[n + 4]); //向源细胞反向发送常量大小的能量
}
}
}
// public void holesReduce() {//所有hole大小都会慢慢减小模拟触突连接随时间消失即细胞的遗忘机制这保证了系统不会被信息撑爆
// for (int x = 0; x < Env.BRAIN_SIZE - 1; x++)
// for (int y = 0; y < Env.BRAIN_SIZE - 1; y++)
// for (int z = 0; z < Env.BRAIN_SIZE - 1; z++) {
// int[] cellHoles = holes[x][y][z];
// if (cellHoles != null)
// for (int i = 0; i < cellHoles.length / 4; i++) {
// int n = i * 4;
// int size = cellHoles[n + 3];
// if (size > 0)
// cellHoles[n + 3] = (int) (size * 0.9);//要改成由基因调整
// }
// }
// }
public void holesReduce() {//所有hole大小都会慢慢减小模拟触突连接随时间消失即细胞的遗忘机制这保证了系统不会被信息撑爆
for (int x = 0; x < Env.BRAIN_SIZE - 1; x++)
for (int y = 0; y < Env.BRAIN_SIZE - 1; y++)
for (int z = 0; z < Env.BRAIN_SIZE - 1; z++) {
int[] cellHoles = holes[x][y][z];
if (cellHoles != null)
for (int i = 0; i < cellHoles.length / HOLE_ARR_SIZE; i++) {
int n = i * HOLE_ARR_SIZE;
int size = cellHoles[n + 3];
if (size > 0)
cellHoles[n + 3] = (int) (size * 0.9);//要改成由基因调整
int fresh = cellHoles[n + 4];
if (fresh > 0)
cellHoles[n + 4] -= Consts.HOLE_REDUCE;//要改成由基因调整
}
}
}
}

View File

@ -32,11 +32,11 @@ public class Env extends JPanel {
/** Speed of test */
public static int SHOW_SPEED = 1000; // 测试速度-1000~1000,可调, 数值越小速度越慢
public static final int FROG_EGG_QTY = 200; // 每轮下n个青蛙蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_EGG_QTY = 300; // 每轮下n个青蛙蛋可调只有最优秀的前n个青蛙们才允许下蛋
public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
public static final int SCREEN = 1; // 分几屏测完
public static final int SCREEN = 4; // 分几屏测完
/** Delete eggs at beginning of each run */
public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除以前保存的青蛙蛋文件如果为false将加载旧蛋文件继续运行

View File

@ -358,8 +358,8 @@ public class BrainPicture extends JPanel {
int[] holes = a.holes[x][y][z];
if (holes != null) {
setPicColor(Color.GRAY);
for (int i = 0; i < holes.length / 4; i++) {
int n = i * 4;
for (int i = 0; i < holes.length / Animal.HOLE_ARR_SIZE; i++) {//这里画出hole连线
int n = i * Animal.HOLE_ARR_SIZE;
drawCentLine(x, y, z, holes[n], holes[n + 1], holes[n + 2]);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.brain;
import static com.gitee.drinkjava2.frog.util.RandomUtils.percent;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.util.Logger;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* Here store counts
*
* 这个类存放脑常量定义变异日志打印相关的方法
* 神经网络中有一些全局常量与结构生成无关这时可以把所有常量定义到animal和egg的constGenes常量数组中用统一的随机方法来变异这些常量
*
* @author Yong Zhu
* @since 15.0
*/
@SuppressWarnings("all")
public class Consts {
public static int CountsQTY; //总常量数量
private static int index_ = 0;
private static int index() {
return index_++;
}
public static final int ADD_EYE = index(); //用index()这种编程技巧而不是直接给定数值是为了增删常量定义时比较方便不会影响其它行
public static final int ADD_BITE = index();
public static final int REDUCE_BITE = index();
public static final int HOLE_FRESH = index();
public static final int HOLE_REDUCE = index();
private static Map<String, Integer> values = new LinkedHashMap<String, Integer>();
static {
try {
Class c = Consts.class;
Field[] fs = c.getDeclaredFields();
for (Field f : fs) { // 用反射来获取常量的名称并保存下来将来在printLog中要按顺序打印出所有常量名
if (int.class.equals(f.getType()) && !"LENGTH".equals(f.getName()) && !"index_".equals(f.getName())) {
values.put(f.getName(), f.getInt(null));
}
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
CountsQTY = values.size();
}
public static boolean[] exist = new boolean[CountsQTY]; //不是每个常量组数都用到只有被用字母代表的才会用到并在这里标记这种方法比MAP要快
static StringBuilder sb = new StringBuilder();
public static void printLog(Animal a) {
sb.setLength(0);
int i = 0;
for (Entry<String, Integer> e : values.entrySet()) {
sb.append(e.getKey()).append("=").append(a.consts[e.getValue()]).append("\t\t");
if (i++ % 6 == 5)
sb.append("\n");
}
Logger.debug(sb.toString());
}
public static void constMutation(Animal a) { //全局参数变异, 这一个方法变异动物的所有常量
for (int i = 0; i < CountsQTY; i++) {
if (percent(20))
a.consts[i] = RandomUtils.vary(a.consts[i]);
}
}
}

View File

@ -10,11 +10,12 @@
*/
package com.gitee.drinkjava2.frog.brain;
import static com.gitee.drinkjava2.frog.brain.Consts.ADD_BITE;
import static com.gitee.drinkjava2.frog.brain.Consts.REDUCE_BITE;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.objects.Eye;
import com.gitee.drinkjava2.frog.objects.OneDotEye;
import com.gitee.drinkjava2.frog.util.Logger;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
@ -81,7 +82,7 @@ public class Genes { //Genes登记所有的基因 指定每个基因允许分
return register(1, true, false, pos[0], pos[1], pos[2]);
}
public static long registerFill(int... pos) {//登记并手工指定基因分布的位置
public static long registerFill(int... pos) {//登记并手工指定基因填满的位置
return register(1, true, true, pos[0], pos[1], pos[2]);
}
@ -93,22 +94,12 @@ public class Genes { //Genes登记所有的基因 指定每个基因允许分
private static final int CS4 = Env.BRAIN_SIZE / 4;
//============开始登记有名字的基因==========
public static long EYE = registerFill(0, 0, 0); //视网膜细胞这个版本暂时只允许视网膜分布在x=0,y=0的z轴上即只能看到一条线状图形
public static long MEM = registerFill(1, 0, 0); //记忆细胞暂时只允许它分布在x=1,y=0的z轴上
public static int[] EYE_POS = new int[]{0, 0, 0};
public static long EYE = registerFill(EYE_POS); //视网膜细胞这个版本暂时只允许视网膜分布在x=0,y=0的z轴上即只能看到一条线状图形
public static int[] BITE_POS = new int[]{2, 0, 0};
public static long BITE = registerFill(BITE_POS); //咬动作细胞定义在一个点上, 这个细胞如激活就咬食物
// public static int[] NOT_BITE_POS = new int[]{2, 0, CS4};
// public static long NOT_BITE = registerFill(NOT_BITE_POS); //不咬动作细胞定义在一个点上, 这个细胞如激活就不咬食物
// public static int[] SWEET_POS = new int[]{2, 0, CS4 * 2};
// public static long SWEET = registerFill(SWEET_POS); //甜味感觉细胞定义在一个点上, 当咬下后且食物为甜这个细胞激活
// public static int[] BITTER_POS = new int[]{2, 0, CS4 * 3};
// public static long BITTER = registerFill(BITTER_POS); //苦味感觉细胞定义在一个点上, 当咬下后且食物为苦这个细胞激活
//========开始登记无名字的基因 =========
static {
}
@ -119,34 +110,21 @@ public class Genes { //Genes登记所有的基因 指定每个基因允许分
for (int z = Env.BRAIN_SIZE - 1; z >= 0; z--)
for (int x = Env.BRAIN_SIZE - 1; x >= 0; x--) {
int y = 0;
int[] src = new int[]{x, y, z};
long cell = a.cells[x][y][z];
if (a.consts[7] == 0)
a.consts[7] = 1;
if (hasGene(cell, BITE) && ((OneDotEye.code % 100) == 0)) {//如果没有输入咬细胞也是有可能定时或随机激活的模拟婴儿期随机运动碰巧咬下了
a.addEng(x, y, z, a.consts[1] / 10);
}
float energy = a.energys[x][y][z];
if (energy >= 1f) { //如果细胞激活了
a.energys[x][y][z] = a.energys[x][y][z] - Math.abs(a.consts[2]) * 0.2f;//所有细胞能量都会自发衰减
if (hasGene(cell, BITE)) { //如果是咬细胞
if ((OneDotEye.code % 20) == 0) { //从上帝视角知道被20整除正好是OneDotEye看到食物出现的时刻
a.awardAAAA(); //所以必然咬中奖励
if (energy >= 1f) { //如果细胞激活了
a.setEng1(x, y, z); //细胞强度不允许超过1见TestInput3
if (hasGene(cell, BITE)) { //TODO:如果是咬细胞
if (OneDotEye.foodSweet(step)) { //如食物是甜的
a.awardAAAA(); //奖励
a.ateFood++;
} else {
a.penaltyAA(); //其它时间是咬错了 可以改成penaltyAAAA或去除本行试试
a.penaltyAA(); //其它时间是咬错了
a.ateWrong++;
}
a.digHole(x, y, z, x - 1, y, z, a.consts[3]);//咬细胞在记忆细胞上挖洞
}
if (hasGene(cell, EYE)) {//视网膜细胞在记忆细胞上挖洞
a.digHole(x, y, z, x + 1, y, z, a.consts[4]);
}
if (hasGene(cell, MEM)) {//记忆细胞在当前细胞所有洞上反向发送能量
a.holeSendEngery(x, y, z, a.consts[5], a.consts[6]);
a.setEng0(x, y, z); //咬完了后细胞能量归0
}
}

View File

@ -15,6 +15,7 @@ import java.util.ArrayList;
import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.brain.Consts;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
@ -36,7 +37,7 @@ public class Egg implements Serializable {
// gene record the 8-tree structure of brain cells
// 基因是随机生成的8叉树数据结构和实际生物每个细胞都要保存一份基因不同程序中每个脑细胞并不需要保存基因的副本这样可以极大地减少内存占用
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>();
public int[] constGenes = new int[Animal.CONSTS_LENGTH]; //animal中的全局常量基因全放在这里用随机数来生成用遗传算法筛选
public int[] constGenes = new int[Consts.CountsQTY]; //animal中的全局常量基因全放在这里用随机数来生成用遗传算法筛选
public Egg() {// 无中生有创建一个蛋先有蛋后有蛙
x = RandomUtils.nextInt(Env.ENV_WIDTH);

View File

@ -23,6 +23,7 @@ import com.gitee.drinkjava2.frog.Animal;
import com.gitee.drinkjava2.frog.Application;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.Frog;
import com.gitee.drinkjava2.frog.brain.Consts;
import com.gitee.drinkjava2.frog.util.LocalFileUtils;
import com.gitee.drinkjava2.frog.util.Logger;
@ -59,19 +60,12 @@ public class FrogEggTool {
if (holes == null)
s.append("0,");
else
s.append(first.holes[x][0][z].length/4).append(",");
s.append(first.holes[x][0][z].length / 4).append(",");
}
Logger.debug("x=" + x + ", holes:" + s);//打印出每个细胞的洞数量
}
// Logger.debug(Arrays.toString(frogs.get(current_screen).constGenes)); //debug;
StringBuilder s = new StringBuilder();
for (int i = 0; i < Animal.CONSTS_LENGTH; i++) {
if (i != 0)
s.append(", ");
s.append("\t" + i).append("=").append(first.consts[i]);
}
Logger.debug("consts: " + s);
Consts.printLog(first);//debug; 打印出每个细胞的常量
if (Env.SAVE_EGGS_FILE) {
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");

View File

@ -2,23 +2,39 @@ package com.gitee.drinkjava2.frog.objects;
import com.gitee.drinkjava2.frog.Env;
import com.gitee.drinkjava2.frog.Frog;
import com.gitee.drinkjava2.frog.brain.Consts;
import com.gitee.drinkjava2.frog.objects.EnvObject.DefaultEnvObject;
import com.gitee.drinkjava2.frog.util.RandomUtils;
/**
* DotEye的作用只有一个就是定期在视网膜细胞上激活一个点告知食物存在
*
* OneDotEye的作用只有一个就是定期在视网膜细胞上激活一个点告知食物存在
* 当前版本中Eye还没用到目前只测试模式识别最简单的情况即只有一个感光细胞的情况下如何形成看到食物时咬下这个条件反射
*
*/
public class OneDotEye extends DefaultEnvObject {
public static int code = 0;
private static int[] food = new int[Env.STEPS_PER_ROUND];
static {
//食物只会出现在15为周期但不固定的时间点上以防止细胞进化出周期进入鞍点, 食物用数字表示0为不存在1为甜2为苦
for (int i = 15; i < Env.STEPS_PER_ROUND - 15; i += 15)
food[i + RandomUtils.nextNegOrPosInt(5)] = 1 + RandomUtils.nextInt(2);
}
public static boolean foodExist(int step) {
return food[step] > 0;
}
public static boolean foodSweet(int step) {
return food[step] == 1;
}
@Override
public void active(int screen, int step) {
code++;
if (code % 20 == 0) { //每隔20步在所有青蛙的视网膜上画一个图案 单个点调试时设为每20步激活时就是食物
if (foodExist(step)) { //如食物存在, 激活所有青蛙的视网膜
for (int i = screen; i < screen + Env.FROG_PER_SCREEN; i++) {
Frog f = Env.frogs.get(i);
f.energys[0][0][0] = f.consts[0];
f.energys[0][0][0] = f.consts[Consts.ADD_EYE];
}
}
}
}

View File

@ -0,0 +1,201 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.temp;
/**
*
* 临时类待删测试一个细胞有三个输入并且每个输入是双通道奖罚情况下是否可以实现所有的模式识别
* 处理逻辑为 (信号x正权重)取1为饱和值 - 信号x负权重当结果大于0.5时输出1 这个逻辑是模拟网上找到的大脑只需单个神经元就可进行XOR异或运算一文
* 原理只不过这里扩展到三个或以上)输入的情况
*
* 三个输入有8种排列组合如一组参数能实现任意8种组合则有2的8次方=256种排列组合去除全为0的输入必须输出0只计算有1信号的输入则有2的7次方=128种组合
* 经实测有31种组合条件不不能找到符合要求的正负权重
*
* 4个通道有16种排列组合如一组参数能实现任意16种组合则有2的16次方=65536种排列组合去除全为0的输入则有2的15次方32768种组合
* 经实测32768组合中有29987种不能找到符合要求的正负权重如只测前1024个组合则有603种情况不能找到解如只测前128组合则有31种情况下找不到解
*
*
*
*/
@SuppressWarnings("all")
public class TestInput3 {
// public static void main(String[] args) {
// testInput3();
// //testInput4();
// }
public static void testInput3() { //这里测试一个细胞有三个树突输入每个输入有正负两种信号且信号以1为饱和测试结果发现有31种情况无法找到解
long notFoundCont = 0;
boolean pass = false;
float p = 0.1f;
for (int i = 0; i < 128; i++) {
found: //
for (float a = 0; a < 1.001; a += p) {
for (float b = 0; b < 1.001; b += p) {
for (float c = 0; c < 1.001; c += p) {
for (float d = 0; d < 1.001; d += p) {
for (float e = 0; e < 1.001; e += p) {
for (float f = 0; f < 1.001; f += p) {
pass = true;
int bt = 1;
int x, y, z;
for (int n = 1; n <= 7; n++) {
x = ((n & 4) > 0) ? 1 : 0;
y = ((n & 2) > 0) ? 1 : 0;
z = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
float v = x * a + y * b + z * c; //正信号累加
if (v > 1) //如饱和取1
v = 1f;
float v1 = x * d + y * e + z * f; //负信号累加
if (v1 > 1)
v1 = 1f;
v = v - v1;
int result = v >= 0.5 ? 1 : 0;
if (result != shouldbe) {
pass = false;
break;
}
bt = bt << 1;
}
if (pass) {
System.out.print("i=" + i + " found, i=" + bin(i));
System.out.println(" " + r(a) + ", " + r(b) + ", " + r(c) + " " + r(d) + ", " + r(e) + ", " + r(f));
bt = 1;
for (int n = 1; n <= 7 && false; n++) {
x = ((n & 4) > 0) ? 1 : 0;
y = ((n & 2) > 0) ? 1 : 0;
z = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
System.out.println(" " + x + "*" + r(a) + " + " + y + "*" + r(b) + " + " + z + "*" + r(c) + " - " + x + "*" + r(d) + " - " + y + "*" + r(e) + " - " + z
+ "*" + r(f) + " = " + shouldbe);
bt = bt << 1;
}
break found;
}
}
}
}
}
}
}
if (!pass) {
System.out.println("i=" + i + " not found, i=" + bin(i));
notFoundCont++;
}
}
System.out.println("notFoundCont=" + notFoundCont);
}
public static void testInput4() {//这里测试一个细胞有4个树突输入每个输入有正负两种信号且信号以1为饱和测试结果发现有603种情况无法找到解
long notFoundCont = 0;
boolean pass = false;
float p = 0.2f;
for (int i = 0; i < 1024; i++) {
found: //
for (float a = 0; a < 1.001; a += p) {
for (float b = 0; b < 1.001; b += p) {
for (float c = 0; c < 1.001; c += p) {
for (float d = 0; d < 1.001; d += p) {
for (float e = 0; e < 1.001; e += p) {
for (float f = 0; f < 1.001; f += p) {
for (float g = 0; g < 1.001; g += p) {
for (float h = 0; h < 1.001; h += p) {
pass = true;
int bt = 1;
int x, y, z, m;
for (int n = 1; n <= 15; n++) {
x = ((n & 8) > 0) ? 1 : 0;
y = ((n & 4) > 0) ? 1 : 0;
z = ((n & 2) > 0) ? 1 : 0;
m = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
float v = x * a + y * b + z * c + m * d; //正信号累加
if (v > 1) //如饱和取1
v = 1f;
float v1 = x * e + y * f + z * g + m * h; //负信号累加
if (v1 > 1)
v1 = 1f;
v = v - v1;
int result = v >= 0.5 ? 1 : 0;
if (result != shouldbe) {
pass = false;
break;
}
bt = bt << 1;
}
if (pass) {
System.out.print("i=" + i + " found, i=" + bin(i));
System.out.println(" " + r(a) + ", " + r(b) + ", " + r(c) + ", " + r(d) + " " + r(e) + ", " + r(f) + ", " + r(g) + ", " + r(h));
bt = 1;
for (int n = 1; n <= 15; n++) {
x = ((n & 8) > 0) ? 1 : 0;
y = ((n & 4) > 0) ? 1 : 0;
z = ((n & 2) > 0) ? 1 : 0;
m = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
System.out.println(" " + x + "*" + r(a) + " + " + y + "*" + r(b) + " + " + z + "*" + r(c) + " + " + m + "*" + r(d) //
+ " - " + x + "*" + r(e) + " - " + y + "*" + r(f) + " - " + z + "*" + r(g) + " - " + m + "*" + r(h) + " = " + shouldbe);
bt = bt << 1;
}
break found;
}
}
}
}
}
}
}
}
}
if (!pass) {
System.out.println("i=" + i + " not found, i=" + bin(i));
notFoundCont++;
}
}
System.out.println("notFoundCont=" + notFoundCont);
}
static float r(float f) { //取小数后2位
return Math.round(f * 100) * 1.0f / 100;
}
static String bin(int i) { //转二进制
String ibin = Integer.toBinaryString(i);
while (ibin.length() < 7)
ibin = "0" + ibin;
return ibin;
}
}

View File

@ -31,7 +31,7 @@ public class ColorUtils {
{
{
if (!(r == b && r == g)) {
rainbow[i] = new Color(((r + 2) % 3) * 122, g * 122, ((b + 1) % 3) * 122);
rainbow[i] = new Color(((r + 2) % 3) * 122, g * 100, ((b + 1) % 3) * 88);
i++;
}
}

View File

@ -94,14 +94,7 @@ public class GeneUtils {
}
}
}
public static void constGenesMutation(Animal a) { //全局参数变异, 这一个方法变异动物的所有常量
for (int i = 0; i < a.consts.length; i++) {
if (percent(20))
a.consts[i] = RandomUtils.vary(a.consts[i]);
}
}
public static void geneMutation(Animal a) { //基因变异,注意这一个方法同时变异所有条基因
for (int g = 0; g < GENE_NUMBERS; g++)
if (percent(50)) {

View File

@ -52,34 +52,38 @@ public class RandomUtils {
return v;
}
public static int vary(int v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(50))
v += (nextInt(3) - 0.5);
else if (percent(50))
v += 2 * (nextInt(2) - 0.5);
else if (percent(50))
v += 4 * (nextInt(2) - 0.5);
else if (percent(50))
v += 8 * (nextInt(2) - 0.5);
else if (percent(50))
v += 16 * (nextInt(2) - 0.5);
else if (percent(50))
v += 32 * (nextInt(2) - 0.5);
else if (percent(50))
v += 64 * (nextInt(2) - 0.5);
else if (percent(50))
v += 100 * (nextInt(2) - 0.5);
return v;
// public static int vary(int v) {// 随机有大概率小变异小概率大变异极小概率极大变异
// if (percent(50))
// v += (nextInt(3) - 0.5);
// else if (percent(50))
// v += 2 * (nextInt(2) - 0.5);
// else if (percent(50))
// v += 4 * (nextInt(2) - 0.5);
// else if (percent(50))
// v += 8 * (nextInt(2) - 0.5);
// else if (percent(50))
// v += 16 * (nextInt(2) - 0.5);
// else if (percent(50))
// v += 32 * (nextInt(2) - 0.5);
// else if (percent(50))
// v += 64 * (nextInt(2) - 0.5);
// else if (percent(50))
// v += 100 * (nextInt(2) - 0.5);
// return v;
// }
public static int vary(int v) {// 随机有大概率小变异小概率大变异极小概率极大变异 这里改进算法用正切函数曲线来实现这个概率
int n = nextNegOrPosInt(900);
return (int) (v + Math.round(2 * Math.tan(0.1f * n * 3.14159 / 180)));
}
// public static void main(String[] args) {
// int n=0;
// for (int i = 0; i < 100; i++) {
// n=vary(n);
// if(n<0)n=0-n;
// System.out.println(vary(0));
// }
// }
// public static void main(String[] args) {
// int n = 0;
// for (int i = 0; i < 100; i++) {
// n = vary(n);
// System.out.println(n);
// }
// }
public static float vary(float v) {// 随机有大概率小变异小概率大变异极小概率极大变异
if (percent(40))

View File

@ -1,12 +1,17 @@
## core目录简介
core目录是当前工作目录如果跑出什么结果就会拷贝一份放到history目录里存档。
当前目标是大方向是由遗传算法来自动排列脑细胞和触突参数,以实现模式识别功能,并与上下左右运动细胞、进食奖罚感觉细胞结合起来,实现吃掉无毒蘑菇,避开有毒蘑菇这个任务。(未完成)
当前小目标:
1)是要利用阴阳8叉树分裂算法进化出第一个可以工作向食物运动的神经网络。(已完成, 见011_yinyan_eatfood)
2)利用阴阳8叉树或4叉树分裂算法(见012_tree4)来进化出具备模式识别功能的神经网络。即实现图像到声音的关联比如对应1,2,3,4 数字的图像会反同激活训练时对应的声音细胞(未完成)
3)简单时序信号的模式识别。比如AB后是C, AD后是E, ABC后是F多次重复后即可形成时序信号的预测关联。功能类似RNN但用分裂算法来实现参数自动生成。
以上2和3识别原理类似都建立在细胞连接的遗忘曲线基础上但是一个强调细胞的空间位置关系另一个强调信号留存的时间
2023-08-25 三个细胞一台戏
本次更新在目录history\014_3cells下。在上次更新里已经说过了为了实现模式识别可以先从最简单的几个细胞的场景开始做起。于是就一路简化最终简化到只剩下三个细胞分别为视细胞、咬细胞、忆细胞。 实验目的是要达到这样一个效果,当食物出现时,视细胞激活,然后视细胞在忆细胞上打个洞,咬细胞则随机激活,然后也在忆细胞上也打个洞,最终实现的效果将会是视细胞激活忆细胞,然后忆细胞在洞上反向发送能量给咬细胞,这样就实现了视细胞到咬细胞的短路,形成一个最简单的条件反射。忆细胞的作用是隔离视细胞和咬细胞,防止形成视细胞直接驱动咬细胞这种简单连接。任务看起来很简单,但做起来就不太美好了,快两个月了才有点进展,先更新上来再说。
![pic1](result20_3cells1.gif) ![pic2](result20_3cells2.gif) ![pic3](result20_3cells3.gif)
上面从左到右三个图分别是对应三种场景下青蛙的行为1奖惩值都很大2奖励值远比惩罚值大3只有奖励没有惩罚。
奖励是当咬下时正好有食物惩罚是当咬下时食物不存在咬了个空。测试时请修改Genes.java源码第138行进行不同惩罚值的调整。可以看到根据奖罚值的不同三个细胞进化出的神经网络参数是不同的奖惩值都很大时细胞就会躺平多咬多错还不如不咬以避免惩罚奖励值远比惩罚值大时细胞就会比较活跃没有食物时也经常空咬当完全没有惩罚时细胞就会放飞自我直接在咬细胞和忆细胞之间进化出信号循环回路锁定全程都在咬而且最过分的是干脆忽略掉视觉信号把视细胞和忆细胞之间的连线直接用一个负值(蓝色)参数来掐断。
当前小小目标:
进化出具备简单模式识别功能的神经网络,即实现图像到声音的关联,
这次更新的主角不是分裂算法(因为就三个细胞,谈不上结构了)而是全局常量。本次程序中控制细胞特性的全局参数有7个分别是
视细胞激活后产生多大强度的能量?
咬细胞激活后产生多大强度的能量?
每个细胞激活后能量随时间流逝,每一步会遗失多少能量?
咬细胞激活后向记忆细胞传送多少能量?
视细胞激活后向记忆细胞传送多少能量
忆细胞激活后反向向视细胞传送多少能量?
忆细胞激活后反向向咬细胞传送多少能量?
这些全局参数是跟随青蛙终身的,一旦青蛙孵化出来就不再动了,在程序里把所有常量放在一个数组里用遗传算法来控制基本规则是小变动有大概率发生大变动有小概率发生。青蛙的参数分为两类一类是与空间位置相关的如脑细胞是否会出现在某个空间位置一类是与位置无关的如每个细胞激活后向其它细胞发送多少能量。前者要放到分裂算法里用一串8/4/2叉基因树来控制空间分布后者就没必要这么浪费了直接用一组全局数字表示即可并用遗传算法来随机变异和筛选它们。在给神经网络编程时如果碰到可以用全局常量来控制的参数尽量不要手工赋值而要用遗传算法来控制因为多变量的优化组合筛选靠人力是不可能做好的。就拿这个例子来说我压根不知道这些参数将会是多大是正还是负但是我知道应该有这些参数这就够了。人工生命项目编程不讲究精准思维模式要从传统的精细化编程转变为以概率、笼统、可能为导向的思维大方向人为确定细节交给电脑去算这和大自然用遗传算法来筛选出脑细胞的参数是一个道理。
从本次更新可以看到,青蛙是工作在一个连续的信息流下面,信息是以脉冲方式在细胞之间互相传递大小不等的能量,可以说是一个最简单的脉冲神经网络大脑了。这个实验不很实美,没有实现一个不漏地吃掉食物但是又不空咬这个目标,但是人生苦短,我不想继续和这三个细胞缠斗下去了,后面将转到多个视觉细胞和引入苦甜奖惩信号细胞来影响洞(权重)的大小,这个会更有趣、更智能,也更接近模式识别任务。我认为通用智能就是模式识别与行为输出结合起来的系统,如果奖罚细胞和行为输出细胞在一开始就做为这个模式识别系统的一个组成部分,并且由遗传算法来筛选参数,那通用人工智能就不远了。

View File

@ -0,0 +1,201 @@
/*
* Copyright 2018 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
* applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.gitee.drinkjava2.frog.temp;
/**
*
* 临时类待删测试一个细胞有三个输入并且每个输入是双通道奖罚情况下是否可以实现所有的模式识别
* 处理逻辑为 (信号x正权重)取1为饱和值 - 信号x负权重当结果大于0.5时输出1 这个逻辑是模拟网上找到的大脑只需单个神经元就可进行XOR异或运算一文
* 原理只不过这里扩展到三个或以上)输入的情况
*
* 三个输入有8种排列组合如一组参数能实现任意8种组合则有2的8次方=256种排列组合去除全为0的输入必须输出0只计算有1信号的输入则有2的7次方=128种组合
* 经实测有31种组合条件不不能找到符合要求的正负权重
*
* 4个通道有16种排列组合如一组参数能实现任意16种组合则有2的16次方=65536种排列组合去除全为0的输入则有2的15次方32768种组合
* 经实测32768组合中有29987种不能找到符合要求的正负权重如只测前1024个组合则有603种情况不能找到解如只测前128组合则有31种情况下找不到解
*
*
*
*/
@SuppressWarnings("all")
public class TestInput3 {
// public static void main(String[] args) {
// testInput3();
// //testInput4();
// }
public static void testInput3() { //这里测试一个细胞有三个树突输入每个输入有正负两种信号且信号以1为饱和测试结果发现有31种情况无法找到解
long notFoundCont = 0;
boolean pass = false;
float p = 0.1f;
for (int i = 0; i < 128; i++) {
found: //
for (float a = 0; a < 1.001; a += p) {
for (float b = 0; b < 1.001; b += p) {
for (float c = 0; c < 1.001; c += p) {
for (float d = 0; d < 1.001; d += p) {
for (float e = 0; e < 1.001; e += p) {
for (float f = 0; f < 1.001; f += p) {
pass = true;
int bt = 1;
int x, y, z;
for (int n = 1; n <= 7; n++) {
x = ((n & 4) > 0) ? 1 : 0;
y = ((n & 2) > 0) ? 1 : 0;
z = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
float v = x * a + y * b + z * c; //正信号累加
if (v > 1) //如饱和取1
v = 1f;
float v1 = x * d + y * e + z * f; //负信号累加
if (v1 > 1)
v1 = 1f;
v = v - v1;
int result = v >= 0.5 ? 1 : 0;
if (result != shouldbe) {
pass = false;
break;
}
bt = bt << 1;
}
if (pass) {
System.out.print("i=" + i + " found, i=" + bin(i));
System.out.println(" " + r(a) + ", " + r(b) + ", " + r(c) + " " + r(d) + ", " + r(e) + ", " + r(f));
bt = 1;
for (int n = 1; n <= 7 && false; n++) {
x = ((n & 4) > 0) ? 1 : 0;
y = ((n & 2) > 0) ? 1 : 0;
z = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
System.out.println(" " + x + "*" + r(a) + " + " + y + "*" + r(b) + " + " + z + "*" + r(c) + " - " + x + "*" + r(d) + " - " + y + "*" + r(e) + " - " + z
+ "*" + r(f) + " = " + shouldbe);
bt = bt << 1;
}
break found;
}
}
}
}
}
}
}
if (!pass) {
System.out.println("i=" + i + " not found, i=" + bin(i));
notFoundCont++;
}
}
System.out.println("notFoundCont=" + notFoundCont);
}
public static void testInput4() {//这里测试一个细胞有4个树突输入每个输入有正负两种信号且信号以1为饱和测试结果发现有603种情况无法找到解
long notFoundCont = 0;
boolean pass = false;
float p = 0.2f;
for (int i = 0; i < 1024; i++) {
found: //
for (float a = 0; a < 1.001; a += p) {
for (float b = 0; b < 1.001; b += p) {
for (float c = 0; c < 1.001; c += p) {
for (float d = 0; d < 1.001; d += p) {
for (float e = 0; e < 1.001; e += p) {
for (float f = 0; f < 1.001; f += p) {
for (float g = 0; g < 1.001; g += p) {
for (float h = 0; h < 1.001; h += p) {
pass = true;
int bt = 1;
int x, y, z, m;
for (int n = 1; n <= 15; n++) {
x = ((n & 8) > 0) ? 1 : 0;
y = ((n & 4) > 0) ? 1 : 0;
z = ((n & 2) > 0) ? 1 : 0;
m = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
float v = x * a + y * b + z * c + m * d; //正信号累加
if (v > 1) //如饱和取1
v = 1f;
float v1 = x * e + y * f + z * g + m * h; //负信号累加
if (v1 > 1)
v1 = 1f;
v = v - v1;
int result = v >= 0.5 ? 1 : 0;
if (result != shouldbe) {
pass = false;
break;
}
bt = bt << 1;
}
if (pass) {
System.out.print("i=" + i + " found, i=" + bin(i));
System.out.println(" " + r(a) + ", " + r(b) + ", " + r(c) + ", " + r(d) + " " + r(e) + ", " + r(f) + ", " + r(g) + ", " + r(h));
bt = 1;
for (int n = 1; n <= 15; n++) {
x = ((n & 8) > 0) ? 1 : 0;
y = ((n & 4) > 0) ? 1 : 0;
z = ((n & 2) > 0) ? 1 : 0;
m = ((n & 1) > 0) ? 1 : 0;
int shouldbe = (i & bt) > 0 ? 1 : 0;
System.out.println(" " + x + "*" + r(a) + " + " + y + "*" + r(b) + " + " + z + "*" + r(c) + " + " + m + "*" + r(d) //
+ " - " + x + "*" + r(e) + " - " + y + "*" + r(f) + " - " + z + "*" + r(g) + " - " + m + "*" + r(h) + " = " + shouldbe);
bt = bt << 1;
}
break found;
}
}
}
}
}
}
}
}
}
if (!pass) {
System.out.println("i=" + i + " not found, i=" + bin(i));
notFoundCont++;
}
}
System.out.println("notFoundCont=" + notFoundCont);
}
static float r(float f) { //取小数后2位
return Math.round(f * 100) * 1.0f / 100;
}
static String bin(int i) { //转二进制
String ibin = Integer.toBinaryString(i);
while (ibin.length() < 7)
ibin = "0" + ibin;
return ibin;
}
}

BIN
result21_input3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB