1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.math4.neuralnet;
19
20 import java.util.List;
21
22 import org.apache.commons.math4.neuralnet.internal.NeuralNetException;
23
24 /**
25 * Utilities for network maps.
26 *
27 * @since 3.3
28 */
29 public final class MapUtils {
30 /**
31 * Class contains only static methods.
32 */
33 private MapUtils() {}
34
35 /**
36 * Computes the quantization error.
37 * The quantization error is the average distance between a feature vector
38 * and its "best matching unit" (closest neuron).
39 *
40 * @param data Feature vectors.
41 * @param neurons List of neurons to scan.
42 * @param distance Distance function.
43 * @return the error.
44 * @throws IllegalArgumentException if {@code data} is empty.
45 */
46 public static double computeQuantizationError(Iterable<double[]> data,
47 Iterable<Neuron> neurons,
48 DistanceMeasure distance) {
49 final MapRanking rank = new MapRanking(neurons, distance);
50
51 double d = 0;
52 int count = 0;
53 for (final double[] f : data) {
54 ++count;
55 d += distance.applyAsDouble(f, rank.rank(f, 1).get(0).getFeatures());
56 }
57
58 if (count == 0) {
59 throw new NeuralNetException(NeuralNetException.NO_DATA);
60 }
61
62 return d / count;
63 }
64
65 /**
66 * Computes the topographic error.
67 * The topographic error is the proportion of data for which first and
68 * second best matching units are not adjacent in the map.
69 *
70 * @param data Feature vectors.
71 * @param net Network.
72 * @param distance Distance function.
73 * @return the error.
74 * @throws IllegalArgumentException if {@code data} is empty.
75 */
76 public static double computeTopographicError(Iterable<double[]> data,
77 Network net,
78 DistanceMeasure distance) {
79 final MapRanking rank = new MapRanking(net, distance);
80
81 int notAdjacentCount = 0;
82 int count = 0;
83 for (final double[] f : data) {
84 ++count;
85 final List<Neuron> p = rank.rank(f, 2);
86 if (!net.getNeighbours(p.get(0)).contains(p.get(1))) {
87 // Increment count if first and second best matching units
88 // are not neighbours.
89 ++notAdjacentCount;
90 }
91 }
92
93 if (count == 0) {
94 throw new NeuralNetException(NeuralNetException.NO_DATA);
95 }
96
97 return ((double) notAdjacentCount) / count;
98 }
99 }