using System; using System.Linq; using System.Security.Cryptography; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.BinaryVectorEncoding; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.PluginInfrastructure; using HeuristicLab.Problems.Binary; using HeuristicLab.Problems.NK.WeightInitializers; using HeuristicLab.Random; namespace HeuristicLab.Problems.NK { [Item("NK Landscape New", "Represents an NK landscape optimization problem.")] [Creatable("Problems")] [StorableClass] public sealed class NKLandscapeNew : BinaryProblem { public override bool Maximization { get { return false; } } #region Parameters public ValueParameter GeneInteractionsParameter { get { return (ValueParameter)Parameters["GeneInteractions"]; } } public ValueParameter InteractionSeedParameter { get { return (ValueParameter)Parameters["InteractionSeed"]; } } public ValueParameter NrOfInteractionsParameter { get { return (ValueParameter)Parameters["NrOfInteractions"]; } } public ValueParameter NrOfFitnessComponentsParameter { get { return (ValueParameter)Parameters["NrOfFitnessComponents"]; } } public ValueParameter WeightsParameter { get { return (ValueParameter)Parameters["Weights"]; } } public IConstrainedValueParameter InteractionInitializerParameter { get { return (IConstrainedValueParameter)Parameters["InteractionInitializer"]; } } public IConstrainedValueParameter WeightsInitializerParameter { get { return (IConstrainedValueParameter)Parameters["WeightsInitializer"]; } } #endregion #region Properties public IInteractionInitializer InteractionInitializer { get { return InteractionInitializerParameter.Value; } } public BoolMatrix GeneInteractions { get { return GeneInteractionsParameter.Value; } } public DoubleArray Weights { get { return WeightsParameter.Value; } } public IntValue InteractionSeed { get { return InteractionSeedParameter.Value; } } #endregion [ThreadStatic] private static MersenneTwister random; public static MersenneTwister Random { get { if (random == null) { random = new MersenneTwister(); } return random; } } [ThreadStatic] private static HashAlgorithm hashAlgorithm; public static HashAlgorithm HashAlgorithm { get { if (hashAlgorithm == null) { hashAlgorithm = HashAlgorithm.Create("MD5"); } return hashAlgorithm; } } [StorableConstructor] private NKLandscapeNew(bool deserializing) : base(deserializing) { } private NKLandscapeNew(NKLandscapeNew original, Cloner cloner) : base(original, cloner) { RegisterEventHandlers(); } public NKLandscapeNew() : base() { Parameters.Add(new ValueParameter("GeneInteractions", "Every column gives the participating genes for each fitness component")); Parameters.Add(new ValueParameter("InteractionSeed", "The seed used for the hash function to generate interaction tables.", new IntValue(Random.Next()))); Parameters.Add(new ValueParameter("NrOfFitnessComponents", "Number of fitness component functions. (nr of columns in the interaction column)", new IntValue(10))); Parameters.Add(new ValueParameter("NrOfInteractions", "Number of genes interacting with each other. (nr of True values per column in the interaction matrix)", new IntValue(3))); Parameters.Add(new ValueParameter("Weights", "The weights for the component functions. If shorted, will be repeated.", new DoubleArray(new[] { 1.0 }))); Parameters.Add(new OptionalConstrainedValueParameter("InteractionInitializer", "Initialize interactions within the component functions.")); Parameters.Add(new OptionalConstrainedValueParameter("WeightsInitializer", "Operator to initialize weights distribution")); InitializeInteractionInitializerParameter(); InitializeWeightsInitializerParameter(); InitializeOperators(); RegisterEventHandlers(); InitializeInteractions(); } private void InitializeInteractionInitializerParameter() { foreach (var initializer in ApplicationManager.Manager.GetInstances()) InteractionInitializerParameter.ValidValues.Add(initializer); InteractionInitializerParameter.Value = InteractionInitializerParameter.ValidValues.First(v => v is RandomInteractionsInitializer); } private void InitializeWeightsInitializerParameter() { foreach (var initializer in ApplicationManager.Manager.GetInstances()) WeightsInitializerParameter.ValidValues.Add(initializer); WeightsInitializerParameter.Value = WeightsInitializerParameter.ValidValues.First(v => v is EqualWeightsInitializer); } public override IDeepCloneable Clone(Cloner cloner) { return new NKLandscapeNew(this, cloner); } #region Events protected override void LengthParameter_ValueChanged(object sender, EventArgs e) { BestKnownQualityParameter.Value = new DoubleValue(Length); NrOfFitnessComponentsParameter.Value = new IntValue(Length); } #endregion #region Helpers [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { RegisterEventHandlers(); } private void RegisterEventHandlers() { NrOfInteractionsParameter.ValueChanged += InteractionParameterChanged; NrOfInteractionsParameter.Value.ValueChanged += InteractionParameterChanged; NrOfFitnessComponentsParameter.ValueChanged += InteractionParameterChanged; NrOfFitnessComponentsParameter.Value.ValueChanged += InteractionParameterChanged; InteractionInitializerParameter.ValueChanged += InteractionInitializerParameter_ValueChanged; WeightsInitializerParameter.ValueChanged += WeightsInitializerParameter_ValueChanged; } void WeightsInitializerParameter_ValueChanged(object sender, EventArgs e) { InitializeWeights(); } void InteractionInitializerParameter_ValueChanged(object sender, EventArgs e) { InitializeInteractions(); } private void InteractionParameterChanged(object sender, EventArgs e) { InitializeInteractions(); } private void InitializeOperators() { NKBitFlipMoveEvaluator nkEvaluator = new NKBitFlipMoveEvaluator(); Encoding.ConfigureOperator(nkEvaluator); Operators.Add(nkEvaluator); } private void InitializeInteractions() { if (InteractionInitializer != null) GeneInteractionsParameter.Value = InteractionInitializer.InitializeInterations( Length, NrOfFitnessComponentsParameter.Value.Value, NrOfInteractionsParameter.Value.Value, Random); } private void InitializeWeights() { if (WeightsInitializerParameter.Value != null) WeightsParameter.Value = new DoubleArray( WeightsInitializerParameter.Value.GetWeights(NrOfFitnessComponentsParameter.Value.Value) .ToArray()); } #endregion #region Evaluation function public static long Hash(long x) { return BitConverter.ToInt64(HashAlgorithm.ComputeHash(BitConverter.GetBytes(x), 0, 8), 0); } public static double F_i(long x, long i, long g_i, long seed) { return Math.Abs((double)Hash((x & g_i) ^ Hash(g_i ^ Hash(i ^ seed)))) / long.MaxValue; } public static double F(long x, long[] g, double[] w, long seed, ref double[] f_i) { double value = 0; for (int i = 0; i < g.Length; i++) { f_i[i] = F_i(x, i, g[i], seed); value += w[i % w.Length] * f_i[i]; } return value; } public static long Encode(BinaryVector v) { long x = 0; for (int i = 0; i < 64 && i < v.Length; i++) { x |= (v[i] ? (long)1 : (long)0) << i; } return x; } public static long[] Encode(BoolMatrix m) { long[] x = new long[m.Columns]; for (int c = 0; c < m.Columns; c++) { x[c] = 0; for (int r = 0; r < 64 && r < m.Rows; r++) { x[c] |= (m[r, c] ? (long)1 : (long)0) << r; } } return x; } public static double[] Normalize(DoubleArray weights) { double sum = 0; double[] w = new double[weights.Length]; foreach (var v in weights) { sum += Math.Abs(v); } for (int i = 0; i < weights.Length; i++) { w[i] = Math.Abs(weights[i]) / sum; } return w; } public static double Evaluate(BinaryVector vector, BoolMatrix interactions, DoubleArray weights, int seed, out double[] f_i) { long x = Encode(vector); long[] g = Encode(interactions); double[] w = Normalize(weights); f_i = new double[interactions.Columns]; return F(x, g, w, (long)seed, ref f_i); } public override double Evaluate(BinaryVector vector, IRandom random) { double[] f_i;//not used atm double quality = Evaluate(vector, GeneInteractions, Weights, InteractionSeed.Value, out f_i); return quality; } #endregion } }