{
    int32_t ord = order[doc];
    ords[slot] = ord;

#include "LuceneInc.h"
#include "FieldComparator.h"
#include "FieldCache.h"
#include "ScoreCachingWrappingScorer.h"
#include "Collator.h"

namespace Lucene {

FieldComparator::~FieldComparator() {
}

void FieldComparator::setScorer(const ScorerPtr& scorer) {
    // Empty implementation since most comparators don't need the score.
    // This can be overridden by those that need it.
}

ByteComparator::ByteComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<uint8_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<ByteParser>(parser);
}

ByteComparator::~ByteComparator() {
}

void ByteComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getBytes(reader, field, parser);
}

DocComparator::DocComparator(int32_t numHits) : NumericComparator<int32_t>(numHits) {
    this->docBase = 0;
}

DocComparator::~DocComparator() {
}

int32_t DocComparator::compareBottom(int32_t doc) {
    // No overflow risk because docIDs are non-negative
    return (bottom - (docBase + doc));
}

void DocComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = docBase + doc;
}

void DocComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    this->docBase = docBase;
}

DoubleComparator::DoubleComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<double>(numHits, field) {
    this->parser = boost::static_pointer_cast<DoubleParser>(parser);
}

DoubleComparator::~DoubleComparator() {
}

int32_t DoubleComparator::compare(int32_t slot1, int32_t slot2) {
    double v1 = values[slot1];
    double v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t DoubleComparator::compareBottom(int32_t doc) {
    double v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void DoubleComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getDoubles(reader, field, parser);
}

IntComparator::IntComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int32_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<IntParser>(parser);
}

IntComparator::~IntComparator() {
}

int32_t IntComparator::compare(int32_t slot1, int32_t slot2) {
    int32_t v1 = values[slot1];
    int32_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t IntComparator::compareBottom(int32_t doc) {
    int32_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void IntComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getInts(reader, field, parser);
}

LongComparator::LongComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int64_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<LongParser>(parser);
}

LongComparator::~LongComparator() {
}

int32_t LongComparator::compare(int32_t slot1, int32_t slot2) {
    int64_t v1 = values[slot1];
    int64_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t LongComparator::compareBottom(int32_t doc) {
    int64_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void LongComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getLongs(reader, field, parser);
}

RelevanceComparator::RelevanceComparator(int32_t numHits) : NumericComparator<double>(numHits) {
}

RelevanceComparator::~RelevanceComparator() {
}

int32_t RelevanceComparator::compare(int32_t slot1, int32_t slot2) {
    double score1 = values[slot1];
    double score2 = values[slot2];
    return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}

int32_t RelevanceComparator::compareBottom(int32_t doc) {
    double score = scorer->score();
    return bottom > score ? -1 : (bottom < score ? 1 : 0);
}

void RelevanceComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = scorer->score();
}

void RelevanceComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
}

void RelevanceComparator::setScorer(const ScorerPtr& scorer) {
    this->scorer = newLucene<ScoreCachingWrappingScorer>(scorer);
}

StringComparatorLocale::StringComparatorLocale(int32_t numHits, const String& field, const std::locale& locale) : collator(newLucene<Collator>(locale)) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringComparatorLocale::~StringComparatorLocale() {
}

int32_t StringComparatorLocale::compare(int32_t slot1, int32_t slot2) {
    return collator->compare(values[slot1], values[slot2]);
}

int32_t StringComparatorLocale::compareBottom(int32_t doc) {
    return collator->compare(bottom, currentReaderValues[doc]);
}

void StringComparatorLocale::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringComparatorLocale::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringComparatorLocale::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringComparatorLocale::value(int32_t slot) {
    return values[slot];
}

StringOrdValComparator::StringOrdValComparator(int32_t numHits, const String& field, int32_t sortPos, bool reversed) {
    this->ords = Collection<int32_t>::newInstance(numHits);
    this->values = Collection<String>::newInstance(numHits);
    this->readerGen = Collection<int32_t>::newInstance(numHits);
    this->sortPos = sortPos;
    this->reversed = reversed;
    this->field = field;
    this->currentReaderGen = -1;
    this->bottomSlot = -1;
    this->bottomOrd = 0;
}

StringOrdValComparator::~StringOrdValComparator() {
}

int32_t StringOrdValComparator::compare(int32_t slot1, int32_t slot2) {
    if (readerGen[slot1] == readerGen[slot2]) {
        int32_t cmp = ords[slot1] - ords[slot2];
        if (cmp != 0) {
            return cmp;
        }
    }
    return values[slot1].compare(values[slot2]);
}

int32_t StringOrdValComparator::compareBottom(int32_t doc) {
    BOOST_ASSERT(bottomSlot != -1);
    int32_t order = this->order[doc];
    int32_t cmp = bottomOrd - order;
    if (cmp != 0) {
        return cmp;
    }
    return bottomValue.compare(lookup[order]);
}

void StringOrdValComparator::convert(int32_t slot) {
    readerGen[slot] = currentReaderGen;
    int32_t index = 0;
    String value(values[slot]);
    if (value.empty()) {
        ords[slot] = 0;
        return;
    }

    if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
        // Since we are the primary sort, the entries in the queue are bounded by bottomOrd
        BOOST_ASSERT(bottomOrd < lookup.size());
        if (reversed) {
            index = binarySearch(lookup, value, bottomOrd, lookup.size() - 1);
        } else {
            index = binarySearch(lookup, value, 0, bottomOrd);
        }
    } else {
        // Full binary search
        index = binarySearch(lookup, value, 0, lookup.size() - 1);
    }

    if (index < 0) {
        index = -index - 2;
    }

    ords[slot] = index;
}

int32_t StringOrdValComparator::binarySearch(Collection<String> lookup, const String& key, int32_t low, int32_t high) {
    Collection<String>::iterator search = std::lower_bound(lookup.begin() + low, lookup.begin() + high, key);
    int32_t keyPos = std::distance(lookup.begin(), search);
    return (search == lookup.end() || key < *search) ? -(keyPos + 1) : keyPos;
}

void StringOrdValComparator::copy(int32_t slot, int32_t doc)

    BOOST_ASSERT(ord >= 0);
    values[slot] = lookup[ord];
    readerGen[slot] = currentReaderGen;
}

void StringOrdValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    StringIndexPtr currentReaderValues(FieldCache::DEFAULT()->getStringIndex(reader, field));
    ++currentReaderGen;
    order = currentReaderValues->order;
    lookup = currentReaderValues->lookup;
    BOOST_ASSERT(!lookup.empty());
    if (bottomSlot != -1) {
        convert(bottomSlot);
        bottomOrd = ords[bottomSlot];
    }
}

void StringOrdValComparator::setBottom(int32_t slot) {
    bottomSlot = slot;
    if (readerGen[slot] != currentReaderGen) {
        convert(bottomSlot);
    }
    bottomOrd = ords[slot];
    BOOST_ASSERT(bottomOrd >= 0);
    BOOST_ASSERT(bottomOrd < lookup.size());
    bottomValue = values[slot];
}

