using System; using System.Collections.Generic; using System.Linq; using System.Text; using HeuristicLab.Services.Optimization.ControllerService.Model; using Newtonsoft.Json.Linq; using Newtonsoft.Json; namespace HeuristicLab.Services.Optimization.ControllerService.Parsers { public static class AlgorithmConverter { #region private methods private static Parameter CreateParameter(JObject property) { var name = (string)property["Name"]; var value = property["Value"]; switch (value.Type) { case JTokenType.Integer: case JTokenType.Float: return new Parameter() { Type = ParameterType.Decimal, Value = new DecimalValue() { Name = name, Value = (double)value } }; case JTokenType.Boolean: return new Parameter() { Type = ParameterType.Boolean, Value = new BoolValue() { Name = name, Value = (bool)value } }; case JTokenType.String: return new Parameter() { Type = ParameterType.Type, Value = new TypeValue() { Name = name, Value = (string)value, Options = (from e in property["Options"] select (string)e).ToArray() } }; case JTokenType.Array: var arr = (JArray)value; // its a matrix if (arr[0].Type == JTokenType.Array) { return CreateMatrixParameter(name, arr); } return CreateVectorParameter(name, arr); default: throw new Exception("Unhandled datatype: " + property.Type); } } private static Parameter CreateMatrixParameter(string name, JArray arr) { double[][] entries = new double[arr.Count][]; for (int i = 0; i < entries.Length; i++) { entries[i] = (from d in arr[i] select (double)d).ToArray(); } return new Parameter { Type = ParameterType.DecimalMatrix, Value = new DecimalMatrix() { Name = name, Value = entries } }; } private static Parameter CreateVectorParameter(string name, JArray arr) { double[] entries = (from d in arr select (double)d).ToArray(); return new Parameter { Type = ParameterType.DecimalVector, Value = new DecimalVector() { Name = name, Value = entries } }; } private class StackEntry { public Algorithm Parent { get; set; } public JToken Child { get; set; } } private static JArray ConvertParametersToJson(IList parameters) { var array = new JArray(); foreach (var param in parameters) { array.Add(JObject.FromObject(param.Value)); } return array; } private struct Entry { public JObject TargetAlgorithm { get; set; } public Algorithm SourceAlgorithm { get; set; } } private static Algorithm ParseAlgorithm(JToken jsonAlgorithm) { var algorithm = new Algorithm(); foreach (JObject param in jsonAlgorithm["AlgorithmParameters"]) { Parameter parameter = CreateParameter(param); algorithm.Parameters.Items.Add(parameter); } var problemParams = jsonAlgorithm["ProblemParameters"]; if (problemParams != null) { algorithm.Problem = new Problem(); foreach (JObject param in problemParams) { Parameter parameter = CreateParameter(param); algorithm.Problem.Parameters.Items.Add(parameter); } } return algorithm; } #endregion #region public methods public static JObject ConvertExperimentToJson(Experiment experiment) { var exp = new JObject(); exp["title"] = experiment.Name; exp["children"] = new JArray(); exp["nodeId"] = experiment.Id; exp["isExperiment"] = true; var stack = new Stack(); foreach (var algo in experiment.Algorithm) stack.Push(new Entry() { TargetAlgorithm = exp, SourceAlgorithm = algo }); while (stack.Count > 0) { var entry = stack.Pop(); var algorithm = ConvertAlgorithmToJson(entry.SourceAlgorithm); (entry.TargetAlgorithm["children"] as JArray).Add(algorithm); if (entry.SourceAlgorithm.ChildAlgorithms.Count > 0) { // push children foreach (var child in entry.SourceAlgorithm.ChildAlgorithms) { stack.Push(new Entry() { TargetAlgorithm = algorithm, SourceAlgorithm = child }); } } } return exp; } public static JArray ConvertExperimentsToJson(IEnumerable experiments) { var jarray = new JArray(); foreach (var exp in experiments) jarray.Add(ConvertExperimentToJson(exp)); return jarray; } public static JArray ConvertAlgorithmsToJson(IEnumerable algorithms) { var jarray = new JArray(); foreach (var algo in algorithms) jarray.Add(ConvertAlgorithmToJson(algo)); return jarray; } public static JArray ConvertScenariosToJson(IEnumerable scenarios) { var jarray = new JArray(); foreach (var scen in scenarios) jarray.Add(ConvertScenarioToJson(scen)); return jarray; } public static JObject ConvertScenarioToJson(OptimizationScenario scenario) { var exp = new JObject(); exp["title"] = scenario.Id; exp["children"] = new JArray(); exp["nodeId"] = scenario.Id; exp["isExperiment"] = false; var stack = new Stack(); var baseAlgorithm = ConvertAlgorithmToJson(scenario.FirstAlgorithm); exp["data"] = baseAlgorithm["data"]; if (scenario.FirstAlgorithm.ChildAlgorithms.Count > 0) { foreach (var child in scenario.FirstAlgorithm.ChildAlgorithms) stack.Push(new Entry() { TargetAlgorithm = exp, SourceAlgorithm = child}); } while (stack.Count > 0) { var entry = stack.Pop(); var algorithm = ConvertAlgorithmToJson(entry.SourceAlgorithm); (entry.TargetAlgorithm["children"] as JArray).Add(algorithm); if (entry.SourceAlgorithm.ChildAlgorithms.Count > 0) { // push children foreach (var child in entry.SourceAlgorithm.ChildAlgorithms) { stack.Push(new Entry() { TargetAlgorithm = algorithm, SourceAlgorithm = child }); } } } return exp; } public static JObject ConvertAlgorithmToJson(Algorithm algorithm) { var jalgo = new JObject(); jalgo["title"] = algorithm.Name; jalgo["nodeId"] = algorithm.Id; var jalgoData = new JObject(); jalgo["data"] = jalgoData; jalgo["isExperiment"] = algorithm.IsExperiment; jalgoData["AlgorithmParameters"] = ConvertParametersToJson(algorithm.Parameters.Items); if (algorithm.Problem != null && algorithm.Problem.Parameters != null) jalgoData["ProblemParameters"] = ConvertParametersToJson(algorithm.Problem.Parameters.Items); jalgo["children"] = new JArray(); return jalgo; } public static JObject ConvertRunToJson(Run run) { var jrun = new JObject(); jrun["id"] = run.Id; jrun["name"] = run.Name; jrun["results"] = ConvertParametersToJson(run.Results); jrun["params"] = ConvertParametersToJson(run.InputParameters); jrun["algorithmName"] = run.AlgorithmName; return jrun; } public static JArray ConvertRunsToJson(IList runs) { var jarray = new JArray(); foreach (var run in runs) jarray.Add(ConvertRunToJson(run)); // if there are multiple different jobs to execute and they have the same id, we must change it here manually var maxId = new Dictionary(); for (int i = 0; i < jarray.Count; i++) { for (int j = i + 1; j < jarray.Count; j++) { if (jarray[i]["id"].ToString() == jarray[j]["id"].ToString()) { int max; if (!maxId.TryGetValue(jarray[i]["id"].ToString(), out max)) { max = 1; maxId[jarray[i]["id"].ToString()] = max; } maxId[jarray[i]["id"].ToString()]++; // change j's entry jarray[j]["id"] = jarray[j]["id"].ToString() + " (" + max + ")"; jarray[j]["name"] = jarray[j]["name"] + " (" + max + ")"; } } } return jarray; } public static Experiment ConvertJsonToExperiment(string json) { var experiment = new Experiment(); var jsonExperiment = JObject.Parse(json); experiment.Name = (string)jsonExperiment["title"]; experiment.Id = (string)jsonExperiment["nodeId"]; var stack = new Stack(); var root = new Algorithm(); if (jsonExperiment["run"] != null && (bool)jsonExperiment["run"]) { experiment.JobDetails = new JobExecutionDetails() { Group = (string)jsonExperiment["group"], Repititions = (int)jsonExperiment["repititions"] }; } // ignore experiment node, skip to its children if (jsonExperiment["experiment"] != null) foreach (var algo in jsonExperiment["experiment"]["children"]) { stack.Push(new StackEntry() { Parent = root, Child = algo }); } if (jsonExperiment["children"] != null) foreach (var algo in jsonExperiment["children"]) { stack.Push(new StackEntry() { Parent = root, Child = algo }); } while (stack.Count > 0) { var entry = stack.Pop(); var data = entry.Child["data"]; var currentAlgo = data == null || !data.HasValues ? new Algorithm() : ParseAlgorithm(entry.Child["data"]); currentAlgo.Name = (string)entry.Child["title"]; currentAlgo.Id = (string)entry.Child["nodeId"]; currentAlgo.IsExperiment = (bool)entry.Child["isExperiment"]; entry.Parent.ChildAlgorithms.Add(currentAlgo); // push children on stack (inverse order to preserve ordering) var cnt = entry.Child["children"].Count(); for (var i = 0; i < cnt; i++) { stack.Push(new StackEntry() { Parent = currentAlgo, Child = entry.Child["children"][cnt - 1 - i] }); } } foreach (var algo in root.ChildAlgorithms) { experiment.Algorithm.Add(algo); } return experiment; } #endregion } }