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 }