ComparableValue StringOrdValComparator::value(int32_t slot) {
    return values[slot];
}

Collection<String> StringOrdValComparator::getValues() {
    return values;
}

int32_t StringOrdValComparator::getBottomSlot() {
    return bottomSlot;
}

String StringOrdValComparator::getField() {
    return field;
}

StringValComparator::StringValComparator(int32_t numHits, const String& field) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringValComparator::~StringValComparator() {
}

int32_t StringValComparator::compare(int32_t slot1, int32_t slot2) {
    return values[slot1].compare(values[slot2]);
}

int32_t StringValComparator::compareBottom(int32_t doc) {
    return bottom.compare(currentReaderValues[doc]);
}

void StringValComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringValComparator::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringValComparator::value(int32_t slot) {
    return values[slot];
}

}


BOOST_ASSERT(ord >= 0);
    values[slot] = lookup[ord];

#include "LuceneInc.h"
#include "FieldComparator.h"
#include "FieldCache.h"
#include "ScoreCachingWrappingScorer.h"
#include "Collator.h"

namespace Lucene {

FieldComparator::~FieldComparator() {
}

void FieldComparator::setScorer(const ScorerPtr& scorer) {
    // Empty implementation since most comparators don't need the score.
    // This can be overridden by those that need it.
}

ByteComparator::ByteComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<uint8_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<ByteParser>(parser);
}

ByteComparator::~ByteComparator() {
}

void ByteComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getBytes(reader, field, parser);
}

DocComparator::DocComparator(int32_t numHits) : NumericComparator<int32_t>(numHits) {
    this->docBase = 0;
}

DocComparator::~DocComparator() {
}

int32_t DocComparator::compareBottom(int32_t doc) {
    // No overflow risk because docIDs are non-negative
    return (bottom - (docBase + doc));
}

void DocComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = docBase + doc;
}

void DocComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    this->docBase = docBase;
}

DoubleComparator::DoubleComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<double>(numHits, field) {
    this->parser = boost::static_pointer_cast<DoubleParser>(parser);
}

DoubleComparator::~DoubleComparator() {
}

int32_t DoubleComparator::compare(int32_t slot1, int32_t slot2) {
    double v1 = values[slot1];
    double v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t DoubleComparator::compareBottom(int32_t doc) {
    double v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void DoubleComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getDoubles(reader, field, parser);
}

IntComparator::IntComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int32_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<IntParser>(parser);
}

IntComparator::~IntComparator() {
}

int32_t IntComparator::compare(int32_t slot1, int32_t slot2) {
    int32_t v1 = values[slot1];
    int32_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t IntComparator::compareBottom(int32_t doc) {
    int32_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void IntComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getInts(reader, field, parser);
}

LongComparator::LongComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int64_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<LongParser>(parser);
}

LongComparator::~LongComparator() {
}

int32_t LongComparator::compare(int32_t slot1, int32_t slot2) {
    int64_t v1 = values[slot1];
    int64_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t LongComparator::compareBottom(int32_t doc) {
    int64_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void LongComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getLongs(reader, field, parser);
}

RelevanceComparator::RelevanceComparator(int32_t numHits) : NumericComparator<double>(numHits) {
}

RelevanceComparator::~RelevanceComparator() {
}

int32_t RelevanceComparator::compare(int32_t slot1, int32_t slot2) {
    double score1 = values[slot1];
    double score2 = values[slot2];
    return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}

int32_t RelevanceComparator::compareBottom(int32_t doc) {
    double score = scorer->score();
    return bottom > score ? -1 : (bottom < score ? 1 : 0);
}

void RelevanceComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = scorer->score();
}

void RelevanceComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
}

void RelevanceComparator::setScorer(const ScorerPtr& scorer) {
    this->scorer = newLucene<ScoreCachingWrappingScorer>(scorer);
}

StringComparatorLocale::StringComparatorLocale(int32_t numHits, const String& field, const std::locale& locale) : collator(newLucene<Collator>(locale)) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringComparatorLocale::~StringComparatorLocale() {
}

int32_t StringComparatorLocale::compare(int32_t slot1, int32_t slot2) {
    return collator->compare(values[slot1], values[slot2]);
}

int32_t StringComparatorLocale::compareBottom(int32_t doc) {
    return collator->compare(bottom, currentReaderValues[doc]);
}

void StringComparatorLocale::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringComparatorLocale::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringComparatorLocale::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringComparatorLocale::value(int32_t slot) {
    return values[slot];
}

StringOrdValComparator::StringOrdValComparator(int32_t numHits, const String& field, int32_t sortPos, bool reversed) {
    this->ords = Collection<int32_t>::newInstance(numHits);
    this->values = Collection<String>::newInstance(numHits);
    this->readerGen = Collection<int32_t>::newInstance(numHits);
    this->sortPos = sortPos;
    this->reversed = reversed;
    this->field = field;
    this->currentReaderGen = -1;
    this->bottomSlot = -1;
    this->bottomOrd = 0;
}

StringOrdValComparator::~StringOrdValComparator() {
}

int32_t StringOrdValComparator::compare(int32_t slot1, int32_t slot2) {
    if (readerGen[slot1] == readerGen[slot2]) {
        int32_t cmp = ords[slot1] - ords[slot2];
        if (cmp != 0) {
            return cmp;
        }
    }
    return values[slot1].compare(values[slot2]);
}

int32_t StringOrdValComparator::compareBottom(int32_t doc) {
    BOOST_ASSERT(bottomSlot != -1);
    int32_t order = this->order[doc];
    int32_t cmp = bottomOrd - order;
    if (cmp != 0) {
        return cmp;
    }
    return bottomValue.compare(lookup[order]);
}

void StringOrdValComparator::convert(int32_t slot) {
    readerGen[slot] = currentReaderGen;
    int32_t index = 0;
    String value(values[slot]);
    if (value.empty()) {
        ords[slot] = 0;
        return;
    }

    if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
        // Since we are the primary sort, the entries in the queue are bounded by bottomOrd
        BOOST_ASSERT(bottomOrd < lookup.size());
        if (reversed) {
            index = binarySearch(lookup, value, bottomOrd, lookup.size() - 1);
        } else {
            index = binarySearch(lookup, value, 0, bottomOrd);
        }
    } else {
        // Full binary search
        index = binarySearch(lookup, value, 0, lookup.size() - 1);
    }

    if (index < 0) {
        index = -index - 2;
    }

    ords[slot] = index;
}

int32_t StringOrdValComparator::binarySearch(Collection<String> lookup, const String& key, int32_t low, int32_t high) {
    Collection<String>::iterator search = std::lower_bound(lookup.begin() + low, lookup.begin() + high, key);
    int32_t keyPos = std::distance(lookup.begin(), search);
    return (search == lookup.end() || key < *search) ? -(keyPos + 1) : keyPos;
}

void StringOrdValComparator::copy(int32_t slot, int32_t doc) {
    int32_t ord = order[doc];
    ords[slot] = ord;

    readerGen[slot] = currentReaderGen;
}

void StringOrdValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    StringIndexPtr currentReaderValues(FieldCache::DEFAULT()->getStringIndex(reader, field));
    ++currentReaderGen;
    order = currentReaderValues->order;
    lookup = currentReaderValues->lookup;
    BOOST_ASSERT(!lookup.empty());
    if (bottomSlot != -1) {
        convert(bottomSlot);
        bottomOrd = ords[bottomSlot];
    }
}

void StringOrdValComparator::setBottom(int32_t slot) {
    bottomSlot = slot;
    if (readerGen[slot] != currentReaderGen) {
        convert(bottomSlot);
    }
    bottomOrd = ords[slot];
    BOOST_ASSERT(bottomOrd >= 0);
    BOOST_ASSERT(bottomOrd < lookup.size());
    bottomValue = values[slot];
}

ComparableValue StringOrdValComparator::value(int32_t slot) {
    return values[slot];
}

Collection<String> StringOrdValComparator::getValues() {
    return values;
}

int32_t StringOrdValComparator::getBottomSlot() {
    return bottomSlot;
}

String StringOrdValComparator::getField() {
    return field;
}

StringValComparator::StringValComparator(int32_t numHits, const String& field) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringValComparator::~StringValComparator() {
}

int32_t StringValComparator::compare(int32_t slot1, int32_t slot2) {
    return values[slot1].compare(values[slot2]);
}

int32_t StringValComparator::compareBottom(int32_t doc) {
    return bottom.compare(currentReaderValues[doc]);
}

void StringValComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringValComparator::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringValComparator::value(int32_t slot) {
    return values[slot];
}

}


#include "LuceneInc.h"
#include "FieldComparator.h"
#include "FieldCache.h"
#include "ScoreCachingWrappingScorer.h"
#include "Collator.h"

namespace Lucene {

FieldComparator::~FieldComparator() {
}

void FieldComparator::setScorer(const ScorerPtr& scorer) {
    // Empty implementation since most comparators don't need the score.
    // This can be overridden by those that need it.
}

ByteComparator::ByteComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<uint8_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<ByteParser>(parser);
}

ByteComparator::~ByteComparator() {
}

void ByteComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getBytes(reader, field, parser);
}

DocComparator::DocComparator(int32_t numHits) : NumericComparator<int32_t>(numHits) {
    this->docBase = 0;
}

DocComparator::~DocComparator() {
}

int32_t DocComparator::compareBottom(int32_t doc) {
    // No overflow risk because docIDs are non-negative
    return (bottom - (docBase + doc));
}

void DocComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = docBase + doc;
}

void DocComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    this->docBase = docBase;
}

DoubleComparator::DoubleComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<double>(numHits, field) {
    this->parser = boost::static_pointer_cast<DoubleParser>(parser);
}

DoubleComparator::~DoubleComparator() {
}

int32_t DoubleComparator::compare(int32_t slot1, int32_t slot2) {
    double v1 = values[slot1];
    double v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t DoubleComparator::compareBottom(int32_t doc) {
    double v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void DoubleComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getDoubles(reader, field, parser);
}

IntComparator::IntComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int32_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<IntParser>(parser);
}

IntComparator::~IntComparator() {
}

int32_t IntComparator::compare(int32_t slot1, int32_t slot2) {
    int32_t v1 = values[slot1];
    int32_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t IntComparator::compareBottom(int32_t doc) {
    int32_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void IntComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getInts(reader, field, parser);
}

LongComparator::LongComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int64_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<LongParser>(parser);
}

LongComparator::~LongComparator() {
}

int32_t LongComparator::compare(int32_t slot1, int32_t slot2) {
    int64_t v1 = values[slot1];
    int64_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t LongComparator::compareBottom(int32_t doc) {
    int64_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void LongComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getLongs(reader, field, parser);
}

RelevanceComparator::RelevanceComparator(int32_t numHits) : NumericComparator<double>(numHits) {
}

RelevanceComparator::~RelevanceComparator() {
}

int32_t RelevanceComparator::compare(int32_t slot1, int32_t slot2) {
    double score1 = values[slot1];
    double score2 = values[slot2];
    return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}

int32_t RelevanceComparator::compareBottom(int32_t doc) {
    double score = scorer->score();
    return bottom > score ? -1 : (bottom < score ? 1 : 0);
}

void RelevanceComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = scorer->score();
}

void RelevanceComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
}

void RelevanceComparator::setScorer(const ScorerPtr& scorer) {
    this->scorer = newLucene<ScoreCachingWrappingScorer>(scorer);
}

StringComparatorLocale::StringComparatorLocale(int32_t numHits, const String& field, const std::locale& locale) : collator(newLucene<Collator>(locale)) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringComparatorLocale::~StringComparatorLocale() {
}

int32_t StringComparatorLocale::compare(int32_t slot1, int32_t slot2) {
    return collator->compare(values[slot1], values[slot2]);
}

int32_t StringComparatorLocale::compareBottom(int32_t doc) {
    return collator->compare(bottom, currentReaderValues[doc]);
}

void StringComparatorLocale::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringComparatorLocale::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringComparatorLocale::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringComparatorLocale::value(int32_t slot) {
    return values[slot];
}

StringOrdValComparator::StringOrdValComparator(int32_t numHits, const String& field, int32_t sortPos, bool reversed) {
    this->ords = Collection<int32_t>::newInstance(numHits);
    this->values = Collection<String>::newInstance(numHits);
    this->readerGen = Collection<int32_t>::newInstance(numHits);
    this->sortPos = sortPos;
    this->reversed = reversed;
    this->field = field;
    this->currentReaderGen = -1;
    this->bottomSlot = -1;
    this->bottomOrd = 0;
}

StringOrdValComparator::~StringOrdValComparator() {
}

int32_t StringOrdValComparator::compare(int32_t slot1, int32_t slot2) {
    if (readerGen[slot1] == readerGen[slot2]) {
        int32_t cmp = ords[slot1] - ords[slot2];
        if (cmp != 0) {
            return cmp;
        }
    }
    return values[slot1].compare(values[slot2]);
}

int32_t StringOrdValComparator::compareBottom(int32_t doc) {
    BOOST_ASSERT(bottomSlot != -1);
    int32_t order = this->order[doc];
    int32_t cmp = bottomOrd - order;
    if (cmp != 0) {
        return cmp;
    }
    return bottomValue.compare(lookup[order]);
}

void StringOrdValComparator::convert(int32_t slot) {
    readerGen[slot] = currentReaderGen;
    int32_t index = 0;
    String value(values[slot]);
    if (value.empty()) {
        ords[slot] = 0;
        return;
    }

    if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
        // Since we are the primary sort, the entries in the queue are bounded by bottomOrd
        BOOST_ASSERT(bottomOrd < lookup.size());
        if (reversed) {
            index = binarySearch(lookup, value, bottomOrd, lookup.size() - 1);
        } else {
            index = binarySearch(lookup, value, 0, bottomOrd);
        }
    } else {
        // Full binary search
        index = binarySearch(lookup, value, 0, lookup.size() - 1);
    }

    if (index < 0) {
        index = -index - 2;
    }

    ords[slot] = index;
}

