Darwinbots Forum
Code center => Suggestions => Topic started by: Zinc Avenger on November 01, 2007, 10:57:43 PM
-
I've been thinking about the structure of genes.
The cond-start-stop structure is very fragile, practically any mutation in the wrong place will break it completely. It is also prohibitively difficult to evolve naturally - what's the chance a cond instruction will appear before a condition to evaluate, then a start will appear, then an appropriate action will evolve with a stop at the end? Vanishingly small.
So why not simplify it?
Remove cond and start.
Change the way genes are handled so that only stop is used.
Make the stop command define the end of a gene. So from the start of the genome to the first stop is the first gene. From the first stop to the second stop is the second gene. From the last stop to the end of the genome is the last gene. Make no stop at all mean the entire genome is one gene.
But that would not allow us to have conditional genes. So I got to thinking - if the gene is defined by the stop command at the end, why not make the condition the last part of the gene?
The way I envision this working is like this: Fire the gene speculatively, calculating the changes to the memory locations, but don't commit them to the simulation. If the value on top of the stack when stop is reached is greater than zero, commit the results to the sim. If not, discard them.
-
That's pretty close to the way that the DNA works in the DNA module for Darwinbots 3. Although instead of executing the gene speculatively and then checking the stack for values, the conditions are integrated into the gene.
The problem with using just the integer stack for conditions is when you try to introduce logic commands. How do you represent true/false? You could just do 0/1, but that doesn't really make sense. What does 500 1000 > 30 add mean? So you really need that second stack (the conditions stack) to keep the language clean.
For DB 3, a simple gene might look like this:
*.nrg 1000 > 50 .repro store
which entirely bypasses the cond-start-stop system.
As far as the current system, the gene structure is actually far more forgiving than people think. Cond statements set a flag that determines whether start or else blocks are enabled. A single cond can control lots of genes. And if there isn't a cond statement anywhere up stream, the program just "assumes" a "true" value for the last cond evaluation.
-
I think we want to keep the start codon as I think we want genomes to be capable of containing non-coding DNA. We want a single point mutation such as the addition of a stop or the removal of a start to be able to have large impacts on the geneome, I.e. to be able to turn on or off whole genes, combine genes, split genes in two, etc. We want junk DNA which can mutate for awhile without selection constraints and then get re-enabled.
That said, I like the idea of doing away with the cond and making it implicit. I agree it would improve the probability of evolving conditional logic if such logic can be scatterred anywhere through the gene. I don't think it would be too difficult to implement (he says in the confidence of ignorance) since the boolean stack is seperate from the integer stack. There might be some sticky order of operations issues. For example:
start
100 .foo store
*.foo 100 =
stop
Should the conditional logic use the old or the new value of .foo?
But I think we could work that out...
-
You don't need to move the condition to the end of the gene if you use the condition stack, too. You could have it anywhere in the gene you wanted to.
Laying aside the option of entirely deconstructing the idea of a gene as I've done with DB3 (which wouldn't be too difficult to do), you could have conditions interspersed within the gene. Something like:
start
*.nrg 1000 >
10 .repro store
*.body 1000 >
stop
-
I like that. Saves a second pass through the DNA. It's a running condition. Memory operations happen when the top value on the boolean stack is true. They don't happen when it isn't. Thus a single gene can contain multiple conditions and sub functions, only portions of which might get expressed depending upon the running condition logic. Example:
start
*.eye5 0 >
5 .dn store
*.eye5 10 >
10 .dn store
*.eye5 20 >
15 .dn store
*.eye5 50 >
-1 .shoot store
0 .shoot >
0 .dn store
stop
Note that last couple of lines are a cascading condition. -1 only gets stored into .shoot if *.eye5 is > 50 and 0 only gets stored into .dn if .shoot is less than 0 which only happens if *.eye5 > 50. Cool.
-
Yep, I like that too
-
Anything that makes conditions easy to evolve is a good thing! The current system is too unwieldy.
-
BTW, in October 19 issue of Science there are two papers describing unusual genes. In one, genome consists of hundreds of tiny chromosomes and genes are coded as small fragments on different chromosomes. Once in RNA form, these fragments are "stitched" together, forming the final mRNA that is translated. In the other one, genes have their beginning and end swapped. For example, a gene "computer" would be coded as "uter-comp". The resulting RNA is then joined together at its ends (bringing comp and uter together), forming a circle. The circle is then cut in the correct place to generate the correct gene.
Just shows how flexible genetic material can be.
-
I know some,well most genes are sepparated in junk-dna and 'normal'-dna, (introns, outtrons, is this correct in english)after they are translated to m-rna, the introns(junk-dna) are being spliced from it.
I haven't heard of gene that lies in different chromosomes. There are many strange things that lies in dna. There cannot really be explained why. Atleast not jet
-
The real process is wondrously complex. All those different stages each allow for some interesting variations from "normal". By comparison, any DNA schemes for DB look hollow and incomplete.
-
Sounds nice and all but I have a small problem:
Lets say the robot does .dx .up and .shoot within a single condition, according to the above the code will look:
*.nrg 1000 > 10 .dx store
*.nrg 1000 > 10 .up store
*.nrg 1000 > -1 .shoot store
Would it be easyer to use:
cond
*.nrg 1000 >
start
10 .dx store
10 .up store
-1 .shoot store
stop
?!
-
Ok, I am not fully understanding the code, how would the following gene work.
(random gene taken from multiply, can't make one up)
cond
*.eye5 25 >
*.refeye *.myeye !=
*.refshoot *.myshoot !=
*.refpoison *.refshell =>
and
and
and
start
16 .shootval store
-6 .shoot store
stop
And how would a gene work if there is some 'or' in it or something else like it.
-
Lets say the robot does .dx .up and .shoot within a single condition...
start
*.nrg 1000 >
10 .dx store
10 .up store
-1 .shoot store
stop
Would be sufficient.
-
Ok, I am not fully understanding the code, how would the following gene work....
start
*.eye5 25 >
*.refeye *.myeye !=
*.refshoot *.myshoot !=
*.refpoison *.refshell =>
and
and
and
16 .shootval store
-6 .shoot store
stop
Think of it this way: conditionals can now be executed in the body of the gene and memory modifications can now be executed in the conditional portion. The way I'm planning on doing this, a gene begins at either a Cond or Start and ends at a stop. Conds or Starts in the middle of genes are ignored. This means that all existing hand-coded bots will continue to work exactly as they do today without a single change. Total backwards compatability. However, the behaviour of evolved bots may change as operations which were previously ignored (boolean operations in the body or memory operations in the conditional header) now execute, for example, changing the value on top of the boolean stack and thus may impact the evolved code in a major way causing logic that used to fire to no longer do so or vice versa.
EDIT: So, a correction. A Start in the middle of a gene isn't exactly ignored. It means "AND together all the values on the boolean stack and place the result on the top of the stack."
So, the gene above works just fine as does:
cond
*.eye5 25 >
*.refeye *.myeye !=
*.refshoot *.myshoot !=
*.refpoison *.refshell =>
and
and
and
start
16 .shootval store
-6 .shoot store
stop
as well as:
cond
*.eye5 25 >
*.refeye *.myeye !=
*.refshoot *.myshoot !=
*.refpoison *.refshell =>
start
16 .shootval store
-6 .shoot store
stop
But
start
*.eye5 25 >
*.refeye *.myeye !=
*.refshoot *.myshoot !=
*.refpoison *.refshell =>
16 .shootval store
-6 .shoot store
stop
will not work the same. The stores to .shootval and .shoot will only be predicated on the result of the last boolean operation (*.refpoison *.refshell =>) not on the logical ANDing of all four. Thus, you can't just remove all the starts from your code. Doing so will change the behaviour of any genes with more than a single line conditional.
-
FYI, I am implementing Phase 1 of this for 2.43q. Conditional commands encountered in the body portion a gene will no longer be ignored. Operations which write to memory will be conditional on the value on the top of the boolean stack. Thus, conditional logic in the body of a gene may cause portions of the gene not to execute.
Phase 2 will involve allowing for memory operations in the conditional portion of the gene and will be implemented later.
-
QUOTE(Botsareus @ Nov 8 2007, 11:11 AM)
Lets say the robot does .dx .up and .shoot within a single condition...
start
*.nrg 1000 >
10 .dx store
10 .up store
-1 .shoot store
stop
Would be sufficient.
I have a better idea, just stay with me, it gets complex. I will start from a simpe example. Then intermediate. then advanced.
I use "A" thru "Z" as code fragments:
If "A" is a 'condition it means something like: *.nrg 1000 >
If "A" is a 'action it means something like: -1 .shoot store
If you don't understand, quote what part you don't understand and I will try to explain in detail.
Introducing a new command called "conditionless"
example1: simple
A 'action
B 'condition
C 'action
D 'action
conditionless
E 'action
F 'action
the top of the dna is automaticaly conditionless, therefor the above means in the old db:
cond
start
A
stop
cond
B
start
C
D
stop
cond
start
E
F
stop
example2: very long but intermediate
A 'condition
B 'condition
C 'action
D or 'condition
E 'action
F and 'condition
G 'action
conditionless
H 'action
I 'condition
J 'action
K 'action
L 'action
conditionless
M 'action
N 'action
O 'action
P 'condition
Q 'action
R or 'condition
S 'condition
T 'action
UU or 'condition
V or 'condition
W 'action
X 'condition
Y or 'condition
Z 'action
means in old db:
cond
A
B
and
start
C
stop
cond
A
B
and
D
or
start
E
stop
cond
A
B
and
D
or
F
and
start
G
stop
cond
start
H
stop
cond
I
start
J
K
L
stop
cond
start
M
N
O
stop
cond
P
start
Q
stop
cond
P
R
or
S
and
start
T
stop
cond
P
R
or
S
and
UU
or
V
or
start
W
stop
cond
X
Y
or
start
Z
stop
example3: advanced example
A 'condition
B 'condition
C and 'condition
D 'action
means:
cond
A
B
C
and
and
start
D
stop
example 3b:
A 'condition
B 'condition
C and 'condition
or
D 'action
means:
cond
A
B
C
and
or
start
D
stop
example4: more advanced example
A 'condition
B 'condition
C and 'condition
D 'action
or
E 'action
means:
cond
A
B
C
and
and
start
D
stop
cond
A
B
C
and
or
start
E
stop
example5: even more advanced example
A 'condition
B 'action
C 'condition
D and 'condition
E 'action
or
F 'action
means:
cond
A
start
B
stop
cond
C
D
and
start
E
stop
cond
A
C
D
and
or
start
F
stop
thank you for your time...
-
That's basically how the system Eric's describing works Bots. Instead of a conditionless command, you would just use cond to reset the boolean stack (I got that correct, right?)
-
Yup. It's already implemented in recent buddy drops. Works well.
-
I might need to write some abusive DNA now just to try it out
-
I might need to write some abusive DNA now just to try it out
Please do! I've done a little testing, but not exhaustive. My suspicsion is that this is a very powerful and profound change whose impact won't be fully explored or fully understood for months.
-
Looks very nice!
Just to check, if I understood this completely, would this work?
start
*.body *.nrg >
*.nrg 500 >
50 .strbody store
and
-50 .strbody store
stop
EDIT:
Oh, what about else? Would this work?
start
*.eye5 50 >
.shoot dec
else
314 rnd .aimsx store
stop
-
Just to check, if I understood this completely, would this work?
' Cooments below
start ' No cond section. If stores followed this, their success would depend on boolean logic above
*.body *.nrg > 'Result of this is pushed on boolean stack. Call it A.
*.nrg 500 > 'Result of this is pushed on boolean stack. Call it B
50 .strbody store ' store will occcur if B is True. Will not if B is False. There is no implicit AND of A and B
and 'A is ANDed with B. Result is pushed on Boolean stack.
-50 .strbody store ' This store will happen if A AND B is True.
stop
EDIT:
Oh, what about else? Would this work?
start
*.eye5 50 > ' Call this C
.shoot dec ' happens if C is true
else
314 rnd .aimsx store ' Never happens. Currently Else applies only to Cond section, which is missing here.
stop
But the same running boolean state works within else statements. For example:
cond
false
start
1 *50 store
else
2 *50 store
2 1 <
3 *50 store
stop
memory location 50 will end up with a value of 2.
-
Is there a way to clear the boolean stack within a gene's body?
-
Is there a way to clear the boolean stack within a gene's body?
There isn't an explicit clear stack command. A bunch of boolean logic operators which pop values would do it. Something like 20 OR's for example, enough that you pop whatever is there and bottom the stack out so that the result of the last one is true.
Another start won't do it. It clears the stack after a Cond by ANDing it all up, but if the current state is the gene body already, it doesn't do anything.
EDIT: Adding a Clear command might be usefull....
-
I added a general purpose clear command that dumps both stacks to the DNA for Darwinbots 3, so I agree
Not sure if we need a single command for each stack or a single one for both stacks though.
-
I think we need two. I can imagine cases where you want to clear the boolean stack for genome flow control reasons but keep your integer stack state.
I'm curious what do you mean by dumping the stack to DNA?
-
oops, heh, typo. I meant "that dumps both stacks from the DNA".
-
It would be also nice to have a command that drops the top value from the boolean stack. It is an extremely important functionality, since it has sense of ENDIF. As for now, I couldn't express it with less than three commands: true or and. I think it's highly expensive (moreover difficult to evolve!) for such basic operation.
-
Sounds good to me. So, I'll add four new commands:
clearbool - empties the boolean stack.
clearint - empties the integer stack
popbool - pops a value off the boolean stack.
popint - pops a value off the integer stack
Okay?
-
I don't like the idea of using cond bla start for else statements.
Here is what I propose:
*.eye5 50 > ' Call this C
.shoot dec ' happens if C is true
else
314 rnd .aimsx store 'happens if C is false
A 'condition
B 'condition
C and 'condition
D 'action
or
E 'action
else
F 'action
means:
cond
A
B
C
and
and
start
D
stop
cond
A
B
C
and
or
start
E
stop
cond
A
B
C
and
or
else
start
F
stop
look here:
cond
A
B
C
and
or
else
start
F
stop
If B or C is false, and A is false then run F
Sounds good to me. So, I'll add four new commands:
clearbool - empties the boolean stack.
clearint - empties the integer stack
popbool - pops a value off the boolean stack.
popint - pops a value off the integer stack
Okay?
I like the conditionless command better because then you don't have to worry about were to put the stop. I will add it myself when I get a chance to program on the outside.
I love the clearbool , clearint commands because I will need them in my extreamly complex sexrepro system.
As far as popbool and popint commands see this post with updates: http://www.darwinbots.com/Forum/index.php?showtopic=2266 (http://www.darwinbots.com/Forum/index.php?showtopic=2266)
-
Auto simplifing the command structute:
If we have
A 'condition
A 'condition
and
C 'action
It is changed to
A 'condition
C 'action
If we have
A 'condition
A 'condition
or
C 'action
It is changed to
A 'condition
C 'action
If we have
conditionless
A 'condition
or
C 'action
It is changed to
conditionless
C 'action
If we have
conditionless
A 'condition
and
C 'action
It is changed to
A 'condition
C 'action
corrected
An else command simply works by reversing the top of the condition stack ex:
A 'condition
B 'condition
C 'condition
or
else
or
means
not(B or C) or A
---
If there is a cndmove , cndmdup , or cndmtt, the above codes do not apply.
move , mdup and mtt, change negative values to positive once. But if any input values is zero they are changed to one.
-
Sounds good to me. So, I'll add four new commands:
clearbool - empties the boolean stack.
clearint - empties the integer stack
popbool - pops a value off the boolean stack.
popint - pops a value off the integer stack
Okay?
You could drop the int suffix, and have it just assumed. So then you would have:
clearbool, clear, popbool, pop
Makes the syntax a little clearner, I think.
-
I'd also shorten 'bool' to just 'b' and put it in the beginning and changed 'pop' to 'drop' (which is more descriptive)
drop
bdrop
clear
bclear
-
(see correction to the above post.)
More simplifications:
A 'condition
B 'action
A
C 'action
is simplfied as
A 'condition
B 'action
C 'action
If there is two elses in a row ex:
conditionless
else
else
is simplfied as
conditionless
---
conditionless
else
B 'action
is simplfied as
B 'action
---
conditionless
A 'action
else
B 'action
is simplfied as
B 'action
conditionless
A 'action
-
You could drop the int suffix, and have it just assumed. So then you would have:
clearbool, clear, popbool, pop
Personally, I like the specificity of popint and popbool but then my code always has longHardToReadLongVariableNames.
I'd also shorten 'bool' to just 'b' and put it in the beginning and changed 'pop' to 'drop' (which is more descriptive)
I like 'bool' better than 'b' and I like 'pop' better than 'drop'. Pop is the well understood term for popping a value off a stack and bool is more descriptive.
The code already supports sysvar synonyms: .aimdx and .aimright for example. I could add built in operator synonyms or add an aliasing mechanism for DNA fiel parsing but I think I'll make it clearbool, clearint, popbool, popint for now.
-
I like 'bool' better than 'b' and I like 'pop' better than 'drop'. Pop is the well understood term for popping a value off a stack and bool is more descriptive.
pop is well understood term for popping a value off a stack and store it in a variable or a register. It's drop that is used for discarding the top value in languages operating with stack, such as Forth. And 'bool' is too long itself to join it with something else, IMHO. I don't insist, I just try to explain my position.
-
b]pop[/b] is well understood term for popping a value off a stack and store it in a variable or a register. It's drop that is used for discarding the top value in languages operating with stack, such as Forth. And 'bool' is too long itself to join it with something else, IMHO. I don't insist, I just try to explain my position.
I've never coded in Forth. My tiny brain just does not think of the term 'drop' as a stack operator. Since actual pops to a location are implicit in DNA, I thought using it for drop was appropriate but if drop is the term actually used in real languages for a pop to nowhere, then we can go with that. It's not a big deal.
I like longer, more descriptive names in general. e.g. .totalmyspecies. The only reason to keep things short is to make DNA text more compact for the human. This all has no impact on the underlying numerical DNA of course.
Can we go with:
ClearBool
DropBool
ClearInt
DropInt
-
I LikeVariableNamesThatAreLongAndDescriptiveToo, but the DNA language has a sort of assembly feel to it that just begs for 3 and 4 letter operators (sysvars not so much).
For DB3, I was toying with different stack operations based on booleans, nd ran into this same problem. So for the boolean versions of dup and swap, (which we might want to add, too), I used dub and swab. In general, most stack operations have a p in them. push, pop, dup, swap, etc. So the rule I chose was that operations on the boolean stack replace any instances of p with b. Thus you have bob (like bobbing hair), swab, and dub.
-
I like longer, more descriptive names in general. e.g. .totalmyspecies. The only reason to keep things short is to make DNA text more compact for the human. This all has no impact on the underlying numerical DNA of course.
Can we go with:
ClearBool
DropBool
ClearInt
DropInt
I prefer a little longer above just a little too short. I fact at seeing it you have to know what it does, and at seeing this I know exactly wat it means, so I agree.
-
Thus you have bob (like bobbing hair), swab, and dub.
Though I'd prefer drob over bob anyway
-
FYI, its implemented as
ClearBool
DropBool
ClearInt
DropInt
in 2.43u. If someone really wants, I'll add synonyms. Just ask.
-
I hope, they are not case-sensitive, are they?
-
I hope, they are not case-sensitive, are they?
All the sysvars get lowercased during DNA file parsing. So, no.
-
I gess I will just have to program my alternate virsion myself...
-
Interesting. I definitely like the drop/clear bool/int commands. Back when I was playing/experimenting/etc, I was doing 'dup xor inc' to pop and discard a value from the stack.
The system I made for branching nested conditionals was rather complicated, and if these changes are in the latest released version of DarwinBots, then it sounds like you've made what I was doing there entirely pointless.
If anyone's curious, here's an example of what I was doing (the commented out lines are the original lines, which were translated to what's below them) - scroll down to the if (1): to see where the branch stuff is:
[div class=\'codetop\']CODE[div class=\'codemain\' style=\'height:200px;white-space:pre;overflow:auto\']'NestedBranchTest.txt compiled by PyBot V1 from NestedBranchTest.pyr.
'def one1 at 991
def one1 991
'def one2 at 992
def one2 992
'def one3 at 993
def one3 993
'def one4 at 994
def one4 994
'def one5 at 995
def one5 995
'def zero1 at 981
def zero1 981
'def zero2 at 982
def zero2 982
'def zero3 at 983
def zero3 983
'def zero4 at 984
def zero4 984
'def zero5 at 985
def zero5 985
'def zero6 at 986
def zero6 986
'def outside1 at 1000
def outside1 1000
'if ():
cond
start
0 *980 1 sub sgn 0 floor *980 sgn - 0 floor | 980 mult store
' #branch-use 980
' #disable-storecheck
' one1=0
0 .one1 store
' one2=0
0 .one2 store
' one3=0
0 .one3 store
' one4=0
0 .one4 store
' one5=0
0 .one5 store
' zero1=0
0 .zero1 store
' zero2=0
0 .zero2 store
' zero3=0
0 .zero3 store
' zero4=0
0 .zero4 store
' zero5=0
0 .zero5 store
' zero6=0
0 .zero6 store
' outside1=0
0 .outside1 store
' if (1):
1
' one1 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .one1 *980 mult store
' if (1):
dup dup 1 &
' one2 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .one2 *980 mult store
' elif 1:
- ++ & - ++ dup - ++ dup 1 &
' zero2 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .zero2 *980 mult store
' if 0:
add add dup ^ inc dup dup 0 &
' zero3 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .zero3 *980 mult store
' elif 1:
- ++ & - ++ dup - ++ dup 1 &
' one3 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .one3 *980 mult store
' else:
- ++ & - ++ | - ++
' zero4 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .zero4 *980 mult store
' if 0:
dup ^ inc dup dup 0 &
' zero5 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .zero5 *980 mult store
' elif 0:
- ++ & - ++ dup - ++ dup 0 &
' zero6 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .zero6 *980 mult store
' else:
- ++ & - ++ | - ++
' one4 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .one4 *980 mult store
' one5 = 1
dup ^ inc
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .one5 *980 mult store
' else:
- ++
' zero1 = 1
dup *980 - ++ & 980 mult inc dup - ++ *980 & 980 mult dec
1 .zero1 *980 mult store
' outside1 = 1
dup ^ inc
1 .outside1 store
' outside2 = 1
1 .outside2 store
stop
(There was some bug in DarwinBots at the time which was keeping that from working properly. I don't know if it's been fixed.)
-
if these changes are in the latest released version of DarwinBots...
Everything described in this post except the "phase 2" of the conditonal logic paradym (allowing stores in the cond section of genes) has been implemented for several months now including clearbool, clearint, dropbool and dropint.
For an example of a complex single gene bot (over 1k base pairs) which contains absolutely no cond sections and uses the inline conditional paradym and the clear operators extensivly, take a look at Seasnake 1.0.