1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)


4  *


5  * This file is part of HeuristicLab.


6  *


7  * HeuristicLab is free software: you can redistribute it and/or modify


8  * it under the terms of the GNU General Public License as published by


9  * the Free Software Foundation, either version 3 of the License, or


10  * (at your option) any later version.


11  *


12  * HeuristicLab is distributed in the hope that it will be useful,


13  * but WITHOUT ANY WARRANTY; without even the implied warranty of


14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the


15  * GNU General Public License for more details.


16  *


17  * You should have received a copy of the GNU General Public License


18  * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.


19  */


20  #endregion


21 


22  using System;


23  using System.Collections.Generic;


24  using HeuristicLab.Common;


25  using HeuristicLab.Core;


26  using HEAL.Attic;


27 


28  namespace HeuristicLab.Algorithms.DataAnalysis {


29  /// <summary>


30  /// The angular distance as defined as a normalized distance measure dependent on the angle between two vectors.


31  /// </summary>


32  [StorableType("C87DE522CB6D485BB2F76FE79B4E4DC6")]


33  [Item("CosineDistance", "The angular distance as defined as a normalized distance measure dependent on the angle between two vectors.")]


34  public class CosineDistance : DistanceBase<IEnumerable<double>> {


35  #region HLConstructors & Cloning


36  [StorableConstructor]


37  protected CosineDistance(StorableConstructorFlag _) : base(_) { }


38  protected CosineDistance(CosineDistance original, Cloner cloner)


39  : base(original, cloner) { }


40  public CosineDistance() { }


41  public override IDeepCloneable Clone(Cloner cloner) {


42  return new CosineDistance(this, cloner);


43  }


44  #endregion


45 


46  #region statics


47  public static double GetDistance(IEnumerable<double> point1, IEnumerable<double> point2) {


48  using (IEnumerator<double> p1Enum = point1.GetEnumerator(), p2Enum = point2.GetEnumerator()) {


49  var innerprod = 0.0;


50  var length1 = 0.0;


51  var length2 = 0.0;


52  while (p1Enum.MoveNext() & p2Enum.MoveNext()) {


53  double d1 = p1Enum.Current, d2 = p2Enum.Current;


54  innerprod += d1 * d2;


55  length1 += d1 * d1;


56  length2 += d2 * d2;


57  }


58  var divisor = Math.Sqrt(length1 * length2);


59  if (divisor.IsAlmost(0)) throw new ArgumentException("Cosine distance is not defined on vectors of length 0");


60  if (p1Enum.MoveNext()  p2Enum.MoveNext()) throw new ArgumentException("Cosine distance not defined on vectors of different length");


61  return 1  innerprod / divisor;


62  }


63  }


64  #endregion


65  public override double Get(IEnumerable<double> a, IEnumerable<double> b) {


66  return GetDistance(a, b);


67  }


68  }


69  } 
