#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.Collections.Generic;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Optimization.Operators.LCS;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Encodings.DecisionList {
[StorableClass]
[Item("DoubleVariable", "")]
public class DoubleVariable : Variable {
[Storable]
private IDiscretizer discretizer;
[Storable]
private IList curIntervals;
[Storable]
private int maxIntervals;
[StorableConstructor]
protected DoubleVariable(bool deserializing) : base(deserializing) { }
protected DoubleVariable(DoubleVariable original, Cloner cloner)
: base(original, cloner) {
if (original.discretizer != null) {
discretizer = (IDiscretizer)original.discretizer.Clone();
curIntervals = new List(original.curIntervals);
}
maxIntervals = original.maxIntervals;
}
public DoubleVariable(string variableName, int maxIntervals)
: base(variableName) {
this.maxIntervals = maxIntervals;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new DoubleVariable(this, cloner);
}
public override void Randomize(IRandom random, double onePercentage, IEnumerable discretizers) {
discretizer = discretizers.ElementAt(random.Next(0, discretizers.Count()));
int microIntervals = discretizer.NumberOfMicroIntervals(variableName);
int maxAllowedIntervals = Math.Min(maxIntervals, microIntervals);
int numberOfIntervals = 2;
if (maxAllowedIntervals > 2) {
numberOfIntervals = random.Next(2, maxAllowedIntervals);
}
attributes = new List(numberOfIntervals);
curIntervals = new List(numberOfIntervals);
for (int i = 0; i < numberOfIntervals - 1; i++) {
int microInt = random.Next(1, microIntervals - (numberOfIntervals - i - 1));
microIntervals -= microInt;
curIntervals.Add(microInt);
attributes.Add(random.NextDouble() < onePercentage);
}
// add last interval
curIntervals.Add(microIntervals);
attributes.Add(random.NextDouble() < onePercentage);
}
public override double ComputeTheoryLength() {
int intervalCount = 0;
bool curSet = attributes.First();
// first interval started
if (curSet) {
intervalCount++;
}
foreach (var attribute in attributes) {
if (curSet != attribute) {
intervalCount++;
curSet = attribute;
}
}
// if the last last interval is not set
if (!curSet) {
intervalCount--;
}
return intervalCount;
}
public override bool Match(string input) {
return Match(double.Parse(input));
}
public bool Match(double input) {
var realCutpoints = GetValuesToCutPoints(discretizer.GetCutPoints(variableName), curIntervals);
int pos = 0;
while (input >= realCutpoints[pos]) {
pos++;
}
return attributes[pos];
}
private IList GetValuesToCutPoints(IEnumerable cutpoints, IList microIntervals) {
var intervalValues = new List();
var cutpointList = cutpoints.ToList();
int cur = -1;
for (int i = 0; i < microIntervals.Count - 1; i++) {
cur += microIntervals[i];
intervalValues.Add(cutpointList[cur]);
}
intervalValues.Add(Double.PositiveInfinity);
return intervalValues;
}
public override void Split(IRandom random) {
// cannot create more than maximal allowed intervals
if (curIntervals.Count >= maxIntervals) { return; }
int selectedInterval = random.Next(0, curIntervals.Count);
// a single microinterval cannot be split
if (curIntervals[selectedInterval] <= 1) { return; }
// split interval
int splitPart1 = random.Next(1, curIntervals[selectedInterval]);
int splitPart2 = curIntervals[selectedInterval] - splitPart1;
// resize old interval
curIntervals[selectedInterval] = splitPart1;
// insert new interval at correct position
curIntervals.Insert(selectedInterval + 1, splitPart2);
// set new interval to the same bool value as old one
attributes.Insert(selectedInterval + 1, attributes[selectedInterval]);
return;
}
public override void Merge(IRandom random) {
// cannot merge a single interval
if (curIntervals.Count == 1) { return; }
int selectedInterval = random.Next(0, curIntervals.Count);
int neighbour;
//if selected interval is the leftmost one, the neighbour on the right side is used
if (selectedInterval == 0) {
neighbour = selectedInterval + 1;
//if the selected interval is the rightmost, the neighbour on the left side is used
} else if (selectedInterval == curIntervals.Count - 1) {
neighbour = selectedInterval - 1;
} else {
if (random.Next() < 0.5) {
neighbour = selectedInterval - 1;
} else {
neighbour = selectedInterval + 1;
}
}
bool value;
if (curIntervals[selectedInterval] > curIntervals[neighbour]) {
value = attributes[selectedInterval];
} else if (curIntervals[selectedInterval] < curIntervals[neighbour]) {
value = attributes[neighbour];
} else {
if (random.Next() < 0.5) {
value = attributes[selectedInterval];
} else {
value = attributes[neighbour];
}
}
curIntervals[selectedInterval] += curIntervals[neighbour];
curIntervals.RemoveAt(neighbour);
attributes[selectedInterval] = value;
attributes.RemoveAt(neighbour);
return;
}
public override void Reinitialize(IRandom random, double onePercentage, IEnumerable descretizers) {
Randomize(random, onePercentage, descretizers);
}
public override void SetToMatch(string variableValue) {
var value = double.Parse(variableValue);
var realCutpoints = GetValuesToCutPoints(discretizer.GetCutPoints(variableName), curIntervals);
int pos = 0;
while (value >= realCutpoints[pos]) {
pos++;
}
attributes[pos] = true;
}
}
}