#region License Information /* HeuristicLab * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.DataAnalysis; using HeuristicLab.Problems.DataAnalysis.Symbolic; using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression; namespace HeuristicLab.Algorithms.DataAnalysis.Experimental { [Item("RBF (alglib)", "")] [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 102)] [StorableClass] public sealed class RBF : FixedDataAnalysisAlgorithm { [StorableConstructor] private RBF(bool deserializing) : base(deserializing) { } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { } private RBF(RBF original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new RBF(this, cloner); } public RBF() : base() { Problem = new RegressionProblem(); Parameters.Add(new ValueParameter("RBase", new DoubleValue(1.0))); Parameters.Add(new ValueParameter("NLayers", new IntValue(3))); Parameters.Add(new ValueParameter("LambdaNS", new DoubleValue(1.0))); } protected override void Run(CancellationToken cancellationToken) { var scaling = CreateScaling(Problem.ProblemData.Dataset, Problem.ProblemData.TrainingIndices.ToArray(), Problem.ProblemData.AllowedInputVariables.ToArray()); double[,] inputMatrix = ExtractData(Problem.ProblemData.Dataset, Problem.ProblemData.TrainingIndices, Problem.ProblemData.AllowedInputVariables.ToArray(), scaling); double[,] target = ExtractData(Problem.ProblemData.Dataset, Problem.ProblemData.TrainingIndices, new string[] { Problem.ProblemData.TargetVariable }); inputMatrix = inputMatrix.HorzCat(target); if (inputMatrix.Cast().Any(x => double.IsNaN(x) || double.IsInfinity(x))) throw new NotSupportedException("Splines does not support NaN or infinity values in the input dataset."); var inputVars = Problem.ProblemData.AllowedInputVariables.ToArray(); if (inputVars.Length > 3) throw new NotSupportedException(); alglib.rbfmodel model; alglib.rbfreport rep; alglib.rbfcreate(inputVars.Length, 1, out model); alglib.rbfsetzeroterm(model); var rbase = ((DoubleValue)Parameters["RBase"].ActualValue).Value; var nlayers = ((IntValue)Parameters["NLayers"].ActualValue).Value; var lambdans = ((DoubleValue)Parameters["LambdaNS"].ActualValue).Value; alglib.rbfsetalgohierarchical(model, rbase, nlayers, lambdans); alglib.rbfsetpoints(model, inputMatrix); alglib.rbfbuildmodel(model, out rep); Results.Add(new Result("TerminationType", new DoubleValue(rep.terminationtype))); Results.Add(new Result("RMSE", new DoubleValue(rep.rmserror))); Results.Add(new Result("Solution", new RegressionSolution(new RBFModel(model, Problem.ProblemData.TargetVariable, inputVars, scaling), (IRegressionProblemData)Problem.ProblemData.Clone()))); } private static ITransformation[] CreateScaling(IDataset dataset, int[] rows, IReadOnlyCollection allowedInputVariables) { var trans = new ITransformation[allowedInputVariables.Count]; int i = 0; foreach (var variable in allowedInputVariables) { var lin = new LinearTransformation(allowedInputVariables); var max = dataset.GetDoubleValues(variable, rows).Max(); var min = dataset.GetDoubleValues(variable, rows).Min(); lin.Multiplier = 1.0 / (max - min); lin.Addend = -min / (max - min); trans[i] = lin; i++; } return trans; } private static double[,] ExtractData(IDataset dataset, IEnumerable rows, IReadOnlyCollection allowedInputVariables, ITransformation[] scaling = null) { double[][] variables; if (scaling != null) { variables = allowedInputVariables.Select((var, i) => scaling[i].Apply(dataset.GetDoubleValues(var, rows)).ToArray()) .ToArray(); } else { variables = allowedInputVariables.Select(var => dataset.GetDoubleValues(var, rows).ToArray()).ToArray(); } int n = variables.First().Length; var res = new double[n, variables.Length]; for (int r = 0; r < n; r++) for (int c = 0; c < variables.Length; c++) { res[r, c] = variables[c][r]; } return res; } } } // UNFINISHED public class RBFModel : NamedItem, IRegressionModel { private alglib.rbfmodel model; public string TargetVariable { get; set; } public IEnumerable VariablesUsedForPrediction { get; private set; } private ITransformation[] scaling; public event EventHandler TargetVariableChanged; public RBFModel(RBFModel orig, Cloner cloner) : base(orig, cloner) { this.TargetVariable = orig.TargetVariable; this.VariablesUsedForPrediction = orig.VariablesUsedForPrediction.ToArray(); this.model = (alglib.rbfmodel)orig.model.make_copy(); this.scaling = orig.scaling.Select(s => cloner.Clone(s)).ToArray(); } public RBFModel(alglib.rbfmodel model, string targetVar, string[] inputs, IEnumerable> scaling) : base("RBFModel", "RBFModel") { this.model = model; this.TargetVariable = targetVar; this.VariablesUsedForPrediction = inputs; this.scaling = scaling.ToArray(); } public override IDeepCloneable Clone(Cloner cloner) { return new RBFModel(this, cloner); } public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) { return new RegressionSolution(this, (IRegressionProblemData)problemData.Clone()); } public IEnumerable GetEstimatedValues(IDataset dataset, IEnumerable rows) { double[] x = new double[VariablesUsedForPrediction.Count()]; double[] y; foreach (var r in rows) { int c = 0; foreach (var v in VariablesUsedForPrediction) { x[c] = scaling[c].Apply(dataset.GetDoubleValue(v, r).ToEnumerable()).First(); // OUCH! c++; } alglib.rbfcalc(model, x, out y); yield return y[0]; } } }