org.jgap.distr.CultureMemoryCell.java Source code

Java tutorial

Introduction

Here is the source code for org.jgap.distr.CultureMemoryCell.java

Source

/*
 * This file is part of JGAP.
 *
 * JGAP offers a dual license model containing the LGPL as well as the MPL.
 *
 * For licensing information please see the file license.txt included with JGAP
 * or have a look at the top of class org.jgap.Chromosome which representatively
 * includes the JGAP license policy applicable for any file delivered with JGAP.
 */
package org.jgap.distr;

import java.io.*;
import java.util.*;
import org.apache.commons.lang.builder.*;

/**
 * Represents a memory cell used within {@link org.jgap.distr.Culture}, a
 * special form of memory.
 * <P>
 * CultureMemoryCell also stores metadata along with the value-to-store, like
 * date/time of setting a value, change history.
 *
 * @author Klaus Meffert
 * @since 2.3
 */
public class CultureMemoryCell implements Serializable, Comparable {
    /** String containing the CVS revision. Read out via reflection!*/
    private final static String CVS_REVISION = "$Revision: 1.13 $";

    /**
     * Informative name of the memory cell (optional)
     */
    private String m_name;

    /**
     * Version of the memory value, i.e. how many times has setValue(..) been
     * called)? First version (no value assigned) is zero, second version (first
     * time a value is assigned to the memory) is 1 etc.
     */
    private int m_version;

    /**
     * Value of the memory cell
     */
    private Object m_value;

    /**
     * How many times has the memory cell been read out?
     */
    private int m_readAccessed;

    /**
     * How many historical values should be kept for evaluation purposes?
     * Values less than one turn history feature off
     */
    private int m_historySize;

    private int m_internalHistorySize;

    /**
     * If history logging turned off, we need to keep the prior version for
     * evaluation purpose, e.g. see getReadAccessedCurrentVersion
     */
    private CultureMemoryCell m_previousVersion;

    /**
     * History of memory values
     */
    private List m_history;

    /**
     * Time in milliseconds when the version number is incremented (e.g. when
     * setting the value of the cell)
     */
    private long m_dateTimeVersion;

