001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.math4.neuralnet; 019 020import java.util.List; 021 022import org.apache.commons.math4.neuralnet.internal.NeuralNetException; 023 024/** 025 * Utilities for network maps. 026 * 027 * @since 3.3 028 */ 029public final class MapUtils { 030 /** 031 * Class contains only static methods. 032 */ 033 private MapUtils() {} 034 035 /** 036 * Computes the quantization error. 037 * The quantization error is the average distance between a feature vector 038 * and its "best matching unit" (closest neuron). 039 * 040 * @param data Feature vectors. 041 * @param neurons List of neurons to scan. 042 * @param distance Distance function. 043 * @return the error. 044 * @throws IllegalArgumentException if {@code data} is empty. 045 */ 046 public static double computeQuantizationError(Iterable<double[]> data, 047 Iterable<Neuron> neurons, 048 DistanceMeasure distance) { 049 final MapRanking rank = new MapRanking(neurons, distance); 050 051 double d = 0; 052 int count = 0; 053 for (final double[] f : data) { 054 ++count; 055 d += distance.applyAsDouble(f, rank.rank(f, 1).get(0).getFeatures()); 056 } 057 058 if (count == 0) { 059 throw new NeuralNetException(NeuralNetException.NO_DATA); 060 } 061 062 return d / count; 063 } 064 065 /** 066 * Computes the topographic error. 067 * The topographic error is the proportion of data for which first and 068 * second best matching units are not adjacent in the map. 069 * 070 * @param data Feature vectors. 071 * @param net Network. 072 * @param distance Distance function. 073 * @return the error. 074 * @throws IllegalArgumentException if {@code data} is empty. 075 */ 076 public static double computeTopographicError(Iterable<double[]> data, 077 Network net, 078 DistanceMeasure distance) { 079 final MapRanking rank = new MapRanking(net, distance); 080 081 int notAdjacentCount = 0; 082 int count = 0; 083 for (final double[] f : data) { 084 ++count; 085 final List<Neuron> p = rank.rank(f, 2); 086 if (!net.getNeighbours(p.get(0)).contains(p.get(1))) { 087 // Increment count if first and second best matching units 088 // are not neighbours. 089 ++notAdjacentCount; 090 } 091 } 092 093 if (count == 0) { 094 throw new NeuralNetException(NeuralNetException.NO_DATA); 095 } 096 097 return ((double) notAdjacentCount) / count; 098 } 099}