ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/owl/trunk/proteinstructure/Graph.java
Revision: 191
Committed: Tue Jun 12 17:15:17 2007 UTC (17 years, 8 months ago) by duarte
File size: 20931 byte(s)
Log Message:
New method getAllEdgeNbhSizes
Line User Rev File contents
1 duarte 123 package proteinstructure;
2 duarte 191
3 duarte 134 import java.io.BufferedReader;
4     import java.io.File;
5     import java.io.FileNotFoundException;
6 duarte 123 import java.io.FileOutputStream;
7 duarte 134 import java.io.FileReader;
8 duarte 123 import java.io.PrintStream;
9     import java.io.IOException;
10 duarte 135 import java.sql.ResultSet;
11     import java.sql.SQLException;
12     import java.sql.Statement;
13 duarte 159 import java.util.Collections;
14 duarte 129 import java.util.TreeMap;
15 duarte 189 import java.util.HashMap;
16 duarte 144 import java.util.regex.Matcher;
17     import java.util.regex.Pattern;
18 duarte 135 import tools.MySQLConnection;
19 duarte 123
20    
21     public class Graph {
22    
23 duarte 135 public final static String MYSQLSERVER="white";
24     public final static String MYSQLUSER=getUserName();
25     public final static String MYSQLPWD="nieve";
26 duarte 144
27     public final static String GRAPHFILEFORMATVERSION = "1.0";
28 duarte 135
29 duarte 175 ContactList contacts;
30 duarte 135 // nodes is a TreeMap of residue serials to residue types (3 letter code)
31 duarte 129 TreeMap<Integer,String> nodes;
32 duarte 159 public String sequence; // the full sequence (with unobserved residues and non-standard aas ='X')
33 duarte 143 public String accode;
34     public String chain;
35 duarte 159 public String chaincode="";
36 duarte 146 public double cutoff;
37     public String ct;
38 stehr 161 public boolean directed=false;
39 duarte 123
40 duarte 159 // fullLength is length of full sequence or:
41     // -if sequence not provided (when reading from db): length of everything except possible unobserved residues at end of chain
42     // -if sequence and nodes not provided (when reading from file and sequence field missing): length except possible unobserved residues at end of chain and possible nodes without contacts at end of chain
43     public int fullLength;
44     public int obsLength; // length without unobserved, non standard aas
45    
46     public int numContacts;
47    
48 duarte 175 public boolean modified;
49    
50 duarte 135 // these 2 fields only used when reading from db
51     int graphid=0;
52     int sm_id=0;
53    
54 duarte 134 /**
55     * Constructs Graph object by passing ArrayList with contacts and TreeMap with nodes (res serials and types)
56     * Must also pass contact type, cutoff, accession code and chain
57     * @param contacts
58     * @param nodes
59     * @param sequence
60     * @param cutoff
61     * @param ct
62     * @param accode
63     * @param chain
64     */
65 duarte 175 public Graph (ContactList contacts, TreeMap<Integer,String> nodes, String sequence, double cutoff,String ct, String accode, String chain, String chaincode) {
66 duarte 123 this.contacts=contacts;
67     this.cutoff=cutoff;
68 duarte 129 this.nodes=nodes;
69     this.sequence=sequence;
70     this.accode=accode;
71     this.chain=chain;
72 duarte 156 this.chaincode=chaincode;
73 duarte 123 this.ct=ct;
74 duarte 159 this.fullLength=sequence.length();
75     this.obsLength=nodes.size();
76     this.numContacts=contacts.size();
77 duarte 175 this.modified=false;
78 duarte 129 if (ct.contains("/")){
79     directed=true;
80     }
81 duarte 123 }
82 duarte 135
83     /**
84 duarte 141 * Constructs Graph object from graph db, given the dbname, accode, chaincode (classic pdb chain code), ct and cutoff
85 duarte 135 * @param dbname
86     * @param accode
87 duarte 141 * @param chaincode
88 duarte 135 * @param cutoff
89     * @param ct
90     */
91 duarte 141 public Graph(String dbname, String accode, String chaincode, double cutoff, String ct) throws GraphIdNotFoundError{
92 duarte 135 this.cutoff=cutoff;
93     this.accode=accode;
94     this.ct=ct;
95 duarte 142 // we set the sequence to empty when we read from graph db. We don't have the full sequence in graph db
96     // when we pass the sequence in getCM to the ContactMap constructor we want to have either a full sequence (with unobserveds) or a blank in case we don't have the info
97     this.sequence="";
98 duarte 135 //TODO graphs in db are never directed, so this doesn't really apply here. Must solve all this!
99     if (ct.contains("/")){
100     directed=true;
101     }
102     MySQLConnection conn = new MySQLConnection(MYSQLSERVER,MYSQLUSER,MYSQLPWD,dbname);
103 duarte 141 getgraphid(conn, chaincode); // initialises graphid, sm_id and chain
104     read_graph_from_db(conn); // gets contacts, nodes and sequence
105 duarte 135 conn.close();
106 duarte 159 this.obsLength=nodes.size();
107     if (!sequence.equals("")){
108     this.fullLength=sequence.length();
109     } else {
110     // if nodes TreeMap has correct residue numbering then this should get the right full length,
111     // we will only miss: gaps (unobserved residues) at the end of the sequence. Those we can't know unless full sequence is given
112     this.fullLength=Collections.max(nodes.keySet());
113     }
114     this.numContacts=contacts.size();
115 duarte 175 this.modified=false;
116 duarte 135 }
117 duarte 152
118     /**
119     * Constructs Graph object from graph db, given the graphid
120     * @param dbname
121     * @param graphid
122     */
123     public Graph(String dbname,int graphid) throws GraphIdNotFoundError{
124     this.graphid=graphid;
125     // we set the sequence to empty when we read from graph db. We don't have the full sequence in graph db
126     // when we pass the sequence in getCM to the ContactMap constructor we want to have either a full sequence (with unobserveds) or a blank in case we don't have the info
127     this.sequence="";
128     MySQLConnection conn = new MySQLConnection(MYSQLSERVER,MYSQLUSER,MYSQLPWD,dbname);
129     read_graph_from_db(conn); // gets contacts, nodes and sequence
130     get_db_graph_info(conn); // gets accode, chaincode, chain, ct and cutoff from db (from graph_id)
131     conn.close();
132     //TODO graphs in db are never directed, so this doesn't really apply here. Must solve all this!
133     if (ct.contains("/")){
134     directed=true;
135     }
136 duarte 159 this.obsLength=nodes.size();
137     if (!sequence.equals("")){
138     this.fullLength=sequence.length();
139     } else {
140     // if nodes TreeMap has correct residue numbering then this should get the right full length,
141     // we will only miss: gaps (unobserved residues) at the end of the sequence. Those we can't know unless full sequence is given
142     this.fullLength=Collections.max(nodes.keySet());
143     }
144     this.numContacts=contacts.size();
145 duarte 175 this.modified=false;
146 duarte 152 }
147 duarte 129
148 duarte 134 /**
149     * Constructs Graph object by reading a file with contacts
150 duarte 144 * If the contacts file doesn't have the sequence then the graph object won't have sequence or nodes
151     * That means it won't be possible to get a ContactMap from it using getCM because CM needs both sequence and nodes
152 duarte 134 * @param contactsfile
153     * @throws IOException
154     * @throws FileNotFoundException
155     */
156 duarte 144 public Graph (String contactsfile) throws IOException, FileNotFoundException{
157 duarte 142 // we set the sequence to blank when we read from file as we don't have the full sequence
158 duarte 144 // if sequence is present in contactsfile then is read from there
159 duarte 142 this.sequence="";
160 duarte 144 this.ct="";
161     this.cutoff=0.0;
162 duarte 155 // we initialise accode, chain and chaincode to empty strings in case the file doesn't specify then
163     this.accode="";
164     this.chain="";
165     this.chaincode="";
166 duarte 134 if (ct.contains("/")){
167     directed=true;
168     }
169 duarte 159 read_graph_from_file(contactsfile); // initialises contacts, and nodes (only if sequence is given)
170     if (!sequence.equals("")){
171     this.fullLength=sequence.length();
172     this.obsLength=nodes.size();
173     } else {
174     // if contacts have correct residue numbering then this should get the right full length up to the maximum node that makes a contact,
175     // we will miss: nodes without contacts at the end of sequence and gaps (unobserved residues) at the end of the sequence.
176     // We don't know more without nodes and sequence
177 duarte 175 this.fullLength=contacts.getMaxNode();
178 duarte 159 // in this case nodes has not been initialised so we set obsLength=fullLength as we don't have the information
179     this.obsLength=fullLength;
180     }
181     this.numContacts=contacts.size();
182 duarte 175 this.modified=false;
183 duarte 134 }
184    
185 duarte 135 //TODO implement (from python) write_graph_to_db, do we really need it here??
186    
187     /** get user name from operating system (for use as database username) */
188     private static String getUserName() {
189     String user = null;
190     user = System.getProperty("user.name");
191     if(user == null) {
192     System.err.println("Could not get user name from operating system. Exiting");
193     System.exit(1);
194     }
195     return user;
196     }
197 duarte 144
198     public void read_graph_from_file (String contactsfile) throws FileNotFoundException, IOException {
199 duarte 175 contacts = new ContactList();
200 duarte 134 System.out.println("Reading contacts from file "+contactsfile);
201     BufferedReader fcont = new BufferedReader(new FileReader(new File(contactsfile)));
202     String line;
203     while ((line = fcont.readLine() ) != null ) {
204 duarte 144 Pattern p = Pattern.compile("^#");
205     Matcher m = p.matcher(line);
206     if (m.find()){
207     // Pattern ps = Pattern.compile("^#VER: (\\d\\.\\d)");
208     // Matcher ms = ps.matcher(line);
209     // if (ms.find()){
210     // if (!ms.group(1).equals(GRAPHFILEFORMATVERSION)){
211     // throw new GraphFileFormatError("The graph file "+contactsfile+" can't be read, wrong file format version");
212     // }
213     // }
214     Pattern ps = Pattern.compile("^#SEQUENCE:\\s*(\\w+)$");
215     Matcher ms = ps.matcher(line);
216     if (ms.find()){
217     sequence=ms.group(1);
218     }
219     ps = Pattern.compile("^#PDB:\\s*(\\w+)");
220     ms = ps.matcher(line);
221     if (ms.find()){
222     accode=ms.group(1);
223     }
224     ps = Pattern.compile("^#PDB CHAIN CODE:\\s*(\\w)");
225     ms = ps.matcher(line);
226     if (ms.find()){
227     chaincode=ms.group(1);
228     }
229     ps = Pattern.compile("^#CHAIN:\\s*(\\w)");
230     ms = ps.matcher(line);
231     if (ms.find()){
232     chain=ms.group(1);
233     }
234     ps = Pattern.compile("^#CT:\\s*([a-zA-Z/]+)");
235     ms = ps.matcher(line);
236     if (ms.find()){
237     ct=ms.group(1);
238     }
239     ps = Pattern.compile("^#CUTOFF:\\s*(\\d+\\.\\d+)");
240     ms = ps.matcher(line);
241     if (ms.find()){
242     cutoff=Double.parseDouble(ms.group(1));
243     }
244     }
245     else{
246     int i = Integer.parseInt(line.split("\\s+")[0]);
247     int j = Integer.parseInt(line.split("\\s+")[1]);
248     contacts.add(new Contact(i,j));
249     }
250 duarte 134 }
251     fcont.close();
252 duarte 152 // if sequence was given we take nodes from it
253 duarte 144 nodes = new TreeMap<Integer, String>();
254     for (int i=0;i<sequence.length();i++){
255     String letter = String.valueOf(sequence.charAt(i));
256 duarte 152 nodes.put(i+1, AA.oneletter2threeletter(letter));
257 duarte 144 }
258    
259 duarte 134 }
260    
261 duarte 135 /**
262     * Reads contacts and nodes from db.
263     * The db must be a graph db following our standard format, i.e. must have tables:
264     * chain_graph, single_model_graph, single_model_node, single_model_edge
265     * We don't care here about the origin of the data (msdsd, pdbase, predicted) for the generation of the graph as long as it follows our data format
266     * We read both edges and nodes from single_model_edge and single_model_node.
267 duarte 152 * The sequence is set to blank, as we can't get the full sequence from graph db
268 duarte 135 * @param conn
269     */
270     public void read_graph_from_db(MySQLConnection conn){
271 duarte 175 contacts = new ContactList();
272 duarte 135 nodes = new TreeMap<Integer, String>();
273     try {
274 duarte 142 // we read only half of the matrix (contacts in one direction only) so that we have the same type of contacts as when creating Graph from Pdb object
275 duarte 135 String sql="SELECT i_num,j_num FROM single_model_edge WHERE graph_id="+graphid+" AND j_num>i_num ORDER BY i_num,j_num ";
276     Statement stmt = conn.createStatement();
277     ResultSet rsst = stmt.executeQuery(sql);
278     while (rsst.next()) {
279     int i=rsst.getInt(1);
280     int j=rsst.getInt(2);
281     contacts.add(new Contact(i,j));
282     }
283     rsst.close();
284     stmt.close();
285     sql="SELECT num,res FROM single_model_node WHERE graph_id="+graphid+" ORDER BY num ";
286     stmt = conn.createStatement();
287     rsst = stmt.executeQuery(sql);
288     while (rsst.next()){
289     int num=rsst.getInt(1);
290     String res=rsst.getString(2);
291     nodes.put(num, AA.oneletter2threeletter(res));
292     }
293     rsst.close();
294     stmt.close();
295     } catch (SQLException e) {
296     e.printStackTrace();
297     }
298    
299     }
300    
301 duarte 141 public void getgraphid (MySQLConnection conn, String chaincode) throws GraphIdNotFoundError{
302     // input is chaincode i.e. pdb chain code
303     // we take chain (internal chain identifier, pchain_code for msdsd and asym_id for pdbase) from pchain_code field in chain_graph
304     // (in the chain_graph table the internal chain identifier is called 'pchain_code')
305 duarte 135 int pgraphid=0;
306 duarte 141 String chainstr="='"+chaincode+"' ";
307     if (chaincode.equals("NULL")){
308     chainstr=" IS NULL ";
309     }
310 duarte 135 try {
311 duarte 141 String sql="SELECT graph_id, pchain_code FROM chain_graph WHERE accession_code='"+accode+"' AND chain_pdb_code"+chainstr+" AND dist="+cutoff;
312 duarte 135 Statement stmt = conn.createStatement();
313     ResultSet rsst = stmt.executeQuery(sql);
314     int check=0;
315     while (rsst.next()) {
316     check++;
317     pgraphid=rsst.getInt(1);
318 duarte 141 chain=rsst.getString(2);
319 duarte 135 }
320     if (check!=1){
321 duarte 141 System.err.println("No pgraph_id match or more than 1 match for accession_code="+accode+", chain_pdb_code="+chaincode+", dist="+cutoff);
322 duarte 135 }
323     rsst.close();
324     stmt.close();
325     // we set the ctstr to the same as ct except in ALL case, where it is BB+SC+BB/SC
326     String ctstr=ct;
327     if (ct.equals("ALL")){
328     ctstr="BB+SC+BB/SC";
329     }
330     sql="SELECT graph_id,single_model_id FROM single_model_graph WHERE pgraph_id="+pgraphid+" AND CT='"+ctstr+"' AND dist="+cutoff+" AND CR='(true)' AND CW=1";
331     stmt = conn.createStatement();
332     rsst = stmt.executeQuery(sql);
333     check=0;
334     while (rsst.next()){
335     check++;
336     graphid=rsst.getInt(1);
337     sm_id=rsst.getInt(2);
338     }
339     if (check!=1){
340     System.err.println("No graph_id match or more than 1 match for pgraph_id="+pgraphid+", CT="+ctstr+" and cutoff="+cutoff);
341     throw new GraphIdNotFoundError("No graph_id match or more than 1 match for pgraph_id="+pgraphid+", CT="+ctstr+" and cutoff="+cutoff);
342     }
343     } catch (SQLException e) {
344     e.printStackTrace();
345     }
346    
347     }
348    
349 duarte 152 public void get_db_graph_info(MySQLConnection conn) throws GraphIdNotFoundError {
350     try {
351     int pgraphid=0;
352     String sql="SELECT pgraph_id,CT,dist FROM single_model_graph WHERE graph_id="+graphid;
353     Statement stmt = conn.createStatement();
354     ResultSet rsst = stmt.executeQuery(sql);
355     int check=0;
356     while (rsst.next()) {
357     check++;
358     pgraphid=rsst.getInt(1);
359     ct=rsst.getString(2);
360     if (ct.equals("BB+SC+BB/SC")) ct="ALL";
361     cutoff=rsst.getDouble(3);
362     }
363     if (check!=1){
364     System.err.println("No pgraph_id match or more than 1 match for graph_id="+graphid);
365     throw new GraphIdNotFoundError("No pgraph_id match or more than 1 match for graph_id="+graphid+" in db"+conn.getDbname());
366     }
367     rsst.close();
368     stmt.close();
369     sql="SELECT accession_code, chain_pdb_code, pchain_code FROM chain_graph WHERE graph_id="+pgraphid;
370     stmt = conn.createStatement();
371     rsst = stmt.executeQuery(sql);
372     check=0;
373     while (rsst.next()){
374     check++;
375     accode=rsst.getString(1);
376     chaincode=rsst.getString(2);
377 duarte 158 // java returns a null if the field is a database null, we want actually the "NULL" string in that case
378     if (chaincode==null) chaincode="NULL";
379 duarte 152 chain=rsst.getString(3);
380     }
381     if (check!=1){
382     System.err.println("No accession_code+chain_pdb_code+pchain_code match or more than 1 match for graph_id="+pgraphid+" in chain_graph table");
383     }
384     rsst.close();
385     stmt.close();
386     } catch (SQLException e) {
387     e.printStackTrace();
388     }
389    
390     }
391    
392 duarte 123 public void write_contacts_to_file (String outfile) throws IOException {
393     PrintStream Out = new PrintStream(new FileOutputStream(outfile));
394     for (Contact pair:contacts){
395     int i_resser=pair.i;
396     int j_resser=pair.j;
397     Out.println(i_resser+"\t"+j_resser);
398     }
399     Out.close();
400     }
401 duarte 144
402     public void write_graph_to_file (String outfile) throws IOException {
403     PrintStream Out = new PrintStream(new FileOutputStream(outfile));
404     Out.println("#VER: "+GRAPHFILEFORMATVERSION);
405     Out.println("#SEQUENCE: "+sequence);
406     Out.println("#PDB: "+accode);
407     Out.println("#PDB CHAIN CODE: "+chaincode);
408     Out.println("#CHAIN: "+chain);
409     Out.println("#CT: "+ct);
410     Out.println("#CUTOFF: "+cutoff);
411     for (Contact pair:contacts){
412     int i_resser=pair.i;
413     int j_resser=pair.j;
414     Out.println(i_resser+"\t"+j_resser);
415     }
416     Out.close();
417     }
418 duarte 175
419 duarte 159 /**
420 duarte 175 * Gets list of contacts as a new ContactList (deep copied)
421     *
422     */
423     public ContactList getContacts(){
424     ContactList newContacts = new ContactList();
425     for (Contact cont:contacts){
426     newContacts.add(new Contact(cont.i,cont.j));
427     }
428     return newContacts;
429     }
430    
431     /**
432     * Gets TreeMap of nodes, deep copying
433     *
434     */
435     public TreeMap<Integer,String> getNodes(){
436     TreeMap<Integer,String> newNodes = new TreeMap<Integer,String>();
437     for (int resser:nodes.keySet()){
438     newNodes.put(resser, nodes.get(resser));
439     }
440     return newNodes;
441     }
442    
443     /**
444     * Deep copies this Graph object returning new one
445     * @return
446     */
447     public Graph copy(){
448     return new Graph(getContacts(),getNodes(),sequence,cutoff,ct,accode,chain,chaincode);
449     }
450    
451     /**
452 duarte 159 * Returns an int matrix with 1s for contacts and 0s for non contacts, i.e. the contact map
453     * In non-crossed cases this should give us the upper half matrix (contacts are only j>i)
454     * In crossed cases this gives us a full matrix (contacts are both j>i and i>j since they are directed)
455     * @return
456     */
457     public int[][] getIntMatrix(){
458     // this initialises the matrix to 0 (i.e. no contact)
459     int[][] cm = new int[fullLength][fullLength];
460     // we put a 1 for all given contacts
461     for (Contact cont:contacts){
462     int i_resser = cont.i;
463     int j_resser = cont.j;
464     cm[i_resser-1][j_resser-1]=1;
465 duarte 129 }
466     return cm;
467     }
468 duarte 159
469 duarte 165 /**
470 duarte 179 * Gets a node's residue type given the residue serial
471     * @param resser
472     * @return
473     */
474     public String getResType(int resser){
475     return nodes.get(resser);
476     }
477    
478     /**
479 duarte 165 * Gets node neighbourhood given a residue serial
480     * @param resser
481     * @return
482     */
483 duarte 179 public NodeNbh getNodeNbh(int resser){
484     NodeNbh nbh = new NodeNbh(resser, getResType(resser));
485 duarte 165 //this could be implemented using the contact map matrix and scanning through 1 column/row
486     //it would be just slightly faster, here we do 2*numContacts iterations, using matrix would be only fullLength iterations
487 duarte 179 //however we would then have the overhead of creating the matrix
488 duarte 165 for (Contact cont:contacts){
489     if (cont.i==resser) nbh.put(cont.j, nodes.get(cont.j));
490     if (cont.j==resser) nbh.put(cont.i, nodes.get(cont.i));
491     }
492     return nbh;
493     }
494    
495     /**
496     * Gets edge neighbourhood (common neighbourhood) given a residue serial pair
497     * @param i_resser
498     * @param j_resser
499     * @return
500     */
501 duarte 179 public EdgeNbh getEdgeNbh(int i_resser, int j_resser){
502     EdgeNbh nbh = new EdgeNbh(i_resser, getResType(i_resser), j_resser, getResType(j_resser));
503     NodeNbh i_nbhd = getNodeNbh(i_resser);
504     NodeNbh j_nbhd = getNodeNbh(j_resser);
505 duarte 175 if (j_nbhd.size()>=i_nbhd.size()) { //with this we will be slightly faster, always iterating through smallest TreeMap
506     for (int resser:i_nbhd.keySet()) {
507     if (j_nbhd.containsKey(resser)) nbh.put(resser, i_nbhd.get(resser));
508     }
509     } else {
510     for (int resser:j_nbhd.keySet()) {
511     if (i_nbhd.containsKey(resser)) nbh.put(resser, j_nbhd.get(resser));
512     }
513 duarte 165 }
514     return nbh;
515     }
516    
517 duarte 175 public void addEdge(Contact cont){
518     contacts.add(cont);
519     numContacts++;
520     modified=true;
521     }
522    
523     public void delEdge(Contact cont){
524     contacts.remove(cont);
525     numContacts--;
526     modified=true;
527     }
528    
529     public void restrictContactsToMaxRange(int range){
530 duarte 179 ContactList edgesToDelete = new ContactList();
531 duarte 175 for (Contact cont:contacts){
532 duarte 179 if (cont.getRange()>range) edgesToDelete.add(cont);
533 duarte 175 }
534 duarte 179 for (Contact cont:edgesToDelete){
535     delEdge(cont);
536     }
537 duarte 175 }
538    
539     public void restrictContactsToMinRange(int range){
540 duarte 179 ContactList edgesToDelete = new ContactList();
541 duarte 175 for (Contact cont:contacts){
542 duarte 179 if (cont.getRange()<range) edgesToDelete.add(cont);
543 duarte 175 }
544 duarte 179 for (Contact cont:edgesToDelete){
545     delEdge(cont);
546     }
547 duarte 175 }
548 duarte 189
549 duarte 191 /**
550     * Returns a HashMap with all edge neighbourhood sizes (if they are >0) for each cell in the contact map
551     * @return
552     */
553     public HashMap<Contact,Integer> getAllEdgeNbhSizes() {
554     HashMap<Contact,Integer> sizes = new HashMap<Contact, Integer>();
555     if (!directed) {
556     for (int i=1; i<fullLength;i++){
557     for (int j=i+1; j<fullLength;j++){
558     int size = getEdgeNbh(i, j).size();
559     if (size>0) sizes.put(new Contact(i,j), size);
560     }
561     }
562     } else {
563     for (int i=1; i<fullLength;i++){
564     for (int j=1; j<fullLength;j++){
565     if (i!=j){
566     int size = getEdgeNbh(i, j).size();
567     if (size>0) sizes.put(new Contact(i,j), size);
568     }
569     }
570     }
571     }
572     return sizes;
573     }
574    
575 duarte 189 //TODO not sure what kind of return we want, for now is a HashMap with three graph objects
576     public HashMap<String,Graph> compare(Graph other) throws Exception{
577     //first check that other has same sequence than this, otherwise throw exception
578     if (!this.sequence.equals(other.sequence)){
579     //TODO throw specific exception
580     throw new Exception("Sequence of 2 graphs to compare differ, can't compare them.");
581     }
582     ContactList common = new ContactList();
583     ContactList onlythis = new ContactList();
584     ContactList onlyother = new ContactList();
585     for (Contact cont:this.contacts){
586     if (other.contacts.contains(cont)) {
587     common.add(cont);
588     } else{
589     onlythis.add(cont);
590     }
591     }
592     for (Contact cont:other.contacts){
593     if (!this.contacts.contains(cont)){
594     onlyother.add(cont);
595     }
596     }
597     Graph commongraph = new Graph (common,getNodes(),sequence,cutoff,ct,accode,chain,chaincode);
598     Graph onlythisgraph = new Graph (onlythis,getNodes(),sequence,cutoff,ct,accode,chain,chaincode);
599     Graph onlyothergraph = new Graph (onlyother,getNodes(),sequence,cutoff,ct,other.accode,other.chain,other.chaincode);
600     HashMap<String,Graph> result = new HashMap<String,Graph>();
601     result.put("common", commongraph);
602     result.put("onlythis", onlythisgraph);
603     result.put("onlyother",onlyothergraph);
604     return result;
605     }
606 duarte 123 }