View Javadoc

1   /*
2    *    This program is free software; you can redistribute it and/or modify
3    *    it under the terms of the GNU General Public License as published by
4    *    the Free Software Foundation; either version 2 of the License, or
5    *    (at your option) any later version.
6    *
7    *    This program is distributed in the hope that it will be useful,
8    *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10   *    GNU General Public License for more details.
11   *
12   *    You should have received a copy of the GNU General Public License
13   *    along with this program; if not, write to the Free Software
14   *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15   */
16  
17  
18  package jr239.co620;
19  /**
20   *
21   * @author jar
22   * jr239@kent.ac.uk
23   */
24  
25  import org.apache.log4j.Logger;
26  import weka.classifiers.Evaluation;
27  import weka.core.Instances;
28  import weka.gui.LogPanel;
29  
30  
31  import java.util.Random; 
32  import java.util.Arrays; 
33  import java.util.HashSet; 
34  import java.util.HashMap; 
35  import java.util.ArrayList; 
36  import java.util.Set; 
37  
38  import java.io.File;
39  import java.io.FileWriter;
40  import java.io.IOException;
41  
42  import combinatorics.Combinator;
43  
44  
45  public class ACOjoinedAttrbSearch {
46      
47      
48      /********************                 protected           *************************/
49    
50      protected static ACOjoinedAttrbSearch getInstance(){
51           synchronized(ACOjoinedAttrbSearch.class) {
52               
53               if (singleInstace == null){
54                   singleInstace = new ACOjoinedAttrbSearch();
55              }
56         }
57           
58           return singleInstace;
59      }
60      //
61       
62   	
63      protected static void startSearch(LogPanel lp ){
64           lg.debug("-----ACOjoinedAttrbSearch==Start----- \n");
65          wl =lp;//weka panel  logger
66          SimpleBayesDataProcessor.getInstance(wl);
67          FileNameFilter ftype= new FileNameFilter("arff");
68          File dataDir = new File(data);
69          dataSetsFielesNames = dataDir.list(ftype);
70          
71          getColony();
72          SimpleBayesDataProcessor.finalSerchUpdateSearchPropertiesFile();
73          lg.debug("-----ACOjoinedAttrbSearch==End----- \n");
74      }
75    
76      
77    
78     private  static void getColony(){
79         String fn="";
80         for(int fl = 0 ; fl <  dataSetsFielesNames.length; fl++){
81             fn=data+dataSetsFielesNames[fl];
82             System.err.println("file="+ fn);
83             setColParam(fn);
84              runColFoldsEvalution();
85              lg.debug("Returned from runFoldsEvaluation");
86              getAverageColonyPerfomance();
87         }
88  
89     }
90             
91      private static void  setColParam(String dataSetFileName){
92        	lg.debug(" ======== Start of ACO search ===========\n");
93  	SimpleBayesDataProcessor.processDataFromSource(dataSetFileName);
94          foldingsNum = SimpleBayesDataProcessor.getFolds();
95  	  //lg.debug("foldingsNum ="+ foldingsNum+" \n");
96  	  //lg.debug("initialDataSetAttributeNumberExcludingClassExcludingClass \n");
97          minAttrbValuesCountPer100 = 1; //this should be read frm a propeties file
98  	initialDataSetAttributeNumberExcludingClass = SimpleBayesDataProcessor.getInitalDataSetAttribsNumber() - classesNumber;
99          setAttrIndexList();	   //   Enumerate the combinition of two (pair of attirbs) based on attrbs  indexes ( not names)
100         set2AttrbsCombinations();   ////sets antsPopulation	 
101       
102         //testCoupleToCoupleIndex();
103         setSearchBuget(2); // initial search bugtet 10 tries'
104         initialSearch = 0;
105         setBaseline(); //weka Naive Bayes classification performance on the given initial dataset previous to any  joining of attributes
106 	
107         antColonySearchesEvaluations=  new ArrayList<EvaluationACO>(foldingsNum);
108         aColEvlTriples=  new ArrayList<EvaluationACO>(foldingsNum);
109         ColTrainigDS = new Instances[foldingsNum] ;
110         ColTrainigDStrpls = new Instances[foldingsNum] ;
111 	
112 	//lg.debug(" Calling SimpleBayesDataProcessor.initColonyEvaluationFolds(); \n");
113 	
114 	SimpleBayesDataProcessor.initColonyEvaluationFolds(); // this seems not to be needed when colony provides JAtrbs? 
115         //simpler manner to get the dataset into a new naive an evaluate it...
116 	//Needed because  colony work only on a part of the initial DataSet.
117 	//Folding is for colony evaluation where the working folder is given to ants to divide into learning and testing
118 	// the external colony folding is for "Xtesing" the colony (not ant level) collective soluion	
119 	//ArrayList<EvaluationACO> antColonySearchesEvaluations =  new ArrayList<EvaluationACO>(foldingsNum); //this seems to be wrong. One EvaluaACO should drive the evaluation
120 	
121 	//lg.debug("Entering \"for (int workingFoldNumber = 0; workingFoldNumber <  foldingsNum ;  workingFoldNumber++)\"  \n");
122 	
123   }
124     //
125     private static Instances[] ColTrainigDS=null, ColTrainigDStrpls= null;
126     private static int antRunID=0;
127     private static void runColFoldsEvalution(){
128         int [] joinedAttrbs = null;
129         for ( workingFoldNumber = 0; workingFoldNumber <  foldingsNum ;  workingFoldNumber++) {
130             //starting the croos validation of the Colony solutions
131 	     //lg.debug(" ............................................................ Fold Number:" + workingFoldNumber  + " ................................................\n");
132 	    //lg.debug(" calling SimpleBayesDataProcessor.setACOworkingSetFold(workingFoldNumber);\n");
133 	    
134 	    resetColonySearchParameters();
135 	    
136 	    SimpleBayesDataProcessor.setACOworkingSetFold(workingFoldNumber);  //colony working set
137 	    
138 	    ////lg.debug("Returned from SimpleBayesDataProcessor.setACOworkingSetFold(workingFoldNumber);\n");
139 	    ////lg.debug(" startColonySearch ;\n");
140 	   
141 	    //startColonySearch(); //k search starts. pheromone weights are updated with best solutions found by ants
142 	    
143             // Search space would be zero when the cost of the naive bayes classifier   joined attributes data set is zero on 
144             // The the space available from improvement is the  N B cost on intial data set  .
145             // If   combination of joined attribs yields  cost zero then not need to search anything more...
146             
147            //max  improvement and phero weight gain will be magnificationFactor 1 * numeber of  updates to the tabel, one per search,
148             // if searh
149             //double searchSpace =  1.00;
150             while(  searchBudget >0 ){
151                 //lg.debug("searchNo n:"+ searchNo +"\n ");
152                 //getSearcherAnts(searchNo ,searchSpace); //each ant start its search why just cut search process whe just found a zero cost point?
153                 
154                 getSearcherAnts();
155                
156                 searchNo ++;
157                 searchBudget --;
158             }
159 	    //lg.debug(" Returned from startColonySearch ;\n");
160 	    //lg.debug("                                             Calling  antColonySearchesEvaluations.add(SimpleBayesDataProcessor \n");
161 	    joinedAttrbs=getHighestPheromWeightCouple();
162             EvaluationACO e  = SimpleBayesDataProcessor.setAC0TestingSetFoldGetColonySearchEvaluation(workingFoldNumber,  joinedAttrbs);
163 	    antColonySearchesEvaluations.add(e);
164             ColTrainigDS[workingFoldNumber]= SimpleBayesDataProcessor.getACOjoinedAttribsTrainingDataSet();
165             
166             EvaluationACO etrples  = SimpleBayesDataProcessor.setAC0TestingSetFoldGetColonySearchEvaluation(workingFoldNumber,  heaviestPherWeightTrple);
167             aColEvlTriples.add(etrples);
168             ColTrainigDStrpls[workingFoldNumber]= SimpleBayesDataProcessor.getACOjoinedAttribsTrainingDataSet();
169             
170 	    //lg.debug("                                              Returned from  antColonySearchesEvaluations.add(SimpleBayesDataProcessor \n");
171 	    //lg.debug(" ............................................................ End of Fold Number:" + workingFoldNumber  + " ................................................\n");
172 	    
173 	}   //end of folds loop
174 	workingFoldNumber=0;
175   }
176   //
177   
178     private static void setSearchBuget( int initialBuget){
179       if (initialBuget > 0) {
180           initialSearchBuget = initialBuget ;
181       }
182       searchBudget = initialSearchBuget; // initialSearchBuget default val is set to 10 ;
183   }
184   
185     private  static void getAverageColonyPerfomance(){
186         //lg.debug(" Start getAverageColonyPerfomance()\n");
187         //String f = SimpleBayesDataProcessor.getSBS()+"colSumary/colsumary.rtf" ; 
188         String f = SimpleBayesDataProcessor.getSBS()+"colsumary.rtf" ; 
189         FileWriter fw = null; 
190         boolean append = true;
191         Instances dc=null, dt = null;
192         double  averageCostCpl = 0.00;
193          double       averageCostTrpl = 0.00;
194          double       ColonyEvaluationsNumber = (1.00) * antColonySearchesEvaluations.size();
195        EvaluationACO[] triples  = aColEvlTriples.toArray(new   EvaluationACO[aColEvlTriples.size()] );
196          EvaluationACO[]       couples = antColonySearchesEvaluations.toArray(new   EvaluationACO[aColEvlTriples.size()] );
197 
198        StringBuilder s = new StringBuilder();
199        s.append(" ======== Start of ACO search ===========\n");
200        for(int fold = 0 ; fold < triples.length;  fold++){
201             EvaluationACO ec = couples[fold];
202              averageCostCpl = averageCostCpl +  ec.avgCost() ;
203              dc= ColTrainigDS[fold];
204              EvaluationACO et =  triples[fold];
205              averageCostTrpl = averageCostTrpl +  et.avgCost() ;
206              dt= ColTrainigDStrpls[fold];
207               s.append( (printEvalSumanryCpl (  ec,   dc,   fold)) );
208               s.append(printEvalSumanryTrpls (  et,   dt,   fold)) ;
209          }
210            
211          double J3ACovrJ2AC =  100.000 * averageCostTrpl/averageCostCpl;
212            s.append(printColEvalAveragesCpl( averageCostCpl,  ColonyEvaluationsNumber ));
213            s.append(printColEvalAveragesTrpl (averageCostTrpl,  ColonyEvaluationsNumber ));
214            s.append("\n%3JAC/2JAC=...............................................................................................................= "+ J3ACovrJ2AC+"%\n\n");
215            s.append(printInitialDataSet());
216            s.append(printPheroTable());
217            s.append("\n ======== End of ACO search ===========\n");
218            
219            try{
220                fw=new FileWriter(f,append);
221                fw.write(s.toString());
222                  fw.close();
223            }catch(IOException e) {
224                System.err.println("Caught IOException: " 
225                +  e.getMessage());
226            }
227            if(dataSetsFielesNames.length<2){
228                 lw(s.toString());
229            }else{
230                lw("sumaries written to"+f+"\n");
231            }
232                
233            
234            
235             //lg.debug(" End of getAverageColonyPerfomance()\n");
236  }
237 //
238 
239     private static StringBuilder printEvalSumanryCpl ( final EvaluationACO ec, final Instances dc,  int i){
240         StringBuilder s = new StringBuilder();
241         double  coloImprov = (baselineEvaluation.avgCost()  -  (ec.avgCost())  );
242         double colDiffOverNBcost=(coloImprov/baselineEvaluation.avgCost()) * 100.0000 ;
243         
244         s.append( 
245                 "==============================================================\n" +
246                                  "                  Colony evaluations. Sumanry  Fold No=" +  i +"\n" +
247                "\n-----------------------------------------------------------------------------------------------------\n"+
248                 dc.relationName()+"Sumanry  Fold No=" +  i +
249                "\n                                                     -----------------------------                                        \n"+
250                ec.toSummaryString() +
251                 "\nNaive Bayes Average Cost (NBC)...............................................................= "+ (100.00 * baselineEvaluation.avgCost())+"%" +
252 		"\n couple averge cost (2JAC)... ......................................................................= "+  (100.00 *ec.avgCost())+"%" + 
253                 "\n NBC - 2JAC....................................................................................................= " + coloImprov +
254                 "\n %(NBC - 2JAC)/NBC.......................................................................................= " + colDiffOverNBcost+"%" +
255                 "\n\n2JA Data Set is\n"+ dc.toSummaryString()+
256                 "\n----------------------------End of \"Couple\" Sumanry FoldNo=" +  i + "----------------------------------\n"
257 	 );
258        return s;
259 }
260 //
261    
262    private static StringBuilder printEvalSumanryTrpls ( final EvaluationACO et, final Instances dt,  int i){
263         StringBuilder s = new StringBuilder();
264         double  coloImprov = (baselineEvaluation.avgCost()  -  (et.avgCost())  );
265         double colDiffOverNBcost=(coloImprov/baselineEvaluation.avgCost()) * 100.0000 ;
266         
267         
268         s.append("\n                                             ----------------------------                                       \n" +
269                    dt.relationName()+"Sumary  Fold No=" +  i + 
270                    "\n                                                   -----------------------------                                          \n"+
271                    et.toSummaryString()+
272                     "\n triple averge cost(3JAC)...............................................................................= "+(100.00 * et.avgCost() )+"%"+ 
273                     "\nNBC - 3JAC.......................................................................................................= " +coloImprov +
274                     "\n %(NBC-3JAC)/NBC...........................................................................................= " + colDiffOverNBcost+"%"+
275                     "\n\n3JA  Data Set is\n"+ dt.toSummaryString()+
276                     "\n-------------------------------End of Sumanry Evl triple No:" +  i + "----------------------------------"+
277                     "\n==============================================================\n" +
278                                          "             End  Colony evaluation  Fold No=" +  i +" \n" +
279                     "\n-----------------------------------------------------------------------------------------------------\n"
280              );
281          
282         return s; 
283     }
284      
285    
286     private static StringBuilder  printColEvalAveragesTrpl( double averageCostTrpl, double ColonyEvaluationsNumber ){
287         StringBuilder s = new StringBuilder();
288         double j3acXfolds =  (averageCostTrpl ) / (ColonyEvaluationsNumber);
289         s.append(  
290                  "\nTriples AvgCost(%3JACXfols)...............................................................................= " + (100.00*    j3acXfolds )+"%"+
291                  "\n %(NBC - 3JAC)/NBC................................................................................................= "+  (100.00*(baselineEvaluation.avgCost()  - j3acXfolds)/(baselineEvaluation.avgCost() ))+"%" + 
292                  "\n\n----------------------------------End of Col Averages--------------------------------------------\n"
293                 );
294         return s;
295     }
296     
297    private static StringBuilder printColEvalAveragesCpl( final double averageCostCpl, final double ColonyEvaluationsNumber ){
298         StringBuilder s = new StringBuilder();
299         double j2acXfolds =  (averageCostCpl ) / (ColonyEvaluationsNumber);
300         s.append("\n\n===================================================================\n" +
301              "Colony Xfold Averages\n" +
302              "--------------------------------------------------------------------------------------------------------------\n"+
303              "Couple  Average Cost (%2JAC/Xfolds).......................................................................=  " + ( 100.00 *j2acXfolds )+"%"  + 
304            "\n %Diff=(NBC - 2JAC)/NBC............................................................................................ = " +   ( 100.00 * (baselineEvaluation.avgCost() -  j2acXfolds)  / (baselineEvaluation.avgCost()) ) +"%"
305            );
306         
307         return s;
308    }
309 
310     
311     private static StringBuilder printPheroTable(){
312     StringBuilder s = new StringBuilder();
313     s.append("\n-----------------------------------Couples PheroWeights  Table------------------------------\n");
314     for (int coupleIndx = 0; coupleIndx<attrbsCouplesPheromoneTable.length; coupleIndx ++){
315         s.append("PheroWeigt for Couple="+  Arrays.asList( attrbsCouplesSet[coupleIndx]) +
316                 " =  " +attrbsCouplesPheromoneTable[coupleIndx]+"\n"
317                 );
318     }
319     s.append( 
320                   "--------------------------------------------------End pw table---------------------------------------------\n\n"+
321                 "Couples SortedIncreasingPheroWeightsList From ants search="+Arrays.asList(sortedIncreasingPheroWeightsList)+"\n"+
322                 maxCountsMsgs.toString()
323             );
324     return s;
325 }
326   
327  
328     private static StringBuilder  printInitialDataSet(){
329           StringBuilder s = new StringBuilder();
330           s.append("\n\n-----------------------------------Initial Data Set is-------------------------------------------------------------------------------------\n"+
331           SimpleBayesDataProcessor.getInitialDataSet().toSummaryString()+
332                  " \n--------------------------------------end of Initial Data Set ------------------------------------------------------------------------------------\n\n"
333             );
334           return s;
335     }
336   
337     /**
338     private static Object[]  getPositionHeviestPheromWeightCouple(int position ){
339 	//lg.debug("Entering getHighestPheromWeightCouple()\n ");
340 	sortedIncreasingPheroWeightsList =  (pheromeneWeightsToCouplesSetMap.keySet()).toArray(new Integer[0]);
341 	Arrays.sort(sortedIncreasingPheroWeightsList);
342 	Integer  heaviestPheroWeight = sortedIncreasingPheroWeightsList[0];
343         if(sortedIncreasingPheroWeightsList.length > 1){
344             heaviestPheroWeight =  sortedIncreasingPheroWeightsList[sortedIncreasingPheroWeightsList.length - position];   //Arrays.sort is increasing ..
345         }
346      
347        
348        HashSet<Couple<Integer>> cs= pheromeneWeightsToCouplesSetMap.get(heaviestPheroWeight);//set of couples with same weight
349        cs.remove(null);//remove  the empty couple element added when this set was created.
350        ArrayList<Couple<Integer>> cplsSet = new ArrayList<Couple<Integer>>(cs) ; //easier to access . Set was needed to filter possib of reapeated couples.
351        cs =null;
352        int heaviestIndex = 0; //heaviest pher weight couple in  the  list of couples with same weights. If only one couple. index will be 0 .list will have only one memenber
353        if (cplsSet.size()> 1){
354 	   heaviestIndex = randomIntGenerator.nextInt(cplsSet.size());
355 	    //lg.debug("getHighestPheromWeightCouple() cplsSet #=" + cplsSet.size() +". Returning coupleToList from radom seleceted index: " + heaviestIndex +"  " ) ;
356        }
357        Couple<Integer> hc = cplsSet.get(heaviestIndex);
358        int[] joinedAttrbsIndxs = getIntList(hc);
359 	//lg.debug(" " +  Arrays.asList(joinedAttrbsIndxs) + 
360 //		"\nLeaving  getHighestPheromWeightCouple().  \n" 
361 //	); 
362         Object[] hw = { hc, joinedAttrbsIndxs};
363         
364 	return hw;
365     }
366      * */
367     //
368     
369      
370     private static int[] getHighestPheromWeightCouple(){
371 	//lg.debug("Entering getHighestPheromWeightCouple()\n ");
372 	sortedIncreasingPheroWeightsList =  (pheromeneWeightsToCouplesSetMap.keySet()).toArray(new Integer[0]);
373 	Arrays.sort(sortedIncreasingPheroWeightsList);
374 	Integer  heaviestPheroWeight =   sortedIncreasingPheroWeightsList[sortedIncreasingPheroWeightsList.length - 1];   //Arrays.sort is increasing ..
375          
376        HashSet<Couple<Integer>> cs= pheromeneWeightsToCouplesSetMap.get(heaviestPheroWeight);//set of couples with same weight
377        cs.remove(null);//remove  the empty couple element added when this set was created.
378        ArrayList<Couple<Integer>> cplsSet = new ArrayList<Couple<Integer>>(cs) ; //easier to access . Set was needed to filter possib of reapeated couples.
379        cs =null;
380        int heaviestIndex = 0; //heaviest pher weight couple in  the  list of couples with same weights. If only one couple. index will be 0 .list will have only one memenber
381        if (cplsSet.size()> 1){
382 	   heaviestIndex = randomIntGenerator.nextInt(cplsSet.size());
383 	    //lg.debug("getHighestPheromWeightCouple() cplsSet #=" + cplsSet.size() +". Returning coupleToList from radom seleceted index: " + heaviestIndex +"  " ) ;
384        }
385        int[] joinedAttrbsIndxs = getIntList(cplsSet.get(heaviestIndex));
386 	//lg.debug(" " +  Arrays.asList(joinedAttrbsIndxs) + 
387 	//	"\nLeaving  getHighestPheromWeightCouple().  \n" 
388 	//); 
389 	return joinedAttrbsIndxs;
390     }
391     //
392        
393     
394     private static  void  getSearcherAnts(){     //, double searchSpace){ why cut when just one zero cost found ?
395         SimpleBayesDataProcessor.setAntContext("Fd"+foldingsNum+"se"+searchNo+"rid"+antRunID);
396 	//lg.info("Entering  getSearcherAnts()\n ");
397         Couple<Integer> joinedAttrbs = null;
398         for(  antNum = 0 ; antNum  < antsPopulation  ;antNum ++ ,antRunID++ ){ //each working(searching) period  takes a differe
399             SimpleBayesDataProcessor.setAntid(antNum);
400 	    //lg.info("getting antNum population, antNum number:" + antNum +".Getting a initial random couple for this antNum. The couple is:");
401             cplIndx=-9;
402 	    if( searchNo == initialSearch) { //considerer a random choice between max count  couple choose and just plain random choice of the couple
403                int randomChoice =randomIntGenerator.nextInt(2);// choice 50 % of the time the choice will be the max count couple. For the first searcher will be top count couple for the others this is true if no previous  this choice
404                boolean c1 =false, c2=false;
405                 if(  (randomChoice < 1) && (maxCountCouplesUsed <maxCountCouplesUsedLimit)  ){
406                      joinedAttrbs  =   get2MaxCountsAttrbs();
407                      if(joinedAttrbs == null){
408                          c1=true;
409                      }
410                      if(!coupledAttrbsSet.add(joinedAttrbs) || usedAattrbsCouplesTable[coupleToIndexMap.get(joinedAttrbs)]){
411                          c2 =true;// double check that couple has been used . Either fails to be added to set or has been marked as used;
412                      }
413                      if(!c1 && !c2){
414                          usedAattrbsCouplesTable[coupleToIndexMap.get(joinedAttrbs)] =true;
415                          maxCountsMsgs = new StringBuilder();
416                          maxCountsMsgs.append("\n\nFold="+ workingFoldNumber +
417                                  "-Initial Search.\nCouple with max Count of Values on majority class is="+
418                                     joinedAttrbs.toString()+"\n\n" );
419                      }else{ // not new maxCountVals for majority class subset of data set found. Number  of maxcounts couples to use is hardcoded to 3.
420                           joinedAttrbs =  getRamdomCouple() ; // getRandom adds  couple to the joined set
421                      }
422                  }else{
423                     // random > 0  Or  couples used > 3
424                         joinedAttrbs =  getRamdomCouple() ; // getRandom adds  couple to the joined set
425                  }//if-else random choice maxCountCouplesUsed <3
426             /**
427             while(!emptyCoupleIndx){
428             try {
429                     ACOjoinedAttrbSearch.class.wait();
430                 } catch (InterruptedException e) {
431                     System.err.println(" waited interrupted on getSerachAnts for coupleIndex\n");
432                 }
433             }
434             emptyCoupleIndx=false;
435             **/
436             cplIndx = coupleToIndexMap.get(joinedAttrbs);
437             // ACOjoinedAttrbSearch.class.notifyAll();   
438              
439             SimpleBayesDataProcessor.computeJoinedAttrbsWorkingDataSet (getIntList(joinedAttrbs));
440             joinedAttrbsEvaluation = SimpleBayesDataProcessor.getClassifierEnginePerformanceOnJoinedAttributesDataset ();// 10 cross validation on the working set of joined attributes chosen
441             setPheroWeightUpdate(cplIndx); 
442             
443             //init Search  end 
444             }else{ // not initialSearch
445                 antsPopulation= 1 ;
446                 exploitXpandCoupleIntoTripple();
447             }
448          
449 	}//ants end
450        
451         antNum=0;
452         
453         if (searchNo == initialSearch){
454             checkAllCouplesExplored();
455             setSamePheroWeightCouplesSets();//initial search
456         }
457 	lg.debug("Returning from setSamePheroWeightCouplesSets() \nLeaving  getSearcherAnts() \n");
458     }//
459     //
460   
461      private static void checkAllCouplesExplored(){
462          boolean AE =false; // all couples explored;
463          int UE = -99;
464          while(!AE){
465             UE = getUnexploredCoupleIndx() ;
466              if ( UE>=0){
467                tryExploreCouple(UE);
468             }
469              else if(UE == (-9)){
470                  AE =true;
471              
472             }else{
473                 String m="somethig wrong  in checkAllCouplesExplored()\n";
474                 lg.warn(m);
475                 System.err.println(m);
476                 System.exit(1);
477             }
478             
479          }
480     }
481     //
482     private static int getUnexploredCoupleIndx(){
483         int UF =-9;//unexplored  not found
484          for(int cpleIndx = 0 ; cpleIndx<usedAattrbsCouplesTable.length; cpleIndx ++){
485              if(!usedAattrbsCouplesTable[cpleIndx]){
486                  UF =cpleIndx; break;
487                  }
488             }
489         return UF;
490     }
491     
492     private static void tryExploreCouple( final int cindex){
493          Integer[] cple = attrbsCouplesSet[cindex];
494          int[] c = {cple[0], cple[1]} ;
495          SimpleBayesDataProcessor.computeJoinedAttrbsWorkingDataSet (c);
496          joinedAttrbsEvaluation = SimpleBayesDataProcessor.getClassifierEnginePerformanceOnJoinedAttributesDataset ();// 10 cross validation on the working set of joined attributes chosen
497          setPheroWeightUpdate(cindex); 
498     }
499     
500     /**
501        //int[] pw = get2heviestPheroWeigtCoupleIndexes();
502       //Object[] dap = getDifferentAttribsNumber(pw);
503        int pp = 0;
504         int[] jw =null;
505        if(pp==0){
506        jw = get2JointWeightCouplesIndexes(); 
507         pp=1;
508        }else{
509            int[] jw2={0,5}; 
510            jw=jw2;
511            pp=0;
512        }
513     **/
514     private static void exploitXpandCoupleIntoTripple(){  // from top scoring couples
515         int[] jw =null;
516         makeJoinWeightsTable();
517         jw = get2JointWeightCouplesIndexes(); 
518         Object[] da = getDifferentAttribsNumber(jw);
519         Boolean allDistinct = (Boolean)da[0];
520 
521         if(allDistinct){
522             Integer[][] c3l = (Integer[][])da[1];
523                     c3 = Arrays.copyOf(c3l, c3l.length);
524                     c3pw = new int[c3.length];
525                     c3l=null;
526 
527 
528             for(int atriple =0 ; atriple< c3.length; atriple++){ 
529                 int[]jal = {c3[atriple][0], c3[atriple][1], c3[atriple][2]};
530                 SimpleBayesDataProcessor.computeJoinedAttrbsWorkingDataSet (jal);
531                  setTriplePheroWeight(jal,  atriple);
532             }
533             
534           setHighestPWtrpl();        
535 
536         }else{ //only 3 distinct attrbs;
537             Integer[]c3l = (Integer[])da[1];
538             int[]jal = {c3l[0], c3l[1], c3l[2]};
539             c3pw = new int[1]; //only one tripple
540             int trpleIndex =0;
541              setTriplePheroWeight(jal,  trpleIndex);
542              heaviestPherWeightTrple=jal;
543         }
544     }
545     //
546     
547     private static void  setHighestPWtrpl(){
548         Integer[] h = c3[getHighestPWtrpleIndex()];
549         heaviestPherWeightTrple = new int[3]; 
550         for(int i =0 ; i<3 ; i++){
551             heaviestPherWeightTrple[i] =  (int)h[i];
552         }
553     }
554     
555     private static int  getHighestPWtrpleIndex(){
556         HashMap<Integer,ArrayList<Integer>> trplePWtoTrpleIndexesListMap = new HashMap<Integer,ArrayList<Integer>>();
557         
558         for(int triplIndx = 0; triplIndx <  c3pw.length ; triplIndx++ ){
559             if( !trplePWtoTrpleIndexesListMap.containsKey(c3pw[triplIndx])){//pheroWeight is the key,
560                 ArrayList<Integer> trplsIndexs = new  ArrayList<Integer>();
561                 trplsIndexs.add(triplIndx);
562                 trplePWtoTrpleIndexesListMap.put(c3pw[triplIndx], trplsIndexs);
563             }else{ //map had the pw as key
564                 ArrayList<Integer> trplsIndexs = trplePWtoTrpleIndexesListMap.get(c3pw[triplIndx] );
565                 trplsIndexs.add(triplIndx);
566                 trplePWtoTrpleIndexesListMap.put(c3pw[triplIndx], trplsIndexs);
567             }
568         }
569         
570         Set<Integer> pheroWeigts = trplePWtoTrpleIndexesListMap.keySet();
571         Integer[] pwlst = pheroWeigts.toArray(new Integer[pheroWeigts.size()]);
572         pheroWeigts = null;
573         Arrays.sort(pwlst);
574         Integer topPheroW= pwlst[pwlst.length - 1];
575         pwlst=null;
576         //ArrayList<Integer> trplsIndexs = trplePWtoTrpleIndexesListMap.get(topPheroW);
577         Integer[] trplsIndexs= trplePWtoTrpleIndexesListMap.get(topPheroW).toArray(new Integer[0]);
578         //trplsIndexs.trimToSize();
579         int trpleIndx = -9;
580         if(trplsIndexs.length>1){
581             trpleIndx = randomIntGenerator.nextInt(trplsIndexs.length);
582         }else{
583             trpleIndx = trplsIndexs[0];
584         }
585         return trpleIndx;
586     }
587     //
588     private static void setTriplePheroWeight(int[] jalist, int atrpleIndex){
589         SimpleBayesDataProcessor.computeJoinedAttrbsWorkingDataSet (jalist);
590         joinedAttrbsEvaluation = SimpleBayesDataProcessor.getClassifierEnginePerformanceOnJoinedAttributesDataset ();
591         double joinedAttrbsCost = joinedAttrbsEvaluation.avgCost();
592         if(joinedAttrbsCost > (2 * NaiveBayesCost)){
593             joinedAttrbsCost = 2 * NaiveBayesCost;
594         }
595         int pheromoneUpdate =  ( int ) (magnifcationFactor * ( ( NaiveBayesCost  - joinedAttrbsCost ) / NaiveBayesCost ));
596         c3pw[atrpleIndex] =  pheromoneUpdate;
597     }
598 
599     private static Object[]  getDifferentAttribsNumber( int[] twoCpls  ){
600         Object[] da = new Object[2];
601         Integer[] c1 = attrbsCouplesSet[twoCpls[0]];
602         Integer[] c2 = attrbsCouplesSet[twoCpls[1]];
603         HashSet<Integer> distinctAttrbsIndexs= new HashSet<Integer>(4);
604         
605         for (int ai = 0; ai <2; ai++){
606             distinctAttrbsIndexs.add(c1[ai]);
607             distinctAttrbsIndexs.add(c2[ai]);
608         }
609         
610         Integer[][] c3Table= null;
611         Integer[]dai = distinctAttrbsIndexs.toArray(new Integer[distinctAttrbsIndexs.size()]);
612         if(dai.length > 3){
613             Combinator<Integer> c3Sets = new Combinator<Integer>(dai, 3);
614              int c3tot = (int)Math.round(c3Sets.getTotal());
615             c3Table= new Integer [c3tot][];
616             
617             int c3i =0;
618             while( c3Sets.hasNext()){
619                 c3Table[c3i]=c3Sets.next();
620                 c3i++;
621             }c3i=0;
622            
623            da[0]= true;
624            da[1]=c3Table;
625            
626         }else{
627             da[0]=false;
628             da[1]=dai;
629         }
630         
631         return da;
632     }
633     //
634     
635     private static void makeJoinWeightsTable(){
636         int[] jw = new int[attrbsCouplesPheromoneTable.length];
637         int pw =-9;
638         jointWeightToCoupleIndexMap= new HashMap<Integer, HashSet<Integer>> ();
639         for( int coupleIndex = 0 ; coupleIndex < attrbsCouplesPheromoneTable.length; coupleIndex ++){
640               pw = attrbsCouplesPheromoneTable[coupleIndex] ; // pw is [1, -1] interested here on  non-negative factors
641               if (pw < 0 ) {
642                   pw =0;
643               }
644               jw[coupleIndex]= pw + attrbsCouplesCountsTable[coupleIndex]; // jw is [2, 0] 
645               mapJointWeighToCoupleIndex(    jw[coupleIndex], coupleIndex);
646         }
647         
648         
649     }
650     //
651     private static int[] get2JointWeightCouplesIndexes(){
652         int couple1= -9, 
653               couple2 = -9;
654         
655         Integer[] jwl = getSortedCouplesJoinedWeightsList();
656         
657         HashSet<Integer> attrbsList = jointWeightToCoupleIndexMap.get(jwl[jwl.length-1]);
658         Integer[] al = attrbsList.toArray(new Integer[attrbsList.size()]);
659         if( al.length>1 ){
660             couple1 = randomIntGenerator.nextInt(al.length);
661             couple2 = randomIntGenerator.nextInt(al.length);
662             while(couple1==couple2){
663                 couple2 = randomIntGenerator.nextInt(al.length);
664             }
665         }else{ //al has only one attrb index get the second top count
666             if(jwl.length ==1){
667                 System.err.println("joint weight list only has one couple index \n");
668                 System.exit(1);
669             }
670             couple1 = al[0];
671             attrbsList = jointWeightToCoupleIndexMap.get(jwl[jwl.length-2]);
672             al = attrbsList.toArray(new Integer[attrbsList.size()]);
673             if( al.length>1 ){ //  if second top count has more than one att index in its list
674             couple2 = randomIntGenerator.nextInt(al.length);
675             while(couple1==couple2){
676                 couple2 = randomIntGenerator.nextInt(al.length);
677                 }
678             }else{ //second count has one attrb in its list
679                 couple2 = al[0];
680             }
681         }
682         int[]  cIndxs = { couple1, couple2};
683         
684         return cIndxs;
685     }
686     
687     private static Integer[]  getSortedCouplesJoinedWeightsList(){
688         Integer[] wl = jointWeightToCoupleIndexMap.keySet().toArray(new Integer[0]);
689         Arrays.sort(wl);
690         return wl;
691     }
692     
693     private static void mapJointWeighToCoupleIndex(int w, int c){
694          if( !jointWeightToCoupleIndexMap.containsKey(w)) {
695              HashSet<Integer> atrrbList = new  HashSet<Integer>();
696              atrrbList.add(c);
697              jointWeightToCoupleIndexMap.put(w, atrrbList);
698          }else{
699              Set<Integer> atrrbList= jointWeightToCoupleIndexMap.get(w);
700              atrrbList.add(c);
701          }
702     }
703     
704     private   static  void  setPheroWeightUpdate( int coupleIndx){
705         int pheromoneUpdate =0,
706              countUpdate =0;
707         double joinedAttrbsCost = -99999999.999999;///controll value. These costs are the weka avgCost for naive bayes, on the initial  attrbs  and for the joined attrbs.
708         
709         Object[] checks = SimpleBayesDataProcessor.cehckJAminCount(minAttrbValuesCountPer100);
710        
711         Boolean hasMinCount = ((Boolean)checks[0]);
712         if(!hasMinCount ){
713            pheromoneUpdate = (int) ( magnifcationFactor * (-1.00) );//maxNormalized cost or max negative amount of phero.
714         }else{
715             joinedAttrbsCost = joinedAttrbsEvaluation.avgCost();
716             if (   joinedAttrbsCost > (2 * NaiveBayesCost )){
717                 joinedAttrbsCost = 2 * NaiveBayesCost;
718             }
719             pheromoneUpdate =  ( int ) (magnifcationFactor * ( ( NaiveBayesCost  - joinedAttrbsCost ) / NaiveBayesCost ));
720             double normalizedMinCount= (Double)checks[1];
721             countUpdate = (int) (magnifcationFactor * normalizedMinCount);
722         }
723          //if joinedattrbs evluation have zero costs means 100 acuracy. Then the biggest possible improvement for a joined attribs classification over Naive Bayes
724          //will be  imrovement = naive bayes avg cost  MINUS joinedAttrbs avgCost.
725          //Then the pheromene update interval is [1,-10 = ][NBC/NBC, -NBC/NBC] NBC = naive avg cost. This is because  joined cost is capped to 2NBC
726          // This is weka Evaluation avgCost(). Total Accuracy  means"deterministic relationship class attribs" allways right 100% accuracy . This is zero cost.
727          // if NaiveBayesCost is less then the pheromone weight for the particular attrbutes tuples is decreased; This is joining attributes decreases the numer of correct predicitions
728 	 
729             //there is an implicit hardcoded constraint that there is one antNum per couple and therefore only one possible update of the 
730             // the weights  per search,,
731         //lg.debug(
732 	//	   "\n pheromoneUpdate =  ( int ) (magnifcationFactor * ( ( NaiveBayesCost  - joinedAttrbsCost ) / NaiveBayesCost ))  =  " + pheromoneUpdate +
733 	//	   "\nUpdating attrbsCouplesPheromoneTable["+ coupleIndx +"] = " + attrbsCouplesPheromoneTable[coupleIndx] +"  plus "+ pheromoneUpdate +" \n"
734         //         );
735         /**
736         dosent fix it 
737         while(emptyCoupleIndx){
738             try {
739                 ACOjoinedAttrbSearch.class.wait();
740             } catch (InterruptedException e) { 
741                  System.err.println(" waited interrupted on SetPheroUpdate for coupleIndex\n");
742             
743             }
744         }
745         emptyCoupleIndx=true;  
746         **/
747           
748 	if(updatedAttrbsCouplesPheromoneTable[coupleIndx]){
749             StringBuilder msg = new  StringBuilder();
750                     msg.append("\n Trying to update more than once same couple index  pw filtered out" +
751                     "\nWorkingFold="+workingFoldNumber+". SeachNum="+ searchNo +". AntNum="+antNum+
752                     ".  coupleIndx="+ coupleIndx +".\n"
753                      );
754              System.err.println(msg.toString()) ;
755              lg.warn(msg.toString());
756              return;
757             //System.exit(1);
758         }
759         attrbsCouplesPheromoneTable[coupleIndx] = 0; // clear the PCV
760         attrbsCouplesPheromoneTable[coupleIndx] =  attrbsCouplesPheromoneTable[coupleIndx]+ pheromoneUpdate;
761         
762         updatedAttrbsCouplesPheromoneTable[coupleIndx] = true;
763         usedAattrbsCouplesTable[coupleIndx] = true;
764         
765         attrbsCouplesPheromoneTable[coupleIndx] =  pheromoneUpdate;
766         attrbsCouplesCountsTable[coupleIndx]= attrbsCouplesCountsTable[coupleIndx] + countUpdate;
767   
768          //ACOjoinedAttrbSearch.class.notifyAll();
769 	 
770 	lg.debug("new value for attrbsCouplesPheromoneTable[ " +  coupleIndx +"] ="  + attrbsCouplesPheromoneTable[coupleIndx] +
771                           "\nLeaving  getSearcherAnts(). for_loop:antNum:"+ antNum +"\nCalling setSamePheroWeightCouplesSets() from getSearcherAnts() " +
772 		      "\n");  
773     }
774     //
775   
776     private static void setSamePheroWeightCouplesSets(){//sets of couples that have same phereomone weights.
777 	//lg.debug("Entering  setSamePheroWeightCouplesSets()\n");
778 	pheromeneWeightsToCouplesSetMap = new HashMap<Integer, HashSet<Couple<Integer>>>();
779 	//lg.debug("created  pheromeneWeightsToCouplesSetMap:" + (!(pheromeneWeightsToCouplesSetMap==null)) + "\n");
780 	for(int i =0 ; i< attrbsCouplesPheromoneTable.length; i++){
781 	    if (pheromeneWeightsToCouplesSetMap.containsKey(attrbsCouplesPheromoneTable[i])){
782 		 HashSet<Couple<Integer>>couplesSet = pheromeneWeightsToCouplesSetMap.get(attrbsCouplesPheromoneTable[i]); // list of couples with the sane pheromWeight
783 		 couplesSet.add(getCoupleFromList(attrbsCouplesSet[i]));
784 		 pheromeneWeightsToCouplesSetMap.put(attrbsCouplesPheromoneTable[i], couplesSet );
785 	    }else{
786 		HashSet<Couple<Integer>>couplesSet =new HashSet<Couple<Integer>> ();
787 		couplesSet.add(null); //empty couple added to avoid this possibility.
788 		couplesSet.add(getCoupleFromList(attrbsCouplesSet[i]));
789 		pheromeneWeightsToCouplesSetMap.put(attrbsCouplesPheromoneTable[i], couplesSet );
790 	    }
791 	}//lg.debug("\ngetSamePheroWeightsCouplesSetsAsString():\n"+  getSamePheroWeightsCouplesSetsAsString()+
792 //		"\nLeaving  setSamePheroWeightCouplesSets()\n");
793     }
794     
795     /**
796     private static String getSamePheroWeightsCouplesSetsAsString(){
797 	//lg.debug("Entering  getSamePheroWeightsCouplesSetsAsString()\n");
798 	StringBuilder s=new StringBuilder("\nCouples with same pheroWeights\n"); HashSet<Couple<Integer>>couplesSet =null;
799 	for( Integer i : pheromeneWeightsToCouplesSetMap.keySet() ){
800 	    s.append( "..............PheromoneWeight:"+i+":CouplesSet:..........\n");
801 	    couplesSet = pheromeneWeightsToCouplesSetMap.get(i);
802 	     couplesSet.remove(null); // "empty couple "null" couple is inserted in the set when created to avoid this possibiliey
803 	    StringBuilder  t = new StringBuilder();int x = 0;
804 	    for (Couple<Integer> cs : couplesSet ){
805 		 
806 		     t .append("    CoupleNo:"+x+":"+ cs.toString()+" \n"); x++;
807 		 
808 	    }s.append(t+"----------End of couplesSet for weight:" + i + "-------------\n");
809 	}//lg.debug("Leaving  getSamePheroWeightsCouplesSetsAsString()\n");
810 	return s.toString();
811     }
812      * */
813     //
814      public static void testInternals () {
815          ACOjoinedAttrbSearch.getColony();
816 //         ACOjoinedAttrbSearch.assertWeightsAttrIndexsMapping();
817      }
818     //
819      public static int[]  getIntList(Set<Integer> s){
820 	 //lg.debug("Entering getIntList(Set<Integer> s)\n Set received is:" + Arrays.toString(s.toArray()) + ":\n");
821          Integer[] si = s.toArray(new Integer[0]);
822          int [] intList = new int[si.length];
823          for(int i =0; i < si.length; i++) {
824              intList[i] = si[i].intValue();
825          }
826 	 //lg.debug("Leaving getIntList(Set<Integer> s). Array returned is:" + Arrays.toString(intList)+"\n");
827          return intList;
828      }
829      //
830      
831      
832     /** =====================================   private side  ============================================== **/
833     private static volatile ACOjoinedAttrbSearch singleInstace = new  ACOjoinedAttrbSearch();
834      private  ACOjoinedAttrbSearch( ){}
835      
836     private static Couple<Integer> getCoupleFromList(Integer[] pair ){
837         
838         return (
839                 new Couple<Integer>(pair[0], pair[1]) 
840                 );
841     }
842     
843        private static Couple<Integer> getCoupleFromList(int[] pair ){
844         
845         return (
846                 new Couple<Integer>(pair[0], pair[1]) 
847                 );
848     }
849     ///
850     
851     private  static Couple<Integer>  getRamdomCouple() {
852         Couple<Integer> cp = null;
853 	 cp = getCoupleFromList( attrbsCouplesSet[randomIntGenerator.nextInt(attrbsCouplesSet.length)]);
854                 
855         int cn = 0;
856 	 while ( usedAattrbsCouplesTable[coupleToIndexMap.get(cp)]  && coupledAttrbsSet.contains(cp) && cn < attrbsCouplesSet.length  ){  // ants search different search of attributtes, to cover a wider area
857              cp = getCoupleFromList( attrbsCouplesSet[randomIntGenerator.nextInt(attrbsCouplesSet.length)]);
858 	     cn ++;
859         }cn=0;
860         coupledAttrbsSet.add(cp);
861 	if (cp == null){
862 	    //lg.fatal(  "getRamdomCouple()  cannot get a new (not selected already) couple." +
863 //		    "\nProbably \"coupledAttrbsSet\" needs to be emptied after a colony search has been completed" );
864 	    System.exit(ABNORMAL_TERMINATION);
865 	}
866         usedAattrbsCouplesTable[coupleToIndexMap.get(cp)] =true;
867         
868         return cp; // attrbsToJoinIndxs
869       }
870       //
871     
872     /**
873     private  static Couple<Integer>  selectAny2Attrbs() {
874         Couple<Integer> cp = null;
875         if(! combinationsOf2Attrbs.hasNext() ){
876            return cp;
877         }
878        
879         //Integer[] pl =  combinationsOf2Attrbs.next();
880         cp = getCoupleFromList(combinationsOf2Attrbs.next());
881                 
882         while (coupledAttrbsSet.contains(cp) ){
883              cp = getCoupleFromList(combinationsOf2Attrbs.next()); //use unique couples of joined attribs 
884         }
885         coupledAttrbsSet.add(cp);
886         //int [] attrbsToJoinIndxs = { cp.
887         return cp; // attrbsToJoinIndxs
888       }
889     **/  
890     
891     //
892     private static void set2AttrbsCombinations(){ //sets the pheromene table
893 	//lg.debug("Entering    private static void set2AttrbsCombinations()\n " );
894     
895 	combinationsOf2Attrbs = new Combinator<Integer>(initialDataSetAttrbIndexList, 2); 
896         twoAttrbsCombinationsNumber = (int)Math.round(combinationsOf2Attrbs.getTotal()) ;
897 	
898 	attrbsCouplesCountsTable = new int [twoAttrbsCombinationsNumber]; // Value record is the count of the  attibute val with smallest count. paralle array with  couples table "attrbsCouplesSet"
899         attrbsCouplesPheromoneTable = new int [twoAttrbsCombinationsNumber]; // paralle array with  couples table "attrbsCouplesSet"
900         coupleToIndexMap  =new  HashMap<Couple<Integer>, Integer> (twoAttrbsCombinationsNumber); 
901         usedAattrbsCouplesTable = new boolean[twoAttrbsCombinationsNumber];
902         updatedAttrbsCouplesPheromoneTable = new boolean[twoAttrbsCombinationsNumber];
903         Arrays.fill(usedAattrbsCouplesTable, false);
904          Arrays.fill(updatedAttrbsCouplesPheromoneTable, false);
905 	//lg.debug("twoAttrbsCombinationsNumber, size  of parallel pheromene index/couples arrays  and antsPopulation set to:"+twoAttrbsCombinationsNumber+"\n");
906         
907 	initPheromeneTable(attrbsCouplesPheromoneTable);
908         initCountsTable(attrbsCouplesCountsTable);
909         attrbsCouplesSet= new Integer [twoAttrbsCombinationsNumber][2];
910 	int i =0;
911 	while(combinationsOf2Attrbs.hasNext() && ( i < twoAttrbsCombinationsNumber) ){
912             attrbsCouplesSet[i] = combinationsOf2Attrbs.next();
913 	    //lg.debug("attrbsCouplesSet["+ i+"]={" + attrbsCouplesSet[i][0] +"," +attrbsCouplesSet[i][1] +"}\n");
914 	    coupleToIndexMap.put((getCoupleFromList( attrbsCouplesSet[i] )), i);
915 	    i++;
916         }i=0;
917         combinationsOf2Attrbs.reset();
918 	//lg.debug("End of set2AttrbsCombinations() \n");
919     }
920     //
921      private static void initCountsTable(int[] t ){ ///  naive bayes average cost NBC - JAC joined attribs average cost.. a zero cost means 100% classification accuracy
922          for(int i = 0; i < t.length ; i++){			       //   Then a zeo value means no preference over any initial "single" attrbs on the naive bayes baseline... 
923             t[i]=0;//control value [1,0] = attValueCount / num of rows (Instances ) in data set
924         }
925     }
926     
927     public final static int PCV = -999999999;
928     private static void initPheromeneTable(int[] t ){ ///  naive bayes average cost NBC - JAC joined attribs average cost.. a zero cost means 100% classification accuracy
929          for(int i = 0; i < t.length ; i++){			       //   Then a zeo value means no preference over any initial "single" attrbs on the naive bayes baseline... 
930             t[i]= (PCV);
931          }
932     }
933     
934     private static void setAttrIndexList(){
935         
936         initialDataSetAttrbIndexList  = new Integer[initialDataSetAttributeNumberExcludingClass];
937                 
938         for ( int i= 0; i <initialDataSetAttributeNumberExcludingClass; i++){
939             initialDataSetAttrbIndexList[i]=i;
940         }
941     
942     }
943     //
944     
945 
946     private static void setBaseline(){
947         baselineEvaluation = SimpleBayesDataProcessor.getBaslineEvaluation();
948 	NaiveBayesCost =   baselineEvaluation.avgCost() ;
949       baseLineMaxClassCounts =SimpleBayesDataProcessor.getBaseLineMaxClassCounts(); 
950     }
951     //
952     
953    
954     private static Couple<Integer> get2MaxCountsAttrbs(){
955         Couple<Integer>  max =null;
956         Double[] counts = maxClassAttrbsMinValuesCounts.toArray(new Double[0]);
957         
958         if(    (maxClassAttrbsMinValuesCounts.size() > 0) //majority class counts
959                                         && 
960                 (  
961                         ((int)maxClassAttrbsMinValuesCounts.get( (maxClassAttrbsMinValuesCounts.size() -1)).doubleValue())  //highest count  is the last element of ArrayList maxClassAttrbsMinValuesCounts
962                                                 >=  
963                         (SimpleBayesDataProcessor.getMinCount())  
964                 )
965          ){
966             int maxCountIndex = counts.length -1;
967             int  usedmaxCountIndex1 = maxCountIndex;
968             int   usedmaxCountIndex2 = maxCountIndex;
969 
970             Integer count  = (int)counts[maxCountIndex].doubleValue();
971             Integer[] attsList = baseLineCountToAttMap.get(count).keySet().toArray(new Integer[0]);
972             if (attsList.length==0){
973                 System.err.println( "Attribs count list is empty for maxCountIndex="+ maxCountIndex+" , at getMaxCountCouple\n" );
974                 System.exit(1);
975             }
976            int a=attsList[0], 
977                  b=a;
978            while( (attsList.length == 1 ) && (b==a) && (maxCountIndex >0) ){
979                maxCountIndex --;
980                count  = (int)counts[maxCountIndex].doubleValue();
981                HashMap<Integer, HashSet<Integer>> aa =  baseLineCountToAttMap. get(count); 
982                Set<Integer> sa =aa.keySet();sa.toArray(new Integer[0]);
983                attsList = sa.toArray(new Integer[0]);
984                //attsList = baseLineCountToAttMap.get(count).keySet().toArray(new Integer[0]);
985                if(attsList.length==1){ //next count att list
986                b=attsList[0]; 
987                }else{
988                    if(attsList.length==0){
989                        System.err.println( "Attribs count list is empty for maxCountIndex="+ maxCountIndex+" , at getMaxCountCouple\n" );
990                        System.exit(1);
991                    } 
992                      while(b==a) {
993                          b=randomIntGenerator.nextInt(attsList.length); 
994                      }
995                }//if attList.length
996            }//while attList.length && ...
997            if(a !=b){ //b   because  attlist of top count had only one att index
998                usedmaxCountIndex2=maxCountIndex; //move down in the count ordered list  from the maxCount to the next below it that had a different Attrbute in its list of attr with vals  with that count
999            }// att list of top count has more than one att index 
1000            while( b==a) {
1001                        b=randomIntGenerator.nextInt(attsList.length); // the top maxCountIndex has a list of more than 1 attribute with vals with this count
1002             }//list do not contain dupplicates 
1003             if(usedmaxCountIndex2 != usedmaxCountIndex1){
1004                 int count1  = (int)counts[usedmaxCountIndex1].doubleValue();
1005                removeUsedMaxs( count1 ,a );
1006                int count2  = (int)counts[usedmaxCountIndex2].doubleValue();
1007                removeUsedMaxs( count2 ,b );
1008             }else{ // only one count has been used because it has a list with more than one attribute
1009                int count1  = (int)counts[usedmaxCountIndex1].doubleValue();
1010                removeUsedMaxs( count1 ,a );
1011                removeUsedMaxs(count1  ,b );
1012             }
1013             max =  new Couple<Integer>(a,b);
1014             maxCountCouplesUsed ++;
1015           
1016        
1017            
1018         }//end of while
1019        
1020      return max;
1021     }
1022     //
1023     
1024     private static void  removeUsedMaxs( final int maxCindx, final int AttrbuteIndex ){
1025          HashMap<Integer, HashSet<Integer>> attrbIndexToValsIndexes = baseLineCountToAttMap.get(maxCindx);
1026        if ( (maxClassAttrbsMinValuesCounts == null) || ( maxCindx >= (maxClassAttrbsMinValuesCounts.size()) ) ) {
1027            return;
1028        }
1029           if(attrbIndexToValsIndexes.size() > 1){
1030                 attrbIndexToValsIndexes.remove(AttrbuteIndex);
1031              }
1032          if( (maxClassAttrbsMinValuesCounts.size() ==0)){
1033              maxClassAttrbsMinValuesCounts.remove(maxCindx);  // all Attrbutes with values with this count have been used
1034          } 
1035     }
1036     //
1037     private static void lw (String output){
1038       wl.logMessage(output);
1039     }
1040   //
1041     
1042     //every colony search needs to be  a clean start on the fold ..working set provided
1043     //On every fold a new solution is found from scracth
1044     private static void resetColonySearchParameters(){
1045         Arrays.fill(usedAattrbsCouplesTable, false);
1046          Arrays.fill(updatedAttrbsCouplesPheromoneTable, false);
1047         
1048          antsPopulation = twoAttrbsCombinationsNumber ;
1049 	coupledAttrbsSet.clear();
1050 	initPheromeneTable(attrbsCouplesPheromoneTable); //empty the contents
1051         initCountsTable(attrbsCouplesCountsTable);
1052         
1053         searchNo =0; 
1054         searchBudget = initialSearchBuget;
1055         maxCountCouplesUsed = 0;//couples with higest number of values , appear in hghier numb of "rows" than other couples 100/ 100 rows ( weka instances)
1056 	
1057         maxClassAttrbsMinValuesCounts =  new ArrayList<Double> (Arrays.asList(baseLineMaxClassCounts[0]));
1058         baseLineCountToAttMap = 
1059                 new  HashMap<Integer, HashMap<Integer, HashSet<Integer>>> (SimpleBayesDataProcessor.getbaseLineCountToAttMap());
1060     } 
1061     
1062     
1063     
1064     
1065     
1066     /*   ---------------------------------------- -------------- -------------- fields ----------------------------------------------- */
1067     
1068     private static HashMap<Couple<Integer>, Integer>  coupleToIndexMap   = null;
1069     private static double NaiveBayesCost = -999999.99999;//contrl value . This is the baseline to evaluate imprvements  by the joined attrbs
1070     private static int  antsPopulation = 1; 
1071 
1072     
1073     private static SimpleBayesDataProcessor dataProcessor = null;// SimpleBayesDataProcessor.getInstance(wl); illegal forward because wl is not set yet...
1074     private static  Evaluation  baselineEvaluation, joinedAttrbsEvaluation = null;
1075     
1076     private static int initialDataSetAttributeNumberExcludingClass=-1;///control value
1077     private static Integer[] initialDataSetAttrbIndexList = null;
1078    
1079    
1080     private static int initialSearchBuget   = 1, searchBudget =1 ; 
1081                               // number of search that can be afforded given resources available.. Elapsed time and memory available should set the bugdet and cost
1082    
1083     private static int classesNumber = 1;// number of attributes, not the values of the a class attribute(IlnessDiagnosis:positive/negative) that are acting as a class...can you have multidimensional classification??
1084    
1085   
1086     
1087     private static HashSet<Couple<Integer>> coupledAttrbsSet = new HashSet<Couple<Integer>>();//set of 2attirbs joined (couples)
1088     
1089      private static Combinator<Integer> combinationsOf2Attrbs =null ;
1090     
1091     //private static  double  BLpctCorrect = 1000.00000; // Correct  classifications ratio  reached by weka naive bayes on initial data set without joining any attrb 
1092    
1093    private static  int  ABNORMAL_TERMINATION= 1;
1094     
1095    private static final Random randomIntGenerator =  new Random();
1096      
1097    private static int foldingsNum = 0;
1098    
1099    private static Logger  lg =  Logger.getLogger(ACOjoinedAttrbSearch.class);
1100    private static LogPanel wl =null;
1101 
1102     private static  int  twoAttrbsCombinationsNumber = -9; // control value
1103     private static  int[] attrbsCouplesPheromoneTable  = null,
1104                                      attrbsCouplesCountsTable = null;
1105     
1106     private static  Integer[][] attrbsCouplesSet = null; //Table for  combianations of 2attribs;
1107      
1108     //Remind that Couples are  the 2 indexes of initial datasete "single"  attributes(columns)  making the 2joinedAttrbutes.Indexes are the initial data set attributes indexes.
1109     private static HashMap<Integer, HashSet<Couple<Integer>>> pheromeneWeightsToCouplesSetMap = null;
1110     private static Integer[] sortedIncreasingPheroWeightsList=null;
1111    
1112     private static  int initialSearch = 0, 
1113                                    searchNo =0;
1114     private static double magnifcationFactor = 1000.0000; // used to make it easier to work with [0,1] quantities 
1115     private static Double [][]baseLineMaxClassCounts = null;
1116     private static  HashMap<Integer, HashMap<Integer, HashSet<Integer>>> baseLineCountToAttMap = null;
1117   
1118     private static int maxCountCouplesUsed =0 ;
1119     private static ArrayList<Double> maxClassAttrbsMinValuesCounts =null; // "in majority class" counts for each attribute values
1120     private static int minAttrbValuesCountPer100 = 5;
1121     private static int maxCountCouplesUsedLimit =3;
1122     
1123     private static boolean[] usedAattrbsCouplesTable = null,
1124                                               updatedAttrbsCouplesPheromoneTable =null;
1125     
1126     private static int workingFoldNumber =0;
1127     private static StringBuilder maxCountsMsgs= null;
1128     private static HashMap<Integer, HashSet<Integer>> jointWeightToCoupleIndexMap = null;
1129     
1130     private static int[] c3pw= null;
1131     private static Integer[][] c3 = null; //combinations of 4 over 3. All possible triples whit 4 distinct attrbs
1132     private static int[] heaviestPherWeightTrple =null;
1133     private static int antNum = 0;
1134     private static ArrayList<EvaluationACO> antColonySearchesEvaluations= null, 
1135                                                                            aColEvlTriples = null;
1136    
1137   
1138    
1139    private static String[] dataSetsFielesNames  = null;
1140    private static int cplIndx= -9; 
1141    private static String projectResources = Main.projectResources;
1142    private static String data= projectResources +"dataSets/";
1143    
1144 }
1145 /// End of Class
1146 
1147