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.sofm; 019 020import org.apache.commons.math4.neuralnet.sofm.util.ExponentialDecayFunction; 021import org.apache.commons.math4.neuralnet.sofm.util.QuasiSigmoidDecayFunction; 022 023/** 024 * Factory for creating instances of {@link NeighbourhoodSizeFunction}. 025 * 026 * @since 3.3 027 */ 028public final class NeighbourhoodSizeFunctionFactory { 029 /** Class contains only static methods. */ 030 private NeighbourhoodSizeFunctionFactory() {} 031 032 /** 033 * Creates an exponential decay {@link NeighbourhoodSizeFunction function}. 034 * It will compute <code>a e<sup>-x / b</sup></code>, 035 * where {@code x} is the (integer) independent variable and 036 * <ul> 037 * <li><code>a = initValue</code> 038 * <li><code>b = -numCall / ln(valueAtNumCall / initValue)</code> 039 * </ul> 040 * 041 * @param initValue Initial value, i.e. 042 * {@link NeighbourhoodSizeFunction#value(long) value(0)}. 043 * @param valueAtNumCall Value of the function at {@code numCall}. 044 * @param numCall Argument for which the function returns 045 * {@code valueAtNumCall}. 046 * @return the neighbourhood size function. 047 * @throws IllegalArgumentException if {@code initValue <= 0}, 048 * {@code valueAtNumCall <= 0}, {@code valueAtNumCall >= initValue} 049 * or {@code numCall <= 0}. 050 */ 051 public static NeighbourhoodSizeFunction exponentialDecay(final double initValue, 052 final double valueAtNumCall, 053 final long numCall) { 054 return new NeighbourhoodSizeFunction() { 055 /** DecayFunction. */ 056 private final ExponentialDecayFunction decay 057 = new ExponentialDecayFunction(initValue, valueAtNumCall, numCall); 058 059 /** {@inheritDoc} */ 060 @Override 061 public int value(long n) { 062 return (int) Math.rint(decay.applyAsDouble(n)); 063 } 064 }; 065 } 066 067 /** 068 * Creates an sigmoid-like {@code NeighbourhoodSizeFunction function}. 069 * The function {@code f} will have the following properties: 070 * <ul> 071 * <li>{@code f(0) = initValue}</li> 072 * <li>{@code numCall} is the inflexion point</li> 073 * <li>{@code slope = f'(numCall)}</li> 074 * </ul> 075 * 076 * @param initValue Initial value, i.e. 077 * {@link NeighbourhoodSizeFunction#value(long) value(0)}. 078 * @param slope Value of the function derivative at {@code numCall}. 079 * @param numCall Inflexion point. 080 * @return the neighbourhood size function. 081 * @throws IllegalArgumentException if {@code initValue <= 0}, 082 * {@code slope >= 0} or {@code numCall <= 0}. 083 */ 084 public static NeighbourhoodSizeFunction quasiSigmoidDecay(final double initValue, 085 final double slope, 086 final long numCall) { 087 return new NeighbourhoodSizeFunction() { 088 /** DecayFunction. */ 089 private final QuasiSigmoidDecayFunction decay 090 = new QuasiSigmoidDecayFunction(initValue, slope, numCall); 091 092 /** {@inheritDoc} */ 093 @Override 094 public int value(long n) { 095 return (int) Math.rint(decay.applyAsDouble(n)); 096 } 097 }; 098 } 099}