using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using HeuristicLab.Collections; using HeuristicLab.Common; using HeuristicLab.Common.Resources; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.OKB.Client; using HeuristicLab.Optimization; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Persistence.Default.Xml; namespace HeuristicLab.OKB.AlgorithmHost { [Item("OKB Algorithm Host", "Load, run and submit values from and to the OKB")] [Creatable("Optimization Knowledge Base")] [StorableClass] public class AlgorithmHost : NamedItem, IAlgorithm { public override System.Drawing.Image ItemImage { get { if (ExecutionState == ExecutionState.Prepared) return VS2008ImageLibrary.ExecutablePrepared; else if (ExecutionState == ExecutionState.Started) return VS2008ImageLibrary.ExecutableStarted; else if (ExecutionState == ExecutionState.Paused) return VS2008ImageLibrary.ExecutablePaused; else if (ExecutionState == ExecutionState.Stopped) return VS2008ImageLibrary.ExecutableStopped; else return VS2008ImageLibrary.Event; } } [Storable] private IAlgorithm algorithm; public IAlgorithm Algorithm { get { return algorithm; } protected set { if (algorithm != value) { if (algorithm != null) DeregisterAlgorithmEvents(); algorithm = value; if (algorithm != null) { algorithm.Problem = problem; RegisterAlgorithmEvents(); } OnAlgorithmChanged(); Prepare(); } } } public event EventHandler AlgorithmChanged; #region constructors public AlgorithmHost() { name = ItemName; description = ItemDescription; executionState = ExecutionState.Stopped; executionTime = TimeSpan.Zero; Runs = new RunCollection(); } public AlgorithmHost(string name) : base(name) { description = ItemDescription; executionState = ExecutionState.Stopped; executionTime = TimeSpan.Zero; Runs = new RunCollection(); } public AlgorithmHost(string name, string description) : base(name, description) { executionState = ExecutionState.Stopped; executionTime = TimeSpan.Zero; Runs = new RunCollection(); } [StorableConstructor] private AlgorithmHost(bool deserializing) : base(deserializing) { } #endregion #region Persistence [StorableHook(HookType.AfterDeserialization)] private void Initialize() { if (algorithm != null) RegisterAlgorithmEvents(); if (runs != null) RegisterRunsEvents(); } public override IDeepCloneable Clone(Cloner cloner) { if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException("Clone not allowed while algorithm host is running"); AlgorithmHost clone = (AlgorithmHost)base.Clone(cloner); clone.executionState = executionState; clone.executionTime = executionTime; clone.algorithm = (IAlgorithm)cloner.Clone(algorithm); clone.runs = (RunCollection)cloner.Clone(runs); clone.Initialize(); return clone; } #endregion #region OKB connection public OKBRunner.StarterKit StarterKit { get; set; } public OKBRunner.StarterKit DownloadStarerKit() { OKBRunner.RunnerServiceClient client = ClientFactory.Create(); client.Login(Environment.MachineName); OKBRunner.StarterKit starterKit = client.GetStarterKit("HL 3.3"); client.Logout(); client.Close(); return starterKit; } private ObservableDictionary algorithmParameterMapping; private ObservableDictionary resultMapping; private OKBRunner.Algorithm okbAlgorithm; public OKBRunner.Algorithm OKBAlgorithm { get { return okbAlgorithm; } internal set { if (value == okbAlgorithm) return; LoadAlgorithm(value.Id); okbAlgorithm = value; } } private ObservableDictionary problemParameterMapping; private OKBRunner.Problem okbProblem; public OKBRunner.Problem OKBProblem { get { return okbProblem; } internal set { if (value == okbProblem) return; LoadProblem(value.Id); okbProblem = value; } } private void LoadAlgorithm(int id) { AlgorithmContainer algorithmContainer; using (var stream = new MemoryStream()) { Load(stream, OKBData.EntityType.Algorithm, id); stream.Seek(0, SeekOrigin.Begin); algorithmContainer = XmlParser.Deserialize(stream); } Algorithm = algorithmContainer.Algorithm; algorithmParameterMapping = algorithmContainer.ParameterMapping; resultMapping = algorithmContainer.ResultMapping; } private void LoadProblem(int id) { ProblemContainer problemContainer; using (var stream = new MemoryStream()) { Load(stream, OKBData.EntityType.Problem, id); stream.Seek(0, SeekOrigin.Begin); problemContainer = XmlParser.Deserialize(stream); } SetProblem(problemContainer.Problem, true); problemParameterMapping = problemContainer.ParameterMapping; } private void Load(Stream stream, OKBData.EntityType type, int id) { OKBData.DataServiceClient client = ClientFactory .Create(); int total = client.Request(type, id); for (int length = 1; length > 0; ) { byte[] buffer = client.GetNextChunk(100); stream.Write(buffer, 0, buffer.Length); length = buffer.Length; } stream.Flush(); } public OKBRunner.ExperimentKit PrepareSubmission(IRun run) { OKBRunner.ExperimentKit experimentKit = PrepareExperiment(); Debug.Assert(run.Algorithm.Name == Algorithm.Name, "run algorithm must match current algorithm"); Debug.Assert(run.Algorithm.Problem.Name == Problem.Name, "run problem must match current problem"); SetParameters(run, experimentKit); SetResults(run, experimentKit); return experimentKit; } public void SubmitRun(OKBRunner.ExperimentKit experimentKit) { var client = ClientFactory.Create(); client.Login(Environment.MachineName); client.AddRun(experimentKit.Algorithm, experimentKit.Problem, StarterKit.Projects.First()); client.Logout(); client.Close(); } public static string FormatSubmission(OKBRunner.ExperimentKit experimentKit) { StringBuilder sb = new StringBuilder(); sb.Append(experimentKit.Algorithm.Name).Append("@").AppendLine(experimentKit.Problem.Name); sb.AppendLine("Parameters:"); foreach (var p in experimentKit.Algorithm.Algorithm_Parameters.Select(ap => ap.Parameter)) { sb.Append(p.Name).Append(": "); if (p.IntParameterValues != null && p.IntParameterValues.Count > 0) sb.Append(p.IntParameterValues[0].Value).AppendLine(); else if (p.FloatParameterValues != null && p.FloatParameterValues.Count > 0) sb.Append(p.FloatParameterValues[0].Value).AppendLine(); else if (p.CharParameterValues != null && p.CharParameterValues.Count > 0) sb.AppendLine(p.CharParameterValues[0].Value); else if (p.OperatorParameterValues != null && p.OperatorParameterValues.Count > 0) sb.Append('<').Append(p.OperatorParameterValues[0].DataType.ClrName).AppendLine(">"); else sb.AppendLine("???"); } sb.AppendLine("Results:"); foreach (var r in experimentKit.Algorithm.Algorithm_Results.Select(ar => ar.Result)) { sb.Append(r.Name).Append(": "); if (r.IntResultValues != null && r.IntResultValues.Count > 0) { sb.Append(r.IntResultValues[0].Value).AppendLine(); } else if (r.FloatResultValues != null && r.FloatResultValues.Count > 0) { sb.Append(r.FloatResultValues[0].Value).AppendLine(); } else if (r.CharResultValues != null && r.CharResultValues.Count > 0) { sb.AppendLine(r.CharResultValues[0].Value); } else if (r.BlobResultValues != null && r.BlobResultValues.Count > 0) { sb.Append("byte[").Append(r.BlobResultValues[0].Value.Bytes.Length).AppendLine("]"); } else sb.AppendLine("???"); } return sb.ToString(); } private void SetResults(IRun run, OKBRunner.ExperimentKit experimentKit) { var results = experimentKit.Algorithm.Algorithm_Results.Select(ar => ar.Result).ToList(); experimentKit.Algorithm.Algorithm_Results.Clear(); foreach (var r in results) { if (resultMapping.ContainsValue(r.Name)) { var rm = resultMapping.Single(kvp => kvp.Value == r.Name); if (run.Results.ContainsKey(rm.Key)) experimentKit.Algorithm.AddResultValue(r.Name, run.Results[rm.Key]); } } } private void SetParameters(IRun run, OKBRunner.ExperimentKit experimentKit) { var algorithmParameters = experimentKit.Algorithm.Algorithm_Parameters.Select(ap => ap.Parameter).ToList(); var problemParameters = experimentKit.Problem.Problem_Parameters.Select(pp => pp.Parameter).ToList(); experimentKit.Algorithm.Algorithm_Parameters.Clear(); foreach (var p in algorithmParameters) { if (algorithmParameterMapping.ContainsValue(p.Name)) { var pm = algorithmParameterMapping.Single(kvp => kvp.Value == p.Name); if (run.Algorithm.Parameters.ContainsKey(pm.Key)) { experimentKit.Algorithm.AddParameterValue(p.Name, run.Algorithm.Parameters[pm.Key].ActualValue); } } } foreach (var p in problemParameters) { if (problemParameterMapping.ContainsValue(p.Name)) { var pm = problemParameterMapping.Single(kvp => kvp.Value == p.Name); if (run.Algorithm.Problem.Parameters.ContainsKey(pm.Key)) { experimentKit.Algorithm.AddParameterValue(p.Name, run.Algorithm.Problem.Parameters[pm.Key].ActualValue); } } } } private OKBRunner.ExperimentKit PrepareExperiment() { OKBRunner.RunnerServiceClient client = ClientFactory.Create(); client.Login(Environment.MachineName); OKBRunner.ExperimentKit experimentKit = client.PrepareExperiment(OKBAlgorithm, OKBProblem); client.Logout(); client.Close(); return experimentKit; } #endregion #region IAlgorithm Members public void CollectResultValues(IDictionary values) { if (algorithm != null) algorithm.CollectResultValues(values); } public bool HasOKBProblem { get; protected set; } private IProblem problem; public IProblem Problem { get { return problem; } set { SetProblem(value, false); } } protected void SetProblem(IProblem value, bool isOkbProblem) { HasOKBProblem = isOkbProblem; if (value == problem) return; problem = value; if (algorithm != null) algorithm.Problem = value; OnProblemChanged(); } public event EventHandler ProblemChanged; protected virtual void OnProblemChanged() { EventHandler handler = ProblemChanged; if (handler != null) handler(this, EventArgs.Empty); } public Type ProblemType { get { return algorithm != null ? algorithm.ProblemType : typeof(IProblem); } } public ResultCollection Results { get { return algorithm != null ? algorithm.Results : null; } } public bool StoreAlgorithmInEachRun { get { return algorithm.StoreAlgorithmInEachRun; } set { if (value != algorithm.StoreAlgorithmInEachRun) { algorithm.StoreAlgorithmInEachRun = value; OnStoreAlgorithmInEachRunChanged(); } } } public event EventHandler StoreAlgorithmInEachRunChanged; protected virtual void OnStoreAlgorithmInEachRunChanged() { EventHandler handler = StoreAlgorithmInEachRunChanged; if (handler != null) handler(this, EventArgs.Empty); } #endregion #region IParameterizedItem Members public void CollectParameterValues(IDictionary values) { if (algorithm != null) algorithm.CollectParameterValues(values); } public IKeyedItemCollection Parameters { get { return algorithm != null ? algorithm.Parameters : null; } } public IKeyedItemCollection ProblemParameters { get { return Problem != null ? Problem.Parameters : null; } } #endregion #region IOptimizer Members public void Prepare(bool clearRuns) { if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped)) throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState)); if (Algorithm != null) { if (clearRuns) runs.Clear(); Algorithm.Prepare(clearRuns); } } [Storable] private RunCollection runs; public RunCollection Runs { get { return runs; } private set { if (value == null) throw new ArgumentNullException(); if (runs != value) { if (runs != null) DeregisterRunsEvents(); runs = value; if (runs != null) RegisterRunsEvents(); } } } #endregion #region IExecutable Members public event EventHandler> ExceptionOccurred; [Storable] private ExecutionState executionState; public ExecutionState ExecutionState { get { return executionState; } private set { if (executionState != value) { executionState = value; OnExecutionStateChanged(); OnItemImageChanged(); } } } public event EventHandler ExecutionStateChanged; [Storable] private TimeSpan executionTime; public TimeSpan ExecutionTime { get { if ((Algorithm != null) && (Algorithm.ExecutionState != ExecutionState.Stopped)) return executionTime + Algorithm.ExecutionTime; else return executionTime; } private set { executionTime = value; OnExecutionTimeChanged(); } } public event EventHandler ExecutionTimeChanged; public void Pause() { if (ExecutionState != ExecutionState.Started) throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState)); if ((Algorithm != null) && (Algorithm.ExecutionState == ExecutionState.Started)) Algorithm.Pause(); } public event EventHandler Paused; public void Prepare() { Prepare(false); } public event EventHandler Prepared; public void Start() { if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused)) throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState)); if (Algorithm != null) Algorithm.Start(); } public event EventHandler Started; public void Stop() { if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused)) throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState)); if ((Algorithm != null) && ((Algorithm.ExecutionState == ExecutionState.Started) || (Algorithm.ExecutionState == ExecutionState.Paused))) Algorithm.Stop(); } public event EventHandler Stopped; #endregion #region events private void OnExecutionStateChanged() { EventHandler handler = ExecutionStateChanged; if (handler != null) handler(this, EventArgs.Empty); } private void OnExecutionTimeChanged() { EventHandler handler = ExecutionTimeChanged; if (handler != null) handler(this, EventArgs.Empty); } private void OnAlgorithmChanged() { EventHandler handler = AlgorithmChanged; if (handler != null) handler(this, EventArgs.Empty); } private void OnPrepared() { ExecutionState = ExecutionState.Prepared; EventHandler handler = Prepared; if (handler != null) handler(this, EventArgs.Empty); } private void OnStarted() { ExecutionState = ExecutionState.Started; EventHandler handler = Started; if (handler != null) handler(this, EventArgs.Empty); } private void OnPaused() { ExecutionState = ExecutionState.Paused; EventHandler handler = Paused; if (handler != null) handler(this, EventArgs.Empty); } private void OnStopped() { ExecutionState = ExecutionState.Stopped; EventHandler handler = Stopped; if (handler != null) handler(this, EventArgs.Empty); } private void OnExceptionOccurred(Exception exception) { EventHandler> handler = ExceptionOccurred; if (handler != null) handler(this, new EventArgs(exception)); } private void RegisterAlgorithmEvents() { algorithm.ExceptionOccurred += new EventHandler>(Algorithm_ExceptionOccurred); algorithm.ExecutionTimeChanged += new EventHandler(Algorithm_ExecutionTimeChanged); algorithm.Paused += new EventHandler(Algorithm_Paused); algorithm.Prepared += new EventHandler(Algorithm_Prepared); algorithm.Started += new EventHandler(Algorithm_Started); algorithm.Stopped += new EventHandler(Algorithm_Stopped); algorithm.Runs.CollectionReset += new CollectionItemsChangedEventHandler(Algorithm_Runs_CollectionReset); algorithm.Runs.ItemsAdded += new CollectionItemsChangedEventHandler(Algorithm_Runs_ItemsAdded); algorithm.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler(Algorithm_Runs_ItemsRemoved); algorithm.ProblemChanged += new EventHandler(Algorithm_ProblemChanged); } private void DeregisterAlgorithmEvents() { algorithm.ExceptionOccurred -= new EventHandler>(Algorithm_ExceptionOccurred); algorithm.ExecutionTimeChanged -= new EventHandler(Algorithm_ExecutionTimeChanged); algorithm.Paused -= new EventHandler(Algorithm_Paused); algorithm.Prepared -= new EventHandler(Algorithm_Prepared); algorithm.Started -= new EventHandler(Algorithm_Started); algorithm.Stopped -= new EventHandler(Algorithm_Stopped); algorithm.Runs.CollectionReset -= new CollectionItemsChangedEventHandler(Algorithm_Runs_CollectionReset); algorithm.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler(Algorithm_Runs_ItemsAdded); algorithm.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler(Algorithm_Runs_ItemsRemoved); algorithm.ProblemChanged -= new EventHandler(Algorithm_ProblemChanged); } private void Algorithm_ExceptionOccurred(object sender, EventArgs e) { OnExceptionOccurred(e.Value); } private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) { OnExecutionTimeChanged(); } private void Algorithm_Paused(object sender, EventArgs e) { OnPaused(); } private void Algorithm_Prepared(object sender, EventArgs e) { OnPrepared(); } private void Algorithm_Started(object sender, EventArgs e) { if (ExecutionState != ExecutionState.Started) OnStarted(); } private void Algorithm_Stopped(object sender, EventArgs e) { ExecutionTime = Algorithm.ExecutionTime; OnStopped(); } private void Algorithm_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs e) { Runs.RemoveRange(e.OldItems); Runs.AddRange(e.Items); } private void Algorithm_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs e) { Runs.AddRange(e.Items); } private void Algorithm_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs e) { Runs.RemoveRange(e.Items); } void Algorithm_ProblemChanged(object sender, EventArgs e) { if (Algorithm.Problem == Problem) return; Problem = Algorithm.Problem; } private void RegisterRunsEvents() { runs.CollectionReset += new CollectionItemsChangedEventHandler(Runs_CollectionReset); runs.ItemsRemoved += new CollectionItemsChangedEventHandler(Runs_ItemsRemoved); } private void DeregisterRunsEvents() { runs.CollectionReset -= new CollectionItemsChangedEventHandler(Runs_CollectionReset); runs.ItemsRemoved -= new CollectionItemsChangedEventHandler(Runs_ItemsRemoved); } private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs e) { foreach (IRun run in e.OldItems) { IItem item; run.Results.TryGetValue("Execution Time", out item); TimeSpanValue executionTime = item as TimeSpanValue; if (executionTime != null) ExecutionTime -= executionTime.Value; } if (Algorithm != null) Algorithm.Runs.RemoveRange(e.OldItems); foreach (IRun run in e.Items) { IItem item; run.Results.TryGetValue("Execution Time", out item); TimeSpanValue executionTime = item as TimeSpanValue; if (executionTime != null) ExecutionTime += executionTime.Value; } } private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs e) { foreach (IRun run in e.Items) { IItem item; run.Results.TryGetValue("Execution Time", out item); TimeSpanValue executionTime = item as TimeSpanValue; if (executionTime != null) ExecutionTime -= executionTime.Value; } if (Algorithm != null) Algorithm.Runs.RemoveRange(e.Items); } #endregion } }