// Search config in the hash table, if it is not there, this config will be // inserted. If inserted, *pCacheConfig will point to the location. // return value // 0 -- not found or can not be pruned // 1 -- find a config that can be pruned in the cache int TryFind(CConfig **arr, CConfig *pConfig, CConfig **pCacheConfig) { *pCacheConfig = NULL; //return 0; int index = pConfig->CalHashValue(); CConfig *p = arr[index]; if (!p) // the config is not found and insert this pConfig to it { #ifdef USE_OWN_CACHE if (usedconfiglength>=MAXUSEDCONFIGSIZE) return 0; CConfig* pNewConfig = newCacheConfig(pConfig->len); if (!pNewConfig) return 0; // cache has been used up, just return; #else if (usedconfiglength>=MAXUSEDCONFIGSIZE) return 0; CConfig* pNewConfig = new CConfig(pConfig->len); assert(pNewConfig); #endif usedconfiglength++; pNewConfig->Copy(pConfig); arr[index] = pNewConfig; *pCacheConfig = pNewConfig; return 0; } if (p->ConfigCmp(pConfig)) return 0; // now the configs are the same if (p->depth <= pConfig->depth) { // if a config hits the hash table with length no less than that in the // table, it cannot be on the path of any optimal solutions not found // yet. Remember if an optimal solution is found, all configs along // the solution path stored in the hash table are released in // Solution_Found() in solver.cpp return 1; } else { p->depth = pConfig->depth; *pCacheConfig = p; return 0; } }
// Solve the instance with the given config // maxlen is the size of the maximum space allocated in pConfig // return value: // -1: unsolvable // 0: unsolved till the depth threshold // n>0: solved at depth of n int CSolver::SolveConfig(CPCPInstance *pPCP, CConfig *pConfig, int maxlen) { int i, j, k; // store the matched pairs and the lengths of resulting configs int arrRetValue[MAXSIZE];; int arrMatchedPair[MAXSIZE]; int matchedPairNum; // ret value long int matchret; int solveret; int ret = -1; int succ; int newlen; // store the location of the config in the cache CConfig* pCacheConfig; CConfig *pNewConfig; // int lookaheadflag; // long tmpret; DEEP: //// Heuristic pruning if (IsPrunable(pPCP, pConfig)) return 0; //// record all pairs which can be matched matchedPairNum = 0; /* if ( pConfig->up && pPCP->maxdown*2<pConfig->len || !pConfig->up && pPCP->maxup*2 <pConfig->len) lookaheadflag=1; // use traditional method else lookaheadflag=0; */ for (i=0;i<pPCP->size;i++) { matchret=pConfig->TestMatchingPair(&pPCP->arrPair[i]); /* if (!lookaheadflag) matchret=pConfig->TestMatchingPair(&pPCP->arrPair[i]); else { matchret=2000000000; for (j=0;j<pPCP->size;j++) { tmpret = pConfig->TestMatchingPairs(pPCP, &pPCP->arrPair[i], &pPCP->arrPair[j]); if (tmpret>0 && tmpret<matchret) matchret = tmpret; } if (matchret==2000000000) matchret=-1; } */ if (matchret==0) // find one solution { pConfig->depth++; arrSelection[pConfig->depth] = pPCP->arrPair[i].ID; succ = Solution_Found(pPCP, pConfig); if (succ>0) { return pConfig->depth; } else ret = 0; pConfig->depth--; } else if (matchret>0) // find one match { // having exceeded the threshold, prune it if (pConfig->depth==iterative_depth_threshold-1) ret=0; else // record the pair { arrRetValue[matchedPairNum] = matchret; arrMatchedPair[matchedPairNum++] = i; } } } //// no matched pair? if (matchedPairNum == 0) RETURNANDCLEAR; //// only one matched pair and the config can be reused? jump back! if (matchedPairNum==1 && arrRetValue[0]<=maxlen ) { pConfig->MatchPair(&pPCP->arrPair[arrMatchedPair[0]], arrSelection); assert(pConfig->len <= maxlen); if (pConfig->up) if (pPCP->upmask) RETURNANDCLEAR; if (!pConfig->up) if (pPCP->downmask) RETURNANDCLEAR; succ = TryFind(hashTable, pConfig, &pCacheConfig); if (succ==1 || succ==2) // this configration is in the cache, prune it { Add_cutoff_node_number(); //if (succ==2) ret = 0; RETURNANDCLEAR; } goto DEEP; } //// sort the matched pair array according to its matchret value for (i=0;i<matchedPairNum-1;i++) for (j=i+1;j<matchedPairNum;j++) { if (arrRetValue[i] > arrRetValue[j]) { k = arrRetValue[i]; arrRetValue[i] = arrRetValue[j]; arrRetValue[j] = k; k = arrMatchedPair[i]; arrMatchedPair[i] = arrMatchedPair[j]; arrMatchedPair[j] = k; } } //// try the pair one by one // count new length for config newlen = pConfig->len+pPCP->offset+MAXLOOPCOUNT*pPCP->offset; // create new config #ifdef USE_CONFIG_POOL pNewConfig = newConfig(newlen); #else pNewConfig = new CConfig(newlen); #endif // try all matched pairs for (i=0;i<matchedPairNum;i++) { // the last matched pair and the config can be reused? Jump back! if (i+1==matchedPairNum && arrRetValue[i]<=maxlen ) { pConfig->MatchPair(&pPCP->arrPair[arrMatchedPair[i]], arrSelection); if (pConfig->up) if (pPCP->upmask) continue; if (!pConfig->up) if (pPCP->downmask) continue; #ifdef USE_CONFIG_POOL deleteConfig(newlen); #else delete pNewConfig; #endif succ = TryFind(hashTable, pConfig, &pCacheConfig); if (succ==1 || succ==2) // this config is in the cache { Add_cutoff_node_number(); //if (succ==2) ret = 0; RETURNANDCLEAR; } goto DEEP; } // duplicate pConfig to config pNewConfig->Copy(pConfig); // match it with the pair pNewConfig->MatchPair(&pPCP->arrPair[arrMatchedPair[i]], arrSelection); // test masks if (pNewConfig->up) if (pPCP->upmask) continue; if (!pNewConfig->up) if (pPCP->downmask) continue; // check cache succ = TryFind(hashTable, pNewConfig, &pCacheConfig); if (succ==1 || succ==2) // this config is in the cache { Add_cutoff_node_number(); continue; } // recursively call the SolveConfig routine solveret=SolveConfig(pPCP, pNewConfig, newlen); // check result if (solveret>0) // solve it { #ifdef USE_CONFIG_POOL deleteConfig(newlen); #else delete pNewConfig; #endif return solveret; } if (solveret==0) // cannot solve it to the iterative_depth_threshold ret=0; } #ifdef USE_CONFIG_POOL deleteConfig(newlen); #else delete pNewConfig; #endif RETURNANDCLEAR; }