int32_t StringOrdValComparator::binarySearch(Collection<String> lookup, const String& key, int32_t low, int32_t high) {
    Collection<String>::iterator search = std::lower_bound(lookup.begin() + low, lookup.begin() + high, key);
    int32_t keyPos = std::distance(lookup.begin(), search);
    return (search == lookup.end() || key < *search) ? -(keyPos + 1) : keyPos;
}

void StringOrdValComparator::copy(int32_t slot, int32_t doc) {
    int32_t ord = order[doc];
    ords[slot] = ord;
    BOOST_ASSERT(ord >= 0);
    values[slot] = lookup[ord];

void StringOrdValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    StringIndexPtr currentReaderValues(FieldCache::DEFAULT()->getStringIndex(reader, field));
    ++currentReaderGen;
    order = currentReaderValues->order;
    lookup = currentReaderValues->lookup;
    BOOST_ASSERT(!lookup.empty());
    if (bottomSlot != -1) {
        convert(bottomSlot);
        bottomOrd = ords[bottomSlot];
    }
}

void StringOrdValComparator::setBottom(int32_t slot) {
    bottomSlot = slot;
    if (readerGen[slot] != currentReaderGen) {
        convert(bottomSlot);
    }
    bottomOrd = ords[slot];
    BOOST_ASSERT(bottomOrd >= 0);
    BOOST_ASSERT(bottomOrd < lookup.size());
    bottomValue = values[slot];
}

ComparableValue StringOrdValComparator::value(int32_t slot) {
    return values[slot];
}

Collection<String> StringOrdValComparator::getValues() {
    return values;
}

int32_t StringOrdValComparator::getBottomSlot() {
    return bottomSlot;
}

String StringOrdValComparator::getField() {
    return field;
}

StringValComparator::StringValComparator(int32_t numHits, const String& field) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringValComparator::~StringValComparator() {
}

int32_t StringValComparator::compare(int32_t slot1, int32_t slot2) {
    return values[slot1].compare(values[slot2]);
}

int32_t StringValComparator::compareBottom(int32_t doc) {
    return bottom.compare(currentReaderValues[doc]);
}

void StringValComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringValComparator::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringValComparator::value(int32_t slot) {
    return values[slot];
}

}


#include "LuceneInc.h"
#include "FieldComparator.h"
#include "FieldCache.h"
#include "ScoreCachingWrappingScorer.h"
#include "Collator.h"

namespace Lucene {

FieldComparator::~FieldComparator() {
}

void FieldComparator::setScorer(const ScorerPtr& scorer) {
    // Empty implementation since most comparators don't need the score.
    // This can be overridden by those that need it.
}

ByteComparator::ByteComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<uint8_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<ByteParser>(parser);
}

ByteComparator::~ByteComparator() {
}

void ByteComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getBytes(reader, field, parser);
}

DocComparator::DocComparator(int32_t numHits) : NumericComparator<int32_t>(numHits) {
    this->docBase = 0;
}

DocComparator::~DocComparator() {
}

int32_t DocComparator::compareBottom(int32_t doc) {
    // No overflow risk because docIDs are non-negative
    return (bottom - (docBase + doc));
}

void DocComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = docBase + doc;
}

void DocComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    this->docBase = docBase;
}

DoubleComparator::DoubleComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<double>(numHits, field) {
    this->parser = boost::static_pointer_cast<DoubleParser>(parser);
}

DoubleComparator::~DoubleComparator() {
}

int32_t DoubleComparator::compare(int32_t slot1, int32_t slot2) {
    double v1 = values[slot1];
    double v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t DoubleComparator::compareBottom(int32_t doc) {
    double v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void DoubleComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getDoubles(reader, field, parser);
}

IntComparator::IntComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int32_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<IntParser>(parser);
}

IntComparator::~IntComparator() {
}

int32_t IntComparator::compare(int32_t slot1, int32_t slot2) {
    int32_t v1 = values[slot1];
    int32_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t IntComparator::compareBottom(int32_t doc) {
    int32_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void IntComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getInts(reader, field, parser);
}

LongComparator::LongComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int64_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<LongParser>(parser);
}

LongComparator::~LongComparator() {
}

int32_t LongComparator::compare(int32_t slot1, int32_t slot2) {
    int64_t v1 = values[slot1];
    int64_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t LongComparator::compareBottom(int32_t doc) {
    int64_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void LongComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getLongs(reader, field, parser);
}

RelevanceComparator::RelevanceComparator(int32_t numHits) : NumericComparator<double>(numHits) {
}

RelevanceComparator::~RelevanceComparator() {
}

int32_t RelevanceComparator::compare(int32_t slot1, int32_t slot2) {
    double score1 = values[slot1];
    double score2 = values[slot2];
    return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}

int32_t RelevanceComparator::compareBottom(int32_t doc) {
    double score = scorer->score();
    return bottom > score ? -1 : (bottom < score ? 1 : 0);
}

void RelevanceComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = scorer->score();
}

void RelevanceComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
}

void RelevanceComparator::setScorer(const ScorerPtr& scorer) {
    this->scorer = newLucene<ScoreCachingWrappingScorer>(scorer);
}

StringComparatorLocale::StringComparatorLocale(int32_t numHits, const String& field, const std::locale& locale) : collator(newLucene<Collator>(locale)) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringComparatorLocale::~StringComparatorLocale() {
}

int32_t StringComparatorLocale::compare(int32_t slot1, int32_t slot2) {
    return collator->compare(values[slot1], values[slot2]);
}

int32_t StringComparatorLocale::compareBottom(int32_t doc) {
    return collator->compare(bottom, currentReaderValues[doc]);
}

void StringComparatorLocale::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringComparatorLocale::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringComparatorLocale::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringComparatorLocale::value(int32_t slot) {
    return values[slot];
}

StringOrdValComparator::StringOrdValComparator(int32_t numHits, const String& field, int32_t sortPos, bool reversed) {
    this->ords = Collection<int32_t>::newInstance(numHits);
    this->values = Collection<String>::newInstance(numHits);
    this->readerGen = Collection<int32_t>::newInstance(numHits);
    this->sortPos = sortPos;
    this->reversed = reversed;
    this->field = field;
    this->currentReaderGen = -1;
    this->bottomSlot = -1;
    this->bottomOrd = 0;
}

StringOrdValComparator::~StringOrdValComparator() {
}

int32_t StringOrdValComparator::compare(int32_t slot1, int32_t slot2) {
    if (readerGen[slot1] == readerGen[slot2]) {
        int32_t cmp = ords[slot1] - ords[slot2];
        if (cmp != 0) {
            return cmp;
        }
    }
    return values[slot1].compare(values[slot2]);
}

int32_t StringOrdValComparator::compareBottom(int32_t doc) {
    BOOST_ASSERT(bottomSlot != -1);
    int32_t order = thi

    int32_t cmp = bottomOrd - order;
    if (cmp != 0) {
        return cmp;
    }
    return bottomValue.compare(lookup[order]);
}

