/* Copyright 2009-2016 David Hadka * * This file is part of the MOEA Framework. * * The MOEA Framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The MOEA Framework is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>. */ package org.moeaframework.core.variable; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.moeaframework.core.PRNG; import org.moeaframework.core.Variable; import org.moeaframework.util.grammar.ContextFreeGrammar; /** * Decision variable for grammars. This class represents the grammar as a * variable-length integer codon which is subsequently converted into a grammar * using {@link ContextFreeGrammar#build}. * * @see ContextFreeGrammar */ public class Grammar implements Variable { private static final long serialVersionUID = 1701058698946283174L; /** * The integer codon of this grammar. */ private int[] codon; /** * The number of values that each codon can represent. Each index in the * codon array can be assigned a value in the range {@code [0, * maximumValue-1]}. */ private int maximumValue = 256; /** * Constructs a grammar variable with the specified initial size. * * @param size the initial size of this grammar */ public Grammar(int size) { this(new int[size]); } /** * Constructs a grammar variable with the specified integer codon * representation. * * @param codon the integer codon representation for this grammar */ public Grammar(int[] codon) { super(); fromArray(codon); } /** * Returns the number of values that each codon can represent. Each index in * the codon array can be assigned a value in the range {@code [0, * maximumValue-1]} * * @return the number of values that each codon can represent */ public int getMaximumValue() { return maximumValue; } /** * Sets the number of values that each codon can represent. Each index in * the codon array can be assigned a value in the range {@code [0, * maximumValue-1]}. * * @param maximumValue the number of values that each codon can represent */ public void setMaximumValue(int maximumValue) { this.maximumValue = maximumValue; } /** * Returns the integer codon representation of this grammar. The returned * object is a clone of the internal storage, and thus can be modified * independently of this instance. * * @return the integer codon representation of this grammar */ public int[] toArray() { return codon.clone(); } /** * Sets the integer codon representation of this grammar. The stored object * is a clone of the argument, and thus can be modified independently of * this instance. * * @param codon the new integer codon representation for this grammar * @throws IllegalArgumentException if any codon value is out of range ( * {@code (value < 0) || (value >= getMaximumValue())}) */ public void fromArray(int[] codon) { for (int i = 0; i < codon.length; i++) { if ((codon[i] < 0) || (codon[i] >= maximumValue)) { throw new IllegalArgumentException("invalid codon value"); } } this.codon = codon.clone(); } /** * Returns the length of the integer codon representation of this grammar. * * @return the length of the integer codon representation of this grammar */ public int size() { return codon.length; } /** * Sets the specified index in the integer codon representation of this * grammar to the specified value. * * @param index the index of the codon to be assigned * @param value the new value for the specified index * @throws ArrayIndexOutOfBoundsException if the index is out of range ( * {@code (index < 0) || (index >= size())}) * @throws IllegalArgumentException if the value is out of range ( * {@code (value < 0) || (value >= getMaximumValue())}) */ public void set(int index, int value) { if ((value < 0) || (value >= maximumValue)) { throw new IllegalArgumentException("invalid codon value"); } codon[index] = value; } /** * Returns the value at the specified index in the integer codon * representation of this grammar. * * @param index the index of the codon value to be returned * @return the value at the specified index in the integer codon * representation of this grammar * @throws ArrayIndexOutOfBoundsException if the index is out of range ( * {@code (index < 0) || (index >= size())}) */ public int get(int index) { return codon[index]; } @Override public Grammar copy() { return new Grammar(codon); } /** * Removes the indices in the range {@code [start, end]} from the integer * codon representation, returning array of the values removed by this cut * operation. For example, * * <pre> * Grammar grammar = new Grammar(new int[] { 0, 1, 2, 3, 4, 5 }); * int[] removed = grammar.cut(2, 4); * </pre> * * results in grammar representing the array {@code [2, 3, 4]} and removed * containing {@code [0, 1, 5]}. * * @param start the start index of the cut operation * @param end the end index of the cut operation * @return the array of values removed by this cut operation */ public int[] cut(int start, int end) { if (start > end) { throw new IllegalArgumentException("start not before end"); } int[] newCodon = new int[codon.length - (end - start + 1)]; int[] result = new int[end - start + 1]; int index = 0; for (int i = 0; i < start; i++) { newCodon[index++] = codon[i]; } for (int i = start; i <= end; i++) { result[i - start] = codon[i]; } for (int i = end + 1; i < codon.length; i++) { newCodon[index++] = codon[i]; } fromArray(newCodon); return result; } /** * Inserts the specified array into this grammar's integer codon * representation at the specified insert index. For example, * * <pre> * Grammar grammar = new Grammar(new int[] { 0, 1, 2, 3, 4, 5 }); * grammar.insert(2, new int[] { 6, 7 }); * </pre> * * results in grammar representing the array {@code [0, 1, 6, 7, 2, 3, 4, * 5]}. * * @param insertIndex the index where the specified array is to be inserted * @param array the array of integer codons to be inserted */ public void insert(int insertIndex, int[] array) { int[] newCodon = new int[codon.length + array.length]; int index = 0; for (int i = 0; i < insertIndex; i++) { newCodon[index++] = codon[i]; } for (int i = 0; i < array.length; i++) { newCodon[index++] = array[i]; } for (int i = insertIndex; i < codon.length; i++) { newCodon[index++] = codon[i]; } fromArray(newCodon); } @Override public int hashCode() { return new HashCodeBuilder().append(codon).toHashCode(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if ((obj == null) || (obj.getClass() != getClass())) { return false; } else { Grammar rhs = (Grammar)obj; return new EqualsBuilder().append(codon, rhs.codon).isEquals(); } } @Override public void randomize() { for (int i = 0; i < codon.length; i++) { codon[i] = PRNG.nextInt(getMaximumValue()); } } }