#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DistributedGA.Core.Domain;
using DistributedGA.Core.Implementation;
using DistributedGA.Core.Interface;
using DistributedGA.Core.Util;
using DistributedGA.Hive;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Operators;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Optimization.Operators {
[Item("P2PMigrationAnalyzer", "Migrates individuals using a P2P network.")]
[StorableClass]
public class P2PMigrationAnalyzer : SingleSuccessorOperator, IAnalyzer, ISingleObjectiveOperator, IDisposable {
// state: messagehandler
[ExcludeFromObjectGraphTraversalAttribute]
private IMessageHandler h;
public bool EnabledByDefault { get { return false; } }
public ILookupParameter MaximizationParameter {
get { return (ILookupParameter)Parameters["Maximization"]; }
}
// for name translation
public ScopeTreeLookupParameter QualityParameter {
get { return (ScopeTreeLookupParameter)Parameters["Quality"]; }
}
public ILookupParameter MigrationIterationsParameter {
get { return (ILookupParameter)Parameters["MigrationIterations"]; }
}
public IValueParameter MigrationRatesParameter {
get { return (IValueParameter)Parameters["MigrationRate"]; }
}
public IValueParameter CommunicationRatesParameter {
get { return (IValueParameter)Parameters["CommunicationRate"]; }
}
public IValueParameter MessageCacheCapacityParameter {
get { return (IValueParameter)Parameters["MessageCacheCapacity"]; }
}
public ILookupParameter RandomParameter {
get { return (ILookupParameter)Parameters["Random"]; }
}
public IValueParameter MigrationIntervalParameter {
get { return (IValueParameter)Parameters["MigrationInterval"]; }
}
public IValueParameter LogParameter {
get { return (IValueParameter)Parameters["Log"]; }
}
public IValueParameter JobGuidParameter {
get { return (IValueParameter)Parameters["JobGUID"]; }
}
public IConstrainedValueParameter> MigrationStrategySelectParameter {
get { return (IConstrainedValueParameter>)Parameters["MigrationStrategySelect"]; }
}
public IConstrainedValueParameter> MigrationStrategyReplaceParameter {
get { return (IConstrainedValueParameter>)Parameters["MigrationStrategyReplace"]; }
}
public BoolValue Maximization {
get { return MaximizationParameter.ActualValue; }
}
public IntValue MigrationIterations {
get { return MigrationIterationsParameter.ActualValue; }
}
public IntValue MigrationInterval {
get { return MigrationIntervalParameter.Value; }
}
public IRandom Random {
get { return RandomParameter.ActualValue; }
}
[StorableConstructor]
protected P2PMigrationAnalyzer(bool deserializing) : base(deserializing) { }
protected P2PMigrationAnalyzer(P2PMigrationAnalyzer original, Cloner cloner) : base(original, cloner) { }
public P2PMigrationAnalyzer()
: base() {
Parameters.Add(new LookupParameter("MigrationIterations"));
Parameters.Add(new LookupParameter("Maximization"));
Parameters.Add(new ScopeTreeLookupParameter("Quality", 1));
Parameters.Add(new ValueParameter("MigrationInterval", "", new IntValue(5)));
Parameters.Add(new ValueParameter("MigrationRate", "", new PercentValue(0.05)));
Parameters.Add(new ValueParameter("CommunicationRate", "", new PercentValue(0.25)));
Parameters.Add(new ValueParameter("MessageCacheCapacity", "", new IntValue(40)));
Parameters.Add(new ValueParameter("LanIpPrefix", "", new StringValue("10.")));
Parameters.Add(new LookupParameter("Random", "The random number generator"));
Parameters.Add(new ValueParameter("ContactServerURL", "", new StringValue("net.tcp://10.20.71.18:9090/DistributedGA.ContactServer/ContactService")));
Parameters.Add(new ValueParameter("JobGUID", "", new StringValue(Guid.NewGuid().ToString())));
Parameters.Add(new ValueParameter("Log", "The log", new Log(1000)));
Parameters.Add(new ValueParameter("ByteArraysAllocated", new IntValue(0)));
Parameters.Add(new ValueParameter("ByteArraysFreed", new IntValue(0)));
Parameters.Add(new ValueParameter("ByteArraysAlive", new IntValue(0)));
var validValues = new ItemSet>();
validValues.Add(new EnumValue(MigrationStrategy.Best));
validValues.Add(new EnumValue(MigrationStrategy.Worst));
validValues.Add(new EnumValue(MigrationStrategy.Random));
Parameters.Add(new ConstrainedValueParameter>("MigrationStrategySelect", validValues, (new EnumValue(MigrationStrategy.Random))));
Parameters.Add(new ConstrainedValueParameter>("MigrationStrategyReplace", validValues, (new EnumValue(MigrationStrategy.Random))));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new P2PMigrationAnalyzer(this, cloner);
}
public override void ClearState() {
base.ClearState();
Dispose();
}
private void Init() {
h = new PeerNetworkMessageHandler();
var lanIpPrefix = ((StringValue)(Parameters["LanIpPrefix"].ActualValue)).Value;
var contactServerUri = ((StringValue)(Parameters["ContactServerURL"].ActualValue)).Value;
var problemInstance = ((StringValue)Parameters["JobGUID"].ActualValue).Value;
var communicationRate = ((PercentValue)Parameters["CommunicationRate"].ActualValue).Value;
var messageCacheCapacity = ((IntValue)Parameters["MessageCacheCapacity"].ActualValue).Value;
h.Init(lanIpPrefix, contactServerUri, problemInstance, messageCacheCapacity, (int)(100 * communicationRate));
h.ExceptionOccurend += ExceptionThrown;
}
public override IOperation Apply() {
if (h == null) {
Init();
}
if (MigrationIterationsParameter.ActualValue == null) {
MigrationIterationsParameter.ActualValue = new IntValue(0);
}
if (MigrationIterations.Value % MigrationInterval.Value == 0) {
IScope scope = ExecutionContext.Scope;
List emigrantsList = new List();
//define how many migrants to send
var migrationRate = ((PercentValue)Parameters["MigrationRate"].ActualValue).Value;
int noOfEmigrants = Convert.ToInt32(scope.SubScopes.Count * migrationRate);
if (noOfEmigrants == 0 && scope.SubScopes.Count > 0) {
noOfEmigrants = 1;
}
var popQualities = QualityParameter.ActualValue;
var pop = new List(scope.SubScopes);
List sortedPop;
if (Maximization.Value) {
sortedPop = pop.Zip(popQualities, Tuple.Create).OrderByDescending(t => t.Item2).Select(t => t.Item1).ToList();
} else {
sortedPop = pop.Zip(popQualities, Tuple.Create).OrderBy(t => t.Item2).Select(t => t.Item1).ToList();
}
var selectedMigStratSelect = MigrationStrategySelectParameter.Value.Value;
var selectedMigStratReplace = MigrationStrategyReplaceParameter.Value.Value;
var rand = Random;
int replIdx = 0;
IScope emigrants = null;
for (int i = 0; i < noOfEmigrants; i++) {
//select emigrant depending on strategy
switch (selectedMigStratSelect) {
case MigrationStrategy.Best:
emigrants = sortedPop[i];
emigrantsList.Add(emigrants);
break;
case MigrationStrategy.Random:
replIdx = rand.Next(sortedPop.Count);
emigrants = sortedPop[replIdx];
emigrantsList.Add(emigrants);
break;
case MigrationStrategy.Worst:
emigrants = sortedPop[scope.SubScopes.Count - i - 1];
emigrantsList.Add(emigrants);
break;
}
}
{
// send
for (int ei = 0; ei < emigrantsList.Count; ei++) {
using (var stream = new MemoryStream()) {
byte[] message;
var emigrantScope = emigrantsList[ei];
var msgScope = new Scope();
var cloner = new Cloner();
foreach (var variable in emigrantScope.Variables) {
msgScope.Variables.Add((IVariable)variable.Clone(cloner));
}
HeuristicLab.Persistence.Default.Xml.XmlGenerator.Serialize(msgScope, stream);
message = stream.GetBuffer();
h.PublishDataToNetwork(ByteArrayWrapper.CreateByteArrayWrapper(message));
}
}
}
{
// recieve
var message = h.GetDataFromNetwork();
List> immigrants = new List>();
//limit number of immigrants to use
if (noOfEmigrants < message.Count) {
immigrants = message.Skip(Math.Max(0, message.Count() - noOfEmigrants)).ToList();
} else {
immigrants = message;
}
// remove individuals from population to make place for immigrants
for (int i = 0; i < immigrants.Count; i++) {
switch (selectedMigStratReplace) {
case MigrationStrategy.Best:
scope.SubScopes.Remove(sortedPop[0]);
sortedPop.RemoveAt(0);
break;
case MigrationStrategy.Random:
replIdx = rand.Next(sortedPop.Count);
scope.SubScopes.Remove(sortedPop[replIdx]);
sortedPop.RemoveAt(replIdx);
break;
case MigrationStrategy.Worst:
//replace random
scope.SubScopes.Remove(sortedPop[sortedPop.Count - 1]);
sortedPop.RemoveAt(sortedPop.Count - 1);
break;
}
}
//insert individual sorted in population
var qualities = QualityParameter.ActualValue;
var qualityTranslatedName = QualityParameter.TranslatedName;
foreach (var msg in immigrants) {
using (var stream = new MemoryStream(msg.Value.Array)) {
var immigrantScope = HeuristicLab.Persistence.Default.Xml.XmlParser.Deserialize(stream);
var qImmigrant = ((DoubleValue)immigrantScope.Variables[qualityTranslatedName].Value).Value;
var insertPos = scope.SubScopes.Count;
var maximization = Maximization.Value;
for (int i = 0; i < qualities.Length; i++) {
var qi = qualities[i].Value;
if ((maximization && qi < qImmigrant) || (!maximization && qi > qImmigrant)) {
insertPos = i;
break;
}
}
scope.SubScopes.Insert(insertPos, immigrantScope);
var log = LogParameter.Value;
double quality = qImmigrant;
log.LogMessage(string.Format("Recieved individual with quality {0} from peer {1}:{2} ; Job: {3}",
quality, msg.Key.IpAddress, msg.Key.Port, msg.Key.ProblemInstance));
}
}
}
}
MigrationIterations.Value++;
((IValueParameter)Parameters["ByteArraysAllocated"]).Value.Value = ByteArrayWrapper.AllocatedCounter;
((IValueParameter)Parameters["ByteArraysFreed"]).Value.Value = ByteArrayWrapper.FreedCounter;
((IValueParameter)Parameters["ByteArraysAlive"]).Value.Value = ByteArrayWrapper.AliveCounter;
return base.Apply();
}
private void ExceptionThrown(object sender, Exception e) {
var log = LogParameter.Value;
log.LogMessage(e.Message);
}
public void Dispose() {
h.Dispose();
h = null;
}
}
}