Source: methods/genetic/Individual.js

import { getRandomInt } from './Random'

/**
 * Represents individual.
 */
export class Individual {
    constructor() {
        this._fitness = null;
        this._rank = null;
        if (this.constructor === Individual) {
            throw new TypeError('Abstract class "Individual" cannot be instantiated directly.');
        }
        if (this.mutate === undefined) {
            throw new TypeError('Classes extending the Individual abstract class');
        }
    }
    getFitness() {
        return this._fitness;
    }
    setFitness(fitness) {
        this._fitness = fitness;
    }
    getRank() {
        return this._rank;
    }
    setRank(rank) {
        this._rank = rank;
    }
    getGenotype() {
        //abstract
    }

    /**
     * Performs mutation with given probability.
     * @param {number } mutationRate mutation probability
     */
    mutate(mutationRate) {
        //abstract
    }

    /**
     * Deep copy of individual.
     */
    copy() {
        //abstract
    }
}

/**
 * Represents binary individual.
 */
export class BinaryIndividual extends Individual {
    /**
     * Creates individual from bit array.
     * @param {Array} bitArray configuration
     */
    constructor(bitArray) {
        super();
        this._bitArray = bitArray;

    }
    /**
     * Performs inversion mutation with given probability.
     * @param {number} mutationRate probability that each bit is inverted
     */
    mutate(mutationRate) {
        for (var i = 0; i < this._bitArray.length; i++) {
            if (Math.random() < mutationRate) {
                this._fitness = null;
                //bit flip
                this._bitArray[i] = !this._bitArray[i];
            }
        }
    }

    /**
     * Gets bit array.
     * @returns {Array} bit array
     */
    getGenotype() {
        return this._bitArray;
    }
    /**
     * Gets bit array.
     * @returns {Array} bit array
     */
    getBitArray() {
        return this._bitArray;
    }
    /**
     * Gets size of bit array.
     * @returns {number} size of bit array
     */
    getSize() {
        return this._bitArray.length;
    }

    /**
     * Returns deep copy of individual.
     * @returns {BinaryIndividual} deep copy
     */
    copy() {
        return new BinaryIndividual(this._bitArray.map(x=>x));
    }
}

/**
 * Represents permutation individual.
 */
export class PermutationIndividual extends Individual {
    /**
     * Creates individual from permutation.
     * @param {Array} permutation configuration
     */
    constructor(permutation) {
        super();
        this._permutation = permutation;

    }

    /**
     * Performs swap mutation.
     * @param mutationRate probability that each value is swapped with another one
     */
    mutate(mutationRate) {
        for (var i = 0; i < this._permutation.length; i++) {
            if (Math.random() < mutationRate) {
                this._fitness = null;
                //swap values but not with itself
                var position = getRandomInt(0, this._permutation.length-1);
                if (position >= i) {
                    position++;
                }
                var temp = this._permutation[i];
                this._permutation[i] = this._permutation[position];
                this._permutation[position] = temp;
            }
        }
    }
    /**
     * Gets permutation array.
     * @returns {Array} permutation array
     */
    getGenotype() {
        return this._permutation;
    }
    /**
     * Gets permutation array.
     * @returns {Array} permutation array
     */
    getArray() {
        return this._permutation;
    }
    /**
     * Gets size of permutation array.
     * @returns {number} size of permutation array
     */
    getSize() {
        return this._permutation.length;
    }
    /**
     * Returns deep copy of individual.
     * @returns {PermutationIndividual} deep copy
     */
    copy() {
        return new PermutationIndividual(this._permutation.map(x=>x));
    }
}