-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathevolver.amlg
More file actions
655 lines (576 loc) · 17.2 KB
/
Copy pathevolver.amlg
File metadata and controls
655 lines (576 loc) · 17.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
;manages a population of entities for genetic programming
;geared to use a haploid/diploid sexual reproduction genetic programming paradigm
{
;creates the _population_manifest entity to keep track of individuals' scores within the population
initialize_population_manifest
(if (not (contains_entity "_population_manifest"))
(create_entities "_population_manifest"
{
metadata
;key is the entity name
;value is an assoc of the following:
; age : number of population cycles it has survived
; score : most recent score
{}
}
)
)
;removes unused records for individuals that no longer exist
remove_unused_records
(let (assoc
living (zip (contained_entities) ))
;filter the list of contained entities to only those that are in the (cached) living set
(assign_to_entities "_population_manifest"
(assoc metadata
(filter
(lambda (contains_index living (current_index)))
(retrieve_from_entity "_population_manifest" "metadata")
)
)
)
)
;adds new records for individuals that are not accounted for
discover_new_individuals
(let (assoc metadata (retrieve_from_entity "_population_manifest" "metadata"))
(let (assoc
new_entities
(filter
(lambda (and
(!= "_population_manifest" (current_value))
(not (contains_index metadata (current_value)))
))
(contained_entities)
)
)
;map each contained entity to an approprate record
(assign_to_entities "_population_manifest" (assoc metadata
(append
(map
(lambda (assoc
score .null
age (+ 0)
))
(zip new_entities)
)
metadata
)
))
)
)
;culls the population to the carrying_capacity by age and score
; age_effect_rate is the multiplier per cycle on the age modifier for score
; age_effect_magnitude is the reciprocal of the percent of the score affected by the aging one population cycle
; carrying_capacity is the maximum number of entities that are allowed to survive
constrain_population
(let (assoc metadata (retrieve_from_entity "_population_manifest" "metadata"))
(let (assoc
to_cull (indices metadata)
;compute scores
;give a boost to youth by multiplying score by 1 + 1/(age * age_effect_rate + age_effect_magnitude)
scores (zip (indices metadata)
(map
(lambda
(if
(= .null (get (current_value) "score"))
0
;valid value
(* (get (current_value) "score")
(+ 1 (/ 1
(+
(* (get (current_value) "age") age_effect_rate)
age_effect_magnitude
)
))
)
)
)
(values metadata)
)
)
)
;sort by score
(assign (assoc to_cull
(sort (lambda
(-
(get scores (current_value 1))
(get scores (current_value))
)
)
to_cull
)
))
;if too many, then cull those over the cap
(if (> (size to_cull) carrying_capacity)
(map
(lambda (destroy_entities (current_value)))
(tail to_cull
(- (size to_cull) carrying_capacity)
)
)
)
)
)
;increments the age of the entire population
age_population
(assign_to_entities "_population_manifest" (assoc metadata
(map
(lambda
(modify (current_value) "age"
(+ 1 (get (current_value) "age"))))
(retrieve_from_entity "_population_manifest" "metadata")
)
))
;updates the score of an individual specified by the parameters id and score respectively
update_score
(declare (assoc
id .null
metadata (call_entity "_population_manifest" "metadata")
prev_score_discount 0.75
score 0
)
;get previous score or initialize
(if
;if already exists, retrieve score and update
(contains_index metadata id)
(let (assoc prev_score (get metadata (list id "score")))
;update score
(assign (assoc
metadata
(modify metadata (list id "score")
;if don't have an existing score, use the current one
(if (= prev_score .null)
score
;otherwise update it
(+
(* prev_score_discount score)
(* (- 1 prev_score_discount) score)
)
)
)
))
)
;initialize record for this entity
(assign (assoc
metadata (modify metadata
id
(assoc
score score
age 0
)
)
))
)
;write it out
(assign_to_entities "_population_manifest" (assoc metadata metadata))
)
;evaluates to an exponentially distributed random number with mean
; specified by the parameter score
resample_score
(* score (- (log (- 1.0 (rand)))))
;gets a random individual for competition purposes
; affect probability by sex, age, or score?
get_random_individual
(rand (filter
(lambda (!= "_population_manifest" (current_value)))
(contained_entities)
))
;returns a list of all individuals in the current set
get_all_individuals
(filter
(lambda (!= "_population_manifest" (current_value)))
(contained_entities)
)
;returns a list of the individuals that are haploids
get_haploids
(filter
(lambda
(and
(= 0
(size (contained_entities (current_value)))
)
;skip the manifest
(!= "_population_manifest" (current_value))
)
)
(contained_entities)
)
;returns a list of the individuals that are diploids
get_diploids
(filter
(lambda
(= 2
(size (contained_entities (current_value)))
)
)
(contained_entities)
)
;returns an assoc of entity ids and scores. if entities is specified, then it will only return the scores for those entities
; metadata can also be specified, but if omitted, it uses the metadata contained in this entity
get_individual_scores
(declare (assoc
entities (call get_all_individuals)
metadata (retrieve_from_entity "_population_manifest" "metadata")
)
(zip
entities
(map
(lambda (get metadata (list (current_value) "score")))
entities
)
)
)
;takes in a list of entities and metadata, constrains them
; to the number represented by take_max_fraction (e.g., the best 10%) and take_min_n (e.g., at least 3)
; defaults to haploids only
get_individuals_with_best_scores
(declare (assoc
entities (call get_haploids)
metadata (retrieve_from_entity "_population_manifest" "metadata")
take_max_fraction 0.125
take_min_n 3
)
;sort from highest to lowest so can cut off lowest at end
(assign (assoc
entities
(sort (lambda
(-
(get metadata (list (current_value 1) "score"))
(get metadata (list (current_value) "score"))
))
entities
)
))
;keep only the best, but make sure there are at least the minimum number
(assign (assoc
entities
(trunc entities
(max take_min_n (* take_max_fraction (size entities)) )
)
))
entities
)
;determines the sex of the entity passed in id, returning "diploid" or "haploid" as appropriate, null otherwise
determine_sex
(if
(contains_label id "diploid")
"diploid"
(contains_label id "haploid")
"haploid"
.null
)
;returns a size for the entity passed in id, a proxy for complexity
; if haploid, will return the size of the ploid, if diploid, will return the larger of either of the ploid
get_individual_size_complexity
(if
(contains_label id "diploid")
(max
(total_entity_size (list id "ploid1"))
(total_entity_size (list id "ploid2"))
)
;else haploid or error, in either case get the total entity size
(total_entity_size id)
)
;template for creating the base entity for diploid
diploid_react_base_template
{
;reacts to the input that is passed in
; will return a randomized union of the two results
react
(mix
(call_entity "ploid1" "react" (args))
(call_entity "ploid2" "react" (args))
0.95 0.95
)
}
;creates a happloid given code with optional id
;returns the id of the entity created
create_haploid
(declare (assoc
id .null
code .null
)
(create_entities
id
(associate "react" code)
)
)
;creates a diploid given code1 and code2 with optional id
;returns the id of the entity created
create_diploid
(declare (assoc
id .null
code1 .null
code2 .null
)
(let (assoc
new_entity (first (create_entities id diploid_react_base_template))
)
(call create_haploid (assoc id (list new_entity "ploid1") code code1))
(call create_haploid (assoc id (list new_entity "ploid2") code code2))
new_entity
)
)
;mates entities with ids specified by the parameters haploid and diploid
; creates a new contained entity
; if the parameter offspring_sex is specified, the options are "haploid" and "diploid". if unspecified, it will choose randomly
; if the parameter id is specified, it will use that name to create the new entity
; if the parameter mutation_rate is specified, it will use that as the mutation rate
; if the parameter mutation_operator_weights is specified, it will use that for the mutation operator weights (see mutate/mutate_entity documentation)
; if the parameter mutation_type_weights is specified, it will use that for the mutation type weights (see mutate/mutate_entity documentation)
mate
(declare (assoc
id .null
offspring_sex .null
mutation_rate 0.01
mutation_operator_weights .null
mutation_type_weights .null
)
(if (or
(= offspring_sex "diploid")
(and (= offspring_sex .null) (< (rand) 0.5) )
)
;diploid
;use haplodiploidy mechanism to make a diploid (female) from diploid (female) and haploid (male)
(seq
(assign (assoc id (first (create_entities id diploid_react_base_template)) ))
;perform mixing
(mix_entities (list diploid "ploid1") (list diploid "ploid2")
0.5 0.5
{
types_must_match .false
nominal_numbers .false
nominal_strings .false
recursive_matching .true
similar_mix_chance 0.95
unnamed_entity_mix_chance 0
}
(list id "ploid1_temp")
)
(clone_entities haploid (list id "ploid2_temp"))
;mutate
(mutate_entity (list id "ploid1_temp") mutation_rate (list id "ploid1") mutation_operator_weights mutation_type_weights)
(destroy_entities (list id "ploid1_temp"))
(mutate_entity (list id "ploid2_temp") mutation_rate (list id "ploid2") mutation_operator_weights mutation_type_weights)
(destroy_entities (list id "ploid2_temp"))
id
)
;haploid
;use haplodiploidy mechanism to make a haploid (male) from diploid (female)
(let (assoc temp_id
(mix_entities (list diploid "ploid1") (list diploid "ploid2")
0.5 0.5
{
types_must_match .false
nominal_numbers .false
nominal_strings .false
recursive_matching .true
similar_mix_chance 0.95
}
)
)
(mutate_entity temp_id mutation_rate id mutation_operator_weights mutation_type_weights)
(destroy_entities temp_id)
id
)
)
)
;merges two entities of the same sex (both haploid or both diploid) specified by id1 and id2
; to an optional merged_id
;returns the new id of the merged entity
;if the sexes do not match, then nothing is performed
merge
(declare (assoc
id1 .null
id2 .null
merged_id .null
)
(if
(= (call determine_sex (assoc id id1)) (call determine_sex (assoc id id2)))
(mix_entities
id1 id2 0.5 0.5
{
types_must_match .false
nominal_numbers .false
nominal_strings .false
recursive_matching .true
similar_mix_chance 0.5
unnamed_entity_mix_chance 0.2
}
merged_id
)
;if different, then can't merge
.null
)
)
;takes haploid1 and haploid2, combines all contained entities,
; and creates a diploid blend of the two
blend_2_haploids_to_diploid
;copy out both ploids from each haploid
;set haploid code to null
;merge entities
;set new entity code with two ploids, one from each, along with react header
(declare (assoc
id .null
)
(assign (assoc id (first (create_entities id diploid_react_base_template)) ))
;combine both haploids
(clone_entities haploid1 (list id "ploid1"))
(clone_entities haploid2 (list id "ploid2"))
id
)
;takes diploid and splits each ploid into the variables id1 and id2
; evaluates to a list of the ids of the two new offspring
split_diploid_to_2_haploids
(declare (assoc
id1 .null
id2 .null
)
(list
(clone_entities (list diploid "ploid1") id1)
(clone_entities (list diploid "ploid2") id2)
)
)
;takes in a list of entities and metadata and randomizes the order
; based on resampling the scores
;returns a list with the randomized best at the end, least best at the front
randomize_individual_order (seq
;resample scores
(assign (assoc
resampled_scores
(map (lambda
(assoc
id (current_value 1)
score (call resample_score (assoc score (get metadata (list (current_value 3) "score")) ) )
))
entities
)
))
;sort resampled from lowest to highest so can pull best off lowest at end when bred
(assign (assoc
resampled_scores
(sort (lambda
(-
(get (current_value) "score")
(get (current_value 1) "score")
))
resampled_scores
)
))
;evaluate to the extracted ids
(map (lambda (get (current_value) "id")) resampled_scores)
)
;performs a population cycle
; scores should be nonnegative values. a score twice as high will reproduce twice as much
; age_effect_rate is the multiplier per cycle on the age modifier for score
; age_effect_magnitude is the reciprocal of the percent of the score affected by aging
; carrying_capacity is the maximum number of entities that are allowed to survive
; population_increase is the number of children to be produced this cycle
; fraction_haploids_reproducing is the fraction of best haploids that will be allowed to reproduce
; fraction_diploids_reproducing is the fraction of best diploids that will be allowed to reproduce
; max_num_haploid_matings is the maximum number of diploids a haploid can mate with
; if the parameter mutation_rate is specified, it will use that as the mutation rate
; if the parameter mutation_operator_weights is specified, it will use that for the mutation operator weights (see mutate/mutate_entity documentation)
; if the parameter mutation_type_weights is specified, it will use that for the mutation type weights (see mutate/mutate_entity documentation)
population_cycle (declare (assoc
age_effect_rate 5
age_effect_magnitude 50
carrying_capacity 80
population_increase 80
fraction_haploids_reproducing 0.4
fraction_diploids_reproducing 0.8
max_num_haploid_matings 5
metadata .null
mutation_rate 0.01
mutation_operator_weights .null
mutation_type_weights .null
)
(call remove_unused_records)
;get a clean list of the data after the records have been cleaned out
(assign (assoc metadata (retrieve_from_entity "_population_manifest" "metadata")))
;perform population cycle
(let (assoc
diploids (call get_diploids)
haploids (call get_haploids)
)
;take just the best
(assign (assoc
diploids
(call get_individuals_with_best_scores (assoc
entities diploids
metadata metadata
take_max_fraction fraction_diploids_reproducing
take_min_n 3
))
haploids
(call get_individuals_with_best_scores (assoc
entities haploids
metadata metadata
take_max_fraction fraction_haploids_reproducing
take_min_n 3
))
))
;randomize order of diploids
(assign (assoc
diploids
(call randomize_individual_order (assoc
entities diploids
metadata metadata
))
))
(let (assoc
total_num_children 0
;number of times the current diploid has mated
cur_diploid_matings 0
;diploids need to have enough offspring to increase population sufficiently
num_children_per_diploid (ceil (/ population_increase (size diploids)))
;haploid matings that have ocurred
haploid_matings (zip haploids (map (lambda (+ 0)) haploids))
;need to make sure that haploids can have sufficient offspring
max_children_per_haploid (max
max_num_haploid_matings
(ceil (/ population_increase (size haploids)))
)
)
(while (and
(< total_num_children population_increase)
(> (size diploids) 0)
)
;remove top diploid if mated enough
(if (>= cur_diploid_matings num_children_per_diploid)
(assign (assoc
diploids (trunc diploids)
cur_diploid_matings 0
))
)
;randomize order of haploids
(assign (assoc
haploids
(call randomize_individual_order (assoc
entities haploids
metadata metadata
))
))
;combine organisms
(call mate (assoc
haploid (last haploids)
diploid (last diploids)
mutation_rate mutation_rate
mutation_operator_weights mutation_operator_weights
mutation_type_weights mutation_type_weights
))
(accum (assoc
total_num_children 1
cur_diploid_matings 1
))
)
)
)
(call age_population)
(call constrain_population (assoc
age_effect_rate age_effect_rate
age_effect_magnitude age_effect_magnitude
carrying_capacity carrying_capacity
))
(call discover_new_individuals)
)
}