FDSFactory.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 org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.exception.LocalizedCoreFormats;
  21. import org.hipparchus.exception.MathIllegalArgumentException;
  22. import org.hipparchus.util.MathArrays;

  23. /** Factory for {@link FieldDerivativeStructure}.
  24.  * <p>This class is a factory for {@link FieldDerivativeStructure} instances.</p>
  25.  * <p>Instances of this class are guaranteed to be immutable.</p>
  26.  * @see FieldDerivativeStructure
  27.  * @param <T> the type of the function parameters and value
  28.  */
  29. public class FDSFactory<T extends CalculusFieldElement<T>> {

  30.     /** Compiler for the current dimensions. */
  31.     private final DSCompiler compiler;

  32.     /** Field the value and parameters of the function belongs to. */
  33.     private final Field<T> valueField;

  34.     /** Field the {@link FieldDerivativeStructure} instances belong to. */
  35.     private final DerivativeField<T> derivativeField;

  36.     /** Simple constructor.
  37.      * @param valueField field for the function parameters and value
  38.      * @param parameters number of free parameters
  39.      * @param order derivation order
  40.      */
  41.     public FDSFactory(final Field<T> valueField, final int parameters, final int order) {
  42.         this.compiler        = DSCompiler.getCompiler(parameters, order);
  43.         this.valueField      = valueField;
  44.         this.derivativeField = new DerivativeField<>(constant(valueField.getZero()),
  45.                                                      constant(valueField.getOne()),
  46.                                                      constant(valueField.getZero().getPi()));
  47.     }

  48.     /** Get the {@link Field} the value and parameters of the function belongs to.
  49.      * @return {@link Field} the value and parameters of the function belongs to
  50.      */
  51.     public Field<T> getValueField() {
  52.         return valueField;
  53.     }

  54.     /** Get the {@link Field} the {@link FieldDerivativeStructure} instances belong to.
  55.      * @return {@link Field} the {@link FieldDerivativeStructure} instances belong to
  56.      */
  57.     public DerivativeField<T> getDerivativeField() {
  58.         return derivativeField;
  59.     }

  60.     /** Build a {@link FieldDerivativeStructure} representing a constant value.
  61.      * @param value value of the constant
  62.      * @return a {@link FieldDerivativeStructure} representing a constant value
  63.      */
  64.     public FieldDerivativeStructure<T> constant(double value) {
  65.         return constant(valueField.getZero().add(value));
  66.     }

  67.     /** Build a {@link FieldDerivativeStructure} representing a constant value.
  68.      * @param value value of the constant
  69.      * @return a {@link FieldDerivativeStructure} representing a constant value
  70.      */
  71.     public FieldDerivativeStructure<T> constant(final T value) {
  72.         final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
  73.         fds.setDerivativeComponent(0, value);
  74.         return fds;
  75.     }

  76.     /** Build a {@link FieldDerivativeStructure} representing a variable.
  77.      * <p>Instances built using this method are considered
  78.      * to be the free variables with respect to which differentials
  79.      * are computed. As such, their differential with respect to
  80.      * themselves is +1.</p>
  81.      * @param index index of the variable (from 0 to
  82.      * {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
  83.      * @param value value of the variable
  84.      * @return a {@link FieldDerivativeStructure} representing a variable
  85.      * @exception MathIllegalArgumentException if index if greater or
  86.      * equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
  87.      */
  88.     public FieldDerivativeStructure<T> variable(final int index, final T value)
  89.         throws MathIllegalArgumentException {

  90.         if (index >= getCompiler().getFreeParameters()) {
  91.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
  92.                                                    index, getCompiler().getFreeParameters());
  93.         }

  94.         final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
  95.         fds.setDerivativeComponent(0, value);

  96.         if (getCompiler().getOrder() > 0) {
  97.             // the derivative of the variable with respect to itself is 1.
  98.             fds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(),
  99.                                        valueField.getOne());
  100.         }

  101.         return fds;

  102.     }

  103.     /** Build a {@link FieldDerivativeStructure} representing a variable.
  104.      * <p>Instances built using this method are considered
  105.      * to be the free variables with respect to which differentials
  106.      * are computed. As such, their differential with respect to
  107.      * themselves is +1.</p>
  108.      * @param index index of the variable (from 0 to
  109.      * {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
  110.      * @param value value of the variable
  111.      * @return a {@link FieldDerivativeStructure} representing a variable
  112.      * @exception MathIllegalArgumentException if index if greater or
  113.      * equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
  114.      */
  115.     public FieldDerivativeStructure<T> variable(final int index, final double value)
  116.         throws MathIllegalArgumentException {

  117.         if (index >= getCompiler().getFreeParameters()) {
  118.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
  119.                                                    index, getCompiler().getFreeParameters());
  120.         }

  121.         final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
  122.         fds.setDerivativeComponent(0, valueField.getZero().newInstance(value));

  123.         if (getCompiler().getOrder() > 0) {
  124.             // the derivative of the variable with respect to itself is 1.
  125.             fds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(),
  126.                                        valueField.getOne());
  127.         }

  128.         return fds;

  129.     }

  130.     /** Build a {@link FieldDerivativeStructure} from all its derivatives.
  131.      * @param derivatives derivatives sorted according to
  132.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  133.      * @return  {@link FieldDerivativeStructure} with specified derivatives
  134.      * @exception MathIllegalArgumentException if derivatives array does not match the
  135.      * {@link DSCompiler#getSize() size} expected by the compiler
  136.      * @exception MathIllegalArgumentException if order is too large
  137.      * @see FieldDerivativeStructure#getAllDerivatives()
  138.      */
  139.     @SafeVarargs
  140.     public final FieldDerivativeStructure<T> build(final T ... derivatives)
  141.         throws MathIllegalArgumentException {

  142.         final T[] data = buildArray();
  143.         if (derivatives.length != data.length) {
  144.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  145.                                                    derivatives.length, data.length);
  146.         }
  147.         System.arraycopy(derivatives, 0, data, 0, data.length);

  148.         return new FieldDerivativeStructure<>(this, data);

  149.     }

  150.     /** Build a {@link FieldDerivativeStructure} from all its derivatives.
  151.      * @param derivatives derivatives sorted according to
  152.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  153.      * @return  {@link FieldDerivativeStructure} with specified derivatives
  154.      * @exception MathIllegalArgumentException if derivatives array does not match the
  155.      * {@link DSCompiler#getSize() size} expected by the compiler
  156.      * @exception MathIllegalArgumentException if order is too large
  157.      * @see FieldDerivativeStructure#getAllDerivatives()
  158.      */
  159.     public FieldDerivativeStructure<T> build(final double ... derivatives)
  160.         throws MathIllegalArgumentException {

  161.         final T[] data = buildArray();
  162.         if (derivatives.length != data.length) {
  163.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  164.                                                    derivatives.length, data.length);
  165.         }
  166.         for (int i = 0; i < data.length; ++i) {
  167.             data[i] = valueField.getZero().add(derivatives[i]);
  168.         }

  169.         return new FieldDerivativeStructure<>(this, data);

  170.     }

  171.     /** Build a {@link FieldDerivativeStructure} with an uninitialized array.
  172.      * <p>This method is intended only for FieldDerivativeStructure internal use.</p>
  173.      * @return a {@link FieldDerivativeStructure} with an uninitialized array
  174.      */
  175.     FieldDerivativeStructure<T> build() {
  176.         return new FieldDerivativeStructure<>(this);
  177.     }

  178.     /** Build an uninitialized array for derivatives data.
  179.      * @return uninitialized array for derivatives data
  180.      */
  181.     private T[] buildArray() {
  182.         return MathArrays.buildArray(valueField, compiler.getSize());
  183.     }

  184.     /** Get the compiler for the current dimensions.
  185.      * @return compiler for the current dimensions
  186.      */
  187.     public DSCompiler getCompiler() {
  188.         return compiler;
  189.     }

  190.     /** Check rules set compatibility.
  191.      * @param factory other factory field to check against instance
  192.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  193.      */
  194.     void checkCompatibility(final FDSFactory<T> factory) throws MathIllegalArgumentException {
  195.         compiler.checkCompatibility(factory.compiler);
  196.     }

  197.     /** Field for {link FieldDerivativeStructure} instances.
  198.      * @param <T> the type of the function parameters and value
  199.      */
  200.     public static class DerivativeField<T extends CalculusFieldElement<T>> implements Field<FieldDerivativeStructure<T>> {

  201.         /** Constant function evaluating to 0.0. */
  202.         private final FieldDerivativeStructure<T> zero;

  203.         /** Constant function evaluating to 1.0. */
  204.         private final FieldDerivativeStructure<T> one;

  205.         /** Constant function evaluating to π. */
  206.         private final FieldDerivativeStructure<T> pi;

  207.         /** Simple constructor.
  208.          * @param zero constant function evaluating to 0.0
  209.          * @param one constant function evaluating to 1.0
  210.          * @param pi constant function evaluating to π
  211.          */
  212.         DerivativeField(final FieldDerivativeStructure<T> zero,
  213.                         final FieldDerivativeStructure<T> one,
  214.                         final FieldDerivativeStructure<T> pi) {
  215.             this.zero = zero;
  216.             this.one  = one;
  217.             this.pi   = pi;
  218.         }

  219.         /** {@inheritDoc} */
  220.         @Override
  221.         public FieldDerivativeStructure<T> getZero() {
  222.             return zero;
  223.         }

  224.         /** {@inheritDoc} */
  225.         @Override
  226.         public FieldDerivativeStructure<T> getOne() {
  227.             return one;
  228.         }

  229.         /** Get the Archimedes constant π.
  230.          * <p>
  231.          * Archimedes constant is the ratio of a circle's circumference to its diameter.
  232.          * </p>
  233.          * @return Archimedes constant π
  234.          * @since 2.0
  235.          */
  236.         public FieldDerivativeStructure<T> getPi() {
  237.             return pi;
  238.         }

  239.         /** {@inheritDoc} */
  240.         @SuppressWarnings("unchecked")
  241.         @Override
  242.         public Class<FieldDerivativeStructure<T>> getRuntimeClass() {
  243.             return (Class<FieldDerivativeStructure<T>>) zero.getClass();
  244.         }

  245.         /** {@inheritDoc} */
  246.         @Override
  247.         public boolean equals(final Object other) {
  248.             if (this == other) {
  249.                 return true;
  250.             } else if (other instanceof DerivativeField) {
  251.                 FDSFactory<T> lhsFactory = zero.getFactory();
  252.                 FDSFactory<?> rhsFactory = ((DerivativeField<?>) other).zero.getFactory();
  253.                 return lhsFactory.compiler == rhsFactory.compiler &&
  254.                        lhsFactory.valueField.equals(rhsFactory.valueField);
  255.             } else {
  256.                 return false;
  257.             }
  258.         }

  259.         /** {@inheritDoc} */
  260.         @Override
  261.         public int hashCode() {
  262.             final DSCompiler compiler = zero.getFactory().getCompiler();
  263.             return 0x58d35de8 ^ (compiler.getFreeParameters() << 16 & compiler.getOrder());
  264.         }

  265.     }

  266. }