CFormula.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*
  2. * CFormula.cpp
  3. *
  4. * Created on: Oct 1, 2016
  5. * Author: Sina M.Baharlou
  6. */
  7. #include "CFormula.hpp"
  8. CFormula::CFormula():
  9. nVars(0),
  10. nClauses(0),
  11. fStats{0,0,0},
  12. fVars(NULL),
  13. fPortions(NULL),
  14. tPortion(0),
  15. nLit(NULL),
  16. evalArray(NULL),
  17. evalClause(NULL),
  18. varMap(NULL),
  19. clCounter(0),
  20. greedyFactor(DEFAULT_GREEDY_FACTOR),
  21. arrayFiller(NULL),
  22. nbSatisfiedClausesFill(0),
  23. nbSatisfiedClausesSolve(0),
  24. lastFillMethod(0),
  25. lastHeuristic(0),
  26. ite(0)
  27. {
  28. this->fType.clear();
  29. this->fComments.clear();
  30. // -- Initializing distribution variables --
  31. rndReal=std::uniform_real_distribution<float>(0.0,1.0);
  32. rndMethod=std::uniform_int_distribution<int>(FIRST_FILL_METHOD,LAST_FILL_METHOD);
  33. rndHeuristic=std::uniform_int_distribution<int>(FIRST_H_METHOD,LAST_H_METHOD);
  34. // -- Init random engine --
  35. struct timespec ts;
  36. unsigned theTick = 0U;
  37. clock_gettime( CLOCK_REALTIME, &ts );
  38. theTick = ts.tv_nsec / 1000000;
  39. theTick += ts.tv_sec * 1000;
  40. rndEngine.seed(theTick);
  41. }
  42. bool CFormula::initFormula(const char* filename)
  43. {
  44. // -- Initialize variables --
  45. this->cFormula.empty();
  46. this->fComments.empty();
  47. this->fType.empty();
  48. this->fStats={0,0,0};
  49. this->clCounter=0;
  50. bool fReached=false;
  51. // -- Free previously allocated variables --
  52. if (this->fVars) free(this->fVars);
  53. if (this->fPortions) free(this->fPortions);
  54. if (this->nLit) free(this->nLit);
  55. if (this->evalArray) free(this->evalArray);
  56. if (this->arrayFiller) free(this->arrayFiller);
  57. if (this->varMap) free(this->varMap);
  58. if (this->evalClause) free(this->evalClause);
  59. // -- Open input file --
  60. ifstream input_file;
  61. input_file.open(filename);
  62. if (!input_file.is_open())
  63. {
  64. printf("STD Error: cannot open '%s'.",filename);
  65. return false;
  66. }
  67. // -- Parse the provided file --
  68. std::string line;
  69. while (std::getline(input_file, line))
  70. {
  71. // -- get the flag (can be 'c' or 'p') --
  72. char flag=line[0];
  73. std::vector<string> tokens;
  74. switch (flag)
  75. {
  76. case COMMENT_FLAG: // -- Comment line has reached --
  77. // -- Add to comment string --
  78. this->fComments.append(&line[1]);
  79. this->fComments.append("\n");
  80. break;
  81. case PROBLEM_FLAG: // -- Problem line has reached --
  82. // -- Tokenize current line --
  83. tokens.empty();
  84. tokens=tokenize(&line[1]," ");
  85. // -- Check if the syntax if correct in order to parse the parameters --
  86. if (tokens.size()<3)
  87. {
  88. printf("There is a syntax error in the problem definition.");
  89. return false;
  90. }
  91. // -- Assign the variables --
  92. this->fType=tokens[0];
  93. this->nVars=stoi(tokens[1])+1; // -- starts from 1
  94. this->nClauses=stoi(tokens[2]);
  95. fReached=true;
  96. // -- allocate the arrays
  97. this->fVars=new bool[this->nVars];
  98. this->fPortions= new float[this->nVars];
  99. this->nLit=new int[this->nVars];
  100. this->evalArray=new int[this->nVars];
  101. this->evalClause=new bool[this->nClauses];
  102. this->varMap=new std::vector<int>[this->nVars];
  103. // -- initialize the arrays
  104. memset(this->fVars,0,this->nVars*sizeof(bool));
  105. memset(this->fPortions,0,this->nVars*sizeof(float));
  106. memset(this->nLit,0,this->nVars*sizeof(int));
  107. memset(this->evalArray,0,this->nVars*sizeof(int));
  108. memset(this->evalClause,0,this->nClauses*sizeof(bool));
  109. // -- Instantiate the arrayFiller class
  110. this->arrayFiller=new ArrayFiller(this->fVars,this->nVars);
  111. break;
  112. case END_FLAG: // -- End of the formula has reached --
  113. input_file.close();
  114. // -- Ppdate stats --
  115. this->tPortion=(float)this->fStats.nPosLits/this->fStats.nLits;
  116. for (unsigned int i=1;i<this->nVars;i++)
  117. this->fPortions[i]/=(float)this->nLit[i];
  118. // -- Init random filler --
  119. this->arrayFiller->setPortionRate(this->tPortion);
  120. this->arrayFiller->setPortionArray(this->fPortions);
  121. this->arrayFiller->fillArray(PORTION_EL_FILL);
  122. return true;
  123. break;
  124. default: // -- Clause line has reached--
  125. if (!fReached)
  126. continue;
  127. this->cFormula.push_back(parseClause(&line[0]," "));
  128. break;
  129. }
  130. }
  131. return true;
  132. }
  133. bool CFormula::evalFormulaQ(unsigned int varIndex,int& clNum)
  134. {
  135. bool fEval=true;
  136. clNum=0;
  137. // -- check through the modified clauses --
  138. for (unsigned int i=0;i<this->varMap[varIndex].size();i++)
  139. {
  140. // -- get the clause --
  141. int cIndex=this->varMap[varIndex].at(i);
  142. Clause cl=this->cFormula[cIndex];
  143. // -- for each literal
  144. for (unsigned int j=0;j<cl.size();j++)
  145. {
  146. Literal lit=cl[j];
  147. // -- get the index and sign
  148. bool neg=(lit<0);
  149. int index=abs(lit);
  150. // -- evaluate the literal
  151. bool litEval=neg^this->fVars[index];
  152. this->evalClause[cIndex]=litEval; // -- update clause truth list
  153. // -- if positive -> clause will be evaluated as positive
  154. if (litEval)
  155. break;
  156. }
  157. }
  158. // -- evaluate the whole formula --
  159. for (unsigned int i=0;i<this->cFormula.size();i++)
  160. {
  161. bool evalClause=this->evalClause[i];
  162. fEval&=evalClause;
  163. if (evalClause)clNum++;
  164. }
  165. return fEval;
  166. }
  167. bool CFormula::evalFormula(int& clNum)
  168. {
  169. bool fEval=true;
  170. clNum=0;
  171. for (unsigned int i=0;i<this->cFormula.size();i++)
  172. {
  173. // -- get the clause --
  174. Clause cl=this->cFormula[i];
  175. bool clEval=false;
  176. // -- for each literal
  177. for (unsigned int j=0;j<cl.size();j++)
  178. {
  179. Literal lit=cl[j];
  180. // -- get the index and sign
  181. bool neg=(lit<0);
  182. int index=abs(lit);
  183. // -- evaluate the literal
  184. bool litEval=neg^this->fVars[index];
  185. this->evalClause[i]=litEval;
  186. // -- if positive -> clause will be evaluated as positive
  187. if (litEval)
  188. {
  189. clEval=true;
  190. clNum++;
  191. break;
  192. }
  193. }
  194. // -- and it with current evaluation of formula
  195. fEval&=clEval;
  196. }
  197. return fEval;
  198. }
  199. bool CFormula::startGSAT(int iterations,int maxTry,int fillMethod,int hMethod)
  200. {
  201. float initGuessMean=0; // -- initial guess average
  202. float negClauseMean=0; // -- average number of negative clauses
  203. float elaborateMean=0; // -- averate number of elaboration
  204. bool fEval=false;
  205. int i;
  206. for (i=0;i<iterations;i++)
  207. {
  208. int initGuess=0;
  209. int clNum=0;
  210. fEval=false;
  211. // -- randomly select the filler method --
  212. FillMethod fMethod;
  213. if (fillMethod==-1)
  214. fMethod=getRandomMethod();
  215. else
  216. fMethod=(FillMethod)fillMethod;
  217. lastFillMethod=fMethod;
  218. ite++;
  219. // -- randomly select the heuristic method --
  220. HeuristicMethod heuristic;
  221. if (hMethod==-1)
  222. heuristic=getRandomHeuristic();
  223. else
  224. heuristic=(HeuristicMethod)hMethod;
  225. lastHeuristic=heuristic;
  226. this->arrayFiller->fillArray(fMethod);
  227. // -- evaluate the function
  228. fEval=this->evalFormula(clNum);
  229. initGuess=clNum;
  230. nbSatisfiedClausesFill=initGuess;
  231. initGuessMean+=initGuess;
  232. // -- return if already found the solution
  233. if (fEval)
  234. break;
  235. for (int j=0;j<maxTry;j++)
  236. {
  237. int choice=0;
  238. // -- select the choice with the given heuristics --
  239. switch (heuristic)
  240. {
  241. case FIRST_BEST:
  242. choice=this->getBestChoice(true);
  243. break;
  244. case RND_BEST:
  245. choice=this->getBestChoice();
  246. break;
  247. case RND_DIST:
  248. choice=this->getRndBest();
  249. break;
  250. case RND:
  251. choice=(int)(rndReal(rndEngine)*this->nVars);
  252. break;
  253. case RND_GREEDY:
  254. if (this->takeBestChoice())
  255. choice=this->getBestChoice();
  256. else
  257. choice=this->getRndBest();
  258. break;
  259. case WALK_SAT:
  260. choice=this->walkSatChoice();
  261. break;
  262. case GSAT_WSAT:
  263. if (this->takeGW())
  264. choice=this->getBestChoice();
  265. else
  266. choice=this->walkSatChoice();
  267. break;
  268. }
  269. toggle(this->fVars[choice]);
  270. fEval=this->evalFormulaQ(choice,clNum);//this->evalFormula(clNum);
  271. if (fEval)
  272. break;
  273. }
  274. negClauseMean+=this->nClauses-clNum;
  275. elaborateMean+=clNum-initGuess;
  276. nbSatisfiedClausesSolve=clNum;
  277. //printf("[iteration %d, fill :%d, heuristic :%d] - init Guess :%d - final Guess :%d - model found :%d\n",i,fMethod,heuristic,initGuess,clNum,fEval);
  278. if (fEval)
  279. break;
  280. }
  281. /*printf("Elaborate mean :%f\n",elaborateMean/(float)i);
  282. printf("Initial guess mean :%f\n",initGuessMean/(float)i);
  283. printf("Neg clause mean :%f\n",negClauseMean/(float)i);*/
  284. return fEval;
  285. }
  286. void CFormula::setGreedyFactor(float factor)
  287. {
  288. this->greedyFactor=factor;
  289. }
  290. void CFormula::setGWFactor(float factor)
  291. {
  292. this->gwFactor=factor;
  293. }
  294. std::vector<string> CFormula::tokenize(char*input,const char*split)
  295. {
  296. char * token;
  297. std::vector<string> token_vec;
  298. token = strtok (input,split);
  299. while (token != NULL)
  300. {
  301. token_vec.push_back(string(token));
  302. token = strtok (NULL, " ");
  303. }
  304. return token_vec;
  305. }
  306. Clause CFormula::parseClause(char*input,const char*split)
  307. {
  308. char * token;
  309. Clause cl;
  310. token = strtok (input,split);
  311. while (token != NULL)
  312. {
  313. Literal lit=stoi(token);
  314. if (lit!=0)
  315. {
  316. int index=abs(lit);
  317. // -- update the stats
  318. this->varMap[index].push_back(clCounter);
  319. if (lit>0)
  320. {
  321. this->fStats.nPosLits++;
  322. this->fPortions[index]+=1;
  323. }
  324. else this->fStats.nNegLits++;
  325. fStats.nLits++;
  326. this->nLit[index]++;
  327. // --
  328. cl.push_back(lit);
  329. }
  330. token = strtok (NULL, " ");
  331. }
  332. this->clCounter++;
  333. return cl;
  334. }
  335. FillMethod CFormula::getRandomMethod()
  336. {
  337. return (FillMethod)rndMethod(rndEngine);
  338. }
  339. HeuristicMethod CFormula::getRandomHeuristic()
  340. {
  341. return (HeuristicMethod)rndHeuristic(rndEngine);
  342. }
  343. bool CFormula::takeBestChoice()
  344. {
  345. double random=rndReal(rndEngine); // -- Get a double random number between 0 and 1
  346. // -- Check if GSAT should take a best action
  347. if (random<=this->greedyFactor)
  348. return true;
  349. return false;
  350. }
  351. bool CFormula::takeGW()
  352. {
  353. double random=rndReal(rndEngine); // -- Get a double random number between 0 and 1
  354. // -- Check if GSAT should take a best action
  355. if (random<=this->gwFactor)
  356. return true;
  357. return false;
  358. }
  359. void CFormula::evalMove(int&min,int&max)
  360. {
  361. min=std::numeric_limits<int>::max();
  362. max=0;
  363. for (unsigned int i=1;i<this->nVars;i++)
  364. {
  365. int clNum=0;
  366. int temp=0;
  367. toggle(this->fVars[i]);
  368. this->evalFormulaQ(i,clNum); //this->evalFormula(clNum);
  369. toggle(this->fVars[i]);
  370. this->evalFormulaQ(i,temp);
  371. this->evalArray[i]=clNum;
  372. if (clNum>max) max=clNum;
  373. if (clNum<min) min=clNum;
  374. }
  375. }
  376. std::vector<int> CFormula::evalUnsatClause(int clIndex,int&min,int&max)
  377. {
  378. min=std::numeric_limits<int>::max();
  379. max=0;
  380. Clause cl=this->cFormula[clIndex];
  381. std::vector<int> evalArray;
  382. for (unsigned int i=0;i<cl.size();i++)
  383. {
  384. Literal lit=cl[i];
  385. int index=abs(lit);
  386. int clNum=0;
  387. int temp=0;
  388. // -- evaluate the positive clauses
  389. toggle(this->fVars[index]);
  390. this->evalFormulaQ(index,clNum); //this->evalFormula(clNum);
  391. toggle(this->fVars[index]);
  392. this->evalFormulaQ(index,temp);
  393. // --
  394. evalArray.push_back(clNum);
  395. if (clNum>max) max=clNum;
  396. if (clNum<min) min=clNum;
  397. }
  398. return evalArray;
  399. }
  400. int CFormula::getBestChoice(bool retFirst)
  401. {
  402. int min,max;
  403. this->evalMove(min,max);
  404. int bestCount=0;
  405. std::vector<int> bestArray;
  406. for (unsigned int i=1;i<this->nVars;i++)
  407. {
  408. if (this->evalArray[i]==max)
  409. {
  410. if (retFirst) return i; // -- return immediately the first choice
  411. bestArray.push_back(i);
  412. bestCount++;
  413. }
  414. }
  415. if (bestCount==1)
  416. return bestArray[0];
  417. // -- randomly select the best choice
  418. int rndIndex=(int)(rndReal(rndEngine)*bestCount);
  419. return bestArray[rndIndex];
  420. }
  421. int CFormula::walkSatChoice(bool retFirst)
  422. {
  423. // -- Randomly get one unsatisfied clause
  424. int clIndex=this->getUnsatClause(retFirst);
  425. int min,max;
  426. // -- List the best choices
  427. std::vector<int> evalArray=evalUnsatClause( clIndex,min,max);
  428. // -- select randomly from the best choices
  429. int bestCount=0;
  430. std::vector<int> bestArray;
  431. for (unsigned int i=0;i<evalArray.size();i++)
  432. {
  433. if (evalArray[i]==max)
  434. {
  435. if (retFirst) return i; // -- return immediately the first choice
  436. bestArray.push_back(i);
  437. bestCount++;
  438. }
  439. }
  440. if (bestCount==1)
  441. return abs(this->cFormula[clIndex].at(bestArray[0]));
  442. // -- randomly select the best choice
  443. int rndIndex=(int)(rndReal(rndEngine)*bestCount);
  444. return abs(this->cFormula[clIndex].at(bestArray[rndIndex]));
  445. }
  446. int CFormula::getUnsatClause(bool retFirst)
  447. {
  448. int clCount=0;
  449. std::vector<int> clArray;
  450. for (unsigned int i=0;i<this->nClauses;i++)
  451. {
  452. if (!this->evalClause[i])
  453. {
  454. if (retFirst) return i; // -- return immediately the first choice
  455. clArray.push_back(i);
  456. clCount++;
  457. }
  458. }
  459. if (clCount==1)
  460. return clArray[0];
  461. // -- randomly select the best choice
  462. int rndIndex=(int)(rndReal(rndEngine)*clCount);
  463. return clArray[rndIndex];
  464. }
  465. int CFormula::getRndBest(bool exponential)
  466. {
  467. int min,max;
  468. float cum=0;
  469. this->evalMove(min,max);
  470. float normalizer=0;
  471. // -- calculate the discrete probability distribution --
  472. float probs[this->nVars];
  473. float rnd =rndReal(rndEngine);
  474. for (unsigned int i=1;i<this->nVars;i++)
  475. {
  476. probs[i]=(float)(this->evalArray[i]-min+DEFAULT_BIAS);
  477. if (exponential)probs[i]=exp(probs[i]);
  478. normalizer+=probs[i];
  479. }
  480. // -- sample from the distribution --
  481. for (unsigned int i=1;i<this->nVars;i++)
  482. {
  483. cum+=probs[i]/normalizer;
  484. if (cum>rnd)
  485. return i;
  486. }
  487. return 0;
  488. }