View Javadoc
1   /*
2    * Licensed to the Hipparchus project 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 Hipparchus project 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    *      https://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  package org.hipparchus.analysis.differentiation;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.exception.LocalizedCoreFormats;
22  import org.hipparchus.exception.MathIllegalArgumentException;
23  import org.hipparchus.util.MathArrays;
24  
25  /** Factory for {@link FieldDerivativeStructure}.
26   * <p>This class is a factory for {@link FieldDerivativeStructure} instances.</p>
27   * <p>Instances of this class are guaranteed to be immutable.</p>
28   * @see FieldDerivativeStructure
29   * @param <T> the type of the function parameters and value
30   */
31  public class FDSFactory<T extends CalculusFieldElement<T>> {
32  
33      /** Compiler for the current dimensions. */
34      private final DSCompiler compiler;
35  
36      /** Field the value and parameters of the function belongs to. */
37      private final Field<T> valueField;
38  
39      /** Field the {@link FieldDerivativeStructure} instances belong to. */
40      private final DerivativeField<T> derivativeField;
41  
42      /** Simple constructor.
43       * @param valueField field for the function parameters and value
44       * @param parameters number of free parameters
45       * @param order derivation order
46       */
47      public FDSFactory(final Field<T> valueField, final int parameters, final int order) {
48          this.compiler        = DSCompiler.getCompiler(parameters, order);
49          this.valueField      = valueField;
50          this.derivativeField = new DerivativeField<>(constant(valueField.getZero()),
51                                                       constant(valueField.getOne()),
52                                                       constant(valueField.getZero().getPi()));
53      }
54  
55      /** Get the {@link Field} the value and parameters of the function belongs to.
56       * @return {@link Field} the value and parameters of the function belongs to
57       */
58      public Field<T> getValueField() {
59          return valueField;
60      }
61  
62      /** Get the {@link Field} the {@link FieldDerivativeStructure} instances belong to.
63       * @return {@link Field} the {@link FieldDerivativeStructure} instances belong to
64       */
65      public DerivativeField<T> getDerivativeField() {
66          return derivativeField;
67      }
68  
69      /** Build a {@link FieldDerivativeStructure} representing a constant value.
70       * @param value value of the constant
71       * @return a {@link FieldDerivativeStructure} representing a constant value
72       */
73      public FieldDerivativeStructure<T> constant(double value) {
74          return constant(valueField.getZero().add(value));
75      }
76  
77      /** Build a {@link FieldDerivativeStructure} representing a constant value.
78       * @param value value of the constant
79       * @return a {@link FieldDerivativeStructure} representing a constant value
80       */
81      public FieldDerivativeStructure<T> constant(final T value) {
82          final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
83          fds.setDerivativeComponent(0, value);
84          return fds;
85      }
86  
87      /** Build a {@link FieldDerivativeStructure} representing a variable.
88       * <p>Instances built using this method are considered
89       * to be the free variables with respect to which differentials
90       * are computed. As such, their differential with respect to
91       * themselves is +1.</p>
92       * @param index index of the variable (from 0 to
93       * {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
94       * @param value value of the variable
95       * @return a {@link FieldDerivativeStructure} representing a variable
96       * @exception MathIllegalArgumentException if index if greater or
97       * equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
98       */
99      public FieldDerivativeStructure<T> variable(final int index, final T value)
100         throws MathIllegalArgumentException {
101 
102         if (index >= getCompiler().getFreeParameters()) {
103             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
104                                                    index, getCompiler().getFreeParameters());
105         }
106 
107         final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
108         fds.setDerivativeComponent(0, value);
109 
110         if (getCompiler().getOrder() > 0) {
111             // the derivative of the variable with respect to itself is 1.
112             fds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(),
113                                        valueField.getOne());
114         }
115 
116         return fds;
117 
118     }
119 
120     /** Build a {@link FieldDerivativeStructure} representing a variable.
121      * <p>Instances built using this method are considered
122      * to be the free variables with respect to which differentials
123      * are computed. As such, their differential with respect to
124      * themselves is +1.</p>
125      * @param index index of the variable (from 0 to
126      * {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
127      * @param value value of the variable
128      * @return a {@link FieldDerivativeStructure} representing a variable
129      * @exception MathIllegalArgumentException if index if greater or
130      * equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
131      */
132     public FieldDerivativeStructure<T> variable(final int index, final double value)
133         throws MathIllegalArgumentException {
134 
135         if (index >= getCompiler().getFreeParameters()) {
136             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
137                                                    index, getCompiler().getFreeParameters());
138         }
139 
140         final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
141         fds.setDerivativeComponent(0, valueField.getZero().newInstance(value));
142 
143         if (getCompiler().getOrder() > 0) {
144             // the derivative of the variable with respect to itself is 1.
145             fds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(),
146                                        valueField.getOne());
147         }
148 
149         return fds;
150 
151     }
152 
153     /** Build a {@link FieldDerivativeStructure} from all its derivatives.
154      * @param derivatives derivatives sorted according to
155      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
156      * @return  {@link FieldDerivativeStructure} with specified derivatives
157      * @exception MathIllegalArgumentException if derivatives array does not match the
158      * {@link DSCompiler#getSize() size} expected by the compiler
159      * @exception MathIllegalArgumentException if order is too large
160      * @see FieldDerivativeStructure#getAllDerivatives()
161      */
162     @SafeVarargs
163     public final FieldDerivativeStructure<T> build(final T ... derivatives)
164         throws MathIllegalArgumentException {
165 
166         final T[] data = buildArray();
167         if (derivatives.length != data.length) {
168             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
169                                                    derivatives.length, data.length);
170         }
171         System.arraycopy(derivatives, 0, data, 0, data.length);
172 
173         return new FieldDerivativeStructure<>(this, data);
174 
175     }
176 
177     /** Build a {@link FieldDerivativeStructure} from all its derivatives.
178      * @param derivatives derivatives sorted according to
179      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
180      * @return  {@link FieldDerivativeStructure} with specified derivatives
181      * @exception MathIllegalArgumentException if derivatives array does not match the
182      * {@link DSCompiler#getSize() size} expected by the compiler
183      * @exception MathIllegalArgumentException if order is too large
184      * @see FieldDerivativeStructure#getAllDerivatives()
185      */
186     public FieldDerivativeStructure<T> build(final double ... derivatives)
187         throws MathIllegalArgumentException {
188 
189         final T[] data = buildArray();
190         if (derivatives.length != data.length) {
191             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
192                                                    derivatives.length, data.length);
193         }
194         for (int i = 0; i < data.length; ++i) {
195             data[i] = valueField.getZero().add(derivatives[i]);
196         }
197 
198         return new FieldDerivativeStructure<>(this, data);
199 
200     }
201 
202     /** Build a {@link FieldDerivativeStructure} with an uninitialized array.
203      * <p>This method is intended only for FieldDerivativeStructure internal use.</p>
204      * @return a {@link FieldDerivativeStructure} with an uninitialized array
205      */
206     FieldDerivativeStructure<T> build() {
207         return new FieldDerivativeStructure<>(this);
208     }
209 
210     /** Build an uninitialized array for derivatives data.
211      * @return uninitialized array for derivatives data
212      */
213     private T[] buildArray() {
214         return MathArrays.buildArray(valueField, compiler.getSize());
215     }
216 
217     /** Get the compiler for the current dimensions.
218      * @return compiler for the current dimensions
219      */
220     public DSCompiler getCompiler() {
221         return compiler;
222     }
223 
224     /** Check rules set compatibility.
225      * @param factory other factory field to check against instance
226      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
227      */
228     void checkCompatibility(final FDSFactory<T> factory) throws MathIllegalArgumentException {
229         compiler.checkCompatibility(factory.compiler);
230     }
231 
232     /** Field for {link FieldDerivativeStructure} instances.
233      * @param <T> the type of the function parameters and value
234      */
235     public static class DerivativeField<T extends CalculusFieldElement<T>> implements Field<FieldDerivativeStructure<T>> {
236 
237         /** Constant function evaluating to 0.0. */
238         private final FieldDerivativeStructure<T> zero;
239 
240         /** Constant function evaluating to 1.0. */
241         private final FieldDerivativeStructure<T> one;
242 
243         /** Constant function evaluating to π. */
244         private final FieldDerivativeStructure<T> pi;
245 
246         /** Simple constructor.
247          * @param zero constant function evaluating to 0.0
248          * @param one constant function evaluating to 1.0
249          * @param pi constant function evaluating to π
250          */
251         DerivativeField(final FieldDerivativeStructure<T> zero,
252                         final FieldDerivativeStructure<T> one,
253                         final FieldDerivativeStructure<T> pi) {
254             this.zero = zero;
255             this.one  = one;
256             this.pi   = pi;
257         }
258 
259         /** {@inheritDoc} */
260         @Override
261         public FieldDerivativeStructure<T> getZero() {
262             return zero;
263         }
264 
265         /** {@inheritDoc} */
266         @Override
267         public FieldDerivativeStructure<T> getOne() {
268             return one;
269         }
270 
271         /** Get the Archimedes constant π.
272          * <p>
273          * Archimedes constant is the ratio of a circle's circumference to its diameter.
274          * </p>
275          * @return Archimedes constant π
276          * @since 2.0
277          */
278         public FieldDerivativeStructure<T> getPi() {
279             return pi;
280         }
281 
282         /** {@inheritDoc} */
283         @SuppressWarnings("unchecked")
284         @Override
285         public Class<FieldDerivativeStructure<T>> getRuntimeClass() {
286             return (Class<FieldDerivativeStructure<T>>) zero.getClass();
287         }
288 
289         /** {@inheritDoc} */
290         @Override
291         public boolean equals(final Object other) {
292             if (this == other) {
293                 return true;
294             } else if (other instanceof DerivativeField) {
295                 FDSFactory<T> lhsFactory = zero.getFactory();
296                 FDSFactory<?> rhsFactory = ((DerivativeField<?>) other).zero.getFactory();
297                 return lhsFactory.compiler == rhsFactory.compiler &&
298                        lhsFactory.valueField.equals(rhsFactory.valueField);
299             } else {
300                 return false;
301             }
302         }
303 
304         /** {@inheritDoc} */
305         @Override
306         public int hashCode() {
307             final DSCompiler compiler = zero.getFactory().getCompiler();
308             return 0x58d35de8 ^ (compiler.getFreeParameters() << 16 & compiler.getOrder());
309         }
310 
311     }
312 
313 }