void StringOrdValComparator::convert(int32_t slot) {
    readerGen[slot] = currentReaderGen;
    int32_t index = 0;
    String value(values[slot]);
    if (value.empty()) {
        ords[slot] = 0;
        return;
    }

    if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
        // Since we are the primary sort, the entries in the queue are bounded by bottomOrd
        BOOST_ASSERT(bottomOrd < lookup.size());
        if (reversed) {
            index = binarySearch(lookup, value, bottomOrd, lookup.size() - 1);
        } else {
            index = binarySearch(lookup, value, 0, bottomOrd);
        }
    } else {
        // Full binary search
        index = binarySearch(lookup, value, 0, lookup.size() - 1);
    }

    if (index < 0) {
        index = -index - 2;
    }

    ords[slot] = index;
}

int32_t StringOrdValComparator::binarySearch(Collection<String> lookup, const String& key, int32_t low, int32_t high) {
    Collection<String>::iterator search = std::lower_bound(lookup.begin() + low, lookup.begin() + high, key);
    int32_t keyPos = std::distance(lookup.begin(), search);
    return (search == lookup.end() || key < *search) ? -(keyPos + 1) : keyPos;
}

void StringOrdValComparator::copy(int32_t slot, int32_t doc) {
    int32_t ord = order[doc];
    ords[slot] = ord;
    BOOST_ASSERT(ord >= 0);
    values[slot] = lookup[ord];
    readerGen[slot] = currentReaderGen;
}

void StringOrdValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    StringIndexPtr currentReaderValues(FieldCache::DEFAULT()->getStringIndex(reader, field));
    ++currentReaderGen;
    order = currentReaderValues->order;
    lookup = currentReaderValues->lookup;
    BOOST_ASSERT(!lookup.empty());
    if (bottomSlot != -1) {
        convert(bottomSlot);
        bottomOrd = ords[bottomSlot];
    }
}

void StringOrdValComparator::setBottom(int32_t slot) {
    bottomSlot = slot;
    if (readerGen[slot] != currentReaderGen) {
        convert(bottomSlot);
    }
    bottomOrd = ords[slot];
    BOOST_ASSERT(bottomOrd >= 0);
    BOOST_ASSERT(bottomOrd < lookup.size());
    bottomValue = values[slot];
}

ComparableValue StringOrdValComparator::value(int32_t slot) {
    return values[slot];
}

Collection<String> StringOrdValComparator::getValues() {
    return values;
}

int32_t StringOrdValComparator::getBottomSlot() {
    return bottomSlot;
}

String StringOrdValComparator::getField() {
    return field;
}

StringValComparator::StringValComparator(int32_t numHits, const String& field) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringValComparator::~StringValComparator() {
}

int32_t StringValComparator::compare(int32_t slot1, int32_t slot2) {
    return values[slot1].compare(values[slot2]);
}

int32_t StringValComparator::compareBottom(int32_t doc) {
    return bottom.compare(currentReaderValues[doc]);
}

void StringValComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringValComparator::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringValComparator::value(int32_t slot) {
    return values[slot];
}

}


if (readerGen[slot1] == readerGen[slot2]) {
        int32_t cmp = ords[slot1] - ords[slot2];
        if (cmp != 0) {
            return cmp;
        }
    }

#include "LuceneInc.h"
#include "FieldComparator.h"
#include "FieldCache.h"
#include "ScoreCachingWrappingScorer.h"
#include "Collator.h"

namespace Lucene {

FieldComparator::~FieldComparator() {
}

void FieldComparator::setScorer(const ScorerPtr& scorer) {
    // Empty implementation since most comparators don't need the score.
    // This can be overridden by those that need it.
}

ByteComparator::ByteComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<uint8_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<ByteParser>(parser);
}

ByteComparator::~ByteComparator() {
}

void ByteComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getBytes(reader, field, parser);
}

DocComparator::DocComparator(int32_t numHits) : NumericComparator<int32_t>(numHits) {
    this->docBase = 0;
}

DocComparator::~DocComparator() {
}

int32_t DocComparator::compareBottom(int32_t doc) {
    // No overflow risk because docIDs are non-negative
    return (bottom - (docBase + doc));
}

void DocComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = docBase + doc;
}

void DocComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    this->docBase = docBase;
}

DoubleComparator::DoubleComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<double>(numHits, field) {
    this->parser = boost::static_pointer_cast<DoubleParser>(parser);
}

DoubleComparator::~DoubleComparator() {
}

int32_t DoubleComparator::compare(int32_t slot1, int32_t slot2) {
    double v1 = values[slot1];
    double v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t DoubleComparator::compareBottom(int32_t doc) {
    double v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void DoubleComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getDoubles(reader, field, parser);
}

IntComparator::IntComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int32_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<IntParser>(parser);
}

IntComparator::~IntComparator() {
}

int32_t IntComparator::compare(int32_t slot1, int32_t slot2) {
    int32_t v1 = values[slot1];
    int32_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t IntComparator::compareBottom(int32_t doc) {
    int32_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void IntComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getInts(reader, field, parser);
}

LongComparator::LongComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int64_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<LongParser>(parser);
}

LongComparator::~LongComparator() {
}

int32_t LongComparator::compare(int32_t slot1, int32_t slot2) {
    int64_t v1 = values[slot1];
    int64_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t LongComparator::compareBottom(int32_t doc) {
    int64_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void LongComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getLongs(reader, field, parser);
}

RelevanceComparator::RelevanceComparator(int32_t numHits) : NumericComparator<double>(numHits) {
}

RelevanceComparator::~RelevanceComparator() {
}

int32_t RelevanceComparator::compare(int32_t slot1, int32_t slot2) {
    double score1 = values[slot1];
    double score2 = values[slot2];
    return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}

int32_t RelevanceComparator::compareBottom(int32_t doc) {
    double score = scorer->score();
    return bottom > score ? -1 : (bottom < score ? 1 : 0);
}

void RelevanceComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = scorer->score();
}

void RelevanceComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
}

void RelevanceComparator::setScorer(const ScorerPtr& scorer) {
    this->scorer = newLucene<ScoreCachingWrappingScorer>(scorer);
}

StringComparatorLocale::StringComparatorLocale(int32_t numHits, const String& field, const std::locale& locale) : collator(newLucene<Collator>(locale)) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringComparatorLocale::~StringComparatorLocale() {
}

int32_t StringComparatorLocale::compare(int32_t slot1, int32_t slot2) {
    return collator->compare(values[slot1], values[slot2]);
}

int32_t StringComparatorLocale::compareBottom(int32_t doc) {
    return collator->compare(bottom, currentReaderValues[doc]);
}

void StringComparatorLocale::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringComparatorLocale::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringComparatorLocale::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringComparatorLocale::value(int32_t slot) {
    return values[slot];
}

