[17828] | 1 | using System;
|
---|
| 2 | using System.Collections.Generic;
|
---|
[17263] | 3 | using System.IO;
|
---|
| 4 | using System.Linq;
|
---|
[18030] | 5 | using System.Text.RegularExpressions;
|
---|
[17379] | 6 | using HEAL.Attic;
|
---|
[17263] | 7 | using HeuristicLab.Optimization;
|
---|
[18046] | 8 | using HeuristicLab.PluginInfrastructure;
|
---|
[17263] | 9 | using Newtonsoft.Json.Linq;
|
---|
| 10 |
|
---|
[17284] | 11 | namespace HeuristicLab.JsonInterface {
|
---|
[17481] | 12 | public readonly struct InstantiatorResult {
|
---|
| 13 |
|
---|
[18059] | 14 | public InstantiatorResult(IOptimizer optimizer, IEnumerable<IRunCollectionModifier> runCollectionModifiers) {
|
---|
[18046] | 15 | Optimizer = optimizer;
|
---|
[18055] | 16 | RunCollectionModifiers = runCollectionModifiers;
|
---|
[18046] | 17 | }
|
---|
| 18 |
|
---|
[17481] | 19 | public IOptimizer Optimizer { get; }
|
---|
[18055] | 20 | public IEnumerable<IRunCollectionModifier> RunCollectionModifiers { get; }
|
---|
[17477] | 21 | }
|
---|
| 22 |
|
---|
| 23 |
|
---|
[17353] | 24 | /// <summary>
|
---|
[17477] | 25 | /// Class to instantiate an IAlgorithm object with a json interface template and config.
|
---|
[17353] | 26 | /// </summary>
|
---|
[17477] | 27 | public class JsonTemplateInstantiator {
|
---|
[17263] | 28 |
|
---|
[18039] | 29 | #region Constants
|
---|
| 30 | private const string RelativePathCurrentDirectoryRegex = @"^(\.)";
|
---|
| 31 | #endregion
|
---|
| 32 |
|
---|
[17477] | 33 | #region Private Properties
|
---|
| 34 | private JToken Template { get; set; }
|
---|
| 35 | private JArray Config { get; set; }
|
---|
| 36 | private IDictionary<string, IJsonItem> Objects { get; set; } = new Dictionary<string, IJsonItem>();
|
---|
| 37 | #endregion
|
---|
[17442] | 38 |
|
---|
[17353] | 39 | /// <summary>
|
---|
| 40 | /// Instantiate an IAlgorithm object with a template and config.
|
---|
| 41 | /// </summary>
|
---|
| 42 | /// <param name="templateFile">Template file (json), generated with JCGenerator.</param>
|
---|
| 43 | /// <param name="configFile">Config file (json) for the template.</param>
|
---|
[17395] | 44 | /// <returns>confugrated IOptimizer object</returns>
|
---|
[17477] | 45 | public static InstantiatorResult Instantiate(string templateFile, string configFile = null) {
|
---|
| 46 | JsonTemplateInstantiator instantiator = new JsonTemplateInstantiator();
|
---|
| 47 | return instantiator.ExecuteInstantiaton(templateFile, configFile);
|
---|
| 48 | }
|
---|
[17322] | 49 |
|
---|
[17477] | 50 | #region Helper
|
---|
| 51 | private InstantiatorResult ExecuteInstantiaton(string templateFile, string configFile = null) {
|
---|
| 52 |
|
---|
| 53 | #region Parse Files
|
---|
[18040] | 54 | string templateFileFullPath = Path.GetFullPath(templateFile);
|
---|
[17477] | 55 | Template = JToken.Parse(File.ReadAllText(templateFile));
|
---|
[17330] | 56 | if(!string.IsNullOrEmpty(configFile))
|
---|
[18040] | 57 | Config = JArray.Parse(File.ReadAllText(Path.GetFullPath(configFile)));
|
---|
[17477] | 58 | #endregion
|
---|
[17379] | 59 |
|
---|
[18050] | 60 | #region Deserialize HL File
|
---|
[17379] | 61 | // extract metadata information
|
---|
[18039] | 62 | string relativePath = Template[Constants.Metadata][Constants.HLFileLocation].ToString().Trim(); // get relative path
|
---|
[18030] | 63 | // convert to absolute path
|
---|
[18039] | 64 | if (Regex.IsMatch(relativePath, RelativePathCurrentDirectoryRegex))
|
---|
| 65 | relativePath = relativePath.Remove(0, 2); // remove first 2 chars -> indicates the current directory
|
---|
[17263] | 66 |
|
---|
[18040] | 67 | string hLFileLocation = Path.Combine(Path.GetDirectoryName(templateFileFullPath), relativePath);
|
---|
[17379] | 68 | ProtoBufSerializer serializer = new ProtoBufSerializer();
|
---|
[17395] | 69 | IOptimizer optimizer = (IOptimizer)serializer.Deserialize(hLFileLocation);
|
---|
[18059] | 70 | optimizer.Prepare(true);
|
---|
[17477] | 71 | #endregion
|
---|
[17379] | 72 |
|
---|
| 73 | // collect all parameterizedItems from template
|
---|
[17477] | 74 | CollectParameterizedItems(optimizer);
|
---|
[17394] | 75 |
|
---|
[17477] | 76 | if (Config != null)
|
---|
| 77 | MergeTemplateWithConfig();
|
---|
[17322] | 78 |
|
---|
[17477] | 79 | // get algorithm root item
|
---|
| 80 | IJsonItem rootItem = Objects.First().Value;
|
---|
[17560] | 81 |
|
---|
[17828] | 82 | // validation
|
---|
| 83 | ValidationResult validationResult = rootItem.GetValidator().Validate();
|
---|
| 84 | if (!validationResult.Success)
|
---|
| 85 | throw validationResult.GenerateException();
|
---|
[17560] | 86 |
|
---|
[17379] | 87 | // inject configuration
|
---|
[17477] | 88 | JsonItemConverter.Inject(optimizer, rootItem);
|
---|
[17266] | 89 |
|
---|
[18059] | 90 | return new InstantiatorResult(optimizer, CollectRunCollectionModifiers());
|
---|
[18050] | 91 | }
|
---|
| 92 |
|
---|
| 93 | /// <summary>
|
---|
| 94 | /// Instantiates all defined (in template) ResultCollectionProcessors and injects the configured parameters.
|
---|
| 95 | /// </summary>
|
---|
[18055] | 96 | private IEnumerable<IRunCollectionModifier> CollectRunCollectionModifiers() {
|
---|
| 97 | IList<IRunCollectionModifier> runCollectionModifiers = new List<IRunCollectionModifier>();
|
---|
[18059] | 98 |
|
---|
| 99 | if (Template is JObject o && !o.ContainsKey(Constants.RunCollectionModifiers))
|
---|
| 100 | return Enumerable.Empty<IRunCollectionModifier>();
|
---|
| 101 |
|
---|
[18055] | 102 | foreach (JObject obj in Template[Constants.RunCollectionModifiers]) {
|
---|
[18050] | 103 | var guid = obj["GUID"].ToString();
|
---|
| 104 | var parameters = obj[Constants.Parameters];
|
---|
| 105 | var type = Mapper.StaticCache.GetType(new Guid(guid));
|
---|
[18059] | 106 | var rcModifier = (IRunCollectionModifier)Activator.CreateInstance(type);
|
---|
| 107 | var rcModifierItem = JsonItemConverter.Extract(rcModifier);
|
---|
[18050] | 108 |
|
---|
[18077] | 109 | SetJObjects(rcModifierItem, parameters);
|
---|
[18050] | 110 |
|
---|
[18059] | 111 | JsonItemConverter.Inject(rcModifier, rcModifierItem);
|
---|
| 112 | runCollectionModifiers.Add(rcModifier);
|
---|
[18046] | 113 | }
|
---|
[18055] | 114 | return runCollectionModifiers;
|
---|
[17263] | 115 | }
|
---|
| 116 |
|
---|
[17477] | 117 | private void CollectParameterizedItems(IOptimizer optimizer) {
|
---|
| 118 | IJsonItem root = JsonItemConverter.Extract(optimizer);
|
---|
| 119 | Objects.Add(root.Path, root);
|
---|
[17410] | 120 |
|
---|
[18077] | 121 | foreach (var kvp in SetJObjects(root, Template[Constants.Parameters]))
|
---|
| 122 | Objects.Add(kvp);
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 | private IDictionary<string, IJsonItem> SetJObjects(IJsonItem root, JToken parameters) {
|
---|
| 126 | var dict = new Dictionary<string, IJsonItem>();
|
---|
| 127 | foreach (JObject obj in parameters) {
|
---|
| 128 | var path = obj[nameof(IJsonItem.Path)].ToString();
|
---|
| 129 | foreach (var item in root) {
|
---|
| 130 | if (item.Path == path) {
|
---|
| 131 | item.SetJObject(obj);
|
---|
| 132 | item.Active = true;
|
---|
| 133 | dict.Add(item.Path, item);
|
---|
[17410] | 134 | }
|
---|
| 135 | }
|
---|
| 136 | }
|
---|
[18077] | 137 | return dict;
|
---|
[17263] | 138 | }
|
---|
[18077] | 139 |
|
---|
[17477] | 140 | private void MergeTemplateWithConfig() {
|
---|
| 141 | foreach (JObject obj in Config) {
|
---|
[17322] | 142 | // build item from config object
|
---|
[18030] | 143 | var prop = obj.Property("Path");
|
---|
| 144 | if (prop == null)
|
---|
| 145 | throw new ArgumentException("Path property is missing.");
|
---|
| 146 | string path = prop.Value.ToString();
|
---|
[17322] | 147 | // override default value
|
---|
[17477] | 148 | if (Objects.TryGetValue(path, out IJsonItem param)) {
|
---|
[17483] | 149 | // remove fixed template parameter from config => dont allow to copy them from concrete config
|
---|
[17828] | 150 | // TODO: shift this into JsonItems?
|
---|
[17473] | 151 | obj.Property(nameof(IIntervalRestrictedJsonItem<int>.Minimum))?.Remove();
|
---|
| 152 | obj.Property(nameof(IIntervalRestrictedJsonItem<int>.Maximum))?.Remove();
|
---|
| 153 | obj.Property(nameof(IConcreteRestrictedJsonItem<string>.ConcreteRestrictedItems))?.Remove();
|
---|
[17828] | 154 | obj.Property(nameof(IMatrixJsonItem.ColumnsResizable))?.Remove();
|
---|
| 155 | obj.Property(nameof(IMatrixJsonItem.RowsResizable))?.Remove();
|
---|
| 156 | obj.Property(nameof(IArrayJsonItem.Resizable))?.Remove();
|
---|
[17473] | 157 | // merge
|
---|
[17477] | 158 | param.SetJObject(obj);
|
---|
[17410] | 159 | } else throw new InvalidDataException($"No parameter with path='{path}' defined!");
|
---|
[17322] | 160 | }
|
---|
| 161 | }
|
---|
| 162 | #endregion
|
---|
[17263] | 163 | }
|
---|
| 164 | }
|
---|