Hi Andreas,
thanks for your reply! I did some testing and the error seems to be somewhere in my repair code. I have to do some investigating tomorrow.
I have another issue regarding the programmable problem.
So I created two problems. One is the programmable problem (single objective) with external evaluation (the one we talked about in the upper posts) and the other one is a "regular" External Evaluation Problem (single-objective). I assume both, with the same Integer bounds and Integer length and without any feasibility checks or repair functions, should now work the same using a genetic algorithm with the same algorithm parameters. In Anylogic I set the number of iterations for the experiment and with the ""regular" External Evaluation Problem (single-objective) everything works just fine. But the programmable problem with external evaluation shows some weird behavior. Somehow HeuristicLab shows a lot more evaluated solutions than Anylogic actually evaluated.
I noticed two cases:
1) HeuristicLab shows thoughout the optimization run more evaluated solutions than Anylogic, until the the predefined amount of iterations (from Anylogic) is reached (e.g. Anylogic shows 300, HL shows 1360 iterations).
2) HeuristicLab shows thoughout the optimization run more evaluated solutions than Anylogic, but the predefined amount of iterations in Anylogic is never reached, Anylogic stops at some random time and HL skyrockets though iterations, until the set maximum is reached (e.g Anylogic shows 122, HL shows 90100).
I tried to play around with the parameters of the algorithm, especially population size and max generations, to adjust that to the predefined iterations from Anylogic, but nothing is helping. Using the "regular" External Evaluation Problem (single-objective), the algorithm just stops at the number predefined iterations from Anylogic and works fine. So I guess it's some problem in the code of the programmable program.
All the best,
Lukas
using System;
using System.Linq;
using System.Collections.Generic;
using HeuristicLab.Collections;
using System.Threading;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.BinaryVectorEncoding;
using HeuristicLab.Encodings.IntegerVectorEncoding;
using HeuristicLab.Encodings.RealVectorEncoding;
using HeuristicLab.Encodings.PermutationEncoding;
using HeuristicLab.Encodings.LinearLinkageEncoding;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.Optimization;
using Google.ProtocolBuffers;
using HeuristicLab.Problems.Programmable;
using HeuristicLab.Problems.ExternalEvaluation;
namespace HeuristicLab.Problems.Programmable {
public class ExternalModulareMontageZweiterVersuch : CompiledProblemDefinition, ISingleObjectiveProblemDefinition {
public bool Maximization { get { return true; } }
public override void Initialize() {
var IntegerBounds = (IntMatrix)vars.IntegerBounds;
var IntegerLength = ((IntValue)vars.IntegerLength).Value;
var enc = new IntegerVectorEncoding("i", length: IntegerLength);
enc.Bounds = IntegerBounds;
Encoding = enc;
vars.cache = new EvaluationCache();
var clients = new CheckedItemCollection<IEvaluationServiceClient>();
var client = new EvaluationServiceClient();
client.ChannelParameter.Value = new EvaluationTCPChannel("127.0.0.1", 2112);
clients.Add(client);
vars.clients = clients;
vars.messageBuilder = new SolutionMessageBuilder();
// Add additional initialization code e.g. private variables that you need for evaluating
}
public double Evaluate(Individual individual, IRandom random) {
var solutionMessage = BuildSolutionMessage(individual);
var cache = (EvaluationCache)vars.cache;
return (cache == null
? EvaluateOnNextAvailableClient(solutionMessage)
: cache.GetValue(solutionMessage, EvaluateOnNextAvailableClient,
GetQualityMessageExtensions()))
.GetExtension(SingleObjectiveQualityMessage.QualityMessage_).Quality;
// Use vars.yourVariable to access variables in the variable store i.e. yourVariable
// var quality = 0.0;
//quality = individual.RealVector("r").Sum(x => x * x);
// return quality;
}
private HashSet<IEvaluationServiceClient> activeClients =
new HashSet<IEvaluationServiceClient>();
private object clientLock = new object();
public virtual ExtensionRegistry GetQualityMessageExtensions() {
var extensions = ExtensionRegistry.CreateInstance();
extensions.Add(SingleObjectiveQualityMessage.QualityMessage_);
return extensions;
}
private QualityMessage EvaluateOnNextAvailableClient(SolutionMessage message) {
var clients = (CheckedItemCollection<IEvaluationServiceClient>)vars.clients;
IEvaluationServiceClient client = null;
lock (clientLock) {
client = clients.CheckedItems.FirstOrDefault(c => !activeClients.Contains(c));
while (client == null && clients.CheckedItems.Any()) {
Monitor.Wait(clientLock);
client = clients.CheckedItems.FirstOrDefault(c => !activeClients.Contains(c));
}
if (client != null)
activeClients.Add(client);
}
try {
return client.Evaluate(message, GetQualityMessageExtensions());
} finally {
lock (clientLock) {
activeClients.Remove(client);
Monitor.PulseAll(clientLock);
}
}
}
private SolutionMessage BuildSolutionMessage(Individual individual,
int solutionId = 0) {
var messageBuilder = (SolutionMessageBuilder)vars.messageBuilder;
lock (clientLock) {
SolutionMessage.Builder protobufBuilder = SolutionMessage.CreateBuilder();
protobufBuilder.SolutionId = solutionId;
foreach (var variable in individual.Values) {
try {
messageBuilder.AddToMessage(variable.Value, variable.Key, protobufBuilder);
}
catch (ArgumentException ex) {
throw new InvalidOperationException(
string.Format(@"ERROR while building solution message:
Parameter {0} cannot be added to the message", variable.Key), ex);
}
}
return protobufBuilder.Build();
}
}
public void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
// Use vars.yourVariable to access variables in the variable store i.e. yourVariable
// Write or update results given the range of vectors and resulting qualities
// Uncomment the following lines if you want to retrieve the best individual
//var orderedIndividuals = individuals.Zip(qualities, (i, q) => new { Individual = i, Quality = q }).OrderBy(z => z.Quality);
//var best = Maximization ? orderedIndividuals.Last().Individual : orderedIndividuals.First().Individual;
//if (!results.ContainsKey("Best Solution")) {
// results.Add(new Result("Best Solution", typeof(RealVector)));
//}
//results["Best Solution"].Value = (IItem)best.RealVector("r").Clone();
}
public IEnumerable<Individual> GetNeighbors(Individual individual, IRandom random) {
// Use vars.yourVariable to access variables in the variable store i.e. yourVariable
// Create new vectors, based on the given one that represent small changes
// This method is only called from move-based algorithms (Local Search, Simulated Annealing, etc.)
// while (true) {
// Algorithm will draw only a finite amount of samples
// Change to a for-loop to return a concrete amount of neighbors
// var neighbor = individual.Copy();
// For instance, perform a single bit-flip in a binary parameter
//var bIndex = random.Next(neighbor.BinaryVector("b").Length);
//neighbor.BinaryVector("b")[bIndex] = !neighbor.BinaryVector("b")[bIndex];
// yield return neighbor;
yield break;
}
}
// Implement further classes and methods
}