StringOrdValComparator::StringOrdValComparator(int32_t numHits, const String& field, int32_t sortPos, bool reversed) {
    this->ords = Collection<int32_t>::newInstance(numHits);
    this->values = Collection<String>::newInstance(numHits);
    this->readerGen = Collection<int32_t>::newInstance(numHits);
    this->sortPos = sortPos;
    this->reversed = reversed;
    this->field = field;
    this->currentReaderGen = -1;
    this->bottomSlot = -1;
    this->bottomOrd = 0;
}

StringOrdValComparator::~StringOrdValComparator() {
}

int32_t StringOrdValComparator::compare(int32_t slot1, int32_t slot2) {

    return values[slot1].compare(values[slot2]);
}

int32_t StringOrdValComparator::compareBottom(int32_t doc) {
    BOOST_ASSERT(bottomSlot != -1);
    int32_t order = this->order[doc];
    int32_t cmp = bottomOrd - order;
    if (cmp != 0) {
        return cmp;
    }
    return bottomValue.compare(lookup[order]);
}

void StringOrdValComparator::convert(int32_t slot) {
    readerGen[slot] = currentReaderGen;
    int32_t index = 0;
    String value(values[slot]);
    if (value.empty()) {
        ords[slot] = 0;
        return;
    }

    if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
        // Since we are the primary sort, the entries in the queue are bounded by bottomOrd
        BOOST_ASSERT(bottomOrd < lookup.size());
        if (reversed) {
            index = binarySearch(lookup, value, bottomOrd, lookup.size() - 1);
        } else {
            index = binarySearch(lookup, value, 0, bottomOrd);
        }
    } else {
        // Full binary search
        index = binarySearch(lookup, value, 0, lookup.size() - 1);
    }

    if (index < 0) {
        index = -index - 2;
    }

    ords[slot] = index;
}

int32_t StringOrdValComparator::binarySearch(Collection<String> lookup, const String& key, int32_t low, int32_t high) {
    Collection<String>::iterator search = std::lower_bound(lookup.begin() + low, lookup.begin() + high, key);
    int32_t keyPos = std::distance(lookup.begin(), search);
    return (search == lookup.end() || key < *search) ? -(keyPos + 1) : keyPos;
}

void StringOrdValComparator::copy(int32_t slot, int32_t doc) {
    int32_t ord = order[doc];
    ords[slot] = ord;
    BOOST_ASSERT(ord >= 0);
    values[slot] = lookup[ord];
    readerGen[slot] = currentReaderGen;
}

void StringOrdValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    StringIndexPtr currentReaderValues(FieldCache::DEFAULT()->getStringIndex(reader, field));
    ++currentReaderGen;
    order = currentReaderValues->order;
    lookup = currentReaderValues->lookup;
    BOOST_ASSERT(!lookup.empty());
    if (bottomSlot != -1) {
        convert(bottomSlot);
        bottomOrd = ords[bottomSlot];
    }
}

void StringOrdValComparator::setBottom(int32_t slot) {
    bottomSlot = slot;
    if (readerGen[slot] != currentReaderGen) {
        convert(bottomSlot);
    }
    bottomOrd = ords[slot];
    BOOST_ASSERT(bottomOrd >= 0);
    BOOST_ASSERT(bottomOrd < lookup.size());
    bottomValue = values[slot];
}

ComparableValue StringOrdValComparator::value(int32_t slot) {
    return values[slot];
}

Collection<String> StringOrdValComparator::getValues() {
    return values;
}

int32_t StringOrdValComparator::getBottomSlot() {
    return bottomSlot;
}

String StringOrdValComparator::getField() {
    return field;
}

StringValComparator::StringValComparator(int32_t numHits, const String& field) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringValComparator::~StringValComparator() {
}

int32_t StringValComparator::compare(int32_t slot1, int32_t slot2) {
    return values[slot1].compare(values[slot2]);
}

int32_t StringValComparator::compareBottom(int32_t doc) {
    return bottom.compare(currentReaderValues[doc]);
}

void StringValComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringValComparator::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringValComparator::value(int32_t slot) {
    return values[slot];
}

}


#include "LuceneInc.h"
#include "FieldComparator.h"
#include "FieldCache.h"
#include "ScoreCachingWrappingScorer.h"
#include "Collator.h"

namespace Lucene {

FieldComparator::~FieldComparator() {
}

void FieldComparator::setScorer(const ScorerPtr& scorer) {
    // Empty implementation since most comparators don't need the score.
    // This can be overridden by those that need it.
}

ByteComparator::ByteComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<uint8_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<ByteParser>(parser);
}

ByteComparator::~ByteComparator() {
}

void ByteComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getBytes(reader, field, parser);
}

DocComparator::DocComparator(int32_t numHits) : NumericComparator<int32_t>(numHits) {
    this->docBase = 0;
}

DocComparator::~DocComparator() {
}

int32_t DocComparator::compareBottom(int32_t doc) {
    // No overflow risk because docIDs are non-negative
    return (bottom - (docBase + doc));
}

void DocComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = docBase + doc;
}

void DocComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    this->docBase = docBase;
}

DoubleComparator::DoubleComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<double>(numHits, field) {
    this->parser = boost::static_pointer_cast<DoubleParser>(parser);
}

DoubleComparator::~DoubleComparator() {
}

int32_t DoubleComparator::compare(int32_t slot1, int32_t slot2) {
    double v1 = values[slot1];
    double v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t DoubleComparator::compareBottom(int32_t doc) {
    double v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void DoubleComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getDoubles(reader, field, parser);
}

IntComparator::IntComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int32_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<IntParser>(parser);
}

IntComparator::~IntComparator() {
}

int32_t IntComparator::compare(int32_t slot1, int32_t slot2) {
    int32_t v1 = values[slot1];
    int32_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t IntComparator::compareBottom(int32_t doc) {
    int32_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void IntComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getInts(reader, field, parser);
}

LongComparator::LongComparator(int32_t numHits, const String& field, const ParserPtr& parser) : NumericComparator<int64_t>(numHits, field) {
    this->parser = boost::static_pointer_cast<LongParser>(parser);
}

LongComparator::~LongComparator() {
}

int32_t LongComparator::compare(int32_t slot1, int32_t slot2) {
    int64_t v1 = values[slot1];
    int64_t v2 = values[slot2];
    return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}

int32_t LongComparator::compareBottom(int32_t doc) {
    int64_t v2 = currentReaderValues[doc];
    return bottom > v2 ? 1 : (bottom < v2 ? -1 : 0);
}

void LongComparator::setNextReader(cons

t IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getLongs(reader, field, parser);
}

RelevanceComparator::RelevanceComparator(int32_t numHits) : NumericComparator<double>(numHits) {
}

RelevanceComparator::~RelevanceComparator() {
}

int32_t RelevanceComparator::compare(int32_t slot1, int32_t slot2) {
    double score1 = values[slot1];
    double score2 = values[slot2];
    return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}

int32_t RelevanceComparator::compareBottom(int32_t doc) {
    double score = scorer->score();
    return bottom > score ? -1 : (bottom < score ? 1 : 0);
}

void RelevanceComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = scorer->score();
}

void RelevanceComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
}

void RelevanceComparator::setScorer(const ScorerPtr& scorer) {
    this->scorer = newLucene<ScoreCachingWrappingScorer>(scorer);
}

StringComparatorLocale::StringComparatorLocale(int32_t numHits, const String& field, const std::locale& locale) : collator(newLucene<Collator>(locale)) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringComparatorLocale::~StringComparatorLocale() {
}

int32_t StringComparatorLocale::compare(int32_t slot1, int32_t slot2) {
    return collator->compare(values[slot1], values[slot2]);
}

int32_t StringComparatorLocale::compareBottom(int32_t doc) {
    return collator->compare(bottom, currentReaderValues[doc]);
}

void StringComparatorLocale::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringComparatorLocale::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringComparatorLocale::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringComparatorLocale::value(int32_t slot) {
    return values[slot];
}

StringOrdValComparator::StringOrdValComparator(int32_t numHits, const String& field, int32_t sortPos, bool reversed) {
    this->ords = Collection<int32_t>::newInstance(numHits);
    this->values = Collection<String>::newInstance(numHits);
    this->readerGen = Collection<int32_t>::newInstance(numHits);
    this->sortPos = sortPos;
    this->reversed = reversed;
    this->field = field;
    this->currentReaderGen = -1;
    this->bottomSlot = -1;
    this->bottomOrd = 0;
}

StringOrdValComparator::~StringOrdValComparator() {
}

int32_t StringOrdValComparator::compare(int32_t slot1, int32_t slot2) {
    if (readerGen[slot1] == readerGen[slot2]) {
        int32_t cmp = ords[slot1] - ords[slot2];
        if (cmp != 0) {
            return cmp;
        }
    }
    return values[slot1].compare(values[slot2]);
}

int32_t StringOrdValComparator::compareBottom(int32_t doc) {
    BOOST_ASSERT(bottomSlot != -1);
    int32_t order = this->order[doc];
    int32_t cmp = bottomOrd - order;
    if (cmp != 0) {
        return cmp;
    }
    return bottomValue.compare(lookup[order]);
}

void StringOrdValComparator::convert(int32_t slot) {
    readerGen[slot] = currentReaderGen;
    int32_t index = 0;
    String value(values[slot]);
    if (value.empty()) {
        ords[slot] = 0;
        return;
    }

    if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
        // Since we are the primary sort, the entries in the queue are bounded by bottomOrd
        BOOST_ASSERT(bottomOrd < lookup.size());
        if (reversed) {
            index = binarySearch(lookup, value, bottomOrd, lookup.size() - 1);
        } else {
            index = binarySearch(lookup, value, 0, bottomOrd);
        }
    } else {
        // Full binary search
        index = binarySearch(lookup, value, 0, lookup.size() - 1);
    }

    if (index < 0) {
        index = -index - 2;
    }

    ords[slot] = index;
}

int32_t StringOrdValComparator::binarySearch(Collection<String> lookup, const String& key, int32_t low, int32_t high) {
    Collection<String>::iterator search = std::lower_bound(lookup.begin() + low, lookup.begin() + high, key);
    int32_t keyPos = std::distance(lookup.begin(), search);
    return (search == lookup.end() || key < *search) ? -(keyPos + 1) : keyPos;
}

void StringOrdValComparator::copy(int32_t slot, int32_t doc) {
    int32_t ord = order[doc];
    ords[slot] = ord;
    BOOST_ASSERT(ord >= 0);
    values[slot] = lookup[ord];
    readerGen[slot] = currentReaderGen;
}

void StringOrdValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    StringIndexPtr currentReaderValues(FieldCache::DEFAULT()->getStringIndex(reader, field));
    ++currentReaderGen;
    order = currentReaderValues->order;
    lookup = currentReaderValues->lookup;
    BOOST_ASSERT(!lookup.empty());
    if (bottomSlot != -1) {
        convert(bottomSlot);
        bottomOrd = ords[bottomSlot];
    }
}

void StringOrdValComparator::setBottom(int32_t slot) {
    bottomSlot = slot;
    if (readerGen[slot] != currentReaderGen) {
        convert(bottomSlot);
    }
    bottomOrd = ords[slot];
    BOOST_ASSERT(bottomOrd >= 0);
    BOOST_ASSERT(bottomOrd < lookup.size());
    bottomValue = values[slot];
}

ComparableValue StringOrdValComparator::value(int32_t slot) {
    return values[slot];
}

Collection<String> StringOrdValComparator::getValues() {
    return values;
}

int32_t StringOrdValComparator::getBottomSlot() {
    return bottomSlot;
}

String StringOrdValComparator::getField() {
    return field;
}

StringValComparator::StringValComparator(int32_t numHits, const String& field) {
    this->values = Collection<String>::newInstance(numHits);
    this->field = field;
}

StringValComparator::~StringValComparator() {
}

int32_t StringValComparator::compare(int32_t slot1, int32_t slot2) {
    return values[slot1].compare(values[slot2]);
}

int32_t StringValComparator::compareBottom(int32_t doc) {
    return bottom.compare(currentReaderValues[doc]);
}

void StringValComparator::copy(int32_t slot, int32_t doc) {
    values[slot] = currentReaderValues[doc];
}

void StringValComparator::setNextReader(const IndexReaderPtr& reader, int32_t docBase) {
    currentReaderValues = FieldCache::DEFAULT()->getStrings(reader, field);
}

void StringValComparator::setBottom(int32_t slot) {
    bottom = values[slot];
}

ComparableValue StringValComparator::value(int32_t slot) {
    return values[slot];
}

}


#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

{
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


{
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message)

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


{
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular)

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);

#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <string>

TEST(ErrorHandlingMatrix, checkLowerTriangular) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;

  y.resize(1, 1);
  y << 1;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << 1, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = 1;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << 1, 0, 2, 3;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, 2, 3, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << 1, 0, 2, 3, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTr

iangular", "y", y));

  y(0, 1) = 1.5;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << 1, 0, 0, 4, 5, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));
  y(0, 2) = 3;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_one_indexed_message) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  std::string message;

  y.resize(2, 3);
  y << 1, 0, 3, 4, 5, 0;
  try {
    check_lower_triangular("checkLowerTriangular", "y", y);
    FAIL() << "should have thrown";
  } catch (std::domain_error& e) {
    message = e.what();
  } catch (...) {
    FAIL() << "threw the wrong error";
  }

  EXPECT_NE(std::string::npos, message.find("[1,3]")) << message;
}

TEST(ErrorHandlingMatrix, checkLowerTriangular_nan) {
  using stan::math::check_lower_triangular;
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> y;
  double nan = std::numeric_limits<double>::quiet_NaN();

  y.resize(1, 1);
  y << nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y.resize(1, 2);
  y << nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 2);
  y << nan, 0, nan, nan;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y << 1, nan, nan, 4;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(3, 2);
  y << nan, 0, 2, nan, 4, 5;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 1) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);

  y.resize(2, 3);
  y << nan, 0, 0, 4, nan, 0;
  EXPECT_NO_THROW(check_lower_triangular("checkLowerTriangular", "y", y));

  y(0, 2) = nan;
  EXPECT_THROW(check_lower_triangular("checkLowerTriangular", "y", y),
               std::domain_error);
}


