StepCode EliminateNakedPairsStep::runOnHouse(House &cell_list) { bool modified = false; std::set<Mask> found_masks; std::set<Mask> duplicate_masks; for (const Cell *cell : cell_list) { if (cell->candidates.none()) { return {true, modified}; } if (cell->candidates.count() != 2) { continue; } const Mask mask = cell->candidates.to_ulong(); if (found_masks.count(mask)) { duplicate_masks.insert(cell->candidates.to_ulong()); } found_masks.insert(mask); } for (auto &mask : duplicate_masks) { for (Cell *cell : cell_list) { if (cell->isFixed()) { continue; } CandidateSet *candidates = &cell->candidates; if (candidates->to_ulong() == mask) { continue; } auto new_cands = CandidateSet(candidates->to_ulong() & ~mask); if (*candidates == new_cands) { continue; } if (DEBUG) { const Mask intersection = candidates->to_ulong() & mask; dbgs() << "Naked Pair " << printCandidateString(mask) << " removes " << printCandidateString(intersection) << " from " << cell->coord << "\n"; } modified = true; changed.insert(cell); *candidates = new_cands; } } return {false, modified}; }
std::tuple<unsigned, unsigned, unsigned, unsigned> OLCTriangle::RunBranchAndBound(unsigned from, unsigned to, unsigned worst_d, bool exhaustive) { /* Some general information about the branch and bound method can be found here: * http://eaton.math.rpi.edu/faculty/Mitchell/papers/leeejem.html * * How to use this method for solving FAI triangles is described here: * http://www.penguin.cz/~ondrap/algorithm.pdf */ // Return early if this tp-range can't beat the current best_d... // Assume a maximum speed of 100 m/s const unsigned fastskiprange = GetPoint(to).DeltaTime(GetPoint(from)) * 100; const unsigned fastskiprange_flat = trace_master.ProjectRange(GetPoint(from).GetLocation(), fastskiprange); if (fastskiprange_flat < worst_d) return std::tuple<unsigned, unsigned, unsigned, unsigned>(0, 0, 0, 0); bool integral_feasible = false; unsigned best_d = 0, tp1 = 0, tp2 = 0, tp3 = 0; unsigned iterations = 0; // note: this is _not_ the breakepoint between small and large triangles, // but a slightly lower value used for relaxed large triangle checking. const unsigned large_triangle_check = trace_master.ProjectRange(GetPoint(from).GetLocation(), 500000) * 0.99; if (!running) { // initiate algorithm. otherwise continue unfinished run running = true; // initialize bound-and-branch tree with root node (note: Candidate set interval is [min, max)) CandidateSet root_candidates(*this, from, to + 1); if (root_candidates.IsFeasible(is_fai, large_triangle_check) && root_candidates.df_max >= worst_d) branch_and_bound.insert(std::pair<unsigned, CandidateSet>(root_candidates.df_max, root_candidates)); } // set max_iterations only if non-exhaustive and predictive solving is enabled. // otherwise use predefined value. if (!exhaustive && predict) max_iterations = tick_iterations; while (!branch_and_bound.empty()) { /* now loop over the tree, branching each found candidate set, adding the branch if it's feasible. * remove all candidate sets with d_max smaller than d_min of the largest integral candidate set * always work on the node with largest d_min */ iterations++; // break loop if max_iterations or max_tree_size exceeded if (iterations > max_iterations || branch_and_bound.size() > max_tree_size) break; // first clean up tree, removeing all nodes with d_max < worst_d branch_and_bound.erase(branch_and_bound.begin(), branch_and_bound.lower_bound(worst_d)); // we might have cleaned up the whole tree. nothing to do then... if (branch_and_bound.empty()) break; /* get node to work on. * change node selection strategy if the tree grows too big. * this is a mixed depht-first/breadth-first approach, the latter * beeing faster, but the first a lot more memory efficient. */ std::multimap<unsigned, CandidateSet>::iterator node; if (branch_and_bound.size() > n_points * 4 && iterations % 16 != 0) { node = branch_and_bound.upper_bound(branch_and_bound.rbegin()->first / 2); if (node == branch_and_bound.end()) --node; } else { node = --branch_and_bound.end(); } if (node->second.df_min >= worst_d && node->second.IsIntegral(*this, is_fai, large_triangle_check)) { // node is integral feasible -> a possible solution worst_d = node->second.df_min; tp1 = node->second.tp1.index_min; tp2 = node->second.tp2.index_min; tp3 = node->second.tp3.index_min; best_d = node->first; integral_feasible = true; } else { // split largest bounding box of node and create child nodes const unsigned tp1_diag = node->second.tp1.GetDiagnoal(); const unsigned tp2_diag = node->second.tp2.GetDiagnoal(); const unsigned tp3_diag = node->second.tp3.GetDiagnoal(); const unsigned max_diag = std::max({tp1_diag, tp2_diag, tp3_diag}); CandidateSet left, right; bool add = false; if (tp1_diag == max_diag && node->second.tp1.GetSize() != 1) { // split tp1 range const unsigned split = (node->second.tp1.index_min + node->second.tp1.index_max) / 2; if (split <= node->second.tp2.index_max) { add = true; left = CandidateSet(TurnPointRange(*this, node->second.tp1.index_min, split), node->second.tp2, node->second.tp3); right = CandidateSet(TurnPointRange(*this, split, node->second.tp1.index_max), node->second.tp2, node->second.tp3); } } else if (tp2_diag == max_diag && node->second.tp2.GetSize() != 1) { // split tp2 range const unsigned split = (node->second.tp2.index_min + node->second.tp2.index_max) / 2; if (split <= node->second.tp3.index_max && split >= node->second.tp1.index_min) { add = true; left = CandidateSet(node->second.tp1, TurnPointRange(*this, node->second.tp2.index_min, split), node->second.tp3); right = CandidateSet(node->second.tp1, TurnPointRange(*this, split, node->second.tp2.index_max), node->second.tp3); } } else if (node->second.tp3.GetSize() != 1) { // split tp3 range const unsigned split = (node->second.tp3.index_min + node->second.tp3.index_max) / 2; if (split >= node->second.tp2.index_min) { add = true; left = CandidateSet(node->second.tp1, node->second.tp2, TurnPointRange(*this, node->second.tp3.index_min, split)); right = CandidateSet(node->second.tp1, node->second.tp2, TurnPointRange(*this, split, node->second.tp3.index_max)); } } if (add) { // add the new candidate set only if it it's feasible and has d_min >= worst_d if (left.df_max >= worst_d && left.IsFeasible(is_fai, large_triangle_check)) { branch_and_bound.insert(std::pair<unsigned, CandidateSet>(left.df_max, left)); } if (right.df_max >= worst_d && right.IsFeasible(is_fai, large_triangle_check)) { branch_and_bound.insert(std::pair<unsigned, CandidateSet>(right.df_max, right)); } } } // remove current node branch_and_bound.erase(node); } if (branch_and_bound.empty()) running = false; if (integral_feasible) { if (tp1 > tp2) std::swap(tp1, tp2); if (tp2 > tp3) std::swap(tp2, tp3); if (tp1 > tp2) std::swap(tp1, tp2); return std::tuple<unsigned, unsigned, unsigned, unsigned>(tp1, tp2, tp3, best_d); } else { return std::tuple<unsigned, unsigned, unsigned, unsigned>(0, 0, 0, 0); } }
//----------------------------------------------------------------------------- // name: void synth( void ) // desc: does wavelet tree learning to build the new tree, then does the // inverse discrete wavelet transform on the new tree to get synthesized // signal //----------------------------------------------------------------------------- void Treesynth::synth( void ) { // Set up candidate set for root (also always the same, but gets deleted) tnew_data->getNode( 0, 0 )->cs = new TS_UINT[1]; tnew_data->getNode( 0, 0 )->cs[0] = 0; tnew_data->getNode( 0, 0 )->cslength = 1; // Synthesize new tree if( startlevel <= 1 ) { for(int n = 0; n < 2; n++) { // level 1 (the level next to the root) // try copying randomly instead of in order // (so instead of LR it could be LL or RR or RL) if( randflip ) { int random = (int)( 2 * rand()/( RAND_MAX + 1.0 ) ); *(tnew->getNode( 1, n )->value) = tree->getValue( 1, random ); } else *(tnew->getNode( 1, n )->value) = tree->getValue( 1, n ); } } else { int l, n; for( l = 1; l <= startlevel; l++ ) { int length = ( 1 << l ); // (int)pow( 2, l ) for( n = 0; n < length; n++ ) { *(tnew->getNode( 1, n )->value) = tree->getValue( 1, n ); if( l == startlevel - 1 ) { tnew_data->getNode( 1, n )->cs = new TS_UINT[length]; tnew_data->getNode( 1, n )->cslength = length; for( int q = 0; q < length; q++ ) tnew_data->getNode( 1, n )->cs[q] = q; } } } } // Breadth-first part int lev; for( lev = startlevel; lev <= stoplevel; lev++ ) { if( lev >= tree->getLevels() - 1 ) break; std::cout << "Processing level " << lev << " "; std::cout << "k is " << (npredecessors = ( 1 << lev ) * kfactor) << std::endl; // (int)(pow( 2, lev ) for( int offset = 0; offset < ( 1 << lev ); offset++ ) { // (int)(pow( 2, lev ) CandidateSet( lev, offset ); if( tnew_data->getNode( lev, offset )->cslength == 0 ) std::cerr << "Double Uh-oh " << lev << "-" << offset << std::endl; // Randomly choose a node from candidate set and steal its children int randPick = (int)( rand()/(RAND_MAX + 1.0) * tnew_data->getNode( lev, offset )->cslength ); randPick = tnew_data->getNode( lev, offset )->cs[randPick]; // left child *(tnew->getNode( lev, offset )->left->value) = tree->getValue( lev+1, 2*randPick ); // right child: changed to make sure nodes referred to are within limits if( 2*offset + 1 < ( 1 << (lev + 1) ) ) { // pow( 2, lev+1 ) if( 2*randPick + 1 < ( 1 << (lev + 1) ) ) // pow( 2, lev+1 ) *(tnew->getNode( lev, offset )->right->value) = tree->getValue( lev+1, 2*randPick + 1 ); else { *(tnew->getNode( lev, offset )->right->value) = tree->getValue( lev+1, 2*randPick ); if( randPick > 0 ) *(tnew->getNode( lev, offset )->left->value) = tree->getValue( lev+1, 2*randPick - 1 ); } } // if it's stoplevel, copy all descendants if( lev == stoplevel ) { int l, m = 2, p; for( l = lev + 2; l < tree->getLevels(); l++ ) { m = 2*m; for( p = 0; p < m; p++ ) *(tnew->getNode( l, m*offset + p )->value) = tree->getValue( l, m*randPick + p ); } } // yeah... } } // Reconstruct signal from new wavelet tree TS_UINT size = tnew->getSize(); memcpy( synsig, tnew->values(), size * sizeof(TS_FLOAT) ); wt1( synsig, size, -1, *pwt ); memset( tnew->values(), 0, size * sizeof(TS_FLOAT) ); }
StepCode EliminateNakedTriplesStep::runOnHouse(House &house) { bool modified = false; if (house.size() <= 3) { return {false, modified}; } std::vector<std::pair<Mask, std::vector<const Cell *>>> found_masks; for (const Cell *cell : house) { std::size_t num_candidates = cell->candidates.count(); if (num_candidates == 0) { return {true, modified}; } if (num_candidates != 2 && num_candidates != 3) { continue; } const Mask mask = cell->candidates.to_ulong(); bool found_match = false; for (unsigned i = 0; i < found_masks.size(); ++i) { const Mask m = found_masks[i].first; // ORing the two masks together will switch on all candidates found in // both masks. If it's less than three, then we're still a triple // candidate. // TODO: If the current mask is size 2 and the OR of the two is 3, then // we should create two masks: one for the two and one for the OR. // Otherwise you could get 1/2 match with 1/2/3 and 1/2/4. // For now, only accept found masks of size 3. Easy naked triples. if (bitCount(m) == 3 && bitCount(mask | m) == 3) { found_match = true; found_masks[i].second.push_back(cell); } } if (!found_match) { std::pair<Mask, std::vector<const Cell *>> pair; pair.first = mask; pair.second.push_back(cell); found_masks.push_back(pair); } } for (auto &pair : found_masks) { if (pair.second.size() != 3) { continue; } auto &matches = pair.second; const Mask mask = pair.first; for (Cell *cell : house) { if (cell->isFixed()) { continue; } if (std::find(matches.begin(), matches.end(), cell) != matches.end()) { continue; } CandidateSet *candidates = &cell->candidates; if (candidates->to_ulong() == mask) { continue; } auto new_cands = CandidateSet(candidates->to_ulong() & ~mask); if (*candidates == new_cands) { continue; } if (DEBUG) { const Mask intersection = candidates->to_ulong() & mask; dbgs() << "Naked Triple " << printCandidateString(mask) << " removes " << printCandidateString(intersection) << " from " << cell->coord << "\n"; } modified = true; changed.insert(cell); *candidates = new_cands; } } return {false, modified}; }