DSFactory.java

  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. import java.io.Serializable;

  19. import org.hipparchus.Field;
  20. import org.hipparchus.exception.LocalizedCoreFormats;
  21. import org.hipparchus.exception.MathIllegalArgumentException;
  22. import org.hipparchus.util.FastMath;

  23. /** Factory for {@link DerivativeStructure}.
  24.  * <p>This class is a factory for {@link DerivativeStructure} instances.</p>
  25.  * <p>Instances of this class are guaranteed to be immutable.</p>
  26.  * @see DerivativeStructure
  27.  * @since 1.1
  28.  */
  29. public class DSFactory implements Serializable {

  30.     /** Serializable UID. */
  31.     private static final long serialVersionUID = 20161222L;

  32.     /** Compiler for the current dimensions. */
  33.     private final transient DSCompiler compiler;

  34.     /** Field the {@link DerivativeStructure} instances belong to. */
  35.     private final transient DSField derivativeField;

  36.     /** Simple constructor.
  37.      * @param parameters number of free parameters
  38.      * @param order derivation order
  39.      */
  40.     public DSFactory(final int parameters, final int order) {
  41.         this.compiler        = DSCompiler.getCompiler(parameters, order);
  42.         this.derivativeField = new DSField(constant(0.0), constant(1.0), constant(FastMath.PI));
  43.     }

  44.     /** Get the {@link Field} the {@link DerivativeStructure} instances belong to.
  45.      * @return {@link Field} the {@link DerivativeStructure} instances belong to
  46.      */
  47.     public DSField getDerivativeField() {
  48.         return derivativeField;
  49.     }

  50.     /** Build a {@link DerivativeStructure} representing a constant value.
  51.      * @param value value of the constant
  52.      * @return a {@link DerivativeStructure} representing a constant value
  53.      */
  54.     public DerivativeStructure constant(double value) {
  55.         final DerivativeStructure ds = new DerivativeStructure(this);
  56.         ds.setDerivativeComponent(0, value);
  57.         return ds;
  58.     }

  59.     /** Build a {@link DerivativeStructure} representing a variable.
  60.      * <p>Instances built using this method are considered
  61.      * to be the free variables with respect to which differentials
  62.      * are computed. As such, their differential with respect to
  63.      * themselves is +1.</p>
  64.      * @param index index of the variable (from 0 to
  65.      * {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
  66.      * @param value value of the variable
  67.      * @exception MathIllegalArgumentException if index if greater or
  68.      * equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
  69.      * @return a {@link DerivativeStructure} representing a variable
  70.      */
  71.     public DerivativeStructure variable(final int index, final double value)
  72.         throws MathIllegalArgumentException {

  73.         if (index >= getCompiler().getFreeParameters()) {
  74.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
  75.                                                    index, getCompiler().getFreeParameters());
  76.         }

  77.         final DerivativeStructure ds = new DerivativeStructure(this);
  78.         ds.setDerivativeComponent(0, value);

  79.         if (getCompiler().getOrder() > 0) {
  80.             // the derivative of the variable with respect to itself is 1.
  81.             ds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(), 1.0);
  82.         }

  83.         return ds;

  84.     }

  85.     /** Build a {@link DerivativeStructure} from all its derivatives.
  86.      * @param derivatives derivatives sorted according to
  87.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  88.      * @return a {@link DerivativeStructure} with specified derivatives
  89.      * @exception MathIllegalArgumentException if derivatives array does not match the
  90.      * {@link DSCompiler#getSize() size} expected by the compiler
  91.      * @exception MathIllegalArgumentException if order is too large
  92.      * @see DerivativeStructure#getAllDerivatives()
  93.      */
  94.     @SafeVarargs
  95.     public final DerivativeStructure build(final double ... derivatives)
  96.         throws MathIllegalArgumentException {

  97.         if (derivatives.length != compiler.getSize()) {
  98.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  99.                                                    derivatives.length, compiler.getSize());
  100.         }

  101.         return new DerivativeStructure(this, derivatives);

  102.     }

  103.     /** Build a {@link DerivativeStructure} with an uninitialized array.
  104.      * <p>This method is intended only for DerivativeStructure internal use.</p>
  105.      * @return a {@link DerivativeStructure} with an uninitialized array
  106.      */
  107.     DerivativeStructure build() {
  108.         return new DerivativeStructure(this);
  109.     }

  110.     /** Get the compiler for the current dimensions.
  111.      * @return compiler for the current dimensions
  112.      */
  113.     public DSCompiler getCompiler() {
  114.         return compiler;
  115.     }

  116.     /** Check rules set compatibility.
  117.      * @param factory other factory field to check against instance
  118.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  119.      */
  120.     void checkCompatibility(final DSFactory factory) throws MathIllegalArgumentException {
  121.         compiler.checkCompatibility(factory.compiler);
  122.     }

  123.     /**
  124.      * Replace the instance with a data transfer object for serialization.
  125.      * @return data transfer object that will be serialized
  126.      */
  127.     private Object writeReplace() {
  128.         return new DataTransferObject(compiler.getFreeParameters(), compiler.getOrder());
  129.     }

  130.     /** Internal class used only for serialization. */
  131.     private static class DataTransferObject implements Serializable {

  132.         /** Serializable UID. */
  133.         private static final long serialVersionUID = 20161222L;

  134.         /** Number of variables.
  135.          * @serial
  136.          */
  137.         private final int variables;

  138.         /** Derivation order.
  139.          * @serial
  140.          */
  141.         private final int order;

  142.         /** Simple constructor.
  143.          * @param variables number of variables
  144.          * @param order derivation order
  145.          */
  146.         DataTransferObject(final int variables, final int order) {
  147.             this.variables = variables;
  148.             this.order     = order;
  149.         }

  150.         /** Replace the deserialized data transfer object with a {@link DSFactory}.
  151.          * @return replacement {@link DSFactory}
  152.          */
  153.         private Object readResolve() {
  154.             return new DSFactory(variables, order);
  155.         }

  156.     }

  157.     /** Field for {link DerivativeStructure} instances.
  158.      */
  159.     public static class DSField implements Field<DerivativeStructure> {

  160.         /** Constant function evaluating to 0.0. */
  161.         private final DerivativeStructure zero;

  162.         /** Constant function evaluating to 1.0. */
  163.         private final DerivativeStructure one;

  164.         /** Constant function evaluating to π. */
  165.         private final DerivativeStructure pi;

  166.         /** Simple constructor.
  167.          * @param zero constant function evaluating to 0.0
  168.          * @param one constant function evaluating to 1.0
  169.          * @param pi constant function evaluating to π
  170.          */
  171.         DSField(final DerivativeStructure zero, final DerivativeStructure one, final DerivativeStructure pi) {
  172.             this.zero = zero;
  173.             this.one  = one;
  174.             this.pi   = pi;
  175.         }

  176.         /** {@inheritDoc} */
  177.         @Override
  178.         public DerivativeStructure getZero() {
  179.             return zero;
  180.         }

  181.         /** {@inheritDoc} */
  182.         @Override
  183.         public DerivativeStructure getOne() {
  184.             return one;
  185.         }

  186.         /** Get the Archimedes constant π.
  187.          * <p>
  188.          * Archimedes constant is the ratio of a circle's circumference to its diameter.
  189.          * </p>
  190.          * @return Archimedes constant π
  191.          * @since 2.0
  192.          */
  193.         public DerivativeStructure getPi() {
  194.             return pi;
  195.         }

  196.         /** {@inheritDoc} */
  197.         @Override
  198.         public Class<DerivativeStructure> getRuntimeClass() {
  199.             return DerivativeStructure.class;
  200.         }

  201.         /** {@inheritDoc} */
  202.         @Override
  203.         public boolean equals(final Object other) {
  204.             if (this == other) {
  205.                 return true;
  206.             } else if (other instanceof DSField) {
  207.                 DSFactory lhsFactory = zero.getFactory();
  208.                 DSFactory rhsFactory = ((DSField) other).zero.getFactory();
  209.                 return lhsFactory.compiler == rhsFactory.compiler;
  210.             } else {
  211.                 return false;
  212.             }
  213.         }

  214.         /** {@inheritDoc} */
  215.         @Override
  216.         public int hashCode() {
  217.             final DSCompiler compiler = zero.getFactory().getCompiler();
  218.             return 0x9943b886 ^ (compiler.getFreeParameters() << 16 & compiler.getOrder());
  219.         }

  220.     }

  221. }