/*
* 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.*;
/**
* Culture is a memory not being bound to a generation, but possibly persistent
* during the whole history of a genotype (over all generations).
* See GPConfiguration for current support of culture with Genetic Programming.<p>
* Also see http://cs.gmu.edu/~sean/papers/culture-gp96.pdf
*
* @author Klaus Meffert
* @since 2.3
*/
public class Culture
implements Serializable, Comparable {
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.16 $";
/**
* The storage to use.
*/
private CultureMemoryCell[] m_memory;
/**
* Storage for named indices.
*/
private List m_memoryNames = new Vector();
/**
* Number of memory cells available.
*/
private int m_size;
/**
* Width of a matrixed memory (optional, but necessary to set if you want
* to treat the memory as a matrix).
*/
private int m_width;
/**
* Constructor.
*
* @param a_size the size of the memory in cells (CultureMemoryCell instances)
*
* @author Klaus Meffert
* @since 2.3
*/
public Culture(final int a_size) {
if (a_size < 1) {
throw new IllegalArgumentException("Size must be greater than zero!");
}
m_size = a_size;
m_memory = new CultureMemoryCell[m_size];
m_width = 1;
}
/**
* Sets a memory cell with a given value. The memory cell will be newly
* created for that.
*
* @param a_index index of the memory cell
* @param a_value value to set in the memory
* @param a_historySize size of history to use, or less than 1 for turning
* history off
* @param a_name informative name of the memory cell
* @return newly created memory cell set with the given value
*
* @author Klaus Meffert
* @since 2.3
*/
public CultureMemoryCell set(final int a_index, final double a_value,
final int a_historySize, final String a_name) {
if (a_index < 0 || a_index >= size()) {
throw new IllegalArgumentException("Illegal memory index!");
}
CultureMemoryCell cell = new CultureMemoryCell(a_name, a_historySize);
cell.setDouble(a_value);
m_memory[a_index] = cell;
return cell;
}
/**
* Sets a memory cell with a given value. The memory cell will be newly
* created for that.
*
* @param a_index index of the memory cell
* @param a_value value to set in the memory
* @param a_historySize size of history to use, or less than 1 for turning
* history off
* @param a_infotext informative name of the memory cell
* @return newly created memory cell set with the given value
*
* @author Klaus Meffert
* @since 3.0
*/
public CultureMemoryCell set(final int a_index, final Object a_value,
final int a_historySize, final String a_infotext) {
if (a_index < 0 || a_index >= size()) {
throw new IllegalArgumentException("Illegal memory index!");
}
CultureMemoryCell cell = new CultureMemoryCell(a_infotext, a_historySize);
cell.setValue(a_value);
m_memory[a_index] = cell;
return cell;
}
/**
* Sets a memory cell with a given value. The memory cell will be newly
* created for that.
*
* @param a_name named index of the memory cell
* @param a_value value to set in the memory
* @param a_historySize size of history to use, or less than 1 for turning
* history off
* @return newly created memory cell set with the given value
*
* @author Klaus Meffert
* @since 3.0
*/
public CultureMemoryCell set(final String a_name, final Object a_value,
final int a_historySize) {
if (a_name == null || a_name.length() < 1) {
throw new IllegalArgumentException("Illegal memory name!");
}
int index = m_memoryNames.indexOf(a_name);
if (index < 0) {
// Create new named index.
// -----------------------
m_memoryNames.add(a_name);
index = m_memoryNames.size() - 1;
}
CultureMemoryCell cell = new CultureMemoryCell(a_name, a_historySize);
cell.setValue(a_value);
m_memory[index] = cell;
return cell;
}
/**
* Retrieves the memory cell at the given index.
*
* @param a_index index of the memory cell to read out
* @return stored memory cell at given index
*
* @author Klaus Meffert
* @since 2.3
*/
public CultureMemoryCell get(final int a_index) {
if (a_index < 0 || a_index >= size()) {
throw new IllegalArgumentException("Illegal memory index!");
}
return m_memory[a_index];
}
/**
* Retrieves the memory cell at the given index.
*
* @param a_name name of the memory cell to read out
* @return stored memory cell for given name, or null if name unknown
*
* @author Klaus Meffert
* @since 3.0
*/
public CultureMemoryCell get(final String a_name) {
if (a_name == null || a_name.length() < 1) {
throw new IllegalArgumentException("Illegal memory name!");
}
int index = m_memoryNames.indexOf(a_name);
if (index < 0) {
throw new IllegalArgumentException("Memory name unknown: " + a_name);
}
return m_memory[index];
}
/**
* Checks if a memory cell with the given name exists.
*
* @param a_name the name of the cell to check
* @return true: cell excists
*
* @author Klaus Meffert
* @since 3.2
*/
public boolean contains(final String a_name) {
if (a_name == null || a_name.length() < 1) {
throw new IllegalArgumentException("Illegal memory name!");
}
int index = m_memoryNames.indexOf(a_name);
return index >=0;
}
/**
* @return size of the memory
*
* @author Klaus Meffert
* @since 2.3
*/
public int size() {
return m_memory.length;
}
/**
* @return String representation of the cultural memory
*
* @author Klaus Meffert
* @since 2.3
*/
public String toString() {
StringBuffer result = new StringBuffer("[");
int len = m_memory.length;
if (m_memory[0] == null) {
result.append(m_memory[0]);
}
else {
result.append(m_memory[0].toString());
}
for (int i = 1; i < len; i++) {
if (m_memory[i] == null) {
result.append(";" + m_memory[i]);
}
else {
result.append(";" + m_memory[i].toString());
}
}
result.append("]");
return result.toString();
}
/**
* Clears the memory.
*
* @author Klaus Meffert
* @since 3.0
*/
public void clear() {
m_memory = new CultureMemoryCell[m_size];
m_memoryNames.clear();
}
/**
* @return cloned list of symbolic memory names
*
* @author Klaus Meffert
* @since 3.0
*/
public List getMemoryNames() {
return new Vector(m_memoryNames);
}
/**
* 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) {
cex.printStackTrace();
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) {
Culture other = (Culture) a_other;
if (other == null) {
return 1;
}
// Problem: Vector does not implement Comparable. Thus we call toArray().
// ----------------------------------------------------------------------
return new CompareToBuilder()
.append(m_size, other.m_size)
.append(m_memory, other.m_memory)
.append(m_memoryNames.toArray(), other.m_memoryNames.toArray())
.toComparison();
}
/**
* Sets the width of the matrix memory. Important to call before using
* setMatrix/getMatrix!
*
* @param a_width the width the matrix should have
*
* @author Klaus Meffert
* @since 3.2
*/
public void setMatrixWidth(int a_width) {
int size = size();
if (a_width > size) {
throw new IllegalArgumentException("Width must not be greater than the"
+ " size of the memory ("
+ size
+ ") !");
}
m_width = a_width;
}
/**
* Stores a value in the matrix memory. Use setMatrixWidth(int) beforehand!
*
* @param a_x the first coordinate of the matrix (width)
* @param a_y the second coordinate of the matrix (height)
* @param a_value the value to store
* @return created or used memory cell
*
* @author Klaus Meffert
* @since 3.2
*/
public CultureMemoryCell setMatrix(int a_x, int a_y, Object a_value) {
int index = a_x * m_width + a_y;
CultureMemoryCell cell = m_memory[index];
if (cell == null) {
cell = new CultureMemoryCell(a_x+"_"+a_y, -1);
}
cell.setValue(a_value);
m_memory[index] = cell;
return cell;
}
/**
* Reads a value from the matrix memory that was previously stored with
* setMatrix(...).
*
* @param a_x the first coordinate of the matrix (width)
* @param a_y the second coordinate of the matrix (height)
* @return read value
*
* @author Klaus Meffert
* @since 3.2
*/
public CultureMemoryCell getMatrix(int a_x, int a_y) {
int index = a_x * m_width + a_y;
return get(index);
}
}