Andreas Andreakis a écrit :
hi,

sorry to send you an email regarding commons math directly. I tried to subscribe to the mailing list, but for some reason, I was considered as spam.
Thus I chose two members randomly.

Well, anyway :) I want to find a solution to the following problem:

(explained by example)
1 *c1 + 4 * c2 + 4* c3 + 4 * c4 = 2.5
1 *c1 + 4 * c2 + 1* c3 + 4 * c4 = 3.0

here the constraints:
1) c1+c2+c3+c4 = 1 (of course this could be expressed as an additional equation: c1 + c2 + c3 + c4 = 1.0)
2) c1,c2,c3 and c4 are all positive

Important is that I need only one and feasible solution, thus the computation should be as fast as possible. So there is no need to search for every possible result. And it needs to work with doubles (not only integers, because some libraries work only with integers)

Actually the solution needs to scale for several dozens c´s ( there will not be only 4 like c1,c2,c3,c4), but more like 50 c1, c2,...,c49, c50 And there will not be only two equations (like in the example) but several hundred.


So the questions are:
1) can I find a solution using commons math. There is an optimization package, but I could not figure out how to use it?

In this case, the estimation package is more suited to your needs. There are much better methods for such problems, but they are not available in commons-math.

The Levenberg-Marquardt solver implemented in thie estimation package should support both under- and over-determined problems (i.e. either more equations than variables or more variables than equations). The case with more variable than equations is still considered experimental, though. I did use it for such non homogeneous linear problems without problems myself.

This solver does not completely fit your needs as is because it currently do not handle constraints. You will have to set up an intermediate unconstrained problem that can be solved and from which the solution of your constrained problem can be derived. Here are a few tricks to do that, take care, they may induce numerical problems:

For equality constraints, either add the constraint to the equation set or remove one parameter (say c1) from the parameter set and compute it as needed by solving the constraint each time from the values of the other ones, i.e. compute c1 = 1 - f(c2, c3, ..., cn).

For simple bounds constraints on parameters (such as ck > ak), replace the real parameter ck by an unconstrained parameter pk using
  ck = ak + pk² (or ak - pk² if the constraint was ck < ak)

For interval constraints on parameters (such as lowk < ck < highk), replace the real parameter ck by an unconstrained parameter pk using
  ck = [ lowkk + highk ] / 2 + atan(pk) * [ highk - lowk ] / pk

Once you have changed your problem using these pk, it is an unconstrained problem that can be solved by our implementation of Levenberg-Marquardt. Once you have the pk values, you compute the ck values.


2) how will the performance be ?

Since the problem is linear, the performance should be fair.

3) could you give me a code snipped which is able to compute the given example ? (I will generalize it then myself)

Try something along these lines. Take care, I wrote this exemple directly in the mail, I did not attempt to even compile it ;-)

Hope this helps,
Luc

import org.apache.commons.math.estimation.EstimatedParameter;
import org.apache.commons.math.estimation.EstimationException;
import org.apache.commons.math.estimation.LevenbergMarquardtEstimator;
import org.apache.commons.math.estimation.SimpleEstimationProblem;
import org.apache.commons.math.estimation.WeightedMeasurement;


public class LinearConstrainedProblem extends SimpleEstimationProblem {

    public static void main(String[] args) {

        try {
            // create the uninitialized problem
            LinearConstrainedProblem pb =
               new LinearConstrainedProblem(0.25, 0.25, 0.25, 0.25)

            // 1 *c1 + 4 * c2 + 4* c3 + 4 * c4 = 2.5
            pb.addEquation(1.0, 4.0, 4.0, 4.0, 2.5);

            // 1 *c1 + 4 * c2 + 1* c3 + 4 * c4 = 3.0
            pb.addEquation(1.0, 4.0, 1.0, 4.0, 3.0);

            // solve the problem, using a Levenberg-Marquardt algorithm
            // with default settings
            LevenbergMarquardtEstimator estimator =
              new LevenbergMarquardtEstimator();
            estimator.estimate(pb);
            System.out.println("RMS after solve = "
                             + estimator.getRMS(pb));

            // display the results
            System.out.println("c1 = " + pb.getC1()
                    + ", c2 = " + pb.getC2()
                    + ", c3 = " + pb.getC3()
                    + ", c4 = " + pb.getC4());

        } catch (EstimationException ee) {
            System.err.println(ee.getMessage());
        }

    }

    /** Fitter for a linear constrained model.
     * @param c1Guess start value for c1 (in fact, ignored)
     * @param c2Guess start value for c2
     * @param c3Guess start value for c3
     * @param c4Guess start value for c4
     */
    public LinearConstrainedProblem() {

        // one parameter (c1) is computed from the other ones
        // and the other ck are derived from pk using ck = pk*pk
        p2 = new EstimatedParameter("p2", Math.sqrt(c2Guess));
        p3 = new EstimatedParameter("p3", Math.sqrt(c3Guess));
        p4 = new EstimatedParameter("p4", Math.sqrt(c4Guess));

        // provide the parameters to the base class which
        // implements the getAllParameters and
        // getUnboundParameters methods
        addParameter(c2);
        addParameter(c3);
        addParameter(c4);

    }

    /** Add an equation.
     * @param a1 coeff for c1
     * @param a2 coeff for c2
     * @param a3 coeff for c3
     * @param a4 coeff for c4
     * @param rhs right hand side of the equation
     */
    public void addEquation(double a1, double a2, double a3,
                            double a4, double rhs) {
        addMeasurement(new Equation(a1, a2, a3, a4, rhs));
    }

    public double getC1() {
        // this solves the equality constraint
        return 1.0 - getC2() - getC3() - getC4();
    }

    public double getC2() {
      double p = p2.getEstimate();
      return p * p;
    }

    public double getC3() {
      double p = p3.getEstimate();
      return p * p;
    }

    public double getC4() {
      double p = p4.getEstimate();
      return p * p;
    }


    /** Internal measurements class, representing one equation. */
    private class Equation extends WeightedMeasurement {

        public Equation(double a1, double a2, double a3,
                        double a4, double rhs) {
            super(1.0, rhs);
            this.a1 = a1;
            this.a2 = a2;
            this.a3 = a3;
            this.a4 = a4;
        }

        public double getTheoreticalValue() {
            return a1 * getC1() + a2 * getC2()
                 + a3 * getC3() + a4 * getC4();
        }

        public double getPartial(EstimatedParameter parameter) {
          if (parameter == p2) {
            return 2.0 * p2.getEstimate() * (a2 - a1);
          } else if (parameter == p3) {
            return 2.0 * p3.getEstimate() * (a3 - a1);
          } else {
            return 2.0 * p4.getEstimate() * (a4 - a1);
          }
        }

        private final double a1;
        private final double a2;
        private final double a3;
        private final double a4;

    }

    private EstimatedParameter p2;
    private EstimatedParameter p3;
    private EstimatedParameter p4;

}


kind regards,
Andreas



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to