com.opengamma.analytics.math.minimization.UncoupledParameterTransforms.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.math.minimization.UncoupledParameterTransforms.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.analytics.math.minimization;

import java.util.Arrays;
import java.util.BitSet;

import org.apache.commons.lang.ObjectUtils;

import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.util.ArgumentChecker;

/**
 * For a set of <i>n</i> function parameters, this takes <i>n</i> ParameterLimitsTransform (which can be the NullTransform which does NOT transform the parameter) which transform
 * a constrained function parameter (e.g. must be between -1 and 1) to a unconstrained fit parameter. It also takes a BitSet (of length <i>n</i>) with an element set to <b>true</b> if
 * that parameter is fixed - a set of <i>n</i> startValues must also be provided, with only those corresponding to fixed parameters being used (i.e. the parameter is fixed at the startValue).
 * The purpose is to allow an optimiser to work with unconstrained parameters without modifying the function that one wishes to optimise.
 */
// TODO not tested
public class UncoupledParameterTransforms implements NonLinearParameterTransforms {
    private final DoubleMatrix1D _startValues;
    private final ParameterLimitsTransform[] _transforms;
    private final boolean[] _freeParameters;
    private final int _nMP;
    private final int _nFP;

    /**
     *
     * @param startValues fixed parameter values (if no parameters are fixed this is completely ignored)
     * @param transforms Array of ParameterLimitsTransform (which can be the NullTransform which does NOT transform the parameter) which transform
     * a constrained function parameter (e.g. must be between -1 and 1) to a unconstrained fit parameter.
     * @param fixed BitSet with an element set to <b>true</b> if that parameter is fixed
     */
    public UncoupledParameterTransforms(final DoubleMatrix1D startValues,
            final ParameterLimitsTransform[] transforms, final BitSet fixed) {
        ArgumentChecker.notNull(startValues, "null start values");
        ArgumentChecker.notEmpty(transforms, "must specify transforms");
        ArgumentChecker.notNull(fixed, "must specify what is fixed (even if none)");
        _nMP = startValues.getNumberOfElements();
        ArgumentChecker.isTrue(_nMP == transforms.length, "Have {}-dimensional start value but {} transforms", _nMP,
                transforms.length);
        _freeParameters = new boolean[_nMP];
        for (int i = 0; i < _nMP; i++) {
            if (i < fixed.size()) {
                _freeParameters[i] = !fixed.get(i);
            } else {
                _freeParameters[i] = true;
            }
        }
        final int count = fixed.cardinality();
        ArgumentChecker.isTrue(count < _nMP, "all parameters are fixed");
        _nFP = _nMP - count;
        _startValues = startValues;
        _transforms = transforms;
    }

    /**
     *
     * @return The number of function parameters
     */
    @Override
    public int getNumberOfModelParameters() {
        return _nMP;
    }

    /**
     *
     * @return The number of fitting parameters (equals the number of model parameters minus the number of fixed parameters)
     */
    @Override
    public int getNumberOfFittingParameters() {
        return _nFP;
    }

    /**
     * Transforms from a set of function parameters (some of which may have constrained range and/or be fixed) to a (possibly smaller) set of unconstrained fitting parameters
     * <b>Note:</b> If a parameter is fixed, it is its value as provided by <i>startValues<\i> not the value given here that will be returned by inverseTransform (and thus used in the function)
     * @param functionParameters The function parameters
     * @return The fitting parameters
     */
    @Override
    public DoubleMatrix1D transform(final DoubleMatrix1D functionParameters) {
        ArgumentChecker.notNull(functionParameters, "function parameters");
        ArgumentChecker.isTrue(functionParameters.getNumberOfElements() == _nMP,
                "functionParameters wrong dimension");
        final double[] fittingParameter = new double[_nFP];
        for (int i = 0, j = 0; i < _nMP; i++) {
            if (_freeParameters[i]) {
                fittingParameter[j] = _transforms[i].transform(functionParameters.getEntry(i));
                j++;
            }
        }
        return new DoubleMatrix1D(fittingParameter);
    }

