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 java.io.Serializable;
20
21 import org.hipparchus.Field;
22 import org.hipparchus.exception.LocalizedCoreFormats;
23 import org.hipparchus.exception.MathIllegalArgumentException;
24 import org.hipparchus.util.FastMath;
25
26 /** Factory for {@link DerivativeStructure}.
27 * <p>This class is a factory for {@link DerivativeStructure} instances.</p>
28 * <p>Instances of this class are guaranteed to be immutable.</p>
29 * @see DerivativeStructure
30 * @since 1.1
31 */
32 public class DSFactory implements Serializable {
33
34 /** Serializable UID. */
35 private static final long serialVersionUID = 20161222L;
36
37 /** Compiler for the current dimensions. */
38 private final transient DSCompiler compiler;
39
40 /** Field the {@link DerivativeStructure} instances belong to. */
41 private final transient DSField derivativeField;
42
43 /** Simple constructor.
44 * @param parameters number of free parameters
45 * @param order derivation order
46 */
47 public DSFactory(final int parameters, final int order) {
48 this.compiler = DSCompiler.getCompiler(parameters, order);
49 this.derivativeField = new DSField(constant(0.0), constant(1.0), constant(FastMath.PI));
50 }
51
52 /** Get the {@link Field} the {@link DerivativeStructure} instances belong to.
53 * @return {@link Field} the {@link DerivativeStructure} instances belong to
54 */
55 public DSField getDerivativeField() {
56 return derivativeField;
57 }
58
59 /** Build a {@link DerivativeStructure} representing a constant value.
60 * @param value value of the constant
61 * @return a {@link DerivativeStructure} representing a constant value
62 */
63 public DerivativeStructure constant(double value) {
64 final DerivativeStructure ds = new DerivativeStructure(this);
65 ds.setDerivativeComponent(0, value);
66 return ds;
67 }
68
69 /** Build a {@link DerivativeStructure} representing a variable.
70 * <p>Instances built using this method are considered
71 * to be the free variables with respect to which differentials
72 * are computed. As such, their differential with respect to
73 * themselves is +1.</p>
74 * @param index index of the variable (from 0 to
75 * {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
76 * @param value value of the variable
77 * @exception MathIllegalArgumentException if index if greater or
78 * equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
79 * @return a {@link DerivativeStructure} representing a variable
80 */
81 public DerivativeStructure variable(final int index, final double value)
82 throws MathIllegalArgumentException {
83
84 if (index >= getCompiler().getFreeParameters()) {
85 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
86 index, getCompiler().getFreeParameters());
87 }
88
89 final DerivativeStructure ds = new DerivativeStructure(this);
90 ds.setDerivativeComponent(0, value);
91
92 if (getCompiler().getOrder() > 0) {
93 // the derivative of the variable with respect to itself is 1.
94 ds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(), 1.0);
95 }
96
97 return ds;
98
99 }
100
101 /** Build a {@link DerivativeStructure} from all its derivatives.
102 * @param derivatives derivatives sorted according to
103 * {@link DSCompiler#getPartialDerivativeIndex(int...)}
104 * @return a {@link DerivativeStructure} with specified derivatives
105 * @exception MathIllegalArgumentException if derivatives array does not match the
106 * {@link DSCompiler#getSize() size} expected by the compiler
107 * @exception MathIllegalArgumentException if order is too large
108 * @see DerivativeStructure#getAllDerivatives()
109 */
110 @SafeVarargs
111 public final DerivativeStructure build(final double ... derivatives)
112 throws MathIllegalArgumentException {
113
114 if (derivatives.length != compiler.getSize()) {
115 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
116 derivatives.length, compiler.getSize());
117 }
118
119 return new DerivativeStructure(this, derivatives);
120
121 }
122
123 /** Build a {@link DerivativeStructure} with an uninitialized array.
124 * <p>This method is intended only for DerivativeStructure internal use.</p>
125 * @return a {@link DerivativeStructure} with an uninitialized array
126 */
127 DerivativeStructure build() {
128 return new DerivativeStructure(this);
129 }
130
131 /** Get the compiler for the current dimensions.
132 * @return compiler for the current dimensions
133 */
134 public DSCompiler getCompiler() {
135 return compiler;
136 }
137
138 /** Check rules set compatibility.
139 * @param factory other factory field to check against instance
140 * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
141 */
142 void checkCompatibility(final DSFactory factory) throws MathIllegalArgumentException {
143 compiler.checkCompatibility(factory.compiler);
144 }
145
146 /**
147 * Replace the instance with a data transfer object for serialization.
148 * @return data transfer object that will be serialized
149 */
150 private Object writeReplace() {
151 return new DataTransferObject(compiler.getFreeParameters(), compiler.getOrder());
152 }
153
154 /** Internal class used only for serialization. */
155 private static class DataTransferObject implements Serializable {
156
157 /** Serializable UID. */
158 private static final long serialVersionUID = 20161222L;
159
160 /** Number of variables.
161 * @serial
162 */
163 private final int variables;
164
165 /** Derivation order.
166 * @serial
167 */
168 private final int order;
169
170 /** Simple constructor.
171 * @param variables number of variables
172 * @param order derivation order
173 */
174 DataTransferObject(final int variables, final int order) {
175 this.variables = variables;
176 this.order = order;
177 }
178
179 /** Replace the deserialized data transfer object with a {@link DSFactory}.
180 * @return replacement {@link DSFactory}
181 */
182 private Object readResolve() {
183 return new DSFactory(variables, order);
184 }
185
186 }
187
188 /** Field for {link DerivativeStructure} instances.
189 */
190 public static class DSField implements Field<DerivativeStructure> {
191
192 /** Constant function evaluating to 0.0. */
193 private final DerivativeStructure zero;
194
195 /** Constant function evaluating to 1.0. */
196 private final DerivativeStructure one;
197
198 /** Constant function evaluating to π. */
199 private final DerivativeStructure pi;
200
201 /** Simple constructor.
202 * @param zero constant function evaluating to 0.0
203 * @param one constant function evaluating to 1.0
204 * @param pi constant function evaluating to π
205 */
206 DSField(final DerivativeStructure zero, final DerivativeStructure one, final DerivativeStructure pi) {
207 this.zero = zero;
208 this.one = one;
209 this.pi = pi;
210 }
211
212 /** {@inheritDoc} */
213 @Override
214 public DerivativeStructure getZero() {
215 return zero;
216 }
217
218 /** {@inheritDoc} */
219 @Override
220 public DerivativeStructure getOne() {
221 return one;
222 }
223
224 /** Get the Archimedes constant π.
225 * <p>
226 * Archimedes constant is the ratio of a circle's circumference to its diameter.
227 * </p>
228 * @return Archimedes constant π
229 * @since 2.0
230 */
231 public DerivativeStructure getPi() {
232 return pi;
233 }
234
235 /** {@inheritDoc} */
236 @Override
237 public Class<DerivativeStructure> getRuntimeClass() {
238 return DerivativeStructure.class;
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public boolean equals(final Object other) {
244 if (this == other) {
245 return true;
246 } else if (other instanceof DSField) {
247 DSFactory lhsFactory = zero.getFactory();
248 DSFactory rhsFactory = ((DSField) other).zero.getFactory();
249 return lhsFactory.compiler == rhsFactory.compiler;
250 } else {
251 return false;
252 }
253 }
254
255 /** {@inheritDoc} */
256 @Override
257 public int hashCode() {
258 final DSCompiler compiler = zero.getFactory().getCompiler();
259 return 0x9943b886 ^ (compiler.getFreeParameters() << 16 & compiler.getOrder());
260 }
261
262 }
263
264 }