FDSFactory.java
/*
* Licensed to the Hipparchus project under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The Hipparchus project licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hipparchus.analysis.differentiation;
import org.hipparchus.CalculusFieldElement;
import org.hipparchus.Field;
import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.exception.MathIllegalArgumentException;
import org.hipparchus.util.MathArrays;
/** Factory for {@link FieldDerivativeStructure}.
* <p>This class is a factory for {@link FieldDerivativeStructure} instances.</p>
* <p>Instances of this class are guaranteed to be immutable.</p>
* @see FieldDerivativeStructure
* @param <T> the type of the function parameters and value
*/
public class FDSFactory<T extends CalculusFieldElement<T>> {
/** Compiler for the current dimensions. */
private final DSCompiler compiler;
/** Field the value and parameters of the function belongs to. */
private final Field<T> valueField;
/** Field the {@link FieldDerivativeStructure} instances belong to. */
private final DerivativeField<T> derivativeField;
/** Simple constructor.
* @param valueField field for the function parameters and value
* @param parameters number of free parameters
* @param order derivation order
*/
public FDSFactory(final Field<T> valueField, final int parameters, final int order) {
this.compiler = DSCompiler.getCompiler(parameters, order);
this.valueField = valueField;
this.derivativeField = new DerivativeField<>(constant(valueField.getZero()),
constant(valueField.getOne()),
constant(valueField.getZero().getPi()));
}
/** Get the {@link Field} the value and parameters of the function belongs to.
* @return {@link Field} the value and parameters of the function belongs to
*/
public Field<T> getValueField() {
return valueField;
}
/** Get the {@link Field} the {@link FieldDerivativeStructure} instances belong to.
* @return {@link Field} the {@link FieldDerivativeStructure} instances belong to
*/
public DerivativeField<T> getDerivativeField() {
return derivativeField;
}
/** Build a {@link FieldDerivativeStructure} representing a constant value.
* @param value value of the constant
* @return a {@link FieldDerivativeStructure} representing a constant value
*/
public FieldDerivativeStructure<T> constant(double value) {
return constant(valueField.getZero().add(value));
}
/** Build a {@link FieldDerivativeStructure} representing a constant value.
* @param value value of the constant
* @return a {@link FieldDerivativeStructure} representing a constant value
*/
public FieldDerivativeStructure<T> constant(final T value) {
final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
fds.setDerivativeComponent(0, value);
return fds;
}
/** Build a {@link FieldDerivativeStructure} representing a variable.
* <p>Instances built using this method are considered
* to be the free variables with respect to which differentials
* are computed. As such, their differential with respect to
* themselves is +1.</p>
* @param index index of the variable (from 0 to
* {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
* @param value value of the variable
* @return a {@link FieldDerivativeStructure} representing a variable
* @exception MathIllegalArgumentException if index if greater or
* equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
*/
public FieldDerivativeStructure<T> variable(final int index, final T value)
throws MathIllegalArgumentException {
if (index >= getCompiler().getFreeParameters()) {
throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
index, getCompiler().getFreeParameters());
}
final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
fds.setDerivativeComponent(0, value);
if (getCompiler().getOrder() > 0) {
// the derivative of the variable with respect to itself is 1.
fds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(),
valueField.getOne());
}
return fds;
}
/** Build a {@link FieldDerivativeStructure} representing a variable.
* <p>Instances built using this method are considered
* to be the free variables with respect to which differentials
* are computed. As such, their differential with respect to
* themselves is +1.</p>
* @param index index of the variable (from 0 to
* {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()} - 1)
* @param value value of the variable
* @return a {@link FieldDerivativeStructure} representing a variable
* @exception MathIllegalArgumentException if index if greater or
* equal to {@link #getCompiler()}.{@link DSCompiler#getFreeParameters() getFreeParameters()}.
*/
public FieldDerivativeStructure<T> variable(final int index, final double value)
throws MathIllegalArgumentException {
if (index >= getCompiler().getFreeParameters()) {
throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
index, getCompiler().getFreeParameters());
}
final FieldDerivativeStructure<T> fds = new FieldDerivativeStructure<>(this);
fds.setDerivativeComponent(0, valueField.getZero().newInstance(value));
if (getCompiler().getOrder() > 0) {
// the derivative of the variable with respect to itself is 1.
fds.setDerivativeComponent(DSCompiler.getCompiler(index, getCompiler().getOrder()).getSize(),
valueField.getOne());
}
return fds;
}
/** Build a {@link FieldDerivativeStructure} from all its derivatives.
* @param derivatives derivatives sorted according to
* {@link DSCompiler#getPartialDerivativeIndex(int...)}
* @return {@link FieldDerivativeStructure} with specified derivatives
* @exception MathIllegalArgumentException if derivatives array does not match the
* {@link DSCompiler#getSize() size} expected by the compiler
* @exception MathIllegalArgumentException if order is too large
* @see FieldDerivativeStructure#getAllDerivatives()
*/
@SafeVarargs
public final FieldDerivativeStructure<T> build(final T ... derivatives)
throws MathIllegalArgumentException {
final T[] data = buildArray();
if (derivatives.length != data.length) {
throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
derivatives.length, data.length);
}
System.arraycopy(derivatives, 0, data, 0, data.length);
return new FieldDerivativeStructure<>(this, data);
}
/** Build a {@link FieldDerivativeStructure} from all its derivatives.
* @param derivatives derivatives sorted according to
* {@link DSCompiler#getPartialDerivativeIndex(int...)}
* @return {@link FieldDerivativeStructure} with specified derivatives
* @exception MathIllegalArgumentException if derivatives array does not match the
* {@link DSCompiler#getSize() size} expected by the compiler
* @exception MathIllegalArgumentException if order is too large
* @see FieldDerivativeStructure#getAllDerivatives()
*/
public FieldDerivativeStructure<T> build(final double ... derivatives)
throws MathIllegalArgumentException {
final T[] data = buildArray();
if (derivatives.length != data.length) {
throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
derivatives.length, data.length);
}
for (int i = 0; i < data.length; ++i) {
data[i] = valueField.getZero().add(derivatives[i]);
}
return new FieldDerivativeStructure<>(this, data);
}
/** Build a {@link FieldDerivativeStructure} with an uninitialized array.
* <p>This method is intended only for FieldDerivativeStructure internal use.</p>
* @return a {@link FieldDerivativeStructure} with an uninitialized array
*/
FieldDerivativeStructure<T> build() {
return new FieldDerivativeStructure<>(this);
}
/** Build an uninitialized array for derivatives data.
* @return uninitialized array for derivatives data
*/
private T[] buildArray() {
return MathArrays.buildArray(valueField, compiler.getSize());
}
/** Get the compiler for the current dimensions.
* @return compiler for the current dimensions
*/
public DSCompiler getCompiler() {
return compiler;
}
/** Check rules set compatibility.
* @param factory other factory field to check against instance
* @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
*/
void checkCompatibility(final FDSFactory<T> factory) throws MathIllegalArgumentException {
compiler.checkCompatibility(factory.compiler);
}
/** Field for {link FieldDerivativeStructure} instances.
* @param <T> the type of the function parameters and value
*/
public static class DerivativeField<T extends CalculusFieldElement<T>> implements Field<FieldDerivativeStructure<T>> {
/** Constant function evaluating to 0.0. */
private final FieldDerivativeStructure<T> zero;
/** Constant function evaluating to 1.0. */
private final FieldDerivativeStructure<T> one;
/** Constant function evaluating to π. */
private final FieldDerivativeStructure<T> pi;
/** Simple constructor.
* @param zero constant function evaluating to 0.0
* @param one constant function evaluating to 1.0
* @param pi constant function evaluating to π
*/
DerivativeField(final FieldDerivativeStructure<T> zero,
final FieldDerivativeStructure<T> one,
final FieldDerivativeStructure<T> pi) {
this.zero = zero;
this.one = one;
this.pi = pi;
}
/** {@inheritDoc} */
@Override
public FieldDerivativeStructure<T> getZero() {
return zero;
}
/** {@inheritDoc} */
@Override
public FieldDerivativeStructure<T> getOne() {
return one;
}
/** Get the Archimedes constant π.
* <p>
* Archimedes constant is the ratio of a circle's circumference to its diameter.
* </p>
* @return Archimedes constant π
* @since 2.0
*/
public FieldDerivativeStructure<T> getPi() {
return pi;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public Class<FieldDerivativeStructure<T>> getRuntimeClass() {
return (Class<FieldDerivativeStructure<T>>) zero.getClass();
}
/** {@inheritDoc} */
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
} else if (other instanceof DerivativeField) {
FDSFactory<T> lhsFactory = zero.getFactory();
FDSFactory<?> rhsFactory = ((DerivativeField<?>) other).zero.getFactory();
return lhsFactory.compiler == rhsFactory.compiler &&
lhsFactory.valueField.equals(rhsFactory.valueField);
} else {
return false;
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
final DSCompiler compiler = zero.getFactory().getCompiler();
return 0x58d35de8 ^ (compiler.getFreeParameters() << 16 & compiler.getOrder());
}
}
}