    /**
     * Default constructor.
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public CultureMemoryCell() {
        this(null);
    }

    /**
     * Sets history size to 3.
     * @param a_name informative name of the memory cell
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public CultureMemoryCell(final String a_name) {
        this(a_name, 3);
    }

    /**
     * Allows to freely specify informative name of memory cell as well as size
     * of history to keep.
     * @param a_name informative name of the memory cell
     * @param a_historySize size of history to keep. Use values less than 1 for
     * turning history logging off
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public CultureMemoryCell(final String a_name, final int a_historySize) {
        setHistorySize(a_historySize);
        m_history = new Vector(getHistorySize());
        setName(a_name);
    }

    /**
     * Sets the informative name of the memory cell.
     * @param a_name informative name
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public void setName(final String a_name) {
        m_name = a_name;
    }

    /**
     * @return informative name of the memory cell
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public String getName() {
        return m_name;
    }

    /**
     * Sets a new memory value.
     * @param a_value the memory value to set
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public void setValue(final Object a_value) {
        if (m_historySize > 0) {
            keepHistory(a_value, getVersion(), getName());
        } else {
            m_previousVersion = getNewInstance(m_value, getVersion(), getName());
        }
        m_value = a_value;
        incrementVersion();
    }

    /**
     * Convenience method to store a primitive double easily.
     *
     * @param a_value double value to store
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public void setDouble(final double a_value) {
        setValue(new Double(a_value));
    }

    /**
     * Convenience method to retrieve a primitive double value from memory
     * easily. Here a ClassCastException could occur!
     * @return double value representing current memory value
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public double getCurrentValueAsDouble() {
        return ((Double) getCurrentValue()).doubleValue();
    }

    /**
     * @return current memory value
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public Object getCurrentValue() {
        m_readAccessed++;
        return m_value;
    }

    /**
     * @return list of most recent entries (except current entry). The item at
     * index 0 is the oldest, the item at highest index is the youngest one.
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public List getHistory() {
        return m_history;
    }

    /**
     * @return version of memory value, read only
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public int getVersion() {
        return m_version;
    }

    /**
     * Increment version number and keep track of current time.
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    protected void incrementVersion() {
        m_version++;
        // Memorize current time.
        m_dateTimeVersion = System.currentTimeMillis();
    }

    /**
     * Puts an entry into history. Stores all information as a new
     * CultureMemoryCell instance.
     *
     * @param a_value memory value to store
     * @param a_version version of the value
     * @param a_name name to store
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    protected void keepHistory(final Object a_value, final int a_version, final String a_name) {
        trimHistory(m_historySize - 1);
        // simply add a new instance of CultureMemoryCell for keeping history track
        CultureMemoryCell cell = getNewInstance(a_value, a_version, a_name);
        cell.m_internalHistorySize = m_historySize;
        m_history.add(cell);
    }

    /**
     * Creates a new instance of CultureMemoryCell preset with the given
     * parameters. Used for creating history entries.
     *
     * @param a_value memory value to store
     * @param a_version version of the value
     * @param a_name name to store
     * @return new instance of CultureMemoryCell
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    protected CultureMemoryCell getNewInstance(final Object a_value, final int a_version, final String a_name) {
        // DON'T USE SETTERS IN HERE BECAUSE OF ENDLESS LOOPS!
        CultureMemoryCell cell = new CultureMemoryCell(a_name, 0);
        cell.m_value = a_value;
        cell.m_version = a_version;
        return cell;
    }

    /**
     * @return number of times the memory cell has been read accessed
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public int getReadAccessed() {
        return m_readAccessed;
    }

    /**
     * @return number of read accesses since current value has been set.
     * Calculated by subtracting number of read accesses for prior version from
     * total number of read accesses
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public int getReadAccessedCurrentVersion() {
        if (m_historySize < 1) {
            // Use internal (simple/atomic) history.
            // -------------------------------------
            return getReadAccessed() - m_previousVersion.getReadAccessed();
        } else {
            // Use sophisticated history (list).
            // ---------------------------------
            CultureMemoryCell cell = (CultureMemoryCell) m_history.get(m_history.size() - 1);
            return getReadAccessed() - cell.getReadAccessed();
        }
    }

    /**
     * Sets the size of the history and scales down the history log it is larger
     * than the given size.
     * @param a_size new size of the history log = how many entries to store
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public void setHistorySize(final int a_size) {
        if (getHistory() != null && a_size > getHistory().size()) {
            trimHistory(a_size);
            m_historySize = a_size;
        } else if (a_size < 0) {
            m_historySize = 0;
        } else {
            m_historySize = a_size;
        }
    }

    /**
     * Trims the history to the given size.
     * @param a_size new size of history
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    protected void trimHistory(final int a_size) {
        // trim length of history
        while (m_history.size() > a_size) {
            // remove one entry (always the first one = oldest one)
            m_history.remove(0);
        }
    }

    /**
     * @return size of the history
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public int getHistorySize() {
        return m_historySize;
    }

    /**
     * @return String representation of the cultural memory cell including all
     * important information (also history log).
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    public String toString() {
        StringBuffer result = new StringBuffer();
        toStringRecursive(result, getHistorySize());
        return result.toString();
    }

    /**
     * Recursive part of toString().
     * @param a_result gathered result so far and modified here
     * @param a_historySize history size just for information purpose
     *
     * @author Klaus Meffert
     * @since 2.3
     */
    protected void toStringRecursive(StringBuffer a_result, final int a_historySize) {
        List history = getHistory();
        a_result.append("[Name:" + getName() + ";");
        a_result.append("Value:" + m_value + ";"); //not getCurrentValue()!
        a_result.append("Version:" + getVersion() + ";");
        a_result.append("Read accessed:" + getReadAccessed() + ";");
        a_result.append("History Size:" + a_historySize + ";");
        a_result.append("History:[");
        for (int i = 0; i < history.size(); i++) {
            if (i > 0) {
                a_result.append(";");
            }
            CultureMemoryCell cell = (CultureMemoryCell) history.get(i);
            // do recursive call
            cell.toStringRecursive(a_result, cell.m_internalHistorySize);
            a_result.append("]");
        }
        a_result.append("]");
    }

    /**
     * @return time in milliseconds when the current version has been created
     *
     * @author Klaus Meffert
     * @since 3.0
     */
    public long getVersionTimeMilliseconds() {
        return m_dateTimeVersion;
    }

    /**
     * The equals-method.
     * @param a_other the other object to compare
     * @return true if the objects are regarded as equal
     *
     * @author Klaus Meffert
     * @since 3.0
     */
    public boolean equals(Object a_other) {
        try {
            return compareTo(a_other) == 0;
        } catch (ClassCastException cex) {
            return false;
        }
    }

    /**
     * The compareTo-method.
     * @param a_other the other object to compare
     * @return -1, 0, 1
     *
     * @author Klaus Meffert
     * @since 3.0
     */
    public int compareTo(Object a_other) {
        CultureMemoryCell other = (CultureMemoryCell) a_other;
        if (other == null) {
            return 1;
        }
        return new CompareToBuilder().append(m_value, other.m_value).append(m_version, other.m_version)
                .append(m_historySize, other.m_historySize).toComparison();
    }
}