Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/JCInstantiator.cs @ 17349

Last change on this file since 17349 was 17349, checked in by dpiringe, 4 years ago

#3026

  • added ConvertableAttribute, a new attribute for classes/structs (usage: convertable with JsonInterface)
  • changed JCGenerator -> is now a static class with one public static method Instantiate
  • changed JCInstantiator -> is now a static class with one public static method GenerateTemplate
  • refactored JsonItem
File size: 7.6 KB
Line 
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.IO;
5using System.Linq;
6using System.Reflection;
7using System.Text;
8using System.Threading.Tasks;
9using HeuristicLab.Core;
10using HeuristicLab.Data;
11using HeuristicLab.Optimization;
12using HeuristicLab.SequentialEngine;
13using Newtonsoft.Json.Linq;
14
15namespace HeuristicLab.JsonInterface {
16  public static class JCInstantiator {
17    private struct InstData {
18      public JToken Template { get; set; }
19      public JArray Config { get; set; }
20      public Dictionary<string, string> TypeList { get; set; }
21      public IDictionary<string, JsonItem> ParameterizedItems { get; set; }
22      public IDictionary<string, JsonItem> ConfigurableItems { get; set; }
23    }
24
25    public static IAlgorithm Instantiate(string templateFile, string configFile = "") {
26      InstData instData = new InstData() {
27        TypeList = new Dictionary<string, string>(),
28        ParameterizedItems = new Dictionary<string, JsonItem>(),
29        ConfigurableItems = new Dictionary<string, JsonItem>()
30      };
31
32      //1. Parse Template and Config files
33      instData.Template = JToken.Parse(File.ReadAllText(templateFile));
34      if(!string.IsNullOrEmpty(configFile))
35        instData.Config = JArray.Parse(File.ReadAllText(configFile));
36      instData.TypeList = instData.Template[Constants.Types].ToObject<Dictionary<string, string>>();
37      string algorithmName = instData.Template[Constants.Metadata][Constants.Algorithm].ToString();
38      string problemName = instData.Template[Constants.Metadata][Constants.Problem].ToString();
39
40      //2. Collect all parameterizedItems from template
41      CollectParameterizedItems(instData);
42
43      //3. select all ConfigurableItems
44      SelectConfigurableItems(instData);
45
46      //4. if config != null -> merge Template and Config
47      if (instData.Config != null)
48        MergeTemplateWithConfig(instData);
49
50      //5. resolve the references between parameterizedItems
51      ResolveReferences(instData);
52
53      //6. get algorthm data and object
54      JsonItem algorithmData = GetData(algorithmName, instData);
55      IAlgorithm algorithm = CreateObject<IAlgorithm>(algorithmData, instData);
56
57      //7. get problem data and object
58      JsonItem problemData = GetData(problemName, instData);
59      IProblem problem = CreateObject<IProblem>(problemData, instData);
60      algorithm.Problem = problem;
61
62      //8. inject configuration
63      JsonItemConverter.Inject(algorithm, algorithmData);
64      JsonItemConverter.Inject(problem, problemData);
65
66      // TODO: let the engine be configurable
67      if (algorithm is EngineAlgorithm)
68        algorithm.Cast<EngineAlgorithm>().Engine = new SequentialEngine.SequentialEngine();
69
70      return algorithm;
71    }
72
73    #region Helper
74    private static void CollectParameterizedItems(InstData instData) {
75      foreach (JObject item in instData.Template[Constants.Objects]) {
76        JsonItem data = BuildJsonItem(item, instData);
77        instData.ParameterizedItems.Add(data.Path, data);
78      }
79    }
80
81    private static void SelectConfigurableItems(InstData instData) {
82      foreach (var item in instData.ParameterizedItems.Values) {
83        if (item.Parameters != null)
84          AddConfigurableItems(item.Parameters, instData);
85
86        if (item.Operators != null)
87          AddConfigurableItems(item.Operators, instData);
88      }
89    }
90
91    private static void AddConfigurableItems(IEnumerable<JsonItem> items, InstData instData) {
92      foreach (var item in items)
93        if (item.IsConfigurable)
94          instData.ConfigurableItems.Add(item.Path, item);
95    }
96
97    private static void ResolveReferences(InstData instData) {
98      foreach(var x in instData.ParameterizedItems.Values)
99        foreach (var p in x.Parameters)
100          if (p.Value is string) {
101            string key = p.Path;
102            if (p.Range != null)
103              key = $"{p.Path}.{p.Value.Cast<string>()}";
104
105            if (instData.ParameterizedItems.TryGetValue(key, out JsonItem value))
106              p.Reference = value;
107          }
108    }
109
110    private static void MergeTemplateWithConfig(InstData instData) {
111      foreach (JObject obj in instData.Config) {
112        // build item from config object
113        JsonItem item = BuildJsonItem(obj, instData);
114        // override default value
115        if (instData.ConfigurableItems.TryGetValue(item.Path, out JsonItem param)) {
116          param.Value = item.Value;
117          // override ActualName (for LookupParameters)
118          if (param.ActualName != null)
119            param.ActualName = item.ActualName;
120        } else throw new InvalidDataException($"No {Constants.FreeParameters.Trim('s')} with path='{item.Path}' defined!");
121      }
122    }
123
124    private static JsonItem GetData(string key, InstData instData)
125    {
126      if (instData.ParameterizedItems.TryGetValue(key, out JsonItem value))
127        return value;
128      else
129        throw new InvalidDataException($"Type of item '{key}' is not defined!");
130    }
131
132    private static T CreateObject<T>(JsonItem data, InstData instData) {
133      if (instData.TypeList.TryGetValue(data.Name, out string typeName)) {
134        Type type = Type.GetType(typeName);
135        return (T)Activator.CreateInstance(type);
136      } else throw new TypeLoadException($"Cannot find AssemblyQualifiedName for {data.Name}.");
137    }
138
139    #region BuildJsonItemMethods
140    private static JsonItem BuildJsonItem(JObject obj, InstData instData) =>
141      new JsonItem() {
142        Name = obj[nameof(JsonItem.Name)]?.ToString(),
143        Path = obj[nameof(JsonItem.Path)]?.ToString(),
144        Value = obj[nameof(JsonItem.Value)]?.ToObject<object>(),
145        Range = obj[nameof(JsonItem.Range)]?.ToObject<object[]>(),
146        Type = GetType(obj[nameof(JsonItem.Path)]?.ToObject<string>(), instData),
147        ActualName = obj[nameof(JsonItem.ActualName)]?.ToString(),
148        Parameters = PopulateParameters(obj, instData),
149        Operators = PopulateOperators(obj, instData)
150      };
151
152    private static string GetType(string path, InstData instData) {
153      if(!string.IsNullOrEmpty(path))
154        if (instData.TypeList.TryGetValue(path, out string value))
155          return value;
156      return null;
157    }
158
159    private static IList<JsonItem> PopulateParameters(JObject obj, InstData instData) {
160      IList<JsonItem> list = new List<JsonItem>();
161
162      // add staticParameters
163      if (obj[Constants.StaticParameters] != null)
164        foreach (JObject param in obj[Constants.StaticParameters])
165          list.Add(BuildJsonItem(param, instData));
166
167      // merge staticParameter with freeParameter
168      if (obj[Constants.FreeParameters] != null) {
169        foreach (JObject param in obj[Constants.FreeParameters]) {
170          JsonItem tmp = BuildJsonItem(param, instData);
171         
172          // search staticParameter from list
173          JsonItem comp = null;
174          foreach (var p in list)
175            if (p.Name == tmp.Name) comp = p;
176          if (comp == null)
177            throw new InvalidDataException($"Invalid {Constants.FreeParameters.Trim('s')}: '{tmp.Name}'!");
178
179          JsonItem.Merge(comp, tmp);
180        }
181      }
182      return list;
183    }
184
185    private static IList<JsonItem> PopulateOperators(JObject obj, InstData instData) {
186      IList<JsonItem> list = new List<JsonItem>();
187      JToken operators = obj[nameof(JsonItem.Operators)];
188      if (operators != null)
189        foreach (JObject sp in operators)
190          list.Add(BuildJsonItem(sp, instData));
191      return list;
192    }
193    #endregion
194    #endregion
195  }
196}
Note: See TracBrowser for help on using the repository browser.