io.github.msdk.features.ransacaligner.RANSAC.java Source code

Java tutorial

Introduction

Here is the source code for io.github.msdk.features.ransacaligner.RANSAC.java

Source

/* 
 * (C) Copyright 2015-2016 by MSDK Development Team
 *
 * This software is dual-licensed under either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package io.github.msdk.features.ransacaligner;

import com.google.common.collect.Range;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import org.apache.commons.math.optimization.fitting.PolynomialFitter;
import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;

/**
 * input: data - a set of observed data points n - the minimum number of data
 * values required to fit the model k - the maximum number of iterations allowed
 * in the algorithm t - a threshold value for determining when a data point fits
 * a model d - the number of close data values required to assert that a model
 * fits well to data
 *
 * output: model which best fit the data
 */
public class RANSAC {

    private int n;
    private double d = 1;
    private int k = 0;
    private int AlsoNumber;
    private final double t;
    private final boolean Linear;
    private final double dataPointsRate;

    public RANSAC(double t, boolean linear, double dataPointsRate) {

        this.t = t;

        this.Linear = linear;

        if (dataPointsRate == 0) {
            this.dataPointsRate = 0.1;
        } else {
            this.dataPointsRate = dataPointsRate;
        }

    }

    /**
     * Set all parameters and start ransac.
     *
     * @param data vector with the points which represent all possible
     * alignments.
     */
    public void alignment(List<AlignStructMol> data) {
        try {
            // If the model is non linear 4 points are taken to build the model,
            // if it is linear only 2 points are taken.
            if (!Linear) {
                n = 4;
            } else {
                n = 2;
            }

            // Minimun number of points required to assert that a model fits
            // well to data
            if (data.size() < 10) {
                d = 3;
            } else {
                d = data.size() * this.dataPointsRate;
            }

            // Calculate the number of trials
            k = (int) getK();

            ransac(data);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /**
     * Calculate k (number of trials)
     *
     * @return number of trials "k" required to select a subset of n good data
     * points.
     */
    private double getK() {
        double w = 0.1;
        double b = Math.pow(w, n);
        return Math.log10(1 - 0.99) / Math.log10(1 - b) + (Math.sqrt(1 - b) / b);
    }

    /**
     * RANSAC algorithm
     *
     * @param data vector with the points which represent all possible
     * alignments.
     */
    public void ransac(List<AlignStructMol> data) {
        double besterr = 9.9E99;

        for (int iterations = 0; iterations < k; iterations++) {
            AlsoNumber = n;
            // Get the initial points
            boolean initN = getInitN(data);
            if (!initN) {
                continue;
            }

            // Calculate the model
            fittPolinomialFunction(data, Linear);

            // If the model has the minimun number of points
            if (AlsoNumber >= d) {
                // Get the error of the model based on the number of points
                double error = 9.9E99;
                try {
                    error = newError(data);
                } catch (Exception ex) {
                    Logger.getLogger(RANSAC.class.getName()).log(Level.SEVERE, null, ex);
                }

                // If the error is less than the error of the last model
                if (error < besterr) {
                    besterr = error;
                    for (int i = 0; i < data.size(); i++) {
                        AlignStructMol alignStruct = data.get(i);
                        if (alignStruct.ransacAlsoInLiers || alignStruct.ransacMaybeInLiers) {
                            alignStruct.Aligned = true;
                        } else {
                            alignStruct.Aligned = false;
                        }

                        alignStruct.ransacAlsoInLiers = false;
                        alignStruct.ransacMaybeInLiers = false;

                    }
                }
            }
            // remove the model
            for (int i = 0; i < data.size(); i++) {
                AlignStructMol alignStruct = data.get(i);
                alignStruct.ransacAlsoInLiers = false;
                alignStruct.ransacMaybeInLiers = false;
            }

        }
    }

    /**
     * Take the initial points ramdoly. The points are divided by the initial
     * number of points. If the fractions contain enough number of points took
     * one point from each part.
     *
     * @param data vector with the points which represent all possible
     * alignments.
     * @return false if there is any problem.
     */
    private boolean getInitN(List<AlignStructMol> data) {
        if (data.size() > n) {
            Collections.sort(data, new AlignStructMol());
            double min = data.get(0).RT;
            double max = data.get(data.size() - 1).RT;

            Range<Double> rtRange = Range.closed(min, ((max - min) / 2) + min);

            int cont = 0, bucle = 0;
            while (cont < n / 2 && bucle < 1000) {
                int index = (int) (data.size() * Math.random());
                if (!data.get(index).ransacMaybeInLiers && rtRange.contains(data.get(index).RT)) {
                    data.get(index).ransacMaybeInLiers = true;
                    cont++;

                }

                bucle++;
            }
            if (bucle >= 1000) {
                getN(data, (n / 2) - cont);
            }

            bucle = 0;
            rtRange = Range.closed(((max - min) / 2) + min, max);

            while (cont < n && bucle < 1000) {

                int index = (int) (data.size() * Math.random());
                if (!data.get(index).ransacMaybeInLiers && rtRange.contains(data.get(index).RT)) {
                    data.get(index).ransacMaybeInLiers = true;
                    cont++;
                }
                bucle++;
            }
            if (bucle >= 1000) {
                getN(data, n - cont);
            }
            return true;
        } else {
            return false;
        }
    }

    private void getN(List<AlignStructMol> data, int newN) {
        if (newN < 1) {
            return;
        }
        int cont = 0;
        while (cont < newN) {
            int index = (int) (data.size() * Math.random());
            if (!data.get(index).ransacMaybeInLiers) {
                data.get(index).ransacMaybeInLiers = true;
                cont++;
            }
        }
    }

    private void fittPolinomialFunction(List<AlignStructMol> data, boolean linear) {
        List<AlignStructMol> points = new ArrayList<AlignStructMol>();

        int degree = 3;
        if (linear) {
            degree = 1;
        }

        PolynomialFitter fitter = new PolynomialFitter(degree, new GaussNewtonOptimizer(true));
        for (int i = 0; i < data.size(); i++) {
            AlignStructMol point = data.get(i);
            if (point.ransacMaybeInLiers) {
                points.add(point);
                fitter.addObservedPoint(1, point.RT, point.RT2);
            }
        }
        try {
            PolynomialFunction function = fitter.fit();
            for (AlignStructMol point : data) {
                double y = point.RT2;
                double bestY = function.value(point.RT);
                if (Math.abs(y - bestY) < t) {
                    point.ransacAlsoInLiers = true;
                    AlsoNumber++;
                } else {
                    point.ransacAlsoInLiers = false;
                }
            }
        } catch (Exception ex) {
        }
    }

    /**
     * calculate the error in the model
     *
     * @param data vector with the points which represent all possible
     * alignments.
     * @param regression regression of the alignment points
     * @return the error in the model
     */
    private double newError(List<AlignStructMol> data) throws Exception {

        double numT = 1;
        for (int i = 0; i < data.size(); i++) {
            if (data.get(i).ransacAlsoInLiers || data.get(i).ransacMaybeInLiers) {
                numT++;
            }
        }
        return 1 / numT;

    }
}