
package com.uwetrottmann.shopr.algorithm;

import com.uwetrottmann.shopr.algorithm.model.Attributes;
import com.uwetrottmann.shopr.algorithm.model.Attributes.Attribute;

public class Similarity {

    public static double similarity(Attributes first, Attributes second) {
        Attribute[] attrsFirst = first.getAllAttributes();
        Attribute[] attrsSecond = second.getAllAttributes();

        int count = 0;
        double similarity = 0;

        // sum up similarity values for all attributes
        for (int i = 0; i < attrsFirst.length; i++) {
            /*
             * The query does only store new vectors for a feature once it has
             * been critiqued (others remain null). This speeds up processing by
             * avoiding useless comparisons (calculating similarity for
             * un-critiqued features).
             */
            if (attrsFirst[i] != null && attrsSecond[i] != null) {
                count++;
                similarity += attributeSimilarity(attrsFirst[i], attrsSecond[i]);
            }
        }

        if (count == 0) {
            throw new IllegalArgumentException(
                    "No attributes have been defined.");
        }

        // average
        similarity /= count;

        return similarity;
    }

    /**
     * Returns a similarity value between 0 and 1. The higher the more similar
     * are the weights of the attribute values.
     */
    public static double attributeSimilarity(Attribute first, Attribute second) {
        double similarity = 0;
        double[] valueWeightsFirst = first.getValueWeights();
        double[] valueWeightsSecond = second.getValueWeights();

        if (valueWeightsFirst.length != valueWeightsSecond.length) {
            throw new IllegalArgumentException(
                    "Attribute value weight vectors must be of same size.");
        }

        // sum up deltas
        for (int i = 0; i < valueWeightsFirst.length; i++) {
            similarity += 1 - Math.abs(valueWeightsFirst[i] - valueWeightsSecond[i]);
        }
        // average
        similarity /= valueWeightsFirst.length;

        return similarity;
    }

}

@@ -1151,39 +1151,56 @@
    %22
-No attributes have been defined
+Could not find one match of attribute to compare
 .%22);
@@ -1907,16 +1907,39 @@
  deltas%0A
+        int count = 0;%0A
         
@@ -1983,32 +1983,214 @@
 .length; i++) %7B%0A
+            if (valueWeightsFirst%5Bi%5D == 0 && valueWeightsSecond%5Bi%5D == 0) %7B%0A                // skip if both weights are 0%0A                continue;%0A            %7D%0A            count++;%0A
             simi
@@ -2261,32 +2261,33 @@
 %5Bi%5D);%0A        %7D%0A
+%0A
         // avera
@@ -2315,32 +2315,13 @@
  /= 
-valueWeightsFirst.length
+count
 ;%0A%0A 

Fix to ignore if both weights are zero.