source: branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/JsonTemplateInstantiator.cs @ 18050

Last change on this file since 18050 was 18050, checked in by dpiringe, 11 months ago

#3026

  • added a new protected virtual property in CheckedItemListView to be able to change the text of the groupBox
  • removed event handling in ResultCollectionPostProcessorControl and overwrote the new property GroupBoxText
  • added a new section in ExportJsonDialog for result collection processors
  • renamed IResultCollectionPostProcessor to IResultCollectionProcessor + all connected classes
  • added/changed the workflow of ResultCollectionProcessors in JsonTemplateGenerator and JsonTemplateInstantiator
    • also changed Constants.cs -> added a new section in template ResultCollectionProcessorItems
File size: 7.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text.RegularExpressions;
6using HEAL.Attic;
7using HeuristicLab.Optimization;
8using HeuristicLab.PluginInfrastructure;
9using Newtonsoft.Json.Linq;
10
11namespace HeuristicLab.JsonInterface {
12  public readonly struct InstantiatorResult {
13    public InstantiatorResult(IOptimizer optimizer, IEnumerable<IResultJsonItem> configuredResultItems) {
14      Optimizer = optimizer;
15      ConfiguredResultItems = configuredResultItems;
16      PostProcessors = Enumerable.Empty<IResultCollectionProcessor>();
17    }
18
19    public InstantiatorResult(IOptimizer optimizer, IEnumerable<IResultJsonItem> configuredResultItems, IEnumerable<IResultCollectionProcessor> postProcessors) {
20      Optimizer = optimizer;
21      ConfiguredResultItems = configuredResultItems;
22      PostProcessors = postProcessors;
23    }
24
25    public IOptimizer Optimizer { get; }
26    public IEnumerable<IResultJsonItem> ConfiguredResultItems { get; }
27    public IEnumerable<IResultCollectionProcessor> PostProcessors { get; }
28  }
29
30
31  /// <summary>
32  /// Class to instantiate an IAlgorithm object with a json interface template and config.
33  /// </summary>
34  public class JsonTemplateInstantiator {
35
36    #region Constants
37    private const string RelativePathCurrentDirectoryRegex = @"^(\.)";
38    #endregion
39
40    #region Private Properties
41    private JToken Template { get; set; }
42    private JArray Config { get; set; }
43    private IDictionary<string, IJsonItem> Objects { get; set; } = new Dictionary<string, IJsonItem>();
44    #endregion
45
46    /// <summary>
47    /// Instantiate an IAlgorithm object with a template and config.
48    /// </summary>
49    /// <param name="templateFile">Template file (json), generated with JCGenerator.</param>
50    /// <param name="configFile">Config file (json) for the template.</param>
51    /// <returns>confugrated IOptimizer object</returns>
52    public static InstantiatorResult Instantiate(string templateFile, string configFile = null) {
53      JsonTemplateInstantiator instantiator = new JsonTemplateInstantiator();
54      return instantiator.ExecuteInstantiaton(templateFile, configFile);
55    }
56
57    #region Helper
58    private InstantiatorResult ExecuteInstantiaton(string templateFile, string configFile = null) {
59
60      #region Parse Files
61      string templateFileFullPath = Path.GetFullPath(templateFile);
62      Template = JToken.Parse(File.ReadAllText(templateFile));
63      if(!string.IsNullOrEmpty(configFile))
64        Config = JArray.Parse(File.ReadAllText(Path.GetFullPath(configFile)));
65      #endregion
66
67      #region Deserialize HL File
68      // extract metadata information
69      string relativePath = Template[Constants.Metadata][Constants.HLFileLocation].ToString().Trim(); // get relative path
70      // convert to absolute path
71      if (Regex.IsMatch(relativePath, RelativePathCurrentDirectoryRegex))
72        relativePath = relativePath.Remove(0, 2); // remove first 2 chars -> indicates the current directory
73
74      string hLFileLocation = Path.Combine(Path.GetDirectoryName(templateFileFullPath), relativePath);
75      ProtoBufSerializer serializer = new ProtoBufSerializer();
76      IOptimizer optimizer = (IOptimizer)serializer.Deserialize(hLFileLocation);
77      #endregion
78
79      // collect all parameterizedItems from template
80      CollectParameterizedItems(optimizer);
81     
82      if (Config != null)
83        MergeTemplateWithConfig();
84
85      // get algorithm root item
86      IJsonItem rootItem = Objects.First().Value;
87
88      // validation
89      ValidationResult validationResult = rootItem.GetValidator().Validate();
90      if (!validationResult.Success)
91        throw validationResult.GenerateException();
92
93      // inject configuration
94      JsonItemConverter.Inject(optimizer, rootItem);
95
96      return new InstantiatorResult(optimizer, CollectResults(), CollectResultCollectionProcessors());
97    }
98
99    /// <summary>
100    /// Instantiates all defined (in template) ResultCollectionProcessors and injects the configured parameters.
101    /// </summary>
102    private IEnumerable<IResultCollectionProcessor> CollectResultCollectionProcessors() {
103      IList<IResultCollectionProcessor> postProcessorList = new List<IResultCollectionProcessor>();
104      foreach (JObject obj in Template[Constants.ResultCollectionProcessorItems]) {
105        var guid = obj["GUID"].ToString();
106        var parameters = obj[Constants.Parameters];
107        var type = Mapper.StaticCache.GetType(new Guid(guid));
108        var rcp = (IResultCollectionProcessor)Activator.CreateInstance(type);
109        var rcpItem = JsonItemConverter.Extract(rcp);
110
111        foreach (JObject param in parameters) {
112          var path = param[nameof(IJsonItem.Path)].ToString();
113          foreach (var item in rcpItem)
114            if (item.Path == path)
115              item.SetJObject(param);
116        }
117
118        JsonItemConverter.Inject(rcp, rcpItem);
119        postProcessorList.Add(rcp);
120      }
121      return postProcessorList;
122    }
123
124    private IEnumerable<IResultJsonItem> CollectResults() {
125      IList<IResultJsonItem> res = new List<IResultJsonItem>();
126      foreach(JObject obj in Template[Constants.Results]) {
127        var resultItem = new ResultJsonItem();
128        resultItem.SetJObject(obj);
129        res.Add(resultItem);
130      }
131      return res;
132    }
133
134    private void CollectParameterizedItems(IOptimizer optimizer) {
135      IJsonItem root = JsonItemConverter.Extract(optimizer);
136      Objects.Add(root.Path, root);
137
138      foreach (JObject obj in Template[Constants.Parameters]) {
139        string path = obj.Property(nameof(IJsonItem.Path)).Value.ToString();
140        foreach(var tmp in root) {
141          if(tmp.Path == path) {
142            tmp.SetJObject(obj);
143            Objects.Add(tmp.Path, tmp);
144          }
145        }
146      }
147    }
148   
149    private void MergeTemplateWithConfig() {
150      foreach (JObject obj in Config) {
151        // build item from config object
152        var prop = obj.Property("Path");
153        if (prop == null)
154          throw new ArgumentException("Path property is missing.");
155        string path = prop.Value.ToString();
156        // override default value
157        if (Objects.TryGetValue(path, out IJsonItem param)) {
158          // remove fixed template parameter from config => dont allow to copy them from concrete config
159          // TODO: shift this into JsonItems?
160          obj.Property(nameof(IIntervalRestrictedJsonItem<int>.Minimum))?.Remove();
161          obj.Property(nameof(IIntervalRestrictedJsonItem<int>.Maximum))?.Remove();
162          obj.Property(nameof(IConcreteRestrictedJsonItem<string>.ConcreteRestrictedItems))?.Remove();
163          obj.Property(nameof(IMatrixJsonItem.ColumnsResizable))?.Remove();
164          obj.Property(nameof(IMatrixJsonItem.RowsResizable))?.Remove();
165          obj.Property(nameof(IArrayJsonItem.Resizable))?.Remove();
166          // merge
167          param.SetJObject(obj);
168        } else throw new InvalidDataException($"No parameter with path='{path}' defined!");
169      }
170    }
171    #endregion
172  }
173}
Note: See TracBrowser for help on using the repository browser.