    /**
     * Transforms from a set of unconstrained fitting parameters to a (possibly larger) set of function parameters (some of which may have constrained range and/or be fixed).
     * @param fittingParameters The fitting parameters
     * @return The function parameters
     */
    @Override
    public DoubleMatrix1D inverseTransform(final DoubleMatrix1D fittingParameters) {
        ArgumentChecker.notNull(fittingParameters, "fitting parameters");
        ArgumentChecker.isTrue(fittingParameters.getNumberOfElements() == _nFP, "fittingParameter wrong dimension");
        final double[] modelParameter = new double[_nMP];
        for (int i = 0, j = 0; i < _nMP; i++) {
            if (_freeParameters[i]) {
                modelParameter[i] = _transforms[i].inverseTransform(fittingParameters.getEntry(j));
                j++;
            } else {
                modelParameter[i] = _startValues.getEntry(i);
            }
        }
        return new DoubleMatrix1D(modelParameter);
    }

    /**
     * Calculates the Jacobian of the transform from function parameters to fitting parameters - the i,j element will be the partial derivative of i^th fitting parameter with respect
     * to the j^th function parameter
     * @param functionParameters The function parameters
     * @return matrix of partial derivative of fitting parameter with respect to function parameters
     */
    // TODO not tested
    @Override
    public DoubleMatrix2D jacobian(final DoubleMatrix1D functionParameters) {
        ArgumentChecker.notNull(functionParameters, "function parameters");
        ArgumentChecker.isTrue(functionParameters.getNumberOfElements() == _nMP,
                "functionParameters wrong dimension");
        final double[][] jac = new double[_nFP][_nMP];
        for (int i = 0, j = 0; i < _nMP; i++) {
            if (_freeParameters[i]) {
                jac[j][i] = _transforms[i].transformGradient(functionParameters.getEntry(i));
                j++;
            }
        }
        return new DoubleMatrix2D(jac);
    }

    /**
     * Calculates the Jacobian of the transform from fitting parameters to function parameters - the i,j element will be the partial derivative of i^th function parameter with respect
     * to the j^th  fitting parameter
     * @param fittingParameters  The fitting parameters
     * @return  matrix of partial derivative of function parameter with respect to fitting parameters
     */
    // TODO not tested
    //  @Override
    //  public DoubleMatrix2D inverseJacobian(final DoubleMatrix1D fittingParameters) {
    //    ArgumentChecker.notNull(fittingParameters, "fitting parameters");
    //    ArgumentChecker.isTrue(fittingParameters.getNumberOfElements() == _nFP, "fitting parameters wrong dimension");
    //    final double[][] jac = new double[_nMP][_nFP];
    //    for (int i = 0, j = 0; i < _nMP; i++) {
    //      if (_fixed[i]) {
    //        jac[i][j] = _transforms[i].inverseTransformGradient(fittingParameters.getEntry(j));
    //        j++;
    //      }
    //    }
    //    return DoubleMatrix2D.noCopy(jac);
    //  }

    @SuppressWarnings("deprecation")
    @Override
    public DoubleMatrix2D inverseJacobian(final DoubleMatrix1D fittingParameters) {
        ArgumentChecker.notNull(fittingParameters, "fitting parameters");
        ArgumentChecker.isTrue(fittingParameters.getNumberOfElements() == _nFP,
                "fitting parameters wrong dimension");
        final double[][] jac = new double[_nMP][_nFP];
        final int[] p = new int[_nMP];
        final int[] q = new int[_nMP];
        int t = 0;
        for (int i = 0; i < _nMP; i++) {
            if (_freeParameters[i]) {
                p[t] = i;
                q[t] = t;
                t++;
            }
        }
        int pderef, qderef;
        for (int i = 0; i < t; i++) {
            pderef = p[i];
            qderef = q[i];
            jac[pderef][qderef] = _transforms[pderef].inverseTransformGradient(fittingParameters.getEntry(qderef));
        }
        return DoubleMatrix2D.noCopy(jac);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(_freeParameters);
        result = prime * result + _startValues.hashCode();
        result = prime * result + Arrays.hashCode(_transforms);
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final UncoupledParameterTransforms other = (UncoupledParameterTransforms) obj;
        if (!Arrays.equals(_freeParameters, other._freeParameters)) {
            return false;
        }
        if (!ObjectUtils.equals(_startValues, other._startValues)) {
            return false;
        }
        return Arrays.equals(_transforms, other._transforms);
    }

}