#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Linq;
using System.Text;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.ConditionActionEncoding;
using HeuristicLab.Encodings.IntegerVectorEncoding;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Encodings.CombinedIntegerVectorEncoding {
[StorableClass]
[Item("CombinedIntegerVector", "Represents a combined vector of integer values.")]
public class CombinedIntegerVector : IntegerVector, IClassifier, ICondition, IAction, IInput {
[Storable]
protected int actionLength;
public int ActionLength { get { return actionLength; } }
///
/// The bounds must contain at least one row with two columns. The first two columns specify min and max values.
/// The max value -1 in a row is the don't care symbol for LCS.
/// Each row represents the bounds for a certain dimension. If fewer rows are given, the rows are cycled
///
[Storable]
protected IntMatrix bounds;
public IntMatrix Bounds { get { return (IntMatrix)bounds.Clone(); } }
public int ConditionLength { get { return Length - actionLength; } }
[StorableConstructor]
protected CombinedIntegerVector(bool deserializing) : base(deserializing) { }
public CombinedIntegerVector() : base() { }
public CombinedIntegerVector(int[] elements, int actionPart, IntMatrix bounds)
: base(elements) {
this.actionLength = actionPart;
//check if combinedVector satisfies bounds and if bounds is set correctly (at leats one row with 2 columns) is missing!
this.bounds = bounds;
}
public CombinedIntegerVector(IntegerVector combinedVector, int actionPart, IntMatrix bounds)
: this(combinedVector.ToArray(), actionPart, bounds) { }
public CombinedIntegerVector(IntegerVector condition, IntegerVector action, IntMatrix bounds)
: base(condition.Concat(action).ToArray()) {
actionLength = action.Length;
//check if combinedVector satisfies bounds and if bounds is set correctly (at leats one row with 2 columns) is missing!
this.bounds = bounds;
}
public CombinedIntegerVector(IntegerVector condition, IntMatrix conditionBounds, IntegerVector action, IntMatrix actionBounds)
: this(condition, action, CombineBounds(conditionBounds, actionBounds)) {
}
private static IntMatrix CombineBounds(IntMatrix conditionBounds, IntMatrix actionBounds) {
int columns = conditionBounds.Columns < actionBounds.Columns ? conditionBounds.Columns : actionBounds.Columns;
IntMatrix bounds = new IntMatrix(conditionBounds.Rows + actionBounds.Rows, columns);
for (int i = 0; i < conditionBounds.Rows; i++) {
for (int j = 0; j < columns; j++) {
bounds[i, j] = conditionBounds[i % conditionBounds.Rows, j];
}
}
for (int i = conditionBounds.Rows; i < actionBounds.Rows + conditionBounds.Rows; i++) {
for (int j = 0; j < columns; j++) {
bounds[i, j] = actionBounds[i % actionBounds.Rows, j];
}
}
return bounds;
}
public CombinedIntegerVector(IRandom random, int length, int min, int max, int actionLenght, int actionMin, int actionMax) :
this(new IntegerVector(length, random, min, max), new IntegerVector(actionLenght, random, actionMin, actionMax), null) {
bounds = new IntMatrix(length + actionLenght, 2);
for (int i = 0; i < length; i++) {
bounds[i, 0] = min;
bounds[i, 1] = max;
}
for (int i = length; i < length + actionLenght; i++) {
bounds[i, 0] = actionMin;
bounds[i, 1] = actionMax;
}
}
public CombinedIntegerVector(int length, int actionPart, IntMatrix bounds)
: base(length) {
this.actionLength = actionPart;
this.bounds = bounds;
}
protected CombinedIntegerVector(CombinedIntegerVector original, Cloner cloner)
: base(original, cloner) {
actionLength = original.actionLength;
bounds = (IntMatrix)original.bounds.Clone();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new CombinedIntegerVector(this, cloner);
}
public ICondition Condition {
get {
int[] condition = new int[Length - actionLength];
Array.Copy(this.array, condition, Length - actionLength);
return new CombinedIntegerVector(condition, 0, bounds);
}
}
public IAction Action {
get {
int[] action = new int[actionLength];
Array.Copy(this.array, Length - actionLength, action, 0, actionLength);
IntMatrix actionBounds = GetElementsOfBoundsForAction(bounds, Length, actionLength);
return new CombinedIntegerVector(action, actionLength, actionBounds);
}
}
private IntMatrix GetElementsOfBoundsForAction(IntMatrix bounds, int length, int actionPartLength) {
IntMatrix actionBounds = new IntMatrix(actionPartLength, bounds.Columns);
int start = length - actionPartLength;
int rows = bounds.Rows;
for (int i = start; i < length; i++) {
int pos = i % rows;
for (int j = 0; j < bounds.Columns; j++) {
actionBounds[i - start, j] = bounds[pos, j];
}
}
return actionBounds;
}
public bool MatchInput(IInput target) {
var targetVector = target as CombinedIntegerVector;
if (targetVector == null) return false;
if (targetVector.Length - targetVector.actionLength != this.Length - this.actionLength) return false;
int curbounds;
for (int i = 0; i < this.Length - this.actionLength; i++) {
curbounds = i % bounds.Rows;
//if don't care symbol is matched, next indices can be checked
if (this[i] == bounds[curbounds, 1] - 1) {
continue;
}
if (this[i] != targetVector[i]) {
return false;
}
}
return true;
}
public bool MatchAction(IClassifier target) {
return MatchAction(target.Action);
}
// no "don't care" symbols have to be considered
public bool MatchAction(IAction target) {
var targetVector = target as CombinedIntegerVector;
if (targetVector == null) return false;
if (targetVector.actionLength != this.actionLength) return false;
int curPos = this.Length - this.actionLength;
int curTargetPos = targetVector.Length - targetVector.actionLength;
for (int i = 0; i < this.actionLength; i++) {
if (!this[curPos + i].Equals(targetVector[curTargetPos + i])) {
return false;
}
}
return true;
}
public bool IsMoreGeneral(IClassifier target) {
return IsMoreGeneral(target as ICondition);
}
public bool IsMoreGeneral(ICondition target) {
var targetVector = target as CombinedIntegerVector;
int curbounds;
if (this.NumberOfGeneralSymbols() <= targetVector.NumberOfGeneralSymbols()) return false;
for (int i = 0; i < ConditionLength; i++) {
curbounds = i % bounds.Rows;
if (this[i] != bounds[curbounds, 1] - 1 && this[i] != targetVector[i]) {
return false;
}
}
return true;
}
#region ICondition Members
public bool Match(IInput target) {
return MatchInput(target);
}
#endregion
#region IAction Members
public bool Match(IAction target) {
return MatchAction(target);
}
#endregion
private int NumberOfGeneralSymbols() {
int numberOfGeneralSymbols = 0;
int curbounds;
for (int i = 0; i < ConditionLength; i++) {
curbounds = i % bounds.Rows;
numberOfGeneralSymbols += this[i] == bounds[curbounds, 1] - 1 ? 1 : 0;
}
return numberOfGeneralSymbols;
}
public override string ToString() {
StringBuilder strBuilder = new StringBuilder(this.Length);
strBuilder.Append('[');
int curbounds;
for (int i = 0; i < this.Length; i++) {
curbounds = i % bounds.Rows;
if (i >= this.Length - this.actionLength || this[i] < bounds[curbounds, 1] - 1) {
strBuilder.Append(this[i]);
} else {
strBuilder.Append('#');
}
if (i < this.Length - 1) {
strBuilder.Append(';');
}
}
strBuilder.Append(']');
return strBuilder.ToString();
}
public bool Identical(IClassifier target) {
var cast = target as CombinedIntegerVector;
if (cast == null) { return false; }
for (int i = 0; i < array.Length; i++) {
if (!array[i].Equals(cast.array[i])) {
return false;
}
}
return true;
}
}
}