[9215] | 1 | using System;
|
---|
| 2 | using System.Collections.Generic;
|
---|
| 3 | using System.Linq;
|
---|
| 4 | using System.Text;
|
---|
| 5 | using HeuristicLab.Services.Optimization.ControllerService.Model;
|
---|
| 6 | using Newtonsoft.Json.Linq;
|
---|
[9227] | 7 | using Newtonsoft.Json;
|
---|
[9215] | 8 |
|
---|
| 9 | namespace HeuristicLab.Services.Optimization.ControllerService.Parsers {
|
---|
| 10 | public static class AlgorithmConverter {
|
---|
[9305] | 11 | #region private methods
|
---|
| 12 | private static Parameter CreateParameter(JObject property) {
|
---|
| 13 | var name = (string)property["Name"];
|
---|
| 14 | var value = property["Value"];
|
---|
| 15 | switch (value.Type) {
|
---|
| 16 | case JTokenType.Integer:
|
---|
| 17 | case JTokenType.Float:
|
---|
| 18 | return new Parameter() { Type = ParameterType.Decimal, Value = new DecimalValue() { Name = name, Value = (double)value } };
|
---|
| 19 | case JTokenType.Boolean:
|
---|
| 20 | return new Parameter() { Type = ParameterType.Boolean, Value = new BoolValue() { Name = name, Value = (bool)value } };
|
---|
| 21 | case JTokenType.String:
|
---|
| 22 | return new Parameter() { Type = ParameterType.Type, Value = new TypeValue() { Name = name, Value = (string)value, Options = (from e in property["Options"] select (string)e).ToArray() } };
|
---|
| 23 | case JTokenType.Array:
|
---|
| 24 | var arr = (JArray)value;
|
---|
| 25 | // its a matrix
|
---|
| 26 | if (arr[0].Type == JTokenType.Array) {
|
---|
| 27 | return CreateMatrixParameter(name, arr);
|
---|
| 28 | }
|
---|
| 29 | return CreateVectorParameter(name, arr);
|
---|
| 30 | default:
|
---|
| 31 | throw new Exception("Unhandled datatype: " + property.Type);
|
---|
| 32 | }
|
---|
| 33 | }
|
---|
[9215] | 34 |
|
---|
[9305] | 35 | private static Parameter CreateMatrixParameter(string name, JArray arr) {
|
---|
| 36 | double[][] entries = new double[arr.Count][];
|
---|
| 37 | for (int i = 0; i < entries.Length; i++) {
|
---|
| 38 | entries[i] = (from d in arr[i] select (double)d).ToArray<double>();
|
---|
| 39 | }
|
---|
| 40 | return new Parameter { Type = ParameterType.DecimalMatrix, Value = new DecimalMatrix() { Name = name, Value = entries } };
|
---|
[9227] | 41 | }
|
---|
| 42 |
|
---|
[9305] | 43 | private static Parameter CreateVectorParameter(string name, JArray arr) {
|
---|
| 44 | double[] entries = (from d in arr select (double)d).ToArray<double>();
|
---|
| 45 | return new Parameter { Type = ParameterType.DecimalVector, Value = new DecimalVector() { Name = name, Value = entries } };
|
---|
| 46 | }
|
---|
| 47 |
|
---|
| 48 | private class StackEntry {
|
---|
| 49 | public Algorithm Parent { get; set; }
|
---|
| 50 | public JToken Child { get; set; }
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | private static JArray ConvertParametersToJson(IList<Parameter> parameters) {
|
---|
| 54 | var array = new JArray();
|
---|
| 55 | foreach (var param in parameters) {
|
---|
| 56 | array.Add(JObject.FromObject(param.Value));
|
---|
| 57 | }
|
---|
| 58 | return array;
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | private struct Entry {
|
---|
| 62 | public JObject TargetAlgorithm { get; set; }
|
---|
| 63 |
|
---|
| 64 | public Algorithm SourceAlgorithm { get; set; }
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | private static Algorithm ParseAlgorithm(JToken jsonAlgorithm) {
|
---|
[9215] | 68 | var algorithm = new Algorithm();
|
---|
[9227] | 69 |
|
---|
[9305] | 70 | foreach (JObject param in jsonAlgorithm["AlgorithmParameters"]) {
|
---|
[9215] | 71 | Parameter parameter = CreateParameter(param);
|
---|
| 72 | algorithm.Parameters.Items.Add(parameter);
|
---|
| 73 | }
|
---|
| 74 |
|
---|
[9305] | 75 | var problemParams = jsonAlgorithm["ProblemParameters"];
|
---|
[9215] | 76 | if (problemParams != null) {
|
---|
| 77 | algorithm.Problem = new Problem();
|
---|
[9305] | 78 | foreach (JObject param in problemParams) {
|
---|
[9215] | 79 | Parameter parameter = CreateParameter(param);
|
---|
| 80 | algorithm.Problem.Parameters.Items.Add(parameter);
|
---|
| 81 | }
|
---|
| 82 | }
|
---|
| 83 | return algorithm;
|
---|
| 84 | }
|
---|
[9305] | 85 | #endregion
|
---|
[9215] | 86 |
|
---|
| 87 |
|
---|
[9305] | 88 | #region public methods
|
---|
| 89 |
|
---|
| 90 |
|
---|
| 91 | public static JObject ConvertExperimentToJson(Experiment experiment) {
|
---|
| 92 | var exp = new JObject();
|
---|
| 93 | exp["title"] = experiment.Name;
|
---|
| 94 | exp["children"] = new JArray();
|
---|
| 95 | exp["nodeId"] = experiment.Id;
|
---|
| 96 | exp["isExperiment"] = true;
|
---|
| 97 |
|
---|
| 98 | var stack = new Stack<Entry>();
|
---|
| 99 | foreach (var algo in experiment.Algorithm)
|
---|
| 100 | stack.Push(new Entry() { TargetAlgorithm = exp, SourceAlgorithm = algo });
|
---|
| 101 |
|
---|
| 102 | while (stack.Count > 0) {
|
---|
| 103 | var entry = stack.Pop();
|
---|
| 104 | var algorithm = ConvertAlgorithmToJson(entry.SourceAlgorithm);
|
---|
| 105 | (entry.TargetAlgorithm["children"] as JArray).Add(algorithm);
|
---|
| 106 |
|
---|
| 107 | if (entry.SourceAlgorithm.ChildAlgorithms.Count > 0) {
|
---|
| 108 | // push children
|
---|
| 109 | foreach (var child in entry.SourceAlgorithm.ChildAlgorithms) {
|
---|
| 110 | stack.Push(new Entry() { TargetAlgorithm = algorithm, SourceAlgorithm = child });
|
---|
[9215] | 111 | }
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | }
|
---|
[9305] | 115 | return exp;
|
---|
[9215] | 116 | }
|
---|
[9227] | 117 |
|
---|
[9305] | 118 | public static JArray ConvertExperimentsToJson(IEnumerable<Experiment> experiments) {
|
---|
| 119 | var jarray = new JArray();
|
---|
| 120 | foreach (var exp in experiments)
|
---|
| 121 | jarray.Add(ConvertExperimentToJson(exp));
|
---|
| 122 | return jarray;
|
---|
[9227] | 123 | }
|
---|
| 124 |
|
---|
[9305] | 125 | public static JArray ConvertAlgorithmsToJson(IEnumerable<Algorithm> algorithms) {
|
---|
| 126 | var jarray = new JArray();
|
---|
| 127 | foreach (var algo in algorithms)
|
---|
| 128 | jarray.Add(ConvertAlgorithmToJson(algo));
|
---|
| 129 | return jarray;
|
---|
[9227] | 130 | }
|
---|
| 131 |
|
---|
| 132 |
|
---|
[9305] | 133 | public static JArray ConvertScenariosToJson(IEnumerable<OptimizationScenario> scenarios) {
|
---|
| 134 | var jarray = new JArray();
|
---|
| 135 | foreach (var scen in scenarios)
|
---|
| 136 | jarray.Add(ConvertScenarioToJson(scen));
|
---|
| 137 | return jarray;
|
---|
[9227] | 138 | }
|
---|
| 139 |
|
---|
[9305] | 140 | public static JObject ConvertScenarioToJson(OptimizationScenario scenario) {
|
---|
| 141 | var exp = new JObject();
|
---|
| 142 | exp["title"] = scenario.Id;
|
---|
| 143 | exp["children"] = new JArray();
|
---|
| 144 | exp["nodeId"] = scenario.Id;
|
---|
| 145 | exp["isExperiment"] = false;
|
---|
| 146 |
|
---|
| 147 | var stack = new Stack<Entry>();
|
---|
| 148 | var baseAlgorithm = ConvertAlgorithmToJson(scenario.FirstAlgorithm);
|
---|
| 149 | exp["data"] = baseAlgorithm["data"];
|
---|
| 150 | if (scenario.FirstAlgorithm.ChildAlgorithms.Count > 0) {
|
---|
| 151 | foreach (var child in scenario.FirstAlgorithm.ChildAlgorithms)
|
---|
| 152 | stack.Push(new Entry() { TargetAlgorithm = exp, SourceAlgorithm = child});
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | while (stack.Count > 0) {
|
---|
| 156 | var entry = stack.Pop();
|
---|
| 157 | var algorithm = ConvertAlgorithmToJson(entry.SourceAlgorithm);
|
---|
| 158 | (entry.TargetAlgorithm["children"] as JArray).Add(algorithm);
|
---|
| 159 |
|
---|
| 160 | if (entry.SourceAlgorithm.ChildAlgorithms.Count > 0) {
|
---|
| 161 | // push children
|
---|
| 162 | foreach (var child in entry.SourceAlgorithm.ChildAlgorithms) {
|
---|
| 163 | stack.Push(new Entry() { TargetAlgorithm = algorithm, SourceAlgorithm = child });
|
---|
| 164 | }
|
---|
| 165 | }
|
---|
| 166 |
|
---|
| 167 | }
|
---|
| 168 | return exp;
|
---|
[9227] | 169 | }
|
---|
| 170 |
|
---|
[9305] | 171 | public static JObject ConvertAlgorithmToJson(Algorithm algorithm) {
|
---|
| 172 | var jalgo = new JObject();
|
---|
| 173 | jalgo["title"] = algorithm.Name;
|
---|
| 174 | jalgo["nodeId"] = algorithm.Id;
|
---|
| 175 | var jalgoData = new JObject();
|
---|
| 176 | jalgo["data"] = jalgoData;
|
---|
| 177 | jalgo["isExperiment"] = algorithm.IsExperiment;
|
---|
| 178 | jalgoData["AlgorithmParameters"] = ConvertParametersToJson(algorithm.Parameters.Items);
|
---|
| 179 | if (algorithm.Problem != null && algorithm.Problem.Parameters != null)
|
---|
| 180 | jalgoData["ProblemParameters"] = ConvertParametersToJson(algorithm.Problem.Parameters.Items);
|
---|
| 181 |
|
---|
| 182 | jalgo["children"] = new JArray();
|
---|
| 183 | return jalgo;
|
---|
[9227] | 184 | }
|
---|
| 185 |
|
---|
[9324] | 186 | public static JObject ConvertRunToJson(Run run) {
|
---|
| 187 | var jrun = new JObject();
|
---|
| 188 | jrun["id"] = run.Id;
|
---|
| 189 | jrun["name"] = run.Name;
|
---|
| 190 | jrun["results"] = ConvertParametersToJson(run.Results);
|
---|
[9350] | 191 | jrun["params"] = ConvertParametersToJson(run.InputParameters);
|
---|
[9395] | 192 | jrun["algorithmName"] = run.AlgorithmName;
|
---|
[9324] | 193 | return jrun;
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | public static JArray ConvertRunsToJson(IList<Run> runs) {
|
---|
| 197 | var jarray = new JArray();
|
---|
| 198 | foreach (var run in runs)
|
---|
| 199 | jarray.Add(ConvertRunToJson(run));
|
---|
[9350] | 200 |
|
---|
| 201 |
|
---|
| 202 | // if there are multiple different jobs to execute and they have the same id, we must change it here manually
|
---|
| 203 | var maxId = new Dictionary<string,int>();
|
---|
| 204 | for (int i = 0; i < jarray.Count; i++) {
|
---|
| 205 | for (int j = i + 1; j < jarray.Count; j++) {
|
---|
| 206 | if (jarray[i]["id"].ToString() == jarray[j]["id"].ToString()) {
|
---|
| 207 | int max;
|
---|
| 208 | if (!maxId.TryGetValue(jarray[i]["id"].ToString(), out max)) {
|
---|
| 209 | max = 1;
|
---|
| 210 | maxId[jarray[i]["id"].ToString()] = max;
|
---|
| 211 | }
|
---|
| 212 | maxId[jarray[i]["id"].ToString()]++;
|
---|
| 213 | // change j's entry
|
---|
| 214 | jarray[j]["id"] = jarray[j]["id"].ToString() + " (" + max + ")";
|
---|
| 215 | jarray[j]["name"] = jarray[j]["name"] + " (" + max + ")";
|
---|
| 216 | }
|
---|
| 217 | }
|
---|
| 218 | }
|
---|
[9324] | 219 | return jarray;
|
---|
| 220 | }
|
---|
| 221 |
|
---|
[9305] | 222 | public static Experiment ConvertJsonToExperiment(string json) {
|
---|
[9227] | 223 | var experiment = new Experiment();
|
---|
| 224 | var jsonExperiment = JObject.Parse(json);
|
---|
[9305] | 225 | experiment.Name = (string)jsonExperiment["title"];
|
---|
| 226 | experiment.Id = (string)jsonExperiment["nodeId"];
|
---|
[9227] | 227 | var stack = new Stack<StackEntry>();
|
---|
| 228 | var root = new Algorithm();
|
---|
| 229 |
|
---|
[9305] | 230 | if (jsonExperiment["run"] != null && (bool)jsonExperiment["run"]) {
|
---|
[9227] | 231 | experiment.JobDetails = new JobExecutionDetails() {
|
---|
[9305] | 232 | Group = (string)jsonExperiment["group"],
|
---|
| 233 | Repititions = (int)jsonExperiment["repititions"]
|
---|
[9227] | 234 | };
|
---|
| 235 | }
|
---|
| 236 |
|
---|
[9305] | 237 | // ignore experiment node, skip to its children
|
---|
| 238 | if (jsonExperiment["experiment"] != null)
|
---|
| 239 | foreach (var algo in jsonExperiment["experiment"]["children"]) {
|
---|
| 240 | stack.Push(new StackEntry() { Parent = root, Child = algo });
|
---|
| 241 | }
|
---|
[9227] | 242 |
|
---|
[9305] | 243 | if (jsonExperiment["children"] != null)
|
---|
| 244 | foreach (var algo in jsonExperiment["children"]) {
|
---|
| 245 | stack.Push(new StackEntry() { Parent = root, Child = algo });
|
---|
| 246 | }
|
---|
| 247 |
|
---|
[9227] | 248 | while (stack.Count > 0) {
|
---|
| 249 | var entry = stack.Pop();
|
---|
| 250 | var data = entry.Child["data"];
|
---|
[9305] | 251 | var currentAlgo = data == null || !data.HasValues ? new Algorithm() : ParseAlgorithm(entry.Child["data"]);
|
---|
| 252 | currentAlgo.Name = (string)entry.Child["title"];
|
---|
| 253 | currentAlgo.Id = (string)entry.Child["nodeId"];
|
---|
| 254 | currentAlgo.IsExperiment = (bool)entry.Child["isExperiment"];
|
---|
[9227] | 255 | entry.Parent.ChildAlgorithms.Add(currentAlgo);
|
---|
| 256 | // push children on stack (inverse order to preserve ordering)
|
---|
| 257 | var cnt = entry.Child["children"].Count();
|
---|
[9305] | 258 | for (var i = 0; i < cnt; i++) {
|
---|
[9227] | 259 | stack.Push(new StackEntry() { Parent = currentAlgo, Child = entry.Child["children"][cnt - 1 - i] });
|
---|
| 260 | }
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 | foreach (var algo in root.ChildAlgorithms) {
|
---|
| 264 | experiment.Algorithm.Add(algo);
|
---|
| 265 | }
|
---|
| 266 |
|
---|
| 267 | return experiment;
|
---|
| 268 | }
|
---|
[9305] | 269 | #endregion
|
---|
[9215] | 270 | }
|
---|
| 271 | }
|
---|