using System.Collections.Generic; using System.IO; using System.Linq; using HEAL.Attic; using HeuristicLab.Optimization; using Newtonsoft.Json.Linq; namespace HeuristicLab.JsonInterface { public readonly struct InstantiatorResult { public InstantiatorResult(IOptimizer optimizer, IEnumerable configuredResultItems) { Optimizer = optimizer; ConfiguredResultItems = configuredResultItems; } public IOptimizer Optimizer { get; } public IEnumerable ConfiguredResultItems { get; } } /// /// Class to instantiate an IAlgorithm object with a json interface template and config. /// public class JsonTemplateInstantiator { #region Private Properties private JToken Template { get; set; } private JArray Config { get; set; } private IDictionary Objects { get; set; } = new Dictionary(); #endregion /// /// Instantiate an IAlgorithm object with a template and config. /// /// Template file (json), generated with JCGenerator. /// Config file (json) for the template. /// confugrated IOptimizer object public static InstantiatorResult Instantiate(string templateFile, string configFile = null) { JsonTemplateInstantiator instantiator = new JsonTemplateInstantiator(); return instantiator.ExecuteInstantiaton(templateFile, configFile); } #region Helper private InstantiatorResult ExecuteInstantiaton(string templateFile, string configFile = null) { #region Parse Files Template = JToken.Parse(File.ReadAllText(templateFile)); if(!string.IsNullOrEmpty(configFile)) Config = JArray.Parse(File.ReadAllText(configFile)); #endregion // extract metadata information string hLFileLocation = Path.GetFullPath(Template[Constants.Metadata][Constants.HLFileLocation].ToString()); #region Deserialize HL File ProtoBufSerializer serializer = new ProtoBufSerializer(); IOptimizer optimizer = (IOptimizer)serializer.Deserialize(hLFileLocation); #endregion // collect all parameterizedItems from template CollectParameterizedItems(optimizer); if (Config != null) MergeTemplateWithConfig(); // get algorithm root item IJsonItem rootItem = Objects.First().Value; //TODO validate // inject configuration JsonItemConverter.Inject(optimizer, rootItem); return new InstantiatorResult(optimizer, CollectResults()); } private IEnumerable CollectResults() { IList res = new List(); foreach(JObject obj in Template[Constants.Results]) { string name = obj.Property("Name").Value.ToString(); res.Add(new ResultJsonItem() { Name = name }); } return res; } private void CollectParameterizedItems(IOptimizer optimizer) { IJsonItem root = JsonItemConverter.Extract(optimizer); Objects.Add(root.Path, root); foreach (JObject obj in Template[Constants.Parameters]) { string path = obj.Property("Path").Value.ToString(); foreach(var tmp in root) { if(tmp.Path == path) { tmp.SetJObject(obj); Objects.Add(tmp.Path, tmp); } } } } private void MergeTemplateWithConfig() { foreach (JObject obj in Config) { // build item from config object string path = obj.Property("Path").Value.ToString(); // override default value if (Objects.TryGetValue(path, out IJsonItem param)) { // remove fixed template parameter from config => dont allow to copy them from concrete config obj.Property(nameof(IIntervalRestrictedJsonItem.Minimum))?.Remove(); obj.Property(nameof(IIntervalRestrictedJsonItem.Maximum))?.Remove(); obj.Property(nameof(IConcreteRestrictedJsonItem.ConcreteRestrictedItems))?.Remove(); // merge param.SetJObject(obj); } else throw new InvalidDataException($"No parameter with path='{path}' defined!"); } } #endregion } }