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.legacy.analysis.function; 019 020import org.apache.commons.math4.legacy.analysis.ParametricUnivariateFunction; 021import org.apache.commons.math4.legacy.analysis.differentiation.DerivativeStructure; 022import org.apache.commons.math4.legacy.analysis.differentiation.UnivariateDifferentiableFunction; 023import org.apache.commons.math4.legacy.exception.DimensionMismatchException; 024import org.apache.commons.math4.legacy.exception.NullArgumentException; 025import org.apache.commons.math4.core.jdkmath.JdkMath; 026 027/** 028 * <a href="http://en.wikipedia.org/wiki/Harmonic_oscillator"> 029 * simple harmonic oscillator</a> function. 030 * 031 * @since 3.0 032 */ 033public class HarmonicOscillator implements UnivariateDifferentiableFunction { 034 /** Amplitude. */ 035 private final double amplitude; 036 /** Angular frequency. */ 037 private final double omega; 038 /** Phase. */ 039 private final double phase; 040 041 /** 042 * Harmonic oscillator function. 043 * 044 * @param amplitude Amplitude. 045 * @param omega Angular frequency. 046 * @param phase Phase. 047 */ 048 public HarmonicOscillator(double amplitude, 049 double omega, 050 double phase) { 051 this.amplitude = amplitude; 052 this.omega = omega; 053 this.phase = phase; 054 } 055 056 /** {@inheritDoc} */ 057 @Override 058 public double value(double x) { 059 return value(omega * x + phase, amplitude); 060 } 061 062 /** 063 * Parametric function where the input array contains the parameters of 064 * the harmonic oscillator function. Ordered as follows: 065 * <ul> 066 * <li>Amplitude</li> 067 * <li>Angular frequency</li> 068 * <li>Phase</li> 069 * </ul> 070 */ 071 public static class Parametric implements ParametricUnivariateFunction { 072 /** 073 * Computes the value of the harmonic oscillator at {@code x}. 074 * 075 * @param x Value for which the function must be computed. 076 * @param param Values of norm, mean and standard deviation. 077 * @return the value of the function. 078 * @throws NullArgumentException if {@code param} is {@code null}. 079 * @throws DimensionMismatchException if the size of {@code param} is 080 * not 3. 081 */ 082 @Override 083 public double value(double x, double ... param) 084 throws NullArgumentException, 085 DimensionMismatchException { 086 validateParameters(param); 087 return HarmonicOscillator.value(x * param[1] + param[2], param[0]); 088 } 089 090 /** 091 * Computes the value of the gradient at {@code x}. 092 * The components of the gradient vector are the partial 093 * derivatives of the function with respect to each of the 094 * <em>parameters</em> (amplitude, angular frequency and phase). 095 * 096 * @param x Value at which the gradient must be computed. 097 * @param param Values of amplitude, angular frequency and phase. 098 * @return the gradient vector at {@code x}. 099 * @throws NullArgumentException if {@code param} is {@code null}. 100 * @throws DimensionMismatchException if the size of {@code param} is 101 * not 3. 102 */ 103 @Override 104 public double[] gradient(double x, double ... param) 105 throws NullArgumentException, 106 DimensionMismatchException { 107 validateParameters(param); 108 109 final double amplitude = param[0]; 110 final double omega = param[1]; 111 final double phase = param[2]; 112 113 final double xTimesOmegaPlusPhase = omega * x + phase; 114 final double a = HarmonicOscillator.value(xTimesOmegaPlusPhase, 1); 115 final double p = -amplitude * JdkMath.sin(xTimesOmegaPlusPhase); 116 final double w = p * x; 117 118 return new double[] { a, w, p }; 119 } 120 121 /** 122 * Validates parameters to ensure they are appropriate for the evaluation of 123 * the {@link #value(double,double[])} and {@link #gradient(double,double[])} 124 * methods. 125 * 126 * @param param Values of norm, mean and standard deviation. 127 * @throws NullArgumentException if {@code param} is {@code null}. 128 * @throws DimensionMismatchException if the size of {@code param} is 129 * not 3. 130 */ 131 private void validateParameters(double[] param) 132 throws NullArgumentException, 133 DimensionMismatchException { 134 if (param == null) { 135 throw new NullArgumentException(); 136 } 137 if (param.length != 3) { 138 throw new DimensionMismatchException(param.length, 3); 139 } 140 } 141 } 142 143 /** 144 * @param xTimesOmegaPlusPhase {@code omega * x + phase}. 145 * @param amplitude Amplitude. 146 * @return the value of the harmonic oscillator function at {@code x}. 147 */ 148 private static double value(double xTimesOmegaPlusPhase, 149 double amplitude) { 150 return amplitude * JdkMath.cos(xTimesOmegaPlusPhase); 151 } 152 153 /** {@inheritDoc} 154 * @since 3.1 155 */ 156 @Override 157 public DerivativeStructure value(final DerivativeStructure t) 158 throws DimensionMismatchException { 159 final double x = t.getValue(); 160 double[] f = new double[t.getOrder() + 1]; 161 162 final double alpha = omega * x + phase; 163 f[0] = amplitude * JdkMath.cos(alpha); 164 if (f.length > 1) { 165 f[1] = -amplitude * omega * JdkMath.sin(alpha); 166 final double mo2 = - omega * omega; 167 for (int i = 2; i < f.length; ++i) { 168 f[i] = mo2 * f[i - 2]; 169 } 170 } 171 172 return t.compose(f); 173 } 174}