#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; } } }