com.act.analysis.surfactant.AtomSplit.java Source code

Java tutorial

Introduction

Here is the source code for com.act.analysis.surfactant.AtomSplit.java

Source

/*************************************************************************
*                                                                        *
*  This file is part of the 20n/act project.                             *
*  20n/act enables DNA prediction for synthetic biology/bioengineering.  *
*  Copyright (C) 2017 20n Labs, Inc.                                     *
*                                                                        *
*  Please direct all queries to act@20n.com.                             *
*                                                                        *
*  This program is free software: you can redistribute it and/or modify  *
*  it under the terms of the GNU General Public License as published by  *
*  the Free Software Foundation, either version 3 of the License, or     *
*  (at your option) any later version.                                   *
*                                                                        *
*  This program is distributed in the hope that it will be useful,       *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*  GNU General Public License for more details.                          *
*                                                                        *
*  You should have received a copy of the GNU General Public License     *
*  along with this program.  If not, see <http://www.gnu.org/licenses/>. *
*                                                                        *
*************************************************************************/

package com.act.analysis.surfactant;

import chemaxon.marvin.calculations.logPPlugin;
import org.apache.commons.lang3.tuple.Pair;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class AtomSplit {
    Set<Integer> leftIndices;
    Set<Integer> rightIndices;

    double leftSum = 0.0, rightSum = 0.0;
    double weightedLeftSum = 0.0, weightedRightSum = 0.0;
    int leftPosCount = 0, leftNegCount = 0;
    int rightPosCount = 0, rightNegCount = 0;
    double leftMin = 0.0, leftMax = 0.0;
    double rightMin = 0.0, rightMax = 0.0;

    protected AtomSplit() {
    }

    public AtomSplit(AtomSplit toCopy) {
        this.leftIndices = new HashSet<>(toCopy.leftIndices);
        this.rightIndices = new HashSet<>(toCopy.rightIndices);
        this.leftSum = toCopy.leftSum;
        this.rightSum = toCopy.rightSum;
        this.weightedLeftSum = toCopy.weightedLeftSum;
        this.weightedRightSum = toCopy.weightedRightSum;
        this.leftPosCount = toCopy.leftPosCount;
        this.leftNegCount = toCopy.leftNegCount;
        this.rightPosCount = toCopy.rightPosCount;
        this.rightNegCount = toCopy.rightNegCount;
        this.leftMin = toCopy.leftMin;
        this.leftMax = toCopy.leftMax;
        this.rightMin = toCopy.rightMin;
        this.rightMax = toCopy.rightMax;
        assert (this.equals(toCopy));
    }

    public Set<Integer> getLeftIndices() {
        return leftIndices;
    }

    public Set<Integer> getRightIndices() {
        return rightIndices;
    }

    public double getLeftSum() {
        return leftSum;
    }

    public double getRightSum() {
        return rightSum;
    }

    public double getWeightedLeftSum() {
        return weightedLeftSum;
    }

    public double getWeightedRightSum() {
        return weightedRightSum;
    }

    public int getLeftPosCount() {
        return leftPosCount;
    }

    public int getLeftNegCount() {
        return leftNegCount;
    }

    public int getRightPosCount() {
        return rightPosCount;
    }

    public int getRightNegCount() {
        return rightNegCount;
    }

    public double getLeftMin() {
        return leftMin;
    }

    public double getLeftMax() {
        return leftMax;
    }

    public double getRightMin() {
        return rightMin;
    }

    public double getRightMax() {
        return rightMax;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        AtomSplit that = (AtomSplit) o;

        if (Double.compare(that.leftSum, leftSum) != 0)
            return false;
        if (Double.compare(that.rightSum, rightSum) != 0)
            return false;
        if (Double.compare(that.weightedLeftSum, weightedLeftSum) != 0)
            return false;
        if (Double.compare(that.weightedRightSum, weightedRightSum) != 0)
            return false;
        if (leftPosCount != that.leftPosCount)
            return false;
        if (leftNegCount != that.leftNegCount)
            return false;
        if (rightPosCount != that.rightPosCount)
            return false;
        if (rightNegCount != that.rightNegCount)
            return false;
        if (Double.compare(that.leftMin, leftMin) != 0)
            return false;
        if (Double.compare(that.leftMax, leftMax) != 0)
            return false;
        if (Double.compare(that.rightMin, rightMin) != 0)
            return false;
        if (Double.compare(that.rightMax, rightMax) != 0)
            return false;
        if (leftIndices != null ? !leftIndices.equals(that.leftIndices) : that.leftIndices != null)
            return false;
        return !(rightIndices != null ? !rightIndices.equals(that.rightIndices) : that.rightIndices != null);

    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = leftIndices != null ? leftIndices.hashCode() : 0;
        result = 31 * result + (rightIndices != null ? rightIndices.hashCode() : 0);
        temp = Double.doubleToLongBits(leftSum);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(rightSum);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(weightedLeftSum);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(weightedRightSum);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + leftPosCount;
        result = 31 * result + leftNegCount;
        result = 31 * result + rightPosCount;
        result = 31 * result + rightNegCount;
        temp = Double.doubleToLongBits(leftMin);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(leftMax);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(rightMin);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(rightMax);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    public static Pair<AtomSplit, AtomSplit> computePlaneSplitsForIntersectingAtom(Collection<Integer> leftAtoms,
            Collection<Integer> rightAtoms, Integer planeIntersectingAtom, logPPlugin plugin,
            Map<Integer, Integer> surfaceComponentCounts) {

        /* Compute variants of the split with the current atom on either side of its plane.
         *
         * This isn't the most clever way to compute the optimal planes, since adjacent split points will end up creating
         * one redundant plane with each computation (if a and b are adjacent, a to the left of the border and b to the
         * right create the same split sets).  However, it's easy to reason about the correctness of this approach, so
         * we'll just live with the inefficiency for now.
         *
         * TODO: extend this to handle an arbitrary set of co-planar points that define the split, and apply the same
         * technique to all triples of atoms.
         * */

        AtomSplit ps = new AtomSplit();
        ps.leftIndices = new HashSet<>(leftAtoms);
        ps.rightIndices = new HashSet<>(rightAtoms);

        for (Integer a : leftAtoms) {
            if (planeIntersectingAtom.equals(a)) {
                // Skip the split point, though it could contribute to the "best" solution.
                continue;
            }
            Double logP = plugin.getAtomlogPIncrement(a);
            Double weightedLogP = logP * surfaceComponentCounts.get(a).doubleValue();
            ps.leftSum += logP;
            ps.weightedLeftSum += weightedLogP;

            if (logP < ps.leftMin) {
                ps.leftMin = logP;
            }
            if (logP > ps.leftMax) {
                ps.leftMax = logP;
            }

            if (logP >= 0.000) {
                ps.leftPosCount++;
            } else {
                ps.leftNegCount++;
            }
        }
        for (Integer a : rightAtoms) {
            if (planeIntersectingAtom.equals(a)) {
                continue;
            }
            Double logP = plugin.getAtomlogPIncrement(a);
            Double weightedLogP = logP * surfaceComponentCounts.get(a);
            ps.rightSum += logP;
            ps.weightedRightSum += weightedLogP;

            if (logP < ps.rightMin) {
                ps.rightMin = logP;
            }
            if (logP > ps.rightMax) {
                ps.rightMax = logP;
            }

            if (logP >= 0.000) {
                ps.rightPosCount++;
            } else {
                ps.rightNegCount++;
            }
        }

        // Create variants with this point added to left and right sides of split plane.
        AtomSplit leftVariant = ps;
        AtomSplit rightVariant = new AtomSplit(ps);
        Double logP = plugin.getAtomlogPIncrement(planeIntersectingAtom);
        Double weightedLogP = logP * surfaceComponentCounts.get(planeIntersectingAtom).doubleValue();

        leftVariant.leftIndices.add(planeIntersectingAtom);
        leftVariant.leftSum += logP;
        leftVariant.weightedLeftSum += weightedLogP;
        if (logP >= 0.000) {
            leftVariant.leftPosCount++;
        } else {
            leftVariant.leftNegCount++;
        }
        if (logP < leftVariant.leftMin) {
            leftVariant.leftMin = logP;
        }
        if (logP > leftVariant.leftMax) {
            leftVariant.leftMax = logP;
        }

        rightVariant.rightIndices.add(planeIntersectingAtom);
        rightVariant.rightSum += logP;
        rightVariant.weightedRightSum += weightedLogP;
        if (logP >= 0.000) {
            rightVariant.rightPosCount++;
        } else {
            rightVariant.rightNegCount++;
        }
        if (logP < rightVariant.rightMin) {
            rightVariant.rightMin = logP;
        }
        if (logP > rightVariant.rightMax) {
            rightVariant.rightMax = logP;
        }

        return Pair.of(leftVariant, rightVariant);
    }
}