Ejemplo n.º 1
0
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};
}
Ejemplo n.º 2
0
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);
  }
}
Ejemplo n.º 3
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) );
}
Ejemplo n.º 4
0
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};
}