ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/owl/trunk/proteinstructure/ContactMap.java
Revision: 131
Committed: Thu May 10 15:53:14 2007 UTC (17 years, 5 months ago) by duarte
File size: 20942 byte(s)
Log Message:
2 new convenience methods: getBoolMatrix and getIntMatrix
Got rid of method to print constraint equations, was useless
Line User Rev File contents
1 duarte 128 package proteinstructure;
2     import java.util.HashMap;
3     import java.util.TreeMap;
4     import java.util.ArrayList;
5     import java.lang.Math;
6    
7     public class ContactMap {
8    
9     // NOTE: residueNums and residueTypes contain also the unobserved or non standard residues
10     // residues and nums2serials contain only observed standard amino acids
11     // If someone wants to check if i_num or i is unobserved,
12     // then this can be done by checking whether nums2serials has such key (for i_num) or value (for i)
13     // WHERE DO WE USE i or i_num:
14     // - i: for contact map iteration and sequence separation
15     // - i_num: for residue types and common neighbours
16     public Integer[] residueNums; // array with all residue nums
17     public String[] residueTypes; // array with all 1-letter code residue type
18     public TreeMap<Integer,String> residues = new TreeMap<Integer,String>();// map from nums to types
19     public HashMap<Integer,Integer> nums2serials = new HashMap<Integer,Integer>(); // map from residue nums to residue serials (i.e. the indexes of the arrays above)
20    
21     public int t; // size of contact map
22     public int effT; // effective size of contact map (do not count the SKIPPED cells)
23     public int l; // length of contact map/protein
24     public int numObsStandAA = 0; // Nr. of standard observed amino acids
25     public int numContacts = 0; // Nr. of contacts
26    
27     public EdgeState[][] CM;
28     public HashMap<Integer,HashMap<Integer,TreeMap<Integer,String>>> CNs; // hashmap containing neighbourhoods, access a single one through getComNbs
29    
30     public ContactMap() {
31     }
32    
33 duarte 129 /**
34     * Constructs a ContactMap passing a list of contacts, the full residue sequence and a map of residue nums to types (only observed standard aas)
35     * @param contacts ArrayList of contacts (as Contact objects)
36     * @param residues map from num to types (only observed standard aas)
37     * @param sequence String with full sequence (i.e. also unobserved and non-standard residues, denoted by X)
38     */
39     public ContactMap(ArrayList<Contact> contacts, TreeMap<Integer,String> residues, String sequence) {
40     this.residues=residues;
41     // we create residueTypes and residueNums arrays from full sequence string
42     residueTypes = new String[sequence.length()];
43     residueNums = new Integer[sequence.length()];
44     for (int i=0;i<sequence.length();i++){
45     residueTypes[i] = String.valueOf(sequence.charAt(i));
46     residueNums[i] = i+1;
47     }
48     // we initialise nums2serials using residues and residueNums
49     nums2serials = new HashMap<Integer,Integer>();
50     for (int i=0;i<residueNums.length;i++){
51     // nums2serials must only contain the standard observed aa, so only members of residues TreeMap
52     if (residues.containsKey(residueNums[i])){
53     nums2serials.put(residueNums[i],i);
54     }
55     }
56     // initialisation of l, numObsStandAA, t, effT from 4 above
57     l = this.residueNums.length;
58     numObsStandAA = this.residues.size();
59     t = (int)((l*(l-1))/2);
60     effT = (int)((numObsStandAA*(numObsStandAA-1))/2);
61     // initialisation of CM
62     CM = new EdgeState[l][l];
63     // first we fill with NONCONTACTs (or SKIPPEDs if the i,j is not in nums2serials)
64     for (int i=0;i<l;i++){
65     for (int j=0;j<l;j++) {
66     if ((!this.nums2serials.containsValue(i)) || (!this.nums2serials.containsValue(j))) {
67     CM[i][j] = EdgeState.SKIPPED;
68     } else {
69     CM[i][j] = EdgeState.NONCONTACT;
70     }
71     }
72     }
73     // then we fill the CONTACTs
74     // the contacts ArrayList we pass as argument must contain the full bidirectional list of contacts
75     for (Contact cont:contacts){
76     int i_num = cont.i;
77     int j_num = cont.j;
78     CM[nums2serials.get(i_num)][nums2serials.get(j_num)]=EdgeState.CONTACT;
79     }
80     // and initialise numContacts
81     numContacts = contacts.size();
82     // finally we initialise the CNs HashMap
83     getAllComNbs();
84     }
85 duarte 128
86     /**
87     * Gets the number of contacts, non contacts and skipped cells due to unobserved residues
88     * from the part of the ContactMap >=(above) the given diagonal
89     * @param diagonal
90     * @return
91     */
92     public int[] getCMStats(int diagonal) {
93     int[] result = new int[3];
94     for (int d=Math.max(1, diagonal);d<l;d++){
95     for (int i=0, j=i+d;i<l-d+1 && j<l;i++, j++){
96     if (CM[i][j] == EdgeState.CONTACT) result[0]++;
97     if (CM[i][j] == EdgeState.NONCONTACT) result[1]++;
98     if (CM[i][j] == EdgeState.SKIPPED) result[2]++;
99     }
100     }
101     return result;
102     }
103    
104     /**
105     * Gets the common neighbourhood for residues i_num, j_num from the precomputed HashMap.
106     * If there is no neighborhood between the two residues it returns an empty TreeMap
107     * @param i_num
108     * @param j_num
109     * @return
110     */
111     public TreeMap<Integer,String> getComNbs(int i_num, int j_num) {
112     // we initialise to an empty TreeMap, if there is no cn for i_num, j_num we return it empty
113     TreeMap<Integer,String> cn = new TreeMap<Integer,String>();
114    
115     if (CNs.containsKey(i_num) && CNs.get(i_num).containsKey(j_num)) {
116     cn = CNs.get(i_num).get(j_num);
117     }
118    
119     return cn;
120     }
121    
122     /**
123     * Gets the common neighbourhood for residues i_num, j_num from the precomputed HashMap
124     * that are >= (above)/<= (below) the given diagonal
125     * If there is no neighborhood between the two residues it returns an empty TreeMap
126     * @param i_num
127     * @param j_num
128     * @param diagonal
129     * @param above
130     * @return
131     */
132     public TreeMap<Integer,String> getComNbs(int i_num, int j_num, int diagonal, boolean above) {
133     // we initialise to an empty TreeMap, if there is no cn for i_num, j_num we return it empty
134     TreeMap<Integer,String> cn = new TreeMap<Integer,String>();
135    
136     int threshold = diagonal;
137    
138     if (CNs.containsKey(i_num) && CNs.get(i_num).containsKey(j_num)) {
139     cn = CNs.get(i_num).get(j_num);
140     }
141    
142     if (!cn.isEmpty()) {
143     ArrayList<Integer> nums2eliminate = new ArrayList<Integer>();
144     for (int num:cn.keySet()){
145     // here we eliminate all the common neighbours that are below or above the given diagonal
146     // (first storing the keys in an ArrayList and then removing from TreeMap)
147     // num, i_num and j_num are nums (i.e. serial numbers from db)
148     if (above) {
149     // just for clarification, the opposite condition is: Math.abs(n-i)>=j-i && Math.abs(n-j)>=j-i
150     if ((Math.abs(nums2serials.get(num)-nums2serials.get(i_num)) < threshold || (Math.abs(nums2serials.get(num)-nums2serials.get(j_num)) < threshold))) {
151     nums2eliminate.add(num);
152     }
153     } else {
154     // just for clarification, the opposite condition is: Math.abs(n-i)<=j-i && Math.abs(n-j)<=j-i
155     if ((Math.abs(nums2serials.get(num)-nums2serials.get(i_num)) > threshold || (Math.abs(nums2serials.get(num)-nums2serials.get(j_num)) > threshold))) {
156     nums2eliminate.add(num);
157     }
158     }
159     }
160     for (int num:nums2eliminate){
161     cn.remove(num); //now we remove all the detected non-valid common neighbours
162     }
163     }
164    
165     return cn;
166     }
167    
168     /**
169     * Gets the common neighbourhood for residues i_num, j_num from the precomputed HashMap
170     * that are >= (above)/<= (below) the current diagonal
171     * If there is no neighborhood between the two residues it returns an empty TreeMap
172     * @param i_num
173     * @param j_num
174     * @param above (true if above diagonal)
175     * @return
176     */
177     public TreeMap<Integer,String> getComNbs(int i_num, int j_num, boolean above) {
178     return getComNbs(i_num, j_num, Math.abs(nums2serials.get(j_num)-nums2serials.get(i_num)), above);
179     }
180    
181     /**
182     * Get all common neighbors for this contact map object. Updates the CNs member and also returns it
183     * @return CNs
184     */
185     public HashMap<Integer,HashMap<Integer,TreeMap<Integer,String>>> getAllComNbs() {
186     // first we reset the existing CNs
187     this.CNs = new HashMap<Integer,HashMap<Integer,TreeMap<Integer,String>>>();
188     // initialise a cns4j HashMap which will store all cn TreeMaps for each j
189     HashMap<Integer,TreeMap<Integer,String>> cns4j = new HashMap<Integer,TreeMap<Integer,String>>();
190     // initialise a cn TreeMap which will store all cns for a given i,j
191     TreeMap<Integer,String> cn = new TreeMap<Integer,String>();
192     for (int i=0;i<l;i++){
193     for (int j=i+1;j<l;j++) {
194     for (int k=0;k<l;k++) { // for each i,j we scan all possible contacts k
195     if ((k != i) && (k != j) &&
196     CM[Math.min(i,k)][Math.max(i,k)].contact() && CM[Math.min(j,k)][Math.max(j,k)].contact()) {
197     cn.put(residueNums[k],residueTypes[k]);
198     // we could have used the following, but would be slower
199     //updateCNsHashMap(residueNums[i],residueNums[j],residueNums[k]);
200     }
201     } // end k
202     if (!cn.isEmpty()) {
203     cns4j.put(residueNums[j], cn);
204     }
205     cn = new TreeMap<Integer,String>(); // reset cn for next k
206     } // end j
207     CNs.put(residueNums[i], cns4j);
208     cns4j = new HashMap<Integer,TreeMap<Integer,String>>(); // reset cns4j for next i
209     } // end i
210    
211     return this.CNs;
212     }
213    
214     /**
215     * Convenience method to update the monster CNs HashMap without thinking too much
216     * @param i_num
217     * @param j_num
218     * @param k_num
219     */
220     public void updateCNsHashMap(int i_num, int j_num, int k_num) {
221     if (CNs.containsKey(i_num)){
222     HashMap<Integer,TreeMap<Integer,String>> cns4j = CNs.get(i_num);
223     if (cns4j.containsKey(j_num)){
224     cns4j.get(j_num).put(k_num, residueTypes[nums2serials.get(k_num)]);
225     } else {
226     TreeMap<Integer,String> cn = new TreeMap<Integer,String>();
227     cn.put(k_num, residueTypes[nums2serials.get(k_num)]);
228     cns4j.put(j_num,cn);
229     }
230     } else {
231     HashMap<Integer,TreeMap<Integer,String>> cns4j = new HashMap<Integer,TreeMap<Integer,String>>();
232     TreeMap<Integer,String> cn = new TreeMap<Integer,String>();
233     cn.put(k_num, residueTypes[nums2serials.get(k_num)]);
234     cns4j.put(j_num, cn);
235     CNs.put(i_num, cns4j);
236     }
237     }
238    
239     /**
240     * Update all common neighbors given contact (this method should be used only for prediction)
241     * @param i
242     * @param j
243     * @param
244     * @return
245     */
246     public void updateComNbsGivenContact(int i, int j, boolean below) {
247    
248     if (CM[i][j].contact()) { // if contact predicted just in case
249    
250     if (below) { // if known contacts are only below the diagonal
251     int d = Math.abs(i-j);
252     int[] idxs = {i, j};
253     for (int idx:idxs){
254     for (int r=Math.max(0,idx-d);r<idx;r++) {
255     if ((r != i) && CM[r][idx].contact()) {
256     updateCNsHashMap(residueNums[Math.min(i,r)],residueNums[Math.max(i,r)],residueNums[idx]);
257     }
258     }
259    
260     for (int c=idx+1;c<=Math.min(l-1,idx+d);c++) {
261     if ((c != j) && CM[idx][c].contact()) {
262     updateCNsHashMap(residueNums[i],residueNums[c],residueNums[idx]);
263     }
264     }
265     }
266    
267     for (int b=i+1; b<j; b++) { // update i-j's common neighbors
268     if (CM[i][b].contact() && CM[b][j].contact()) {
269     updateCNsHashMap(residueNums[i],residueNums[j],residueNums[b]);
270     }
271     }
272     } else { // if known contacts can be also above the diagonal
273     for (int k=0;k<l;k++) {
274     if ((k != i) && (k != j)) {
275     if (CM[i][j].contact() && CM[Math.min(i,k)][Math.max(i,k)].contact()) {
276     updateCNsHashMap(residueNums[Math.min(j,k)],residueNums[Math.max(j,k)],residueNums[i]);
277     }
278     if (CM[i][j].contact() && CM[Math.min(j,k)][Math.max(j,k)].contact()) {
279     updateCNsHashMap(residueNums[Math.min(i,k)],residueNums[Math.max(i,k)],residueNums[j]);
280     }
281     if (CM[Math.min(i,k)][Math.max(i,k)].contact() && CM[Math.min(j,k)][Math.max(j,k)].contact()) {
282     updateCNsHashMap(residueNums[i],residueNums[j],residueNums[k]);
283     }
284     }
285     }
286     }
287     }
288     }
289    
290     /**
291     * Returns true if this contact map has no contacts at all
292     * @return
293     */
294     public boolean hasNoContacts() {
295     boolean noContacts = true;
296     for (int i=0;i<l;i++){
297     for (int j=i+1;j<l;j++){
298     if (this.CM[i][j].contact()) {
299     noContacts = false;
300     return noContacts;
301     }
302     }
303     }
304     return noContacts;
305     }
306    
307     /**
308     * Returns whether the given cell has at least N common neighbors
309     * @param i_num
310     * @param j_num
311     * @param N
312     * @return
313     */
314     public boolean cellHasNComNbs(int i_num, int j_num, int N){
315     TreeMap<Integer,String> cn = getComNbs(i_num, j_num);
316     boolean hasNCNs = false;
317     if (((N==0) && cn.isEmpty()) || ((N!=0) && cn.size()>=N)) hasNCNs=true;
318     return hasNCNs;
319     }
320    
321     /**
322     * Returns number of contacts in the whole contact map with at least N common neighbors
323     * Useful to find out how many contacts don't have common neighbors at all (N=0)
324     * Will only count the ones above given diagonal value (use diagonal=1 for count in whole contact map)
325     * @param N
326     * @param diagonal
327     * @return
328     */
329     public int getNumContactsWithNComNbs(int N, int diagonal){
330     int numContactsWithNcns = 0;
331     for (int d=Math.max(1, diagonal);d<l;d++){
332     for (int i=0, j=i+d;i<l-d+1 && j<l;i++, j++){
333     if (CM[i][j].contact()){
334     if (cellHasNComNbs(residueNums[i], residueNums[j], N)){
335     numContactsWithNcns++;
336     }
337     }
338     }
339     }
340     return numContactsWithNcns;
341     }
342    
343     /**
344     * Puts into a new ContactMap object the part of this ContactMap that is strictly below the given diagonal (i.e. not including the diagonal itself)
345     * The rest is filled with NONCONTACT
346     * @param diagonal
347     * @return
348     */
349     //TODO we fill above range diagonals with NONCONTACT, thus we are "forcing" the return object to be a OrigCM but we want this method for ContactMap's, how to solve this?
350     public ContactMap cutCMToBelowRange(int diagonal) {
351     ContactMap newcm = this.semiDeepCopy(true);
352     for (int d=1;d<Math.min(diagonal,l);d++){
353     for (int i=0, j=i+d;i<l-d+1 && j<l;i++, j++){
354     newcm.CM[i][j]=this.CM[i][j];
355     }
356     }
357    
358     for (int d=Math.min(diagonal,l);d<l;d++) {
359     for (int i=0, j=i+d;i<l-d+1 && j<l;i++, j++){
360     newcm.CM[i][j] = EdgeState.NONCONTACT;
361     }
362     }
363     newcm.getAllComNbs(); // finally we re-calculate the common neighbours for the new contact map
364     newcm.updateNumContacts(); // and we recount contacts
365     return newcm;
366     }
367    
368     /**
369     * From all contacts in smallerCM, gets a contact map which contains only those contacts that are reachable from this ContactMap
370     * @param smallerCM
371     * @return
372     */
373     public ContactMap getReachable(ContactMap smallerCM){
374     ContactMap newcm = this.semiDeepCopy(true);
375     for (int i=0;i<l;i++) {
376     for (int j=i+1;j<l;j++){
377     // we loop through all contacts of this contact map
378     if (this.CM[i][j].contact()) {
379     // if for this contact there's at least 1 cn in smallerCM
380     if (smallerCM.cellHasNComNbs(residueNums[i],residueNums[j], 1)){
381     // we assign contact, the rest is kept as it was initialised with semiDeepCopy
382     newcm.CM[i][j]=EdgeState.CONTACT;
383     }
384     }
385     }
386     }
387     newcm.getAllComNbs(); // finally we re-calculate the CNs for the new ContactMap before returning it
388     newcm.updateNumContacts(); // and we recount contacts
389     return newcm;
390     }
391    
392     /**
393     * Returns a new ContactMap result of subtracting smallerCM ContactMap from this ContactMap (set subtraction)
394     * @param smallerCM
395     * @return
396     */
397     public ContactMap subtract (ContactMap smallerCM){
398     ContactMap newcm = this.semiDeepCopy(false); // we copied this cm with all its contacts
399     for (int i=0;i<l;i++) {
400     for (int j=i+1;j<l;j++){
401     // if contact exists in bigger set and also in smaller set then we eliminate it
402     if (this.CM[i][j].contact() && smallerCM.CM[i][j].contact()) {
403     // we assign NONCONTACT
404     newcm.CM[i][j]=EdgeState.NONCONTACT;
405     }
406     }
407     }
408     newcm.getAllComNbs(); // finally we re-calculate the CNs for the new ContactMap before returning it
409     newcm.updateNumContacts(); // and we recount contacts
410     return newcm;
411     }
412    
413     /**
414     * Returns a new ContactMap result of adding secondCM to this ContactMap (set union)
415     * @param secondCM
416     * @return
417     */
418     public ContactMap add (ContactMap secondCM){
419     ContactMap newcm = this.semiDeepCopy(false); // we copied this cm with all its contacts
420     for (int i=0;i<l;i++) {
421     for (int j=i+1;j<l;j++){
422     // if contact doesn't exist in first set, but exists in second set then we add the contact to the resulting set
423     if (!this.CM[i][j].contact() && secondCM.CM[i][j].contact()) {
424     // we assign CONTACT
425     newcm.CM[i][j]=EdgeState.CONTACT;
426     }
427     }
428     }
429     newcm.getAllComNbs(); // finally we re-calculate the CNs for the new ContactMap before returning it
430     newcm.updateNumContacts(); // and we recount contacts
431     return newcm;
432     }
433    
434     /**
435     * The method performs a semi deep copy of a ContactMap. By semi deep I mean:
436     * primitives are copied, CM and CNs are copied but residueNums, residueTypes,residues,nums2serials are not copied, but only re-referenced
437     * This is because we don't really need to copy the arrays as they should always stay the same between source and destination
438     * If blanckCM is true then CM and CNs will be just initialised to UNKNOWN in CM and blanks in CNs
439     * @return
440     * @param blankCM
441     */
442     public ContactMap semiDeepCopy(boolean blankCM){
443     ContactMap destinationCM = new ContactMap();
444     // primitives we simply copy
445     destinationCM.t = this.t;
446     destinationCM.effT = this.effT;
447     destinationCM.l = this.l;
448     destinationCM.numObsStandAA = this.numObsStandAA;
449     destinationCM.numContacts = 0; // we wipe it out initially, it stays so unless blankCM is true where is copied from this.numContacts
450     // we don't deep copy here, we can reference the same arrays, they will be always the same for source and destination
451     // TODO should we deep copy the arrays too??
452     destinationCM.residueNums = this.residueNums;
453     destinationCM.residueTypes = this.residueTypes;
454     destinationCM.residues = this.residues;
455     destinationCM.nums2serials = this.nums2serials;
456     // the only thing we need to deep copy is the ContactMap
457     destinationCM.CM = new EdgeState[l][l];
458     if (!blankCM){
459     for (int i=0;i<l;i++) {
460     for (int j=i+1;j<l;j++){
461     destinationCM.CM[i][j] = this.CM[i][j]; //enum copies should be alright
462     }
463     }
464     destinationCM.numContacts=this.numContacts;
465     } else {
466     for (int i=0;i<l;i++) {
467     for (int j=i+1;j<l;j++){
468     destinationCM.CM[i][j] = EdgeState.UNKNOWN;
469     }
470     }
471     }
472     // for CNs we create a new object and call the getAllComNbs that gets CNs from the already copied ContactMap array
473     destinationCM.CNs = new HashMap<Integer,HashMap<Integer,TreeMap<Integer,String>>>();
474     if (!blankCM){
475     destinationCM.CNs = destinationCM.getAllComNbs();
476     }
477     return destinationCM;
478     }
479    
480     /**
481     * Semi deep copy from given otherCM to this ContactMap all data member fields
482     * @param otherCM
483     * @param blankCM true if we want a blank ContactMap matrix, false if we want to copy from otherCM.CM
484     */
485     public void semiDeepCopyFromOtherCM(ContactMap otherCM, boolean blankCM){
486     // primitives we simply copy
487     this.t = otherCM.t;
488     this.effT = otherCM.effT;
489     this.l = otherCM.l;
490     this.numObsStandAA = otherCM.l;
491     this.numContacts = 0;
492     // we don't deep copy here, we can reference the same arrays, they will be always the same for source and destination
493     // TODO should we deep copy the arrays too??
494     this.residueNums = otherCM.residueNums;
495     this.residueTypes = otherCM.residueTypes;
496     this.residues = otherCM.residues;
497     this.nums2serials = otherCM.nums2serials;
498     // the only thing we need to deep copy is the ContactMap
499     this.CM = new EdgeState[l][l];
500     if (!blankCM){
501     for (int i=0;i<l;i++) {
502     for (int j=i+1;j<l;j++){
503     CM[i][j] = otherCM.CM[i][j]; //enum copies should be alright
504     }
505     }
506     this.numContacts=otherCM.numContacts;
507     } else {
508     for (int i=0;i<l;i++) {
509     for (int j=i+1;j<l;j++){
510     CM[i][j] = EdgeState.UNKNOWN;
511     }
512     }
513     }
514     // for CNs we create a new object and call the getAllComNbs that gets CNs from the already copied ContactMap array
515     this.CNs = new HashMap<Integer,HashMap<Integer,TreeMap<Integer,String>>>();
516     if (!blankCM){
517     this.CNs = this.getAllComNbs();
518     }
519    
520     }
521    
522     /**
523     * To update the numContacts data member, to be used after a ContactMap matrix has been changed in a ContactMap object
524     *
525     */
526     public void updateNumContacts(){
527     this.numContacts=0;
528     for (int i=0;i<l;i++){
529     for (int j=i+1;j<l;j++) {
530     if (this.CM[i][j].contact()) this.numContacts++;
531     }
532     }
533     }
534    
535     /**
536     * Returns true if this ContactMap and otherCM have exactly the same set of contacts (true/false, disregarding other EdgeStates)
537     * @param otherCM
538     * @return
539     */
540     public boolean hasSameContacts (ContactMap otherCM){
541     boolean coincides = true;
542     for (int i=0;i<l;i++){
543     for (int j=i+1;j<l;j++) {
544     if ((this.CM[i][j].contact() && !otherCM.CM[i][j].contact())
545     || !this.CM[i][j].contact() && otherCM.CM[i][j].contact()) {
546     coincides = false;
547     return coincides;
548     }
549     }
550     }
551     return coincides;
552     }
553 duarte 131
554     /**
555     * Returns a boolean matrix with the contact map
556     */
557     public boolean[][] getBoolMatrix(){
558     boolean[][] cmbool = new boolean[l][l];
559     for (int i=0;i<l;i++){
560     for (int j=0;j<l;j++) {
561     cmbool[i][j]=CM[i][j].contact();
562     }
563     }
564     return cmbool;
565     }
566 duarte 128
567     /**
568 duarte 131 * Returns an int (0,1) matrix with the contact map
569 duarte 128 */
570 duarte 131 public int[][] getIntMatrix(){
571     int[][] cmint = new int[l][l];
572     for (int i=0;i<l;i++){
573     for (int j=0;j<l;j++) {
574     cmint[i][j]=0;
575     if (CM[i][j].contact()){
576     cmint[i][j]=1;
577     }
578     }
579     }
580     return cmint;
581 duarte 128 }
582 duarte 131
583 duarte 128 }