Compare commits
4 Commits
85e3b7ca33
...
1e14538caf
Author | SHA1 | Date | |
---|---|---|---|
1e14538caf | |||
a02dcf1893 | |||
9abddc49ef | |||
7f22b4e425 |
@ -426,18 +426,77 @@ make_instruction_clone!(exec, int, _size, Gene, 1);
|
|||||||
|
|
||||||
/// Returns a nested element inside a block based on an int.
|
/// Returns a nested element inside a block based on an int.
|
||||||
pub fn _extract(vals: Vec<Gene>, auxs: Vec<i128>) -> Option<Gene> {
|
pub fn _extract(vals: Vec<Gene>, auxs: Vec<i128>) -> Option<Gene> {
|
||||||
Some(match vals[0].clone() {
|
match vals[0].clone() {
|
||||||
Gene::Block(val) => {
|
block @ Gene::Block(_) => {
|
||||||
if *val.len() == 0 {
|
let block_len = block.rec_len();
|
||||||
|
if block_len == 0 {
|
||||||
return None;
|
return None;
|
||||||
} else {
|
} else {
|
||||||
let ndx = (auxs[0] % *val.len()).abs();
|
let ndx = (auxs[0] % block_len as i128).abs() as usize;
|
||||||
// @TODO: Finish this later!
|
Some(vals[0].clone().code_at_point(ndx)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val => Some(val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_instruction_aux!(code, code, _extract, Gene, 1, int, 1, i128);
|
||||||
|
|
||||||
|
/// Inserts a gene at a given position in into the top block based off an
|
||||||
|
/// int from the top of the int stack. The top code item is coerced into a block
|
||||||
|
/// if needed.
|
||||||
|
pub fn _insert(vals: Vec<Gene>, auxs: Vec<i128>) -> Option<Gene> {
|
||||||
|
let mut block = match vals[0].clone() {
|
||||||
|
iblock @ Gene::Block(_) => iblock,
|
||||||
|
val => Gene::Block(Box::new(vec![val])),
|
||||||
|
};
|
||||||
|
if block.rec_len() == 0 {
|
||||||
|
return _combine(vec![block, vals[1].clone()]);
|
||||||
|
}
|
||||||
|
let ndx = auxs[0].abs() as usize % block.rec_len();
|
||||||
|
block.with_code_inserted_at_point(vals[1].clone(), ndx);
|
||||||
|
Some(block)
|
||||||
|
}
|
||||||
|
make_instruction_aux!(code, code, _insert, Gene, 2, int, 1, i128);
|
||||||
|
|
||||||
|
/// Pushes the first position of the 2nd code item within the top code item.
|
||||||
|
/// If not found, pushes -1. If top code item isn't a block, returns 0 if top
|
||||||
|
/// two code items equal, -1 otherwise.
|
||||||
|
pub fn _first_position(vals: Vec<Gene>) -> Option<i128> {
|
||||||
|
let bad_cond: bool = match &vals[0] {
|
||||||
|
Gene::Block(val) => val.len() == 0,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
if bad_cond {
|
||||||
|
if vals[0] == vals[1] {
|
||||||
|
return Some(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match &vals[0] {
|
||||||
|
Gene::Block(val) => {
|
||||||
|
for (idx, el) in val.iter().enumerate() {
|
||||||
|
if el == &vals[1] {
|
||||||
|
return Some(idx as i128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Error: Invariant of only a block failed in _first_position!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(-1)
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, int, _first_position, Gene, 2);
|
||||||
|
|
||||||
|
/// Reverses the top block. Does nothing if not a block.
|
||||||
|
pub fn _reverse(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
Some(match vals[0].clone() {
|
||||||
|
Gene::Block(mut val) => {
|
||||||
|
val.reverse();
|
||||||
|
Gene::Block(val)
|
||||||
|
}
|
||||||
val => val,
|
val => val,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
make_instruction_clone!(code, code, _reverse, Gene, 1);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -1027,4 +1086,160 @@ mod tests {
|
|||||||
code_size(&mut test_state);
|
code_size(&mut test_state);
|
||||||
assert_eq!(vec![2], test_state.int);
|
assert_eq!(vec![2], test_state.int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extract_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
let test_code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(4),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneString(vec!['t'])])),
|
||||||
|
])),
|
||||||
|
Gene::GeneInt(10),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneBoolean(false)])),
|
||||||
|
]))];
|
||||||
|
|
||||||
|
test_state.code = test_code.clone();
|
||||||
|
test_state.int = vec![0];
|
||||||
|
code_member(&mut test_state);
|
||||||
|
assert_eq!(test_code.clone(), test_state.code);
|
||||||
|
|
||||||
|
test_state.code = test_code.clone();
|
||||||
|
test_state.int = vec![2];
|
||||||
|
code_extract(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
|
||||||
|
test_state.code = test_code.clone();
|
||||||
|
test_state.int = vec![4];
|
||||||
|
code_extract(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(4)], test_state.code);
|
||||||
|
|
||||||
|
test_state.code = test_code.clone();
|
||||||
|
test_state.int = vec![9];
|
||||||
|
code_extract(&mut test_state);
|
||||||
|
assert_eq!(
|
||||||
|
vec![Gene::Block(Box::new(vec![Gene::GeneBoolean(false)]))],
|
||||||
|
test_state.code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneInt(1), Gene::GeneInt(1)])),
|
||||||
|
])),
|
||||||
|
];
|
||||||
|
test_state.int = vec![1];
|
||||||
|
let inserted_block = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneInt(1), Gene::GeneInt(1)])),
|
||||||
|
]))];
|
||||||
|
code_insert(&mut test_state);
|
||||||
|
assert_eq!(inserted_block, test_state.code);
|
||||||
|
|
||||||
|
test_state.code = vec![
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(4),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneString(vec!['t'])])),
|
||||||
|
])),
|
||||||
|
Gene::GeneInt(10),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneBoolean(false)])),
|
||||||
|
])),
|
||||||
|
];
|
||||||
|
test_state.int = vec![4];
|
||||||
|
let inserted_block = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(4),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneString(vec!['t'])])),
|
||||||
|
])),
|
||||||
|
Gene::GeneInt(10),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneBoolean(false)])),
|
||||||
|
]))];
|
||||||
|
code_insert(&mut test_state);
|
||||||
|
assert_eq!(inserted_block, test_state.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_position_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
])),
|
||||||
|
];
|
||||||
|
code_first_position(&mut test_state);
|
||||||
|
assert_eq!(vec![2], test_state.int);
|
||||||
|
test_state.int.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneBoolean(false), Gene::GeneBoolean(false)];
|
||||||
|
code_first_position(&mut test_state);
|
||||||
|
assert_eq!(vec![0], test_state.int);
|
||||||
|
test_state.int.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneBoolean(false), Gene::GeneBoolean(true)];
|
||||||
|
code_first_position(&mut test_state);
|
||||||
|
assert_eq!(vec![-1], test_state.int);
|
||||||
|
test_state.int.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![
|
||||||
|
Gene::GeneInt(-6),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
])),
|
||||||
|
];
|
||||||
|
code_first_position(&mut test_state);
|
||||||
|
assert_eq!(vec![-1], test_state.int);
|
||||||
|
test_state.int.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn code_reverse_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(1)];
|
||||||
|
code_reverse(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(false),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
]))];
|
||||||
|
code_reverse(&mut test_state);
|
||||||
|
assert_eq!(
|
||||||
|
vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneBoolean(false),
|
||||||
|
]))],
|
||||||
|
test_state.code
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,3 +200,4 @@ pub mod common;
|
|||||||
pub mod logical;
|
pub mod logical;
|
||||||
pub mod numeric;
|
pub mod numeric;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod vector;
|
||||||
|
36
src/instructions/vector.rs
Normal file
36
src/instructions/vector.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::push::state::PushState;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
|
pub fn _concat<T>(vals: Vec<Vec<T>>) -> Option<Vec<T>>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
let mut concat_vec = vals[0].clone();
|
||||||
|
concat_vec.extend(vals[1].clone().into_iter());
|
||||||
|
Some(concat_vec)
|
||||||
|
}
|
||||||
|
make_instruction_clone!(vector_int, vector_int, _concat, Vec<i128>, 2);
|
||||||
|
make_instruction_clone!(vector_float, vector_float, _concat, Vec<Decimal>, 2);
|
||||||
|
make_instruction_clone!(vector_string, vector_string, _concat, Vec<Vec<char>>, 2);
|
||||||
|
make_instruction_clone!(vector_boolean, vector_boolean, _concat, Vec<bool>, 2);
|
||||||
|
make_instruction_clone!(vector_char, vector_char, _concat, Vec<char>, 2);
|
||||||
|
make_instruction_clone!(string, string, _concat, Vec<char>, 2);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::push::state::EMPTY_STATE;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vector_concat() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.vector_int = vec![vec![4, 5, 6], vec![1, 2, 3]];
|
||||||
|
vector_int_concat(&mut test_state);
|
||||||
|
assert_eq!(vec![vec![1, 2, 3, 4, 5, 6]], test_state.vector_int);
|
||||||
|
|
||||||
|
test_state.string = vec![vec!['s', 't'], vec!['t', 'e']];
|
||||||
|
string_concat(&mut test_state);
|
||||||
|
assert_eq!(vec![vec!['t', 'e', 's', 't']], test_state.string);
|
||||||
|
}
|
||||||
|
}
|
@ -54,3 +54,170 @@ pub enum Gene {
|
|||||||
Block(Box<Vec<Gene>>),
|
Block(Box<Vec<Gene>>),
|
||||||
CrossoverPadding,
|
CrossoverPadding,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Gene {
|
||||||
|
/// Returns the len of a gene. If the gene is a block, returns
|
||||||
|
/// the size of the block counting the size of nested blocks.
|
||||||
|
pub fn rec_len(&self) -> usize {
|
||||||
|
let mut size: usize = 0;
|
||||||
|
match self {
|
||||||
|
Gene::Block(val) => {
|
||||||
|
for el in val.iter() {
|
||||||
|
match el {
|
||||||
|
iblock @ Gene::Block(_) => size += iblock.rec_len() + 1,
|
||||||
|
_ => size += 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => size += 1,
|
||||||
|
};
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts code at a point in the genome. Recurses into a block
|
||||||
|
/// if necessary. Point is based on an int. Pulled straight from HushGP.
|
||||||
|
pub fn code_at_point(self, index: usize) -> Option<Gene> {
|
||||||
|
if index == 0 {
|
||||||
|
return Some(self);
|
||||||
|
}
|
||||||
|
let mut idx = index;
|
||||||
|
match self {
|
||||||
|
Gene::Block(val) => {
|
||||||
|
for el in val.iter() {
|
||||||
|
idx -= 1;
|
||||||
|
if idx == 0 {
|
||||||
|
return Some(el.clone());
|
||||||
|
}
|
||||||
|
match el {
|
||||||
|
iblock @ Gene::Block(_) => {
|
||||||
|
if let Some(next_depth) = iblock.clone().code_at_point(idx) {
|
||||||
|
return Some(next_depth);
|
||||||
|
}
|
||||||
|
idx -= iblock.rec_len();
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
val => Some(val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert an element into a block recursively counting along the way.
|
||||||
|
/// Depth first. Modifies in-place.
|
||||||
|
pub fn with_code_inserted_at_point(&mut self, gene: Gene, idx: usize) {
|
||||||
|
if idx > self.rec_len() {
|
||||||
|
match self {
|
||||||
|
Gene::Block(val) => val.push(gene.clone()),
|
||||||
|
_ => {
|
||||||
|
panic!("Error: self must be a block for with_code_inserted_at_point to work!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = self.attempt_code_insert(gene, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to insert an item into a block.
|
||||||
|
fn attempt_code_insert(&mut self, gene: Gene, index: usize) -> bool {
|
||||||
|
let mut idx = index;
|
||||||
|
match self {
|
||||||
|
Gene::Block(val) => {
|
||||||
|
for (n, el) in val.iter_mut().enumerate() {
|
||||||
|
if idx == 0 {
|
||||||
|
val.insert(n, gene.clone());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
match el {
|
||||||
|
iblock @ Gene::Block(_) => {
|
||||||
|
// This line has side effects on iblock if inserts properly.
|
||||||
|
let success = iblock.attempt_code_insert(gene.clone(), idx - 1);
|
||||||
|
if success {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
idx -= iblock.rec_len() + 1
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
idx -= 1;
|
||||||
|
}
|
||||||
|
if idx == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => panic!("Error: self must be a block for attempt_code_insert to work!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rec_len_test() {
|
||||||
|
let block = Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneInt(1), Gene::GeneInt(1)])),
|
||||||
|
]));
|
||||||
|
assert_eq!(4, block.rec_len());
|
||||||
|
|
||||||
|
let block = Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(4),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneString(vec!['t'])])),
|
||||||
|
])),
|
||||||
|
Gene::GeneInt(10),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneBoolean(false)])),
|
||||||
|
]));
|
||||||
|
assert_eq!(10, block.rec_len());
|
||||||
|
|
||||||
|
let block = Gene::Block(Box::new(vec![]));
|
||||||
|
assert_eq!(0, block.rec_len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert_test() {
|
||||||
|
let mut block = Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneInt(1), Gene::GeneInt(1)])),
|
||||||
|
]));
|
||||||
|
let inserted_block = Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneInt(1), Gene::GeneInt(1)])),
|
||||||
|
]));
|
||||||
|
block.with_code_inserted_at_point(Gene::GeneInt(20), 1);
|
||||||
|
assert_eq!(inserted_block, block);
|
||||||
|
|
||||||
|
let mut block = Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(4),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneString(vec!['t'])])),
|
||||||
|
])),
|
||||||
|
Gene::GeneInt(10),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneBoolean(false)])),
|
||||||
|
]));
|
||||||
|
let inserted_block = Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(4),
|
||||||
|
Gene::GeneInt(20),
|
||||||
|
Gene::GeneFloat(dec!(6.0)),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneString(vec!['t'])])),
|
||||||
|
])),
|
||||||
|
Gene::GeneInt(10),
|
||||||
|
Gene::Block(Box::new(vec![Gene::GeneBoolean(false)])),
|
||||||
|
]));
|
||||||
|
block.with_code_inserted_at_point(Gene::GeneInt(20), 4);
|
||||||
|
assert_eq!(inserted_block, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user