<commit_before>#include "fmd.h"
#include <algorithm>

namespace CSA
{

const std::string BASES = "TGCNA";

FMDPosition::FMDPosition(usint forward_start, usint reverse_start,
  usint end_offset): forward_start(forward_start), reverse_start(reverse_start),
  end_offset(end_offset)
{
}

FMDPosition::FMDPosition(): forward_start(0), reverse_start(0), end_offset(-1)
{
}

FMDPosition
FMDPosition::flip() const
{
  // Swap the two intervals of the bi-interval
  return FMDPosition(reverse_start, forward_start, end_offset);
}

bool FMDPosition::operator==(const FMDPosition& other) const
{
  // Compare all the fields.
  return
    forward_start == other.forward_start &&
    reverse_start == other.reverse_start &&
    end_offset == other.end_offset;
}

sint
FMDPosition::range(const RangeVector& ranges) const
{
  // Get an iterator for making rank queries.
  // TODO: Is it efficient to do this a lot?
  RangeVector::Iterator iter(ranges);

  // Look up the range that the forward starting position is in
  sint start_range = iter.rank(forward_start);
  
  // And the range the forward end is in
  sint end_range = iter.rank(forward_start + end_offset);
  
  if(start_range == end_range)
  {
    // Both ends of the interval are in the same range.
    return start_range;
  }
  else
  {
    // There is no range spanning our forward-strand interval.
    return -1;
  }
}

sint
FMDPosition::ranges(const RangeVector& ranges) const
{
  // Get an iterator for making rank queries.
  // TODO: Is it efficient to do this a lot?
  RangeVector::Iterator iter(ranges);

  // Look up the range that the starting position is in
  sint start_range = iter.rank(forward_start);
  
  // And the range the end is in
  sint end_range = iter.rank(forward_start + end_offset);
  
  // Return the number of ranges we intersect (1s hit plus 1)
  return(end_range - start_range + 1);
}

std::ostream& operator<< (std::ostream& o, FMDPosition const& position)
{
  // Report both the ranges that we represent.
  return o << position.forward_start << "-" << 
    (position.forward_start + position.end_offset) << "|" << 
    position.reverse_start << "-" << (position.reverse_start + 
    position.end_offset);
}

Mapping::Mapping(): location(0, 0), is_mapped(false)
{
}

Mapping::Mapping(pair_type location, bool is_mapped): location(location), 
  is_mapped(is_mapped)
{
}

// Stuff for FMDIterators that traverse the suffix tree.

FMDIterator::FMDIterator(const FMD& parent, usint depth, bool beEnd): 
  parent(parent), depth(depth), stack(), pattern()
{
  // By default we start out with empty everything, which is what we should have
  // at the end.
  
  if(!beEnd) 
  {
    // Start at the beginning.
    search();
  }
}

FMDIterator::FMDIterator(const FMDIterator& toCopy): parent(toCopy.parent), 
  depth(toCopy.depth), stack(toCopy.stack), pattern(toCopy.pattern)
{
  // Already made a duplicate stack. Nothing to do.
}

FMDIterator& FMDIterator::operator++()
{
  // Advance
  search();
  
  // Return ourselves.
  return *this;
}

FMDIterator FMDIterator::operator++(int)
{
  // Copy ourselves
  FMDIterator copy(*this);
  
  // Advance
  search();
  
  // Return the copy
  return copy;
}

std::pair<std::string, FMDPosition> FMDIterator::operator*() const 
{ 
  // Grab the pattern and the FMDPosition from the top of the stack to go with
  // it.
  return std::make_pair(pattern, stack.back().first);
}

bool FMDIterator::operator==(const FMDIterator& other) const<commit_msg>Updating implementation of iterators to use SA coordinates<commit_after>#include "fmd.h"
#include <algorithm>

namespace CSA
{

const std::string BASES = "TGCNA";

FMDPosition::FMDPosition(usint forward_start, usint reverse_start,
  usint end_offset): forward_start(forward_start), reverse_start(reverse_start),
  end_offset(end_offset)
{
}

FMDPosition::FMDPosition(): forward_start(0), reverse_start(0), end_offset(-1)
{
}

FMDPosition
FMDPosition::flip() const
{
  // Swap the two intervals of the bi-interval
  return FMDPosition(reverse_start, forward_start, end_offset);
}

bool FMDPosition::operator==(const FMDPosition& other) const
{
  // Compare all the fields.
  return
    forward_start == other.forward_start &&
    reverse_start == other.reverse_start &&
    end_offset == other.end_offset;
}

sint
FMDPosition::range(const RangeVector& ranges) const
{
  // Get an iterator for making rank queries.
  // TODO: Is it efficient to do this a lot?
  RangeVector::Iterator iter(ranges);

  // Look up the range that the forward starting position is in
  sint start_range = iter.rank(forward_start);
  
  // And the range the forward end is in
  sint end_range = iter.rank(forward_start + end_offset);
  
  if(start_range == end_range)
  {
    // Both ends of the interval are in the same range.
    return start_range;
  }
  else
  {
    // There is no range spanning our forward-strand interval.
    return -1;
  }
}

sint
FMDPosition::ranges(const RangeVector& ranges) const
{
  // Get an iterator for making rank queries.
  // TODO: Is it efficient to do this a lot?
  RangeVector::Iterator iter(ranges);

  // Look up the range that the starting position is in
  sint start_range = iter.rank(forward_start);
  
  // And the range the end is in
  sint end_range = iter.rank(forward_start + end_offset);
  
  // Return the number of ranges we intersect (1s hit plus 1)
  return(end_range - start_range + 1);
}

std::ostream& operator<< (std::ostream& o, FMDPosition const& position)
{
  // Report both the ranges that we represent.
  return o << position.forward_start << "-" << 
    (position.forward_start + position.end_offset) << "|" << 
    position.reverse_start << "-" << (position.reverse_start + 
    position.end_offset);
}

Mapping::Mapping(): location(0, 0), is_mapped(false)
{
}

Mapping::Mapping(pair_type location, bool is_mapped): location(location), 
  is_mapped(is_mapped)
{
}

// Stuff for FMDIterators that traverse the suffix tree.

FMDIterator::FMDIterator(const FMD& parent, usint depth, bool beEnd): 
  parent(parent), depth(depth), stack(), pattern()
{
  // By default we start out with empty everything, which is what we should have
  // at the end.
  
  if(!beEnd) 
  {
    // Start at the beginning.
    search();
  }
}

FMDIterator::FMDIterator(const FMDIterator& toCopy): parent(toCopy.parent), 
  depth(toCopy.depth), stack(toCopy.stack), pattern(toCopy.pattern)
{
  // Already made a duplicate stack. Nothing to do.
}

FMDIterator& FMDIterator::operator++()
{
  // Advance
  search();
  
  // Return ourselves.
  return *this;
}

FMDIterator FMDIterator::operator++(int)
{
  // Copy ourselves
  FMDIterator copy(*this);
  
  // Advance
  search();
  
  // Return the copy
  return copy;
}

std::pair<std::string, FMDPosition> FMDIterator::operator*() const 
{ 
  // Grab the FMSPosition we want to return
  FMDPosition toConvert = stack.back().first 
  
  // We need to convert it from BWT coordinates (which we use internally for
  // extension) and SA coordinates (which are natural for locate).
  convertToSAIndex(toConvert.forward_start);
  convertToSAIndex(toConvert.reverse_start);
  
  // Grab the pattern and the FMDPosition from the top of the stack to go with
  // it.
  return std::make_pair(pattern, toReturn);
}

bool FMDIterator::operator==(const FMDIterator& other) const
{'fraction_non_alphanumeric': 0.11490470313999726, 'fraction_numerical': 0.0024681201151789387, 'mean_word_length': 3.8821954484605086, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '25430', 'n_tokens_mistral': 2391, 'n_tokens_neox': 2316, 'n_words': 692}