Commit f4685141 authored by Phuong Khanh Tran's avatar Phuong Khanh Tran
Browse files

Update Molecule.java

parent 9fbdf464
Loading
Loading
Loading
Loading
+234 −2
Original line number Diff line number Diff line
@@ -6,6 +6,9 @@ import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;


/**
 * Represents a molecule containing atoms and edges.
@@ -66,13 +69,11 @@ public class Molecule implements Serializable {

        // Compare the number of elements
        if (!Arrays.equals(this.numElements, otherMolecule.numElements)) {
//            System.out.println("different numElements");
            return null; // Number of elements is different, molecules are not equal
        }

        // Compare the number of edges
        if (this.numEdges != otherMolecule.numEdges) {
//            System.out.println("different numEdges");
            return null; // Number of edges is different, molecules are not equal
        }

@@ -123,6 +124,226 @@ public class Molecule implements Serializable {
        return this;
    }


    /**
     * Finds the Most Similar Molecule
     */
    public int mostSimilar(Molecule otherMolecule) {

        int similarity=0; //counts similarity points

        // Points for an intersection of elements between this and otherMolecule
        for(int i=0;i<this.numElements.length;i++)
        {
            similarity+= Math.min( this.numElements[i], otherMolecule.numElements[i]);
        }

        //Points for same number of atoms
        if(this.numAtoms==otherMolecule.numAtoms)
        {
            similarity++;
        }

        //Points for same number of edges
        if(this.numEdges==otherMolecule.numEdges)
        {
            similarity++;
        }


        // Clean the otherMolecule atom list of any marked atoms
        for(Atom cleanAtom : otherMolecule.atomArrayList)
        {
            cleanAtom.marked = false;

            //clean the connected arraylist
            for(int i=0;i<cleanAtom.connectedMarked.size();i++)
            {
                cleanAtom.connectedMarked.set(i,false);
            }
        }
        // Clean the dbMolecule atom list of any marked atoms

        // Compare the atom lists
        for(Atom dbAtom : this.atomArrayList) {
            boolean matchingEdge=false;

            for (Atom newAtom : otherMolecule.atomArrayList) {

                if (!newAtom.marked && newAtom.elementType == dbAtom.elementType) { //Check if elements are the same
                    boolean [] edgeMarked = new boolean[newAtom.connected.size()];
                    // Compare connected of each atom
                    //for each connected atom in dbAtom
                    for (Atom.ElemOrderPair dbValues : dbAtom.connected.values()) {
                        int marker=0;

                        for (Atom.ElemOrderPair newAtomValues : newAtom.connected.values()) {
                            //if its a match
                            //if first 2 yes, add points for min of bondOrder between the 2
                            if (!newAtom.connectedMarked.get(marker) && !edgeMarked[marker] && dbValues.eType == newAtomValues.eType )
                            {
                                if( dbValues.bondOrder == newAtomValues.bondOrder)
                                {
                                    //mark the newAtom edge as already found
                                    newAtom.connectedMarked.set(marker,true);
                                    matchingEdge=true;
                                    edgeMarked[marker]=true;
                                    similarity++; //add a point for each edge that is the same
                                    break;
                                }

                            }
                            marker++;

                        }
                    }

                }

                if(matchingEdge)
                {
                    newAtom.marked=true;
                    break;
                }
            }

        }

        // If all comparisons passed, the molecules are equal
        return similarity;
    }

    public Molecule isSubGraphPresent(Molecule subgraph) {
        //compare the number of elements
        for (int ii = 0; ii < numElements.length; ii++)
            if (this.numElements[ii] < subgraph.numElements[ii])
                return null;

        // Compare # of edges
        if (this.numEdges < subgraph.numEdges)
            return null;

        //Hashmap of candidates
        HashMap<Atom, ArrayList<Atom>> CandidateList = new HashMap<>();

        //For each atom in the array list
        for (Atom possibleCandidate : this.atomArrayList) {
            Object[] cndArray = possibleCandidate.connected.values().toArray();
            for (Atom keyAtom : subgraph.atomArrayList) {
                if (!keyAtom.equals(possibleCandidate)) {
                    if (keyAtom.elementType == possibleCandidate.elementType) {
                        if (keyAtom.degree <= possibleCandidate.degree) {
                            boolean validConnects = true;
                            boolean[] edgeMarked = new boolean[possibleCandidate.connected.size()];
                            for (Atom.ElemOrderPair keyValue : keyAtom.connected.values()) {
                                boolean edgeFound = false;
                                for (int aa = 0; aa < edgeMarked.length; aa++) {
                                    if (!edgeMarked[aa] && keyValue.eType == ((Atom.ElemOrderPair) cndArray[aa]).eType && keyValue.bondOrder == ((Atom.ElemOrderPair) cndArray[aa]).bondOrder) {
                                        edgeMarked[aa] = true;
                                        edgeFound = true;
                                        break;
                                    }
                                }
                                if (!edgeFound) {
                                    validConnects = false;
                                }
                            }
                            if (validConnects) {
                                //add atom to list
                                if (!CandidateList.containsKey(keyAtom)) {
                                    CandidateList.put(keyAtom, new ArrayList<>());
                                }
                                CandidateList.get(keyAtom).add(possibleCandidate);
                            }
                        }
                    }
                }
            }
        }
        //if it matches the type (elem and connections) as one in the subgraph, add it to candidate list for subgrpah

        //Look through list of candidates, and if any of the lists are empty return null
        for (Atom sweep : subgraph.atomArrayList)
            if (!CandidateList.containsKey(sweep))
                return null;


        //Unmark all atoms (marked = visited)
        for (Atom cleanAtom : this.atomArrayList)
            cleanAtom.marked = false;
        for (Atom cleanAtom : subgraph.atomArrayList)
            cleanAtom.marked = false;

        //BFS node: parent atom, other candidates
        //Make a linked list of the BFS node
        LinkedList<subGraphNode> subgraphTraversal = new LinkedList<subGraphNode>();
        //head is the first atom (parent is null)
        subgraphTraversal.addFirst(new subGraphNode(null, subgraph.atomArrayList.get(0)));
        for (Atom c : CandidateList.get(subgraph.atomArrayList.get(0))) {
            //c.marked = true;
            subgraphTraversal.get(0).options.add(c);
        }
        subgraphTraversal.getFirst().self.marked = true;
        int pointer = 0;
        while(true) {
            subGraphNode current = subgraphTraversal.get(pointer);

            if(current.options.isEmpty()) {
                //If there are no options to choose from, move pointer backwards (to parent) and restart cycke
                //if parent is null return null
                if(current.parent == null)
                    return null;
                else
                    pointer = subgraphTraversal.indexOf(current.parent);
            }
            else {
                boolean mustReverse = false;
                int adjAdded = 0;
                //remove option (choose it)
                Atom path = current.options.remove(0);
                path.marked = true;
                //else add adjacent local nodes
                for(String k :current.self.connected.keySet()) {
                    for(Atom a: subgraph.atomArrayList) {
                        if(!a.marked && a.getName().equals(k)) {
                            a.marked = true;
                            subgraphTraversal.add(new subGraphNode(current,a));
                            adjAdded++;
                            //add options to adjacent (checking validity:not marked and connected to parent)
                            ArrayList<Atom> aList = CandidateList.get(a);
                            boolean candFound = false;
                            for(Atom cand: aList) {
                                if(!cand.marked) { //not marked
                                    if(cand.connected.containsKey(path.getName())) {  //is connected
                                        subgraphTraversal.getLast().options.add(cand);
                                        candFound = true;
                                    }
                                }
                            }
                            if(!candFound)
                                mustReverse = true;
                            break;
                        }
                    }
                }
                if(mustReverse) {
                    path.marked = false;
                    for(int ff = 0; ff < adjAdded;ff++) {
                        subgraphTraversal.getLast().self.marked = false;
                        subgraphTraversal.remove(subgraphTraversal.getLast());
                    }
                }
                else{
                    if(subgraphTraversal.getLast().equals(subgraphTraversal.get(pointer)))
                        return this;
                    pointer++;
                }
            }

        }
    }


    /**
     * Return number of atoms of the molecule
     */
@@ -130,6 +351,17 @@ public class Molecule implements Serializable {
        return numAtoms;
    }

    class subGraphNode implements Serializable {
        public subGraphNode parent;
        public ArrayList<Atom> options;
        public Atom self;
        public  subGraphNode(subGraphNode p, Atom s) {
            this.parent = p;
            this.self = s;
            this.options = new ArrayList<Atom>();
        }
    };


}