long double evalInt(int dimension, std::vector<int> power,
		    std::vector<EIntrepidBurkardt> rule)

// @HEADER
//                           Intrepid2 Package
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Questions? Contact Kyungjoo Kim  (example@nnthink.com), or
//                    Mauro Perego  (example@nnthink.com)
// @HEADER

/** \file
\brief  Unit test (CubatureDirect): correctness of
        integration of monomials for 1D reference cells.
\author Created by P. Bochev and D. Ridzal.
*/

#include "Intrepid2_CubatureTensorSorted.hpp"
#include "Intrepid2_Utils.hpp"
#include "Teuchos_oblackholestream.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_GlobalMPISession.hpp"

using namespace Intrepid2;

/*
  Computes integrals of monomials over a given reference cell.
*/
long double evalQuad(std::vector<int> power, int dimension,
		     std::vector<int> order,
		     std::vector<EIntrepidBurkardt> rule) {

  CubatureTensorSorted<long double> lineCub(dimension,order,rule,false);
  order[0]--; order[1]--;
  CubatureTensorSorted<long double> lineCub1(dimension,order,rule,false);
  lineCub.update(1.0,lineCub1,1.0);

  int size = lineCub.getNumPoints();
  FieldContainer<long double> cubPoints(size,dimension);
  FieldContainer<long double> cubWeights(size);
  lineCub.getCubature(cubPoints,cubWeights);

  int mid  = size/2;
  long double Q = 0.0;
  if (size%2) {
    Q  = cubWeights(mid);
    for (int i=0; i<dimension; i++) {
      Q *= powl(cubPoints(mid,i),(long double)power[i]);
    }
  }

  for (int i=0; i<mid; i++) {
    long double value1 = cubWeights(i);
    long double value2 = cubWeights(size-i-1);
    for (int j=0; j<dimension; j++) {
      value1 *= powl(cubPoints(i,j),(long double)power[j]);
      value2 *= powl(cubPoints(size-i-1,j),(long double)power[j]);
    }
    Q += value1+value2;
  }
  return Q;
}

{
  long double I = 1.0;

  for (int i=0; i<dimension; i++) {
    if (rule[i]==BURK_CLENSHAWCURTIS||rule[i]==BURK_FEJER2||
	rule[i]==BURK_LEGENDRE||rule[i]==BURK_PATTERSON ||
	rule[i]==BURK_TRAPEZOIDAL) {
      if (power[i]%2)
	I *= 0.0;
      else
	I *= 2.0/((long double)power[i]+1.0);
    }
    else if (rule[i]==BURK_LAGUERRE) {
      I *= tgammal((long double)(power[i]+1));
    }
    else if (rule[i]==BURK_CHEBYSHEV1) {
      long double bot, top;
      if (!(power[i]%2)) {
	top = 1; bot = 1;
	for (int j=2;j<=power[i];j+=2) {
	  top *= (long double)(j-1);
	  bot *= (long double)j;
	}
	I *= M_PI*top/bot;
      }
      else {
	I *= 0.0;
      }
    }
    else if (rule[i]==BURK_CHEBYSHEV2) {
      long double bot, top;
      if (!(power[i]%2)) {
      top = 1; bot = 1;
      for (int j=2;j<=power[i];j+=2) {
	top *= (long double)(j-1);
	bot *= (long double)j;
      }
      bot *= (long double)(power[i]+2);
      I   *= M_PI*top/bot;
      }
      else {
	I *= 0.0;
      }
    }
    else if (rule[i]==BURK_HERMITE||rule[i]==BURK_GENZKEISTER) {
      if (power[i]%2) {
	I *= 0.0;
      }
      else {
	long double value = 1.0;
	if ((power[i]-1)>=1) {
	  int n_copy = power[i]-1;
	  while (1<n_copy) {
	    value  *= (long double)n_copy;
	    n_copy -= 2;
	  }
	}
	I *= value*sqrt(M_PI)/powl(2.0,(long double)power[i]/2.0);
      }
    }
  }
  return I;
}

int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
Kokkos::initialize();
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
  << "===============================================================================\n" \
  << "|                                                                             |\n" \
  << "|                         Unit Test (CubatureTensorSorted)                    |\n" \
  << "|                                                                             |\n" \
  << "|     1) Computing integrals of monomials in 2D                               |\n" \
  << "|                                                                             |\n" \
  << "|  Questions? Contact  Drew Kouri (example@nnthink.com) or                     |\n" \
  << "|                      Denis Ridzal (example@nnthink.com).                     |\n" \
  << "|                                                                             |\n" \
  << "|  Intrepid's website: http://example.com           |\n" \
  << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
  << "|                                                                             |\n" \
  << "===============================================================================\n"\
  << "| TEST 12: integrals of monomials in 2D - Anisotropic but no growth rules     |\n"\
  << "===============================================================================\n";

  int dimension           = 2;
  int         errorFlag   = 0;
  long double reltol      = 1.0e+02*INTREPID_TOL;
  int         maxDeg      = 0;
  long double analyticInt = 0;
  long double testInt     = 0;
  int         maxOrder    = 20;
  std::vector<int> power(2,0);
  std::vector<EIntrepidBurkardt> rule1(2,BURK_CLENSHAWCURTIS);
  std::vector<int> order(2,0);

  *outStream << "\nIntegrals of monomials on a reference line (edge):\n";
  // compute and compare integrals
  try {
    for (int i=0; i<=maxOrder; i++) {
      maxDeg = i-2;

      order[0] = i; order[1] = i;
      for (int j=0; j <= maxDeg; j++) {
	power[0] = j;
	for (int k=0; k <= maxDeg; k++) {
	  power[1] = k;
	  analyticInt = 2.0*evalInt(dimension, power, rule1);
	  testInt     = evalQuad(power,dimension,order,rule1);

	  long double abstol  = (analyticInt == 0.0 ? reltol : std::fabs(reltol*analyticInt) );
	  long double absdiff = std::fabs(analyticInt - testInt);
	  *outStream << "Cubature order " << std::setw(2) << std::left << i
		     << " integrating "
		     << "x^" << std::setw(2) << std::left << j << "y^"
		     << std::setw(2) << std::left
		     << k <<  ":" << "   " << std::scientific
		     << std::setprecision(16) << testInt
		     << "   " << analyticInt << "   " << std::setprecision(4)
		     << absdiff << "   "
		     << "<?" << "   " << abstol << "\n";
	  if (absdiff > abstol) {
	    errorFlag++;
	    *outStream << std::right << std::setw(104) << "^^^^---FAILURE!\n";
	  }
	} // end for k
	*outStream << "\n";
      } // end for j
      *outStream << "\n";
    } // end for i
  }
  catch (std::logic_error &err) {
    *outStream << err.what() << "\n";
    errorFlag = -1;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
Kokkos::finalize();
  return errorFlag;
}