diff --git a/history/005_letter_test/src/main/java/com/github/drinkjava2/frog/brain/Organ.java b/history/005_letter_test/src/main/java/com/github/drinkjava2/frog/brain/Organ.java new file mode 100644 index 0000000..d2ce3ff --- /dev/null +++ b/history/005_letter_test/src/main/java/com/github/drinkjava2/frog/brain/Organ.java @@ -0,0 +1,176 @@ +/* + * 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.github.drinkjava2.frog.brain; + +import java.awt.Color; +import java.io.Serializable; + +import com.github.drinkjava2.frog.Env; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.util.RandomUtils; + +/** + * Organ is a cone-cylinder shape zone inside of brain,, organ can be saved in + * egg, organ will create cells in brain. Most organ's size, angle, location and + * cell parameters are randomly created + * + * 器官是脑的一部分,多个器官在脑内可以允许部分或完全重叠出现在同一脑内位置,器官都是可以变异的,所有器官都会保存在蛋里面。 + * + * 器官是一种外形为锥圆柱体或长方体的脑内区,它的作用是在它的形状范围内在脑细胞内登记行为,当然如果脑细胞不存在它首先会新建一个脑细胞。 + * 器官的数量、形状、大小、角度、位置、神经元分布方式,以及神经元的内部参数可以随机生成和变异, 并由生存竟争来淘汰筛选。 + * + * 器官可以组合成复杂的网络结构或曲折的信号传导路径,例如一个圆柱形神经传导器官,可以变异为由两个圆柱状传导器官首尾相接,然后这两个器官各 + * 自变异,就有可能形成弯的传导路径或更复杂的网络结构。看起来复杂,但大自然可以做到比这更复杂的进化逻辑,先假设大自然是万能的,只要是有用的 + * 变异逻辑,就有可能出现。 + * + * 器官描述细胞的行为,其中洞数量和参数是有可能随机变异的。行为则是硬编码不可以变异,模拟单个神经元的逻辑,不同的细胞可以登记属于多个不同的 + * 器官,虽然器官行为不可以变异,但是可以写出尽可能多种不同的行为(貌似神经元的活动也只有有限的几种),由生存竟争来筛选。 + * + * 器官通常是单例,每个脑细胞都指向一些器官单例,器官这个单例参与神经活动时是无状态的,有状态的神经元的参数是保存在Cell中而不是器官中,这种设计是为了减少 + * Cell的内存占用 + * + * 信息(光子)的逻辑: + * 能量上限很低的细胞,相当于信息的中转站,来多少光子就转发多少光子;能量上限高的细胞,可以起到记忆作用,它的原理是多个洞、反复累集的光子能量, + * 可以在收到某个方向光子的信号后短暂释放,以这个细胞中为心形成一个新的波源,波的发散方向就是洞的分布方向,只有位于波的驻点位置的细胞才会吸收和释放更多 + * 能量,光子总是直线传播,不在合适交点(波的驻点)位置的细胞吸收不到能量。 + * + * 光子自带传播方向,并在每个测试步长中自动走一格,为什么还需要脑细胞的静态洞和动态洞?
+ * 因为光子只能直线传播,而洞具有分发、收集、改变光子方向等作用,能增加脑的复杂,cell中根据光子的方向动态生成的洞是智能的基石,它能将有关联关系的 + * 重复光子信号从海量的自然界噪声信号中抽取出来产生关联。 + * + * @author Yong Zhu + * @since 1.0.4 + */ +public class Organ implements Serializable, Cloneable {// 因为要保存在蛋文件里,所以必须支持串行化 + private static final long serialVersionUID = 1L; + + // 以下是各种器官类型,每个神经元都属于一个器官,每个器官都有一个type类型参数 + public static final int EMPTY = 0;// 空细胞,不处理光子 + 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++; // 每个器官都有一个唯一的编号,作用是同一个编号的光子间将不产生绑定 + public int color = 1;// 这个不重要,表示它生成的光子的显示在脑图中的颜色号,见ColorUtils + public float fat = 0;// 细胞活跃多,则fat值大,如果fat值很低,则这个器官被丢弃的可能性加大,这个值很重要,它使得孤岛器官被淘汰 + public boolean allowVary;// 是否允许变异,有一些器官是手工创建的,在项目初级阶段禁止它们参与变异和生存竟争。 + public boolean allowBorrow;// 是否允许在精子中将这个器官借出,有一些器官是手工创建的,在项目初级阶段禁止它们借出 + public String organName;// 器官的名字,通常只有手工创建的器官才有名字,可以用frog.findOrganByName来查找到这个器官 + + // ======= 本行以下是一些假设的参数,受变异和生存竟争影响 ,并通过大样本数、随机变异、生存竟争来进行多参数的优化选择 ======== + + public int type; // 器官类型,见上面的常量定义,这个字段通常很稳定。一旦变异,将从根本上改变器官的播种行为和神经元的行为 + + public Shape shape; // 器官的形状,不同的形状要写出不同的播种行为 + + public float cellDistance; // 细胞播种间隔,每隔多少个cell进行器官行为的播种 + + public float centerDensityRate; // 中心相对于边沿的播种密度比,为1时为均匀分布 + + public int holeLimit;// 细胞允许创建动态洞的数量上限,详见Cell类的holes.字段 + + public float energyLimit;// 细胞能量上限,当能量超过能存贮的上限,多余的光子能量将不被细胞吸收,直接煙灭或以光子的形式转发出去 + + public float outputRate;// 细胞激活后,一次脉冲会释放出细胞存贮的能量比率(或释放出一个固定值), 根据能量守恒,这个值通常小于1 + + public float outputDoor;// 输出阀值,细胞当前能量小于这个阀值时,细胞不会产生输出 + + public float inputRate;// 能量接收率,细胞存贮的能量占输入能量的比率(或吸收一个固定值), 根据能量守恒,这个值通常小于1 + + public float inputDoor;// 接收阀值,接收的能量小于这个阀值时,细胞不会吸收这份能量,直接煙灭或以光子的形式转发出去 + + public float radius;// 细胞即使没有洞,也可以处理光子,这个radius是细胞的管辖半径,但处理信号角度只限于穿透和反射或6个正方向 + + public float dropRate;// 是一个介于0~1的值,反映了细胞存贮能量的下降速率,在每一步长中细胞能量都以这个速率损失,可以参考遗忘曲线 + + // =====注意以下三个字段可以让细胞具备一些固定角度的洞,这个不占内存,但缺点是不灵活,不智能,详见与Cell类中动态洞的对比 ===== + public Hole[] holes; // 输出洞 + + public Organ() {// 缺省构造器,生成具有缺省参数但没有形状的器官 + allowVary = true; + allowBorrow = true; + type = 0; + cellDistance = 1; + centerDensityRate = 1; + holeLimit = 10; + energyLimit = 100; + outputRate = 30; + outputDoor = 30; + inputRate = 100; + inputDoor = 5; + radius = 1; + dropRate = 95; + holes = null; + } + + /** Only call once after organ be created */ + public Organ[] vary(Frog f) { // 器官变异,仅会在青蛙下蛋时即new Egg(frog)中被调用一次,返回本身或变异后的一个或一组类似器官返回 + if (!allowVary) + return new Organ[] { this };// 如果不允许变异,器官就把自身返回,存放在蛋里 + // 各参数 随机有大概率小变异,小概率大变异,极小概率极大变异 + type = RandomUtils.vary(type, 10);// 这个type通常不允许变,所以只给它10%的机率去变, 也就是说在正常变异概率上再乘以10%的变异可能性 + shape = RandomUtils.vary(shape); + cellDistance = RandomUtils.vary(cellDistance); + centerDensityRate = RandomUtils.vary(centerDensityRate); + holeLimit = RandomUtils.vary(holeLimit); + energyLimit = RandomUtils.vary(energyLimit); + outputRate = RandomUtils.vary(outputRate); + outputDoor = RandomUtils.vary(outputDoor); + inputRate = RandomUtils.vary(inputRate); + inputDoor = RandomUtils.vary(inputDoor); + radius = RandomUtils.vary(radius); + dropRate = RandomUtils.vary(dropRate); + holes = RandomUtils.vary(holes); + return new Organ[] { this }; + } + + /** Only call once when frog created , Child class can override this method */ + public void init(Frog f, int orgNo) { // 在青蛙生成时会调用这个方法,进行一些初始化,通常是根据参数来播种脑细胞 + // 里是器官播种脑细胞的具体代码,对于手工生成的器官,也可以重写这个方法,对于自动生成的器官,必须根据type和shape等来播种,要写死在这里 + if (shape != null) + shape.createCellsRegOrgan(f, orgNo); // 先均匀播种脑细胞试试 + } + + /** each step will call Organ's active methodd */ + public void active(Frog f) { // 每一步测试都会调用active方法,通常用于手动生成的器官,自动生成的器官其行为仅由脑细胞来决定 + // do nothing + } + + /** Child class can override this method to drawing picture */ + public void drawOnBrainPicture(Frog f, BrainPicture pic) { // 把器官的轮廓显示在脑图上 + if (shape == null) + return;// 如果没有形状,就不画 + if (!Env.SHOW_FIRST_FROG_BRAIN || !f.alive) // 如果不允许画或青蛙死了,就直接返回 + return; + pic.setPicColor(Color.LIGHT_GRAY); // 缺省是灰色 + shape.drawOnBrainPicture(pic); + } + + public static Organ randomCuboidOrgan() { + Organ o = new Organ(); + o.shape = RandomUtils.randomCuboid(); + return o; + } + + public static Organ randomConeOrgan() { + Organ o = new Organ(); + o.shape = RandomUtils.randomCone(); + return o; + } + +}