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
extern crate rand;
extern crate serde;

use rand::prelude::*;

use serde::{Serialize, Deserialize};

use std::{
    collections::HashMap,
    fmt::Debug
};

mod add;
mod crc32;
mod keccak;
mod md5;
mod mult;
mod sha1;
mod sha2;
mod xor;

use add::{Add, InvAdd};
use crc32::{Crc32, InvCrc32};
use keccak::{Keccak, InvKeccak};
use md5::{Md5, InvMd5};
use mult::{Mult, InvMult};
use sha1::{Sha1, InvSha1};
use sha2::{Sha2, InvSha2};
use xor::{Xor, InvXor, XorWithInv};

/// (De)serializable description of bitransform's preferences.
#[derive(Serialize, Deserialize)]
pub struct BitransformDesc {
    id: String,
    prefs: Vec<usize>
}

/// Provides methods around certain bitstring function to use it for evolution of boolnet population.
pub trait Bitransform: Debug + Sync {
    /// Key to get entry about this Bitransform from BitransformRegister instance
    /// and set Evolver to this Bitransform's instance.
    fn id() -> String where Self: Sized;

    /// Short info about this Bitransform: input, output, preferences.
    fn info() -> String where Self: Sized;

    /// Constructor, provided with bitransform's preferences.
    fn new(prefs: &[usize]) -> Result<Box<dyn Bitransform>, String> where Self: Sized;

    /// Make serializable description of this bitransform's preferences.
    fn desc(&self) -> BitransformDesc;

    /// Size of input to direct bitstring function in bits.
    fn dir_inp_size(&self) -> usize;

    /// Boolnet input size in bits.
    fn inp_size(&self) -> usize;

    /// Boolnet output size in bits.
    fn outp_size(&self) -> usize;

    /// Calculate underlying (direct) bitstring function for `args` batch.
    fn dir_func(&self, args: &[u128]) -> Vec<u128>;

    /// Make random input batch.
    /// The length of batch elements must be `inp_size()`.
    fn rand_inp(&self, rng: &mut ThreadRng) -> Vec<u128>;

    /// Score output batch, in regard to input batch and underlying bitstring function.
    /// Usually the score is the mean number of different bits in some 2 bitstrings.
    fn score_inp_outp(&self, inp: &[u128], outp: &[u128]) -> f64;

    /// Makes entry about this `Bitransform` to be added to `BitransformRegister` instance.
    fn reg_entry() -> (String, fn() -> String, fn(&[usize]) -> Result<Box<dyn Bitransform>, String>) // see BitransformRegister below
    where Self: Sized {
        (Self::id(), Self::info, Self::new)
    }
}

/// Connects Bitransform id with its info and constructor methods.
pub struct BitransformRegister {
    entries: HashMap<String, (fn() -> String, fn(&[usize]) -> Result<Box<dyn Bitransform>, String>)> // id -> (T::info(), T::new(&prefs))
}

const ERR_BITRAN_ALREADY_REGISTERED: &str = "Bitransform already registered";
const ERR_BITRAN_NOT_REGISTERED: &str = "Bitransform not registered";

impl BitransformDesc {
    pub fn new(id: impl ToString, prefs: &[usize]) -> Self {
        let id = id.to_string();
        let prefs = prefs.clone().to_vec();
        Self{id, prefs}
    }
}

impl BitransformRegister {
    /// Adds entries about Bitransforms.
    /// Such entries are provided by `Bitransform::reg_entry()` method.
    pub fn add(&mut self, entries: Vec<(String, fn() -> String, fn(&[usize]) -> Result<Box<dyn Bitransform>, String>)>) -> Result<(), String> {
        for (id, f_info, f_new) in entries {
            match self.entries.insert(id.clone(), (f_info, f_new)) {
                None => {},
                Some(..) => return Err(format!("{}: {}", ERR_BITRAN_ALREADY_REGISTERED, &id))
            };
        }
        Ok(())
    }

    /// Makes bitransform from its serializable description.
    /// Bitransform must be present in the register.
    pub fn new_from_desc(&self, desc: &BitransformDesc) -> Result<Box<dyn Bitransform>, String> {
        match self.entries.get(& desc.id) {
            Some((_, f_new)) => f_new(& desc.prefs),
            None => Err(format!("{}: {}", ERR_BITRAN_NOT_REGISTERED, & desc.id))
        }
    }

    /// Returns the list that consists of pairs (`id`, `info`), alphabetically sorted by `id`,
    /// for Bitransforms in this register.
    pub fn list(&self) -> Vec<(String, String)> {
        let mut list = Vec::<(String, String)>::with_capacity(self.entries.len());
        for (id, (f_info, _)) in & self.entries {
            list.push((id.clone(), f_info()));
        }
        // Sort alphabetically
        list.sort_by(|a, b| a.cmp(&b));
        list
    }

    /// Creates register with prepackaged Bitransforms.
    pub fn new_default() -> Self {
        let entries = HashMap::<String, (fn() -> String, fn(&[usize]) -> Result<Box<dyn Bitransform>, String>)>::new();
        let mut reg = Self{entries};
        let _ = reg.add(vec![
            Xor::reg_entry(), InvXor::reg_entry(), XorWithInv::reg_entry(),
            Add::reg_entry(), InvAdd::reg_entry(),
            Mult::reg_entry(), InvMult::reg_entry(),
            Crc32::reg_entry(), InvCrc32::reg_entry(),
            Md5::reg_entry(), InvMd5::reg_entry(),
            Sha1::reg_entry(), InvSha1::reg_entry(),
            Sha2::reg_entry(), InvSha2::reg_entry(),
            Keccak::reg_entry(), InvKeccak::reg_entry()
        ]);
        reg
    }

}