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 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 }