<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "searchiteratorverifier.h"
#include "initrange.h"
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchlib/queryeval/emptysearch.h>
#include <vespa/searchlib/queryeval/truesearch.h>
#include <vespa/searchlib/queryeval/termwise_search.h>
#include <vespa/searchlib/queryeval/andsearch.h>
#include <vespa/searchlib/queryeval/orsearch.h>
#include <vespa/searchlib/common/bitvectoriterator.h>
#include <set>

namespace search {
namespace test {

using namespace search::queryeval;
using std::make_unique;

class DocIdIterator : public SearchIterator
{
public:
    DocIdIterator(const SearchIteratorVerifier::DocIds & docIds, bool strict) :
        _strict(strict),
        _currIndex(0),
        _docIds(docIds)
    { }

    void initRange(uint32_t beginId, uint32_t endId) override {
        SearchIterator::initRange(beginId, endId);
        _currIndex = 0;
        if (_strict) {
            doSeek(beginId);
        }
    }

    void doSeek(uint32_t docId) override {
        while ((_currIndex < _docIds.size()) && (_docIds[_currIndex] < docId)) {
            _currIndex++;
        }
        if ((_currIndex < _docIds.size()) && (_docIds[_currIndex] < getEndId())) {
            if (_docIds[_currIndex] == docId || _strict) {
                setDocId(_docIds[_currIndex]);
            }
        } else {
            setAtEnd();
        }
    }

    void doUnpack(uint32_t docid) { (void) docid; }

    vespalib::Trinary is_strict() const override {
        return _strict ? vespalib::Trinary::True : vespalib::Trinary::False;
    }

private:
    const bool _strict;
    uint32_t   _currIndex;
    const SearchIteratorVerifier::DocIds _docIds;
};

SearchIteratorVerifier::SearchIteratorVerifier() :
    _trueTfmd(),
    _docIds(),
    _everyOddBitSet(BitVector::create(getDocIdLimit()))
{
    for (size_t i(1); i < getDocIdLimit(); i += 2) {
        _everyOddBitSet->setBit(i);
    }
    // (0),1 and 10,11 and 20,21 .... 200,201 etc are hits
    // 0 is of course invalid.
    for (size_t i(0); (i*10+1) < getDocIdLimit(); i++) {
        if (i > 0) {
            _docIds.push_back(i * 10);
        }
        _docIds.push_back(i*10 + 1);
    }
    std::set<uint32_t> orSet;
    for (uint32_t docId : _docIds) {
        orSet.insert(docId);
    }
    _everyOddBitSet->foreach_truebit([&orSet](uint32_t docId){orSet.insert(docId);});
    for (uint32_t docId : orSet) {
        _expectedOr.push_back(docId);
    }
    for (uint32_t docId : _docIds) {
        if (_everyOddBitSet->testBit(docId)) {
            _expectedAnd.push_back(docId);
        }
    }
}

SearchIterator::UP
SearchIteratorVerifier::createIterator(const DocIds &docIds, bool strict)
{
    return make_unique<DocIdIterator>(docIds, strict);
}

SearchIterator::UP
SearchIteratorVerifier::createEmptyIterator()
{
    return make_unique<EmptySearch>();
}

SearchIterator::UP
SearchIteratorVerifier::createFullIterator() const
{
    return make_unique<TrueSearch>(_trueTfmd);
}
SearchIteratorVerifier::~SearchIteratorVerifier() { }

void
SearchIteratorVerifier::verify() const {
    TEST_DO(verifyTermwise());
    TEST_DO(verifyInitRange());
}

void
SearchIteratorVerifier::verifyTermwise() const {
    TEST_DO(verify(false));
    TEST_DO(verify(true));
}

void
SearchIteratorVerifier::verifyInitRange() const {
    InitRangeVerifier initRangeTest;
    TEST_DO(initRangeTest.verify(*create(false)));
    TEST_DO(initRangeTest.verify(*create(true)));
}

void
SearchIteratorVerifier::verify_get_hits(bool strict) const {
    constexpr const size_t FIRST_LEGAL = 64;
    SearchIterator::UP iterator = create(strict);
    iterator->initFullRange();
    EXPECT_TRUE(iterator->seek(FIRST_LEGAL));
    EXPECT_EQUAL(FIRST_LEGAL, iterator->getDocId());
    BitVector::UP hits = iterator->get_hits(1);
    for (size_t i(0); i < FIRST_LEGAL; i++) {
        EXPECT_FALSE(hits->testBit(i));
    }
    EXPECT_TRUE(hits->testBit(FIRST_LEGAL));
}

void
SearchIteratorVerifier::verify(bool strict) const {
    SearchIterator::UP iterator = create(strict);
    TEST_DO(verify(*iterator, strict, _docIds));
    TEST_DO(verifyTermwise(std::move(iterator), strict, _docIds));
    TEST_DO(verifyAnd(strict));
    TEST_DO(verifyOr(strict));
    TEST_DO(verify_get_hits(strict));
}

void
SearchIteratorVerifier::verifyAnd(bool strict) const {
    fef::TermFieldMatchData tfmd;
    MultiSearch::Children children;
    children.emplace_back(create(strict).release());
    children.emplace_back(BitVectorIterator::create(_everyOddBitSet.get(), getDocIdLimit(), tfmd, false).release());
    SearchIterator::UP search(AndSearch::create(children, strict, UnpackInfo()));
    TEST_DO(verify(*search, strict, _expectedAnd));
    TEST_DO(verifyTermwise(std::move(search), strict, _expectedAnd));
}

void
SearchIteratorVerifier::verifyOr(bool strict) const {
    fef::TermFieldMatchData tfmd;
    MultiSearch::Children children;
    children.emplace_back(create(strict).release());
    children.emplace_back(BitVectorIterator::create(_everyOddBitSet.get(), getDocIdLimit(), tfmd, strict).release());
    SearchIterator::UP search(OrSearch::create(children, strict, UnpackInfo()));
    TEST_DO(verify(*search, strict, _expectedOr));
    TEST_DO(verifyTermwise(std::move(search), strict, _expectedOr));
}

void
SearchIteratorVerifier::verifyTermwise(SearchIterator::UP iterator, bool strict, const DocIds & docIds) {
    SearchIterator::UP termwise = make_termwise(std::move(iterator), strict);
    TEST_DO(verify(*termwise, strict, docIds));
}

void
SearchIteratorVerifier::verify(SearchIterator & iterator, bool strict, const DocIds & docIds)
{
    TEST_DO(verify(iterator, Ranges({{1, getDocIdLimit()}}), strict, docIds));
    TEST_DO(verify(iterator, Ranges({{1, getDocIdLimit()}}), strict, docIds));
    for (uint32_t rangeWidth : { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 202 }) {
        Ranges ranges;
        for (uint32_t sum(1); sum < getDocIdLimit(); sum += rangeWidth) {
            ranges.emplace_back(sum, std::min(sum+rangeWidth, getDocIdLimit()));
        }
        TEST_DO(verify(iterator, ranges, strict, docIds));
        std::reverse(ranges.begin(), ranges.end());
        TEST_DO(verify(iterator, ranges, strict, docIds));
    }
}

void
SearchIteratorVerifier::verify(SearchIterator & iterator, const Ranges & ranges, bool strict, const DocIds & docIds)
{
    DocIds result = search(iterator, ranges, strict);
    ASSERT_EQUAL(docIds.size(), result.size());
    for (size_t i(0); i < docIds.size(); i++) {
        EXPECT_EQUAL(docIds[i], result[i]);
    }
}

SearchIteratorVerifier::DocIds
SearchIteratorVerifier::search(SearchIterator & it, const Ranges & ranges, bool strict)
{
    DocIds result;
    for (Range range : ranges) {
        DocIds part = strict ? searchStrict(it, range) : searchRelaxed(it, range);
        result.insert(result.end(), part.begin(), part.end());
    }
    std::sort(result.begin(), result.end());
    return result;
}

SearchIteratorVerifier::DocIds
SearchIteratorVerifier::searchRelaxed(SearchIterator & it, Range range)
{
    DocIds result;
    it.initRange(range.first, range.second);
    for (uint32_t docid = range.first; docid < range.second; ++docid) {
        if (it.seek(docid)) {
            result.emplace_back(docid);
        }
    }
    return result;
}

SearchIteratorVerifier::DocIds
SearchIteratorVerifier::searchStrict(SearchIterator & it, Range range)
{
    DocIds result;
    it.initRange(range.first, range.second);
    for (uint32_t docId = it.seekFirst(range.first); (docId < range.second) && !it.isAtEnd(); docId = it.seekNext(docId + 1)) {
        result.push_back(docId);
    }
    return result;
}

}
}
<commit_msg>Use a docid that is actually a hit.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "searchiteratorverifier.h"
#include "initrange.h"
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchlib/queryeval/emptysearch.h>
#include <vespa/searchlib/queryeval/truesearch.h>
#include <vespa/searchlib/queryeval/termwise_search.h>
#include <vespa/searchlib/queryeval/andsearch.h>
#include <vespa/searchlib/queryeval/orsearch.h>
#include <vespa/searchlib/common/bitvectoriterator.h>
#include <set>

namespace search {
namespace test {

using namespace search::queryeval;
using std::make_unique;

class DocIdIterator : public SearchIterator
{
public:
    DocIdIterator(const SearchIteratorVerifier::DocIds & docIds, bool strict) :
        _strict(strict),
        _currIndex(0),
        _docIds(docIds)
    { }

    void initRange(uint32_t beginId, uint32_t endId) override {
        SearchIterator::initRange(beginId, endId);
        _currIndex = 0;
        if (_strict) {
            doSeek(beginId);
        }
    }

    void doSeek(uint32_t docId) override {
        while ((_currIndex < _docIds.size()) && (_docIds[_currIndex] < docId)) {
            _currIndex++;
        }
        if ((_currIndex < _docIds.size()) && (_docIds[_currIndex] < getEndId())) {
            if (_docIds[_currIndex] == docId || _strict) {
                setDocId(_docIds[_currIndex]);
            }
        } else {
            setAtEnd();
        }
    }

    void doUnpack(uint32_t docid) { (void) docid; }

    vespalib::Trinary is_strict() const override {
        return _strict ? vespalib::Trinary::True : vespalib::Trinary::False;
    }

private:
    const bool _strict;
    uint32_t   _currIndex;
    const SearchIteratorVerifier::DocIds _docIds;
};

SearchIteratorVerifier::SearchIteratorVerifier() :
    _trueTfmd(),
    _docIds(),
    _everyOddBitSet(BitVector::create(getDocIdLimit()))
{
    for (size_t i(1); i < getDocIdLimit(); i += 2) {
        _everyOddBitSet->setBit(i);
    }
    // (0),1 and 10,11 and 20,21 .... 200,201 etc are hits
    // 0 is of course invalid.
    for (size_t i(0); (i*10+1) < getDocIdLimit(); i++) {
        if (i > 0) {
            _docIds.push_back(i * 10);
        }
        _docIds.push_back(i*10 + 1);
    }
    std::set<uint32_t> orSet;
    for (uint32_t docId : _docIds) {
        orSet.insert(docId);
    }
    _everyOddBitSet->foreach_truebit([&orSet](uint32_t docId){orSet.insert(docId);});
    for (uint32_t docId : orSet) {
        _expectedOr.push_back(docId);
    }
    for (uint32_t docId : _docIds) {
        if (_everyOddBitSet->testBit(docId)) {
            _expectedAnd.push_back(docId);
        }
    }
}

SearchIterator::UP
SearchIteratorVerifier::createIterator(const DocIds &docIds, bool strict)
{
    return make_unique<DocIdIterator>(docIds, strict);
}

SearchIterator::UP
SearchIteratorVerifier::createEmptyIterator()
{
    return make_unique<EmptySearch>();
}

SearchIterator::UP
SearchIteratorVerifier::createFullIterator() const
{
    return make_unique<TrueSearch>(_trueTfmd);
}
SearchIteratorVerifier::~SearchIteratorVerifier() { }

void
SearchIteratorVerifier::verify() const {
    TEST_DO(verifyTermwise());
    TEST_DO(verifyInitRange());
}

void
SearchIteratorVerifier::verifyTermwise() const {
    TEST_DO(verify(false));
    TEST_DO(verify(true));
}

void
SearchIteratorVerifier::verifyInitRange() const {
    InitRangeVerifier initRangeTest;
    TEST_DO(initRangeTest.verify(*create(false)));
    TEST_DO(initRangeTest.verify(*create(true)));
}

void
SearchIteratorVerifier::verify_get_hits(bool strict) const {
    constexpr const size_t FIRST_LEGAL = 61;
    SearchIterator::UP iterator = create(strict);
    iterator->initFullRange();
    EXPECT_TRUE(iterator->seek(FIRST_LEGAL));
    EXPECT_EQUAL(FIRST_LEGAL, iterator->getDocId());
    BitVector::UP hits = iterator->get_hits(1);
    for (size_t i(0); i < FIRST_LEGAL; i++) {
        EXPECT_FALSE(hits->testBit(i));
    }
    EXPECT_TRUE(hits->testBit(FIRST_LEGAL));
}

void
SearchIteratorVerifier::verify(bool strict) const {
    SearchIterator::UP iterator = create(strict);
    TEST_DO(verify(*iterator, strict, _docIds));
    TEST_DO(verifyTermwise(std::move(iterator), strict, _docIds));
    TEST_DO(verifyAnd(strict));
    TEST_DO(verifyOr(strict));
    TEST_DO(verify_get_hits(strict));
}

void
SearchIteratorVerifier::verifyAnd(bool strict) const {
    fef::TermFieldMatchData tfmd;
    MultiSearch::Children children;
    children.emplace_back(create(strict).release());
    children.emplace_back(BitVectorIterator::create(_everyOddBitSet.get(), getDocIdLimit(), tfmd, false).release());
    SearchIterator::UP search(AndSearch::create(children, strict, UnpackInfo()));
    TEST_DO(verify(*search, strict, _expectedAnd));
    TEST_DO(verifyTermwise(std::move(search), strict, _expectedAnd));
}

void
SearchIteratorVerifier::verifyOr(bool strict) const {
    fef::TermFieldMatchData tfmd;
    MultiSearch::Children children;
    children.emplace_back(create(strict).release());
    children.emplace_back(BitVectorIterator::create(_everyOddBitSet.get(), getDocIdLimit(), tfmd, strict).release());
    SearchIterator::UP search(OrSearch::create(children, strict, UnpackInfo()));
    TEST_DO(verify(*search, strict, _expectedOr));
    TEST_DO(verifyTermwise(std::move(search), strict, _expectedOr));
}

void
SearchIteratorVerifier::verifyTermwise(SearchIterator::UP iterator, bool strict, const DocIds & docIds) {
    SearchIterator::UP termwise = make_termwise(std::move(iterator), strict);
    TEST_DO(verify(*termwise, strict, docIds));
}

void
SearchIteratorVerifier::verify(SearchIterator & iterator, bool strict, const DocIds & docIds)
{
    TEST_DO(verify(iterator, Ranges({{1, getDocIdLimit()}}), strict, docIds));
    TEST_DO(verify(iterator, Ranges({{1, getDocIdLimit()}}), strict, docIds));
    for (uint32_t rangeWidth : { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 100, 202 }) {
        Ranges ranges;
        for (uint32_t sum(1); sum < getDocIdLimit(); sum += rangeWidth) {
            ranges.emplace_back(sum, std::min(sum+rangeWidth, getDocIdLimit()));
        }
        TEST_DO(verify(iterator, ranges, strict, docIds));
        std::reverse(ranges.begin(), ranges.end());
        TEST_DO(verify(iterator, ranges, strict, docIds));
    }
}

void
SearchIteratorVerifier::verify(SearchIterator & iterator, const Ranges & ranges, bool strict, const DocIds & docIds)
{
    DocIds result = search(iterator, ranges, strict);
    ASSERT_EQUAL(docIds.size(), result.size());
    for (size_t i(0); i < docIds.size(); i++) {
        EXPECT_EQUAL(docIds[i], result[i]);
    }
}

SearchIteratorVerifier::DocIds
SearchIteratorVerifier::search(SearchIterator & it, const Ranges & ranges, bool strict)
{
    DocIds result;
    for (Range range : ranges) {
        DocIds part = strict ? searchStrict(it, range) : searchRelaxed(it, range);
        result.insert(result.end(), part.begin(), part.end());
    }
    std::sort(result.begin(), result.end());
    return result;
}

SearchIteratorVerifier::DocIds
SearchIteratorVerifier::searchRelaxed(SearchIterator & it, Range range)
{
    DocIds result;
    it.initRange(range.first, range.second);
    for (uint32_t docid = range.first; docid < range.second; ++docid) {
        if (it.seek(docid)) {
            result.emplace_back(docid);
        }
    }
    return result;
}

SearchIteratorVerifier::DocIds
SearchIteratorVerifier::searchStrict(SearchIterator & it, Range range)
{
    DocIds result;
    it.initRange(range.first, range.second);
    for (uint32_t docId = it.seekFirst(range.first); (docId < range.second) && !it.isAtEnd(); docId = it.seekNext(docId + 1)) {
        result.push_back(docId);
    }
    return result;
}

}
}
<|endoftext|>


<commit_before><commit_msg>CheckBox::GetSavedValue return type is TriState<commit_after><|endoftext|>


<commit_before>#include "background.hpp"
#include <algorithm>

#define FRAMES 20
#define DIFF_THRESH 40
#define MARGIN_SIDE 0.1
#define MARGIN_BOTTOM 0.15

Background::Background(std::string filename): file(filename) {
  std::cout << "Initializing stuff.." << std::endl;
  video.open(file);
  if (!video.isOpened()) {
      std::cerr << "Could not open video file \"" << file << "\". Aborting." << std::endl;
      exit(-1);
    }

  width = (int)video.get(CV_CAP_PROP_FRAME_WIDTH);
  height = (int)video.get(CV_CAP_PROP_FRAME_HEIGHT);
  backgroundModel = cv::Mat(cv::Size(width, height), CV_8UC1, cv::Scalar::all(0));
//   std::cout << "Video size is " << width << "x" << height << "." << std::endl;
  pixels = new std::vector<unsigned char>[width*height];
}

void Background::computeBasicModel() {
  std::cout << "Computing basic background model.." << std::endl;
  assert(video.isOpened());

  cv::Mat frame, gray;
//  cv::namedWindow( "Frame", CV_WINDOW_AUTOSIZE );
//  cv::namedWindow( "Frame2", CV_WINDOW_AUTOSIZE );

  // read frame by frame and process
  while(video.read(frame)) {
      // convert to grayscale and apply Gaussian blur
      cv::cvtColor(frame, gray, CV_RGB2GRAY);
      grayscaleGaussianBlur(gray, gray, 5);

      for (int row = 0; row < gray.rows; ++row) {
#pragma omp parallel for
          for (int col = 0; col < gray.cols; ++col) {
              pixels[row * width + col].push_back((int)gray.at<uchar>(row, col));
            }
        }

      frames.push_back(gray.clone());

//      cv::imshow( "Frame", gray );
//      cv::imshow( "Frame2", frames.back() );
//      cv::waitKey(5);
    }

  // compute medians and get background model
  for (int row = 0; row < backgroundModel.rows; ++row) {
#pragma omp parallel for
      for (int col = 0; col < backgroundModel.cols; ++col) {
          backgroundModel.at<uchar>(row, col) = getMean(pixels[row * width + col]);
        }
    }

  // izračunati koliko se maksimalno frame razlikuje od modela pozadine
  // postaviti granicu empirijski
  video.release();
  video.open(file);

  long int difference_score = 0;
  int cnt = 0;

  while(video.read(frame)) {
      cnt++;
      if(cnt % FRAMES != 0) {
          continue;
        }

      cv::cvtColor(frame, gray, CV_RGB2GRAY);
      grayscaleGaussianBlur(gray, gray, 5);

      long int difference = 0;
      for (int row = 0; row < gray.rows; ++row) {
#pragma omp parallel for reduction(+:difference)
          for (int col = 0; col < gray.cols; ++col) {
              if(abs((int)gray.at<uchar>(row, col)-(int)backgroundModel.at<uchar>(row, col)) >= DIFF_THRESH) {
                  difference++;
                }
            }
        }

      if(difference > difference_score) {
          difference_score = difference;
        }
    }

  std::cout << "Difference score: " << difference_score << std::endl;

  //  if(difference_score < 2000.0)
  //    exit(0);

  cv::Mat hist;
  cv::Mat centralBgModel = cv::Mat(backgroundModel, cv::Range(0, backgroundModel.rows*(1.0 - MARGIN_BOTTOM)), cv::Range(backgroundModel.cols * MARGIN_SIDE, backgroundModel.cols*(1.0 - MARGIN_SIDE)));
  drawHistogram(centralBgModel, hist);

  cv::namedWindow( "Background", CV_WINDOW_AUTOSIZE );
  cv::imshow( "Background", backgroundModel );
  cv::namedWindow( "Histogram", CV_WINDOW_AUTOSIZE );
  cv::imshow( "Histogram", hist );
  cv::waitKey(0);

  exit(0);

}

Background::~Background() {
  video.release();
  delete [] pixels;
}

unsigned char Background::getMean(std::vector<unsigned char> &v) {
  int hash[256] = { 0 };
  for (unsigned int var = 0; var < v.size(); ++var) {
      hash[v[var]]++;
    }
  int max = 0, maxIndex = 0;
  for (int var = 0; var < 256; ++var) {
      if(hash[var] > max) {
          max = hash[var];
          maxIndex = var;
        }
    }

  return maxIndex;
}

unsigned char Background::getMedian(std::vector<unsigned char> &v) {
  size_t n = v.size() / 2;
  nth_element(v.begin(), v.begin()+n, v.end());

  return v[n];
}

void Background::drawHistogram(cv::Mat &m, cv::Mat &hist, unsigned int height, unsigned int binWidth, unsigned int binSpacing) {
  assert(height > 0);
  assert(binWidth > 0);

  unsigned int bins[256] = { 0 };
  for (int row = 0; row < m.rows; ++row) {
      for (int col = 0; col < m.cols; ++col) {
          bins[(unsigned int)m.at<uchar>(row, col)]++;
        }
    }

  unsigned int max = 0;
  for (int bin = 0; bin < 256; ++bin) {
      if(bins[bin] > max) {
          max = bins[bin];
        }
    }

  unsigned int width = 256 * binWidth + 255 * binSpacing;
  hist = cv::Mat(height, width, CV_8UC1, cv::Scalar::all(0));

  unsigned int size;
  for (unsigned int bin = 0, position = 0; bin < 256; ++bin, position += binWidth + binSpacing) {
      size = (bins[bin]/(float)max) * height;
      cv::rectangle(hist, cv::Point(position, height - 1), cv::Point(position + binWidth - 1, height - 1 -size), cv::Scalar(255), CV_FILLED);
    }

}

<commit_msg>Removed difference score calculation<commit_after>#include "background.hpp"
#include <algorithm>

#define FRAMES 20
#define DIFF_THRESH 40
#define MARGIN_SIDE 0.1
#define MARGIN_BOTTOM 0.15

Background::Background(std::string filename): file(filename) {
  std::cout << "Initializing stuff.." << std::endl;
  video.open(file);
  if (!video.isOpened()) {
      std::cerr << "Could not open video file \"" << file << "\". Aborting." << std::endl;
      exit(-1);
    }

  width = (int)video.get(CV_CAP_PROP_FRAME_WIDTH);
  height = (int)video.get(CV_CAP_PROP_FRAME_HEIGHT);
  backgroundModel = cv::Mat(cv::Size(width, height), CV_8UC1, cv::Scalar::all(0));
//   std::cout << "Video size is " << width << "x" << height << "." << std::endl;
  pixels = new std::vector<unsigned char>[width*height];
}

void Background::computeBasicModel() {
  std::cout << "Computing basic background model.." << std::endl;
  assert(video.isOpened());

  cv::Mat frame, gray;
//  cv::namedWindow( "Frame", CV_WINDOW_AUTOSIZE );
//  cv::namedWindow( "Frame2", CV_WINDOW_AUTOSIZE );

  // read frame by frame and process
  while(video.read(frame)) {
      // convert to grayscale and apply Gaussian blur
      cv::cvtColor(frame, gray, CV_RGB2GRAY);
      grayscaleGaussianBlur(gray, gray, 5);

      for (int row = 0; row < gray.rows; ++row) {
#pragma omp parallel for
          for (int col = 0; col < gray.cols; ++col) {
              pixels[row * width + col].push_back((int)gray.at<uchar>(row, col));
            }
        }

      frames.push_back(gray.clone());

//      cv::imshow( "Frame", gray );
//      cv::imshow( "Frame2", frames.back() );
//      cv::waitKey(5);
    }

  // compute medians and get background model
  for (int row = 0; row < backgroundModel.rows; ++row) {
#pragma omp parallel for
      for (int col = 0; col < backgroundModel.cols; ++col) {
          backgroundModel.at<uchar>(row, col) = getMean(pixels[row * width + col]);
        }
    }

  cv::Mat hist;
  cv::Mat centralBgModel = cv::Mat(backgroundModel, cv::Range(0, backgroundModel.rows*(1.0 - MARGIN_BOTTOM)), cv::Range(backgroundModel.cols * MARGIN_SIDE, backgroundModel.cols*(1.0 - MARGIN_SIDE)));
  drawHistogram(centralBgModel, hist);

//  cv::namedWindow( "Background", CV_WINDOW_AUTOSIZE );
//  cv::imshow( "Background", backgroundModel );
//  cv::namedWindow( "Histogram", CV_WINDOW_AUTOSIZE );
//  cv::imshow( "Histogram", hist );
//  cv::waitKey(0);

  // 2sigma okolo peaka?

//  exit(0);

}

Background::~Background() {
  video.release();
  delete [] pixels;
}

unsigned char Background::getMean(std::vector<unsigned char> &v) {
  int hash[256] = { 0 };
  for (unsigned int var = 0; var < v.size(); ++var) {
      hash[v[var]]++;
    }
  int max = 0, maxIndex = 0;
  for (int var = 0; var < 256; ++var) {
      if(hash[var] > max) {
          max = hash[var];
          maxIndex = var;
        }
    }

  return maxIndex;
}

unsigned char Background::getMedian(std::vector<unsigned char> &v) {
  size_t n = v.size() / 2;
  nth_element(v.begin(), v.begin()+n, v.end());

  return v[n];
}

void Background::drawHistogram(cv::Mat &m, cv::Mat &hist, unsigned int height, unsigned int binWidth, unsigned int binSpacing) {
  assert(height > 0);
  assert(binWidth > 0);

  unsigned int bins[256] = { 0 };
  for (int row = 0; row < m.rows; ++row) {
      for (int col = 0; col < m.cols; ++col) {
          bins[(unsigned int)m.at<uchar>(row, col)]++;
        }
    }

  unsigned int max = 0;
  for (int bin = 0; bin < 256; ++bin) {
      if(bins[bin] > max) {
          max = bins[bin];
        }
    }

  unsigned int width = 256 * binWidth + 255 * binSpacing;
  hist = cv::Mat(height, width, CV_8UC1, cv::Scalar::all(0));

  unsigned int size;
  for (unsigned int bin = 0, position = 0; bin < 256; ++bin, position += binWidth + binSpacing) {
      size = (bins[bin]/(float)max) * height;
      cv::rectangle(hist, cv::Point(position, height - 1), cv::Point(position + binWidth - 1, height - 1 -size), cv::Scalar(255), CV_FILLED);
    }

}

<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "backend.h"
#include "backendnode.h"

#include "audiooutput.h"
#include "effect.h"
#include "mediaobject.h"
#include "videowidget.h"
#include "volumeeffect.h"

//windows specific (DirectX Media Object)
#include <dmo.h>

#include <QtCore/QSettings>
#include <QtCore/QSet>
#include <QtCore/QVariant>

#include <QtCore/QtPlugin>

QT_BEGIN_NAMESPACE

Q_EXPORT_PLUGIN2(phonon_ds9, Phonon::DS9::Backend);

namespace Phonon
{
    namespace DS9
    {
        bool Backend::AudioMoniker::operator==(const AudioMoniker &other)
        {
            return other->IsEqual(*this) == S_OK;
        }

        Backend::Backend(QObject *parent, const QVariantList &)
            : QObject(parent)
        {
			::CoInitialize(0);

            //registering meta types
            qRegisterMetaType<HRESULT>("HRESULT");
            qRegisterMetaType<Graph>("Graph");
        }

        Backend::~Backend()
        {
            m_audioOutputs.clear();
            m_audioEffects.clear();
			::CoUninitialize();
        }

        QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
        {
            switch (c)
            {
            case MediaObjectClass:
                return new MediaObject(parent);
            case AudioOutputClass:
                return new AudioOutput(this, parent);
#ifndef QT_NO_PHONON_EFFECT
            case EffectClass:
                return new Effect(m_audioEffects[ args[0].toInt() ], parent);
#endif //QT_NO_PHONON_EFFECT
#ifndef QT_NO_PHONON_VIDEO
            case VideoWidgetClass:
                return new VideoWidget(qobject_cast<QWidget *>(parent));
#endif //QT_NO_PHONON_VIDEO
#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
            case VolumeFaderEffectClass:
                return new VolumeEffect(parent);
#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
            default:
                return 0;
            }
        }

        bool Backend::supportsVideo() const
        {
#ifndef QT_NO_PHONON_VIDEO
            return true;
#else
            return false;
#endif //QT_NO_PHONON_VIDEO
        }

        QStringList Backend::availableMimeTypes() const
        {
            QStringList ret;
            {
                QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\mplayer2\\mime types"), QSettings::NativeFormat);
                ret += settings.childGroups();
            }
            {
                QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\wmplayer\\mime types"), QSettings::NativeFormat);
                ret += settings.childGroups();
            }

            ret.removeDuplicates();
            ret.replaceInStrings("\\", "/");
            qSort(ret);
            return ret;
        }

		Filter Backend::getAudioOutputFilter(int index) const
		{
			Filter ret;
			if (index >= 0 && index < m_audioOutputs.count()) {
				m_audioOutputs.at(index)->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(&ret));
			} else {
				//just return the default audio renderer (not directsound)
				ret = Filter(CLSID_AudioRender, IID_IBaseFilter);
			}
			return ret;
		}

        QList<int> Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const
        {
            QList<int> ret;

            switch(type)
            {
            case Phonon::AudioOutputDeviceType:
                {
#ifdef Q_OS_WINCE
					ret << 0; // only one audio device with index 0
#else
					ComPointer<ICreateDevEnum> devEnum(CLSID_SystemDeviceEnum, IID_ICreateDevEnum);
					if (!devEnum) {
						return ret; //it is impossible to enumerate the devices
					}
                    ComPointer<IEnumMoniker> enumMon;
                    HRESULT hr = devEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, enumMon.pparam(), 0);
                    if (FAILED(hr)) {
                        break;
                    }
                    AudioMoniker mon;

                    //let's reorder the devices so that directshound appears first
                    int nbds = 0; //number of directsound devices

                    while (S_OK == enumMon->Next(1, mon.pparam(), 0)) {
                        LPOLESTR str = 0;
                        mon->GetDisplayName(0,0,&str);
                        const QString name = QString::fromUtf16((unsigned short*)str);
						ComPointer<IMalloc> alloc;
						::CoGetMalloc(1, alloc.pparam());
                        alloc->Free(str);

                        int insert_pos = 0;
                        if (!m_audioOutputs.contains(mon)) {
                            insert_pos = m_audioOutputs.count();
                            m_audioOutputs.append(mon);
                        } else {
                            insert_pos = m_audioOutputs.indexOf(mon);
                        }

                        if (name.contains(QLatin1String("DirectSound"))) {
                            ret.insert(nbds++, insert_pos);
                        } else {
                            ret.append(insert_pos);
                        }
                    }
#endif
					break;
                }
#ifndef QT_NO_PHONON_EFFECT
            case Phonon::EffectType:
                {
                    m_audioEffects.clear();
                    ComPointer<IEnumDMO> enumDMO;
                    HRESULT hr = ::DMOEnum(DMOCATEGORY_AUDIO_EFFECT, DMO_ENUMF_INCLUDE_KEYED, 0, 0, 0, 0, enumDMO.pparam());
                    if (SUCCEEDED(hr)) {
                        CLSID clsid;
                        while (S_OK == enumDMO->Next(1, &clsid, 0, 0)) {
                            ret += m_audioEffects.count();
                            m_audioEffects.append(clsid);
                        }
                    }
                    break;
                }
                break;
#endif //QT_NO_PHONON_EFFECT
            default:
                break;
            }
			return ret;
        }

        QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const
        {
            QHash<QByteArray, QVariant> ret;
            switch (type)
            {
            case Phonon::AudioOutputDeviceType:
                {
#ifdef Q_OS_WINCE
					ret["name"] = QLatin1String("default audio device");
#else
                    const AudioMoniker &mon = m_audioOutputs[index];
                    LPOLESTR str = 0;
                    HRESULT hr = mon->GetDisplayName(0,0, &str);
                    if (SUCCEEDED(hr)) {
                        QString name = QString::fromUtf16((unsigned short*)str);
						ComPointer<IMalloc> alloc;
						::CoGetMalloc(1, alloc.pparam());
                        alloc->Free(str);
                        ret["name"] = name.mid(name.indexOf('\\') + 1);
					}
#endif
                }
                break;
#ifndef QT_NO_PHONON_EFFECT
            case Phonon::EffectType:
                {
                    WCHAR name[80]; // 80 is clearly stated in the MSDN doc
                    HRESULT hr = ::DMOGetName(m_audioEffects[index], name);
                    if (SUCCEEDED(hr)) {
                        ret["name"] = QString::fromUtf16((unsigned short*)name);
                    }
                }
                break;
#endif //QT_NO_PHONON_EFFECT
            default:
                break;
            }
			return ret;
        }

        bool Backend::endConnectionChange(QSet<QObject *> objects)
        {
            if (objects.isEmpty())
                return true;
            //end of a transaction
            for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
                if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
                    MediaObject *mo = node->mediaObject();
                    if (mo) {
                        switch(mo->transactionState)
                        {
                        case Phonon::ErrorState:
                        case Phonon::StoppedState:
                        case Phonon::LoadingState:
                            //nothing to do
                            break;
                        case Phonon::PausedState:
                            mo->pause();
                            break;
                        default:
                            mo->play();
                            break;
                        }

                        return mo->state() != Phonon::ErrorState;
                    }
                }
            }

            return false;
        }

        bool Backend::startConnectionChange(QSet<QObject *> objects)
        {
            if (objects.isEmpty())
                return true;

            //let's save the state of the graph (before we stop it)
            for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
                if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
                    if (MediaObject *mo = node->mediaObject()) {

                        if (mo->state() != Phonon::StoppedState) {
                            mo->transactionState = mo->state();
                            mo->ensureStopped(); //we have to stop the graph..
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        bool Backend::connectNodes(QObject *_source, QObject *_sink)
        {
            BackendNode *source = qobject_cast<BackendNode*>(_source);
            if (!source) {
                return false;
            }
            BackendNode *sink = qobject_cast<BackendNode*>(_sink);
            if (!sink) {
                return false;
            }

            //setting the graph if needed
            if (source->mediaObject() == 0 && sink->mediaObject() == 0) {
                    //error: no graph selected
                    return false;
            } else if (source->mediaObject() && source->mediaObject() != sink->mediaObject()) {
                //this' graph becomes the common one
                source->mediaObject()->grabNode(sink);
            } else if (source->mediaObject() == 0) {
                //sink's graph becomes the common one
                sink->mediaObject()->grabNode(source);
            }

            return source->mediaObject()->connectNodes(source, sink);
        }

        bool Backend::disconnectNodes(QObject *_source, QObject *_sink)
        {
            BackendNode *source = qobject_cast<BackendNode*>(_source);
            if (!source) {
                return false;
            }
            BackendNode *sink = qobject_cast<BackendNode*>(_sink);
            if (!sink) {
                return false;
            }

            return source->mediaObject() == 0 ||
                source->mediaObject()->disconnectNodes(source, sink);
        }
    }
}

QT_END_NAMESPACE

#include "moc_backend.cpp"
<commit_msg>small mistake fixed in the detection of the connections<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "backend.h"
#include "backendnode.h"

#include "audiooutput.h"
#include "effect.h"
#include "mediaobject.h"
#include "videowidget.h"
#include "volumeeffect.h"

//windows specific (DirectX Media Object)
#include <dmo.h>

#include <QtCore/QSettings>
#include <QtCore/QSet>
#include <QtCore/QVariant>

#include <QtCore/QtPlugin>

QT_BEGIN_NAMESPACE

Q_EXPORT_PLUGIN2(phonon_ds9, Phonon::DS9::Backend);

namespace Phonon
{
    namespace DS9
    {
        bool Backend::AudioMoniker::operator==(const AudioMoniker &other)
        {
            return other->IsEqual(*this) == S_OK;
        }

        Backend::Backend(QObject *parent, const QVariantList &)
            : QObject(parent)
        {
			::CoInitialize(0);

            //registering meta types
            qRegisterMetaType<HRESULT>("HRESULT");
            qRegisterMetaType<Graph>("Graph");
        }

        Backend::~Backend()
        {
            m_audioOutputs.clear();
            m_audioEffects.clear();
			::CoUninitialize();
        }

        QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
        {
            switch (c)
            {
            case MediaObjectClass:
                return new MediaObject(parent);
            case AudioOutputClass:
                return new AudioOutput(this, parent);
#ifndef QT_NO_PHONON_EFFECT
            case EffectClass:
                return new Effect(m_audioEffects[ args[0].toInt() ], parent);
#endif //QT_NO_PHONON_EFFECT
#ifndef QT_NO_PHONON_VIDEO
            case VideoWidgetClass:
                return new VideoWidget(qobject_cast<QWidget *>(parent));
#endif //QT_NO_PHONON_VIDEO
#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
            case VolumeFaderEffectClass:
                return new VolumeEffect(parent);
#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
            default:
                return 0;
            }
        }

        bool Backend::supportsVideo() const
        {
#ifndef QT_NO_PHONON_VIDEO
            return true;
#else
            return false;
#endif //QT_NO_PHONON_VIDEO
        }

        QStringList Backend::availableMimeTypes() const
        {
            QStringList ret;
            {
                QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\mplayer2\\mime types"), QSettings::NativeFormat);
                ret += settings.childGroups();
            }
            {
                QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\wmplayer\\mime types"), QSettings::NativeFormat);
                ret += settings.childGroups();
            }

            ret.removeDuplicates();
            ret.replaceInStrings("\\", "/");
            qSort(ret);
            return ret;
        }

		Filter Backend::getAudioOutputFilter(int index) const
		{
			Filter ret;
			if (index >= 0 && index < m_audioOutputs.count()) {
				m_audioOutputs.at(index)->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(&ret));
			} else {
				//just return the default audio renderer (not directsound)
				ret = Filter(CLSID_AudioRender, IID_IBaseFilter);
			}
			return ret;
		}

        QList<int> Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const
        {
            QList<int> ret;

            switch(type)
            {
            case Phonon::AudioOutputDeviceType:
                {
#ifdef Q_OS_WINCE
					ret << 0; // only one audio device with index 0
#else
					ComPointer<ICreateDevEnum> devEnum(CLSID_SystemDeviceEnum, IID_ICreateDevEnum);
					if (!devEnum) {
						return ret; //it is impossible to enumerate the devices
					}
                    ComPointer<IEnumMoniker> enumMon;
                    HRESULT hr = devEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, enumMon.pparam(), 0);
                    if (FAILED(hr)) {
                        break;
                    }
                    AudioMoniker mon;

                    //let's reorder the devices so that directshound appears first
                    int nbds = 0; //number of directsound devices

                    while (S_OK == enumMon->Next(1, mon.pparam(), 0)) {
                        LPOLESTR str = 0;
                        mon->GetDisplayName(0,0,&str);
                        const QString name = QString::fromUtf16((unsigned short*)str);
						ComPointer<IMalloc> alloc;
						::CoGetMalloc(1, alloc.pparam());
                        alloc->Free(str);

                        int insert_pos = 0;
                        if (!m_audioOutputs.contains(mon)) {
                            insert_pos = m_audioOutputs.count();
                            m_audioOutputs.append(mon);
                        } else {
                            insert_pos = m_audioOutputs.indexOf(mon);
                        }

                        if (name.contains(QLatin1String("DirectSound"))) {
                            ret.insert(nbds++, insert_pos);
                        } else {
                            ret.append(insert_pos);
                        }
                    }
#endif
					break;
                }
#ifndef QT_NO_PHONON_EFFECT
            case Phonon::EffectType:
                {
                    m_audioEffects.clear();
                    ComPointer<IEnumDMO> enumDMO;
                    HRESULT hr = ::DMOEnum(DMOCATEGORY_AUDIO_EFFECT, DMO_ENUMF_INCLUDE_KEYED, 0, 0, 0, 0, enumDMO.pparam());
                    if (SUCCEEDED(hr)) {
                        CLSID clsid;
                        while (S_OK == enumDMO->Next(1, &clsid, 0, 0)) {
                            ret += m_audioEffects.count();
                            m_audioEffects.append(clsid);
                        }
                    }
                    break;
                }
                break;
#endif //QT_NO_PHONON_EFFECT
            default:
                break;
            }
			return ret;
        }

        QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const
        {
            QHash<QByteArray, QVariant> ret;
            switch (type)
            {
            case Phonon::AudioOutputDeviceType:
                {
#ifdef Q_OS_WINCE
					ret["name"] = QLatin1String("default audio device");
#else
                    const AudioMoniker &mon = m_audioOutputs[index];
                    LPOLESTR str = 0;
                    HRESULT hr = mon->GetDisplayName(0,0, &str);
                    if (SUCCEEDED(hr)) {
                        QString name = QString::fromUtf16((unsigned short*)str);
						ComPointer<IMalloc> alloc;
						::CoGetMalloc(1, alloc.pparam());
                        alloc->Free(str);
                        ret["name"] = name.mid(name.indexOf('\\') + 1);
					}
#endif
                }
                break;
#ifndef QT_NO_PHONON_EFFECT
            case Phonon::EffectType:
                {
                    WCHAR name[80]; // 80 is clearly stated in the MSDN doc
                    HRESULT hr = ::DMOGetName(m_audioEffects[index], name);
                    if (SUCCEEDED(hr)) {
                        ret["name"] = QString::fromUtf16((unsigned short*)name);
                    }
                }
                break;
#endif //QT_NO_PHONON_EFFECT
            default:
                break;
            }
			return ret;
        }

        bool Backend::endConnectionChange(QSet<QObject *> objects)
        {
            if (objects.isEmpty())
                return true;
            //end of a transaction
            for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
                if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
                    MediaObject *mo = node->mediaObject();
                    if (mo) {
                        switch(mo->transactionState)
                        {
                        case Phonon::ErrorState:
                        case Phonon::StoppedState:
                        case Phonon::LoadingState:
                            //nothing to do
                            break;
                        case Phonon::PausedState:
                            mo->pause();
                            break;
                        default:
                            mo->play();
                            break;
                        }

                        return mo->state() != Phonon::ErrorState;
                    }
                }
            }

            return false;
        }

        bool Backend::startConnectionChange(QSet<QObject *> objects)
        {
            if (objects.isEmpty())
                return true;

            //let's save the state of the graph (before we stop it)
            for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
                if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
                    if (MediaObject *mo = node->mediaObject()) {
                        if (mo->state() != Phonon::StoppedState) {
                            mo->transactionState = mo->state();
                            mo->ensureStopped(); //we have to stop the graph..
                        }
                        return true;
                    }
                }
            }

            return false;
        }

        bool Backend::connectNodes(QObject *_source, QObject *_sink)
        {
            BackendNode *source = qobject_cast<BackendNode*>(_source);
            if (!source) {
                return false;
            }
            BackendNode *sink = qobject_cast<BackendNode*>(_sink);
            if (!sink) {
                return false;
            }

            //setting the graph if needed
            if (source->mediaObject() == 0 && sink->mediaObject() == 0) {
                    //error: no graph selected
                    return false;
            } else if (source->mediaObject() && source->mediaObject() != sink->mediaObject()) {
                //this' graph becomes the common one
                source->mediaObject()->grabNode(sink);
            } else if (source->mediaObject() == 0) {
                //sink's graph becomes the common one
                sink->mediaObject()->grabNode(source);
            }

            return source->mediaObject()->connectNodes(source, sink);
        }

        bool Backend::disconnectNodes(QObject *_source, QObject *_sink)
        {
            BackendNode *source = qobject_cast<BackendNode*>(_source);
            if (!source) {
                return false;
            }
            BackendNode *sink = qobject_cast<BackendNode*>(_sink);
            if (!sink) {
                return false;
            }

            return source->mediaObject() == 0 ||
                source->mediaObject()->disconnectNodes(source, sink);
        }
    }
}

QT_END_NAMESPACE

#include "moc_backend.cpp"
<|endoftext|>


<commit_before>#ifndef SPARSE_AMT_HPP
#define SPARSE_AMT_HPP

#include "sparse.hpp"

namespace amt {

  template<class T, std::size_t ... Is, class Func>
  static constexpr std::array<T, sizeof...(Is)> unpack(std::index_sequence<Is...>,
                                                       const Func& func) {
    return {func(std::integral_constant<std::size_t, Is>{})...};
  }

  template<class T, std::size_t N, class Func>
  static constexpr std::array<T, N> unpack(const Func& func) {
    return unpack<T>(std::make_index_sequence<N>(), func);
  }

  template<class T, std::size_t level, std::size_t B, std::size_t L>
  struct node {
    static_assert(level > 0, "level error");
    static_assert(L > 0, "L error");
    static_assert(B > 0, "B error");

    static constexpr std::size_t max_size = 1ul << B;
    static_assert(max_size <= sizeof(std::size_t) * 8, "size error");

    static constexpr std::size_t shift = L + B * (level - 1ul);
    static constexpr std::size_t mask = (1ul << shift) - 1ul;

    using child_node = node<T, level - 1, B, L>;
    using children_type = sparse::array<child_node>;

    children_type children;

    struct split {
      const std::size_t sub;
      const std::size_t rest;

      split(std::size_t index):
        sub(index >> shift),
        rest(index & mask) {
        assert(sub < max_size);
      }
    };

    static children_type make_single(split index, const T& value) {
      return children_type().set(index.sub, child_node(index.rest, value));
    }

    node(std::size_t index, const T& value):
      children(make_single(index, value)) {
    }

    node(children_type children):
      children(std::move(children)) { }

    const T& get(split index) const {
      assert(children.contains(index.sub));
      return children.get(index.sub).get(index.rest);
    }

    node set(split index, const T& value) const {
      if(children.contains(index.sub)) {
        return children.set(index.sub, children.get(index.sub).set(index.rest, value));
      } else {
        return children.set(index.sub, child_node(index.rest, value));
      }
    }

    friend node emplace(node self, split index, const T& value) {
      if(!self.children.unique()) return self.set(index, value);

      // note: splitting inside function slightly increases perfs
      // TODO: investigate

      if(self.children.contains(index.sub)) {
        auto& child = self.children.get(index.sub);
        // since we're the only ref to children we may safely transfer their
        // ownership
        child = emplace(std::move(child), index.rest, value);
        return self;
      }

      return self.children.set(index.sub, child_node(index.rest, value));
    }

    template<class Cont>
    void iter(std::size_t offset, const Cont& cont) const {
      children.iter([&](std::size_t sub, const child_node& child) {
        child.iter(offset + (sub << shift), cont);
      });
    }

  };

  template<class T, std::size_t B, std::size_t L>
  struct node<T, 0, B, L> {
    static constexpr std::size_t level = 0;
    static constexpr std::size_t max_size = 1ul << L;
    static_assert(max_size <= sizeof(std::size_t) * 8, "size error");

    using children_type = sparse::array<T>;
    children_type children;

    node(std::size_t index, const T& value):
      children(children_type().set(index, value)) { }

    node(children_type children):
      children(std::move(children)) { }

    node(node&&) = default;
    node(const node&) = default;

    node& operator=(node&&) = default;
    node& operator=(const node&) = default;

    const T& get(std::size_t index) const {
      return children.get(index);
    }

    node set(std::size_t index, const T& value) const {
      return children.set(index, value);
    }

    friend node emplace(node self, std::size_t index, const T& value) {
      if(!self.children.unique()) return self.set(index, value);

      if(self.children.contains(index)) {
        self.children.get(index) = value;
        return self;
      }

      return self.children.set(index, value);
    }

    template<class Cont>
    void iter(std::size_t offset, const Cont& cont) const {
      children.iter([&](std::size_t index, const T& value) {
        cont(offset + index, value);
      });
    }

  };

  template<class T, std::size_t B, std::size_t L>
  class array {
    static constexpr std::size_t index_bits = sizeof(std::size_t) * 8;
    static constexpr std::size_t max_level = (index_bits - L) / B;

    using root_type = node<T, max_level, B, L>;
    root_type root;

  public:
    array(root_type root={{}}):
      root(std::move(root)) { }

    const T& get(std::size_t index) const {
      return root.get(index);
    }

    array set(std::size_t index, const T& value) const& {
       return root.set(index, value);
    }

    array set(std::size_t index, const T& value) && {
       // since we're a temporary we may safely transfer ownership
       return emplace(std::move(root), index, value);
    }

    template<class Cont>
    void iter(const Cont& cont) const {
      root.iter(0, cont);
    }

  };

  template<class K>
  struct traits;

  template<class K, class V, std::size_t B, std::size_t L>
  class map {
    using storage_type = array<V, B, L>;
    storage_type storage;
  public:
    map(storage_type storage={}): storage(std::move(storage)) { }

    const V& get(const K& key) const {
      return storage.get(traits<K>::index(key));
    }

    map set(const K& key, const V& value) const& {
       return storage.set(traits<K>::index(key), value);
    }

    map set(const K& key, const V& value) && {
       return std::move(storage).set(traits<K>::index(key), value);
    }

  };

  template<class T>
  struct traits<T*> {
    static std::size_t index(T* value) { return std::size_t(value); }
  };

  template<>
  struct traits<unsigned long> {
    static std::size_t index(std::size_t value) { return value; }
  };

  template<>
  struct traits<long> {
    static std::size_t index(long value) { return value; }
  };

  template<>
  struct traits<int> {
    static std::size_t index(int value) { return value; }
  };

  template<>
  struct traits<unsigned int> {
    static std::size_t index(unsigned int value) { return value; }
  };

}

#endif
<commit_msg>default type parameters<commit_after>#ifndef SPARSE_AMT_HPP
#define SPARSE_AMT_HPP

#include "sparse.hpp"

namespace amt {

  template<class T, std::size_t ... Is, class Func>
  static constexpr std::array<T, sizeof...(Is)> unpack(std::index_sequence<Is...>,
                                                       const Func& func) {
    return {func(std::integral_constant<std::size_t, Is>{})...};
  }

  template<class T, std::size_t N, class Func>
  static constexpr std::array<T, N> unpack(const Func& func) {
    return unpack<T>(std::make_index_sequence<N>(), func);
  }

  template<class T, std::size_t level, std::size_t B, std::size_t L>
  struct node {
    static_assert(level > 0, "level error");
    static_assert(L > 0, "L error");
    static_assert(B > 0, "B error");

    static constexpr std::size_t max_size = 1ul << B;
    static_assert(max_size <= sizeof(std::size_t) * 8, "size error");

    static constexpr std::size_t shift = L + B * (level - 1ul);
    static constexpr std::size_t mask = (1ul << shift) - 1ul;

    using child_node = node<T, level - 1, B, L>;
    using children_type = sparse::array<child_node>;

    children_type children;

    struct split {
      const std::size_t sub;
      const std::size_t rest;

      split(std::size_t index):
        sub(index >> shift),
        rest(index & mask) {
        assert(sub < max_size);
      }
    };

    static children_type make_single(split index, const T& value) {
      return children_type().set(index.sub, child_node(index.rest, value));
    }

    node(std::size_t index, const T& value):
      children(make_single(index, value)) {
    }

    node(children_type children):
      children(std::move(children)) { }

    const T& get(split index) const {
      assert(children.contains(index.sub));
      return children.get(index.sub).get(index.rest);
    }

    node set(split index, const T& value) const {
      if(children.contains(index.sub)) {
        return children.set(index.sub, children.get(index.sub).set(index.rest, value));
      } else {
        return children.set(index.sub, child_node(index.rest, value));
      }
    }

    friend node emplace(node self, split index, const T& value) {
      if(!self.children.unique()) return self.set(index, value);

      // note: splitting inside function slightly increases perfs
      // TODO: investigate

      if(self.children.contains(index.sub)) {
        auto& child = self.children.get(index.sub);
        // since we're the only ref to children we may safely transfer their
        // ownership
        child = emplace(std::move(child), index.rest, value);
        return self;
      }

      return self.children.set(index.sub, child_node(index.rest, value));
    }

    template<class Cont>
    void iter(std::size_t offset, const Cont& cont) const {
      children.iter([&](std::size_t sub, const child_node& child) {
        child.iter(offset + (sub << shift), cont);
      });
    }

  };

  template<class T, std::size_t B, std::size_t L>
  struct node<T, 0, B, L> {
    static constexpr std::size_t level = 0;
    static constexpr std::size_t max_size = 1ul << L;
    static_assert(max_size <= sizeof(std::size_t) * 8, "size error");

    using children_type = sparse::array<T>;
    children_type children;

    node(std::size_t index, const T& value):
      children(children_type().set(index, value)) { }

    node(children_type children):
      children(std::move(children)) { }

    node(node&&) = default;
    node(const node&) = default;

    node& operator=(node&&) = default;
    node& operator=(const node&) = default;

    const T& get(std::size_t index) const {
      return children.get(index);
    }

    node set(std::size_t index, const T& value) const {
      return children.set(index, value);
    }

    friend node emplace(node self, std::size_t index, const T& value) {
      if(!self.children.unique()) return self.set(index, value);

      if(self.children.contains(index)) {
        self.children.get(index) = value;
        return self;
      }

      return self.children.set(index, value);
    }

    template<class Cont>
    void iter(std::size_t offset, const Cont& cont) const {
      children.iter([&](std::size_t index, const T& value) {
        cont(offset + index, value);
      });
    }

  };

  template<class T, std::size_t B=6, std::size_t L=6>
  class array {
    static constexpr std::size_t index_bits = sizeof(std::size_t) * 8;
    static constexpr std::size_t max_level = (index_bits - L) / B;

    using root_type = node<T, max_level, B, L>;
    root_type root;

  public:
    array(root_type root={{}}):
      root(std::move(root)) { }

    const T& get(std::size_t index) const {
      return root.get(index);
    }

    array set(std::size_t index, const T& value) const& {
       return root.set(index, value);
    }

    array set(std::size_t index, const T& value) && {
       // since we're a temporary we may safely transfer ownership
       return emplace(std::move(root), index, value);
    }

    template<class Cont>
    void iter(const Cont& cont) const {
      root.iter(0, cont);
    }

    const T* find(std::size_t index) const {
      return root.find(index);
    }

  };

  template<class K>
  struct traits;

  template<class K, class V, std::size_t B=6, std::size_t L=6>
  class map {
    using storage_type = array<V, B, L>;
    storage_type storage;
  public:
    map(storage_type storage={}): storage(std::move(storage)) { }

    const V& get(const K& key) const {
      return storage.get(traits<K>::index(key));
    }

    map set(const K& key, const V& value) const& {
       return storage.set(traits<K>::index(key), value);
    }

    map set(const K& key, const V& value) && {
       return std::move(storage).set(traits<K>::index(key), value);
    }

    const V* find(const K& key) const {
      return storage.find(traits<K>::index(key));
    }

  };

  template<class T>
  struct traits<T*> {
    static std::size_t index(T* value) { return std::size_t(value); }
  };

  template<>
  struct traits<unsigned long> {
    static std::size_t index(std::size_t value) { return value; }
  };

  template<>
  struct traits<long> {
    static std::size_t index(long value) { return value; }
  };

  template<>
  struct traits<int> {
    static std::size_t index(int value) { return value; }
  };

  template<>
  struct traits<unsigned int> {
    static std::size_t index(unsigned int value) { return value; }
  };

}

#endif
<|endoftext|>


<commit_before>/// Implementation of the Number-Theoretical Transform in GF(P) Galois field
#include <iostream>
#include <algorithm>
#include <stdint.h>

#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
#define MY_CPU_AMD64
#endif

#if defined(MY_CPU_AMD64) || defined(_M_IA64)
#define MY_CPU_64BIT
#endif

typedef uint32_t ElementT;        // data items type, 32-bit unsigned integer for GF(P) computations with P>65536
typedef uint64_t DoubleElementT;  // twice wider type to hold intermediate results

template <ElementT P>
ElementT GF_Add (ElementT X, ElementT Y)
{
    ElementT res = X + Y;
    return res - ((res>=P)+(res<X))*P;   // (res>=P || res<X)? res-P : res;
}

template <ElementT P>
ElementT GF_Sub (ElementT X, ElementT Y)
{
    ElementT res = X - Y;
    return res + (res>X)*P;   // res<=X? res : res+P
}

#if 0
// Alternative GF_Mul64 implementation

#include <inttypes.h>
typedef unsigned __int128 uint128_t;
typedef uint128_t FourElement;    // 4x wider type to hold intermediate MUL results

template <ElementT P>
ElementT GF_Mul64 (ElementT X, ElementT Y)
{
    //return ElementT( (DoubleElementT(X)*Y) % P);
    DoubleElementT res = DoubleElementT(X)*Y;
    DoubleElementT invP = DoubleElementT((FourElement(1)<<64) / P);
    res -= DoubleElementT(((res)*FourElement(invP)) >> 64) * P;
    return ElementT(res>=P? res-P : res);
}

#else

// GF_Mul64 is optimized for 64-bit CPUs
template <ElementT P>
ElementT GF_Mul64 (ElementT X, ElementT Y)
{
    return ElementT( (DoubleElementT(X)*Y) % P);
}

#endif

// GF_Mul32 is optimized for 32-bit CPUs, SIMD and GPUs
template <ElementT P>
ElementT GF_Mul32 (ElementT X, ElementT Y)
{
    // invP32 := (2**64)/P - 2**32  :  if 2**31<P<2**32, then 2**32 < (2**64)/P < 2**33, and invP32 is a 32-bit value
    const DoubleElementT estInvP = ((DoubleElementT(1)<<63) / P) << 1;                          // == invP & (~1)
    const ElementT       invP32  = ElementT(estInvP*P > (estInvP+1)*P? estInvP : estInvP+1);    // we can't use 1<<64 for exact invP computation so, when required, we add one in other way
    DoubleElementT res = DoubleElementT(X)*Y;
    res  -=  ((res + (res>>32)*invP32) >> 32) * P;    // The same as res -= ((res*invP) >> 64) * P, where invP = (2**64)/P, but optimized for 32-bit computations
    return ElementT(res>=P? res-P : res);
}

#ifdef MY_CPU_64BIT
#define GF_Mul GF_Mul64
#else
#define GF_Mul GF_Mul32
#endif

template <typename T, T P>
void apply (T* data, size_t N, size_t SIZE, T root)
{
    T root_sqr = GF_Mul<P> (root, root);  // first root of power N of 1
    if (N>1024) {
        #pragma omp task
        apply<T,P> (data,   N/2, SIZE, root_sqr);
        #pragma omp task
        apply<T,P> (data+N, N/2, SIZE, root_sqr);
        #pragma omp taskwait
    } else if (N>1) {
        apply<T,P> (data,   N/2, SIZE, root_sqr);
        apply<T,P> (data+N, N/2, SIZE, root_sqr);
    }

    T root_i = root;   // first root of power 2N of 1
    for (size_t i=0; i<N*SIZE; i+=SIZE) {
        for (size_t k=0; k<SIZE; k++) {
            size_t i1 = i+k, i2 = i+k+N*SIZE;
            T temp   = GF_Mul<P> (root_i, data[i2]);
            data[i2] = GF_Sub<P> (data[i1], temp);
            data[i1] = GF_Add<P> (data[i1], temp);
        }
        root_i = GF_Mul<P> (root_i, root);  // next root of power 2N of 1
    }
}

template <size_t Exp, size_t SIZE, typename T, T P>
class NTT
{
    enum { N = 1<<Exp };
public:
    void ntt (T* data)
    {
        T root = 1557;                      // init 'root' with root of 1 of power 2**20 in GF(0xFFF00001)
        for (int i=20; --i>Exp; )
            root = GF_Mul<P> (root, root);  // find root of 1 of power 2N
        apply<T,P> (data, N, SIZE, root);
    }
};

// Find first root of 1 of power 2**N
template <typename T, T P>
void FindRoot (int N)
{
    for (T i=2; i<P; i++)
    {
        T q = i;
        for (int j=0; j<N; j++)
        {
            if (q==1)  goto next;
            q = GF_Mul<P> (q,q);
        }
        if (q==1)
        {
            std::cout << i << "\n";
            break;
        }
next:;
    }
}

// Test the GF_Mul32 correctness
template <ElementT P>
void Test_GF_Mul32()
{
    int n = 0;
    for (ElementT i=P; --i; )
    {
        std::cout << std::hex << "\r" << i << "...";
        for (ElementT j=i; --j; )
            if (GF_Mul64<P> (i,j)  !=  GF_Mul32<P> (i,j))
            {
                std::cout << std::hex << "\r" << i << "*" << j << "=" << GF_Mul64<P> (i,j) << " != " << GF_Mul32<P> (i,j) << "\n" ;
                if (++n>10) return;
            }
    }
}

int main()
{
    const ElementT P = 0xFFF00001;
    // Test_GF_Mul32<P>();
    // FindRoot<ElementT,P>(20);  // prints 1557

    const size_t SIZE = 128<<20;  // 512 MB
    ElementT *data = new ElementT[SIZE];
    for (int i=0; i<SIZE; i++)
        data[i] = i;
    NTT<19,SIZE/1048576,ElementT,P> transformer;
    #pragma omp parallel num_threads(16)
    #pragma omp single
    transformer.ntt(data);
    return 0;
}
<commit_msg>NTT: hand-optimized GF_Mul64 for MSVC improved speed by 5% more<commit_after>/// Implementation of the Number-Theoretical Transform in GF(P) Galois field
#include <iostream>
#include <algorithm>
#include <stdint.h>

#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
#define MY_CPU_AMD64
#endif

#if defined(MY_CPU_AMD64) || defined(_M_IA64)
#define MY_CPU_64BIT
#endif

typedef uint32_t ElementT;        // data items type, 32-bit unsigned integer for GF(P) computations with P>65536
typedef uint64_t DoubleElementT;  // twice wider type to hold intermediate results

template <ElementT P>
ElementT GF_Add (ElementT X, ElementT Y)
{
    ElementT res = X + Y;
    return res - ((res>=P)+(res<X))*P;   // (res>=P || res<X)? res-P : res;
}

template <ElementT P>
ElementT GF_Sub (ElementT X, ElementT Y)
{
    ElementT res = X - Y;
    return res + (res>X)*P;   // res<=X? res : res+P
}

#if 0
// Alternative GF_Mul64 implementation

#include <inttypes.h>
typedef unsigned __int128 uint128_t;
typedef uint128_t FourElement;    // 4x wider type to hold intermediate MUL results

template <ElementT P>
ElementT GF_Mul64 (ElementT X, ElementT Y)
{
    DoubleElementT res = DoubleElementT(X)*Y;
    DoubleElementT invP = DoubleElementT((FourElement(1)<<64) / P);
    res -= DoubleElementT(((res)*FourElement(invP)) >> 64) * P;
    return ElementT(res>=P? res-P : res);
}

#elif _MSC_VER

template <ElementT P>
ElementT GF_Mul64 (ElementT X, ElementT Y)
{
    const DoubleElementT estInvP = ((DoubleElementT(1)<<63) / P) << 1;
    const DoubleElementT invP    = (estInvP*P > (estInvP+1)*P? estInvP : estInvP+1);
    DoubleElementT res = DoubleElementT(X)*Y;
    res -= __umulh(res,invP) * P;
    return ElementT(res>=P? res-P : res);
}

#else

// GF_Mul64 is optimized for 64-bit CPUs
template <ElementT P>
ElementT GF_Mul64 (ElementT X, ElementT Y)
{
    return ElementT( (DoubleElementT(X)*Y) % P);
}

#endif

// GF_Mul32 is optimized for 32-bit CPUs, SIMD and GPUs
template <ElementT P>
ElementT GF_Mul32 (ElementT X, ElementT Y)
{
    // invP32 := (2**64)/P - 2**32  :  if 2**31<P<2**32, then 2**32 < (2**64)/P < 2**33, and invP32 is a 32-bit value
    const DoubleElementT estInvP = ((DoubleElementT(1)<<63) / P) << 1;                          // == invP & (~1)
    const ElementT       invP32  = ElementT(estInvP*P > (estInvP+1)*P? estInvP : estInvP+1);    // we can't use 1<<64 for exact invP computation so, when required, we add one in other way
    DoubleElementT res = DoubleElementT(X)*Y;
    res  -=  ((res + (res>>32)*invP32) >> 32) * P;    // The same as res -= ((res*invP) >> 64) * P, where invP = (2**64)/P, but optimized for 32-bit computations
    return ElementT(res>=P? res-P : res);
}

#ifdef MY_CPU_64BIT
#define GF_Mul GF_Mul64
#else
#define GF_Mul GF_Mul32
#endif

template <typename T, T P>
void apply (T* data, size_t N, size_t SIZE, T root)
{
    T root_sqr = GF_Mul<P> (root, root);  // first root of power N of 1
    if (N>1024) {
        #pragma omp task
        apply<T,P> (data,   N/2, SIZE, root_sqr);
        #pragma omp task
        apply<T,P> (data+N, N/2, SIZE, root_sqr);
        #pragma omp taskwait
    } else if (N>1) {
        apply<T,P> (data,   N/2, SIZE, root_sqr);
        apply<T,P> (data+N, N/2, SIZE, root_sqr);
    }

    T root_i = root;   // first root of power 2N of 1
    for (size_t i=0; i<N*SIZE; i+=SIZE) {
        for (size_t k=0; k<SIZE; k++) {
            size_t i1 = i+k, i2 = i+k+N*SIZE;
            T temp   = GF_Mul<P> (root_i, data[i2]);
            data[i2] = GF_Sub<P> (data[i1], temp);
            data[i1] = GF_Add<P> (data[i1], temp);
        }
        root_i = GF_Mul<P> (root_i, root);  // next root of power 2N of 1
    }
}

template <size_t Exp, size_t SIZE, typename T, T P>
class NTT
{
    enum { N = 1<<Exp };
public:
    void ntt (T* data)
    {
        T root = 1557;                      // init 'root' with root of 1 of power 2**20 in GF(0xFFF00001)
        for (int i=20; --i>Exp; )
            root = GF_Mul<P> (root, root);  // find root of 1 of power 2N
        apply<T,P> (data, N, SIZE, root);
    }
};

// Find first root of 1 of power 2**N
template <typename T, T P>
void FindRoot (int N)
{
    for (T i=2; i<P; i++)
    {
        T q = i;
        for (int j=0; j<N; j++)
        {
            if (q==1)  goto next;
            q = GF_Mul<P> (q,q);
        }
        if (q==1)
        {
            std::cout << i << "\n";
            break;
        }
next:;
    }
}

// Test the GF_Mul32 correctness
template <ElementT P>
void Test_GF_Mul32()
{
    int n = 0;
    for (ElementT i=P; --i; )
    {
        std::cout << std::hex << "\r" << i << "...";
        for (ElementT j=i; --j; )
            if (GF_Mul64<P> (i,j)  !=  GF_Mul32<P> (i,j))
            {
                std::cout << std::hex << "\r" << i << "*" << j << "=" << GF_Mul64<P> (i,j) << " != " << GF_Mul32<P> (i,j) << "\n" ;
                if (++n>10) return;
            }
    }
}

int main()
{
    const ElementT P = 0xFFF00001;
    // Test_GF_Mul32<P>();
    // FindRoot<ElementT,P>(20);  // prints 1557

    const size_t SIZE = 128<<20;  // 512 MB
    ElementT *data = new ElementT[SIZE];
    for (int i=0; i<SIZE; i++)
        data[i] = i;
    NTT<19,SIZE/1048576,ElementT,P> transformer;
    #pragma omp parallel num_threads(16)
    #pragma omp single
    transformer.ntt(data);
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>entities are automatically converted to prefab instance when creating prefab - closes #1068<commit_after><|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#pragma once
#include"ork/ork.hpp"

#if ORK_MSC
#pragma warning(push)
#pragma warning(disable:4061) //enum val not explicitly handled by a case label
#pragma warning(disable:4365) //return' signed/unsigned mismatch
#pragma warning(disable:4371) //layout changed
#pragma warning(disable:4623) //default constructor implicitly deleted
#pragma warning(disable:4625) //implicit copy constructor
#pragma warning(disable:4626) //implicit copy assignment
#pragma warning(disable:5026) //implicit move constructor
#pragma warning(disable:5027) //implicit move assignment
#pragma warning(disable:5039) //pointer or reference to throwing function passed to extern C function
#endif

#include"catch.hpp"

#if ORK_NEED_STL_SUPPRESS
#pragma warning(pop)
#endif
<commit_msg>Disabled warning for catch<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#pragma once
#include"ork/ork.hpp"

#if ORK_MSC
#pragma warning(push)
#pragma warning(disable:4061) //enum val not explicitly handled by a case label
#pragma warning(disable:4365) //return' signed/unsigned mismatch
#pragma warning(disable:4371) //layout changed
#pragma warning(disable:4583) //destructor is not implicitly called
#pragma warning(disable:4623) //default constructor implicitly deleted
#pragma warning(disable:4625) //implicit copy constructor
#pragma warning(disable:4626) //implicit copy assignment
#pragma warning(disable:5026) //implicit move constructor
#pragma warning(disable:5027) //implicit move assignment
#pragma warning(disable:5039) //pointer or reference to throwing function passed to extern C function
#endif

#include"catch.hpp"

#if ORK_NEED_STL_SUPPRESS
#pragma warning(pop)
#endif
<|endoftext|>


<commit_before>#include "box.hpp"

Vec LeesEdwardsBox::diff(Vec r1, Vec r2){
    flt Ly = boxsize[1];
    flt dy = r1[1]-r2[1];
    int im = (int) round(dy / Ly);
    dy = dy - (im*Ly);

    flt Lx = boxsize[0];
    flt dx = r1[0] - r2[0];
    dx = dx - round((dx/Lx)-im*gamma)*Lx-im*gamma*Lx;

    #ifdef VEC2D
    return Vec(dx, dy);
    #endif
    #ifdef VEC3D
    flt dz = remainder(r1[2] - r2[2], boxsize[2]);
    return Vec(dx, dy, dz);
    #endif
};

array<int,NDIM> LeesEdwardsBox::box_round(Vec r1, Vec r2){
    Vec dr = r1 - r2;
    array<int,NDIM> boxes;
    boxes[1] = (int) round(dr[1] / boxsize[1]);
    boxes[0] = (int) round((dr[0]/boxsize[0])-boxes[1]*gamma);
    #ifdef VEC3D
    boxes[2] = (int) round(dr[2] / boxsize[2]);
    #endif
    return boxes;
};

Vec LeesEdwardsBox::diff(Vec r1, Vec r2, array<int,NDIM> boxes){
    Vec dr = r1 - r2;
    dr[0] -= (boxes[0] + boxes[1]*gamma)*boxsize[0];
    dr[1] -= boxes[1]*boxsize[1];
    #ifdef VEC3D
    dr[2] -= boxes[2]*boxsize[2];
    #endif
    return dr;
}

SCbox::SCbox(flt L, flt R) : L(L), R(R){};

flt SCbox::V(){
    #ifdef VEC2D
    return R*L + R*R*M_PI;
    #else
    flt endcap = R*R*M_PI;
    return endcap*L + endcap*R*4/3;
    #endif
};

Vec SCbox::dist(Vec r1){
    // Vector to nearest point on central line
    if(r1[0] < -L/2) r1[0] += L/2;
    else if(r1[0] > L/2) r1[0] -= L/2;
    else r1[0] = 0;
    return r1;
};

Vec SCbox::edgedist(Vec r1){
    // Vector to nearest edge
    if(r1[0] < -L/2) r1[0] += L/2;
    else if(r1[0] > L/2) r1[0] -= L/2;
    else r1[0] = 0;

    flt dmag = r1.mag(); // distance to center
    if(dmag == 0){
        #ifdef VEC2D
        return Vec(0, R);
        #else
        return Vec(0, R, 0);
        #endif
    }
    return r1 * ((R-dmag)/dmag);
}

bool SCbox::inside(Vec r1, flt buffer){
    if(r1[0] < -L/2) r1[0] += L/2;
    else if(r1[0] > L/2) r1[0] -= L/2;
    else r1[0] = 0;
    flt newR = R - buffer;
    return r1.sq() < newR*newR;
};

Vec SCbox::randLoc(flt min_dist_to_wall){
    if(min_dist_to_wall >= R) return Vec();
    Vec v;
    flt Rmin = R - min_dist_to_wall;
    flt Rminsq = pow(Rmin, 2.0);
    while(true){
        v = randVecBoxed();
        v[0] -= 0.5;
        v[0] *= (L + 2*Rmin);

        v[1] -= 0.5;
        v[1] *= 2*Rmin;

        #ifndef VEC2D
        v[2] -= 0.5;
        v[2] *= 2*Rmin;
        #endif

        flt distsq = pow(v[1],2);
        if(abs(v[0]) >= L/2.0) distsq += pow(abs(v[0]) - L/2.0, 2.0);

        #ifndef VEC2D
        distsq += pow(v[2],2);
        #endif

        if(distsq <= Rminsq) break;
    };
    return v;
};

Vec atomgroup::com() const{
    Vec v = Vec();
    for(unsigned int i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        flt curmass = (*this)[i].m;
        v += (*this)[i].x * curmass;
    }
    return v / mass();
};

flt atomgroup::mass() const{
    flt m = 0;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        m += (*this)[i].m;
    }
    return m;
};

Vec atomgroup::comv() const {
    return momentum() / mass();
};

Vec atomgroup::momentum() const{
    Vec tot = Vec();
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        flt curmass = a.m;
        tot += a.v * curmass;
    }
    return tot;
};

flt atomgroup::gyradius() const{
    Vec avgr = Vec();
    for(uint i = 0; i<size(); i++){
        avgr += (*this)[i].x;
    }
    avgr /= size(); // now avgr is the average location, akin to c.o.m.
    flt Rgsq = 0;
    for(uint i = 0; i<size(); i++){
        Rgsq += ((*this)[i].x - avgr).sq();
    }

    return sqrt(Rgsq/size());
};

#ifdef VEC3D
Vec atomgroup::angmomentum(const Vec &loc, Box &box) const{
    Vec tot = Vec();
    for(uint i=0; i<size(); i++){
        flt curmass = (*this)[i].m;
        if(curmass <= 0 or curmass) continue;
        Vec newloc = box.diff((*this)[i].x, loc);
        tot += newloc.cross((*this)[i].v) * curmass; // r x v m = r x p
    }
    return tot;
};
#elif defined VEC2D
flt atomgroup::angmomentum(const Vec &loc, Box &box) const{
    flt tot = 0;
    Vec newloc;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        newloc = box.diff(a.x, loc);
        tot += newloc.cross(a.v) * a.m; // r x v m = r x p
    }
    return tot;
};
#endif

#ifdef VEC3D
flt atomgroup::moment(const Vec &loc, const Vec &axis, Box &box) const{
    if (axis.sq() == 0) return 0;
    flt tot = 0;
    Vec newloc;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        newloc = box.diff(a.x, loc).perpto(axis);
        tot += newloc.dot(newloc) * a.m;
    }
    return tot;
};

Matrix<flt> atomgroup::moment(const Vec &loc, Box &box) const{
    Matrix<flt> I;
    for(uint i=0; i<size(); i++){
        flt curmass = (*this)[i].m;
        if(curmass <= 0 or isinf(curmass)) continue;
        Vec r = box.diff((*this)[i].x, loc);
        flt x = r.getx(), y = r.gety(), z = r.getz();
        I[0][0] += curmass * (y*y + z*z);
        I[1][1] += curmass * (x*x + z*z);
        I[2][2] += curmass * (x*x + y*y);
        I[0][1] -= curmass * (x*y);
        I[0][2] -= curmass * (x*z);
        I[1][2] -= curmass * (y*z);
    }
    I[1][0] = I[0][1];
    I[2][0] = I[0][2];
    I[2][1] = I[1][2];
    return I;
};

Vec atomgroup::omega(const Vec &loc, Box &box) const{
    Matrix<flt> Inv = moment(loc, box).SymmetricInverse();
    return Inv * (angmomentum(loc, box));
};

void atomgroup::addOmega(Vec w, Vec loc, Box &box){
    for(uint i=0; i<size(); i++){
        Vec r = box.diff((*this)[i].x, loc);
        (*this)[i].v -= r.cross(w);
    }
};
#elif defined VEC2D
flt atomgroup::moment(const Vec &loc, Box &box) const{
    flt tot = 0;
    Vec newloc;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        newloc = box.diff(a.x, loc);
        tot += newloc.dot(newloc) * a.m;
    }
    return tot;
};

void atomgroup::addOmega(flt w, Vec loc, Box &box){
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        Vec r = box.diff(a.x, loc);
        a.v -= r.perp().norm()*w;
    }
};
#endif

flt atomgroup::kinetic(const Vec &originvelocity) const{
    flt totE = 0;
    Vec curv;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m == 0 or isinf(a.m)) continue;
        curv = a.v - originvelocity;
        totE += a.m/2 * curv.dot(curv);
    }
    return totE;
};

void atomgroup::addv(Vec v){
    for(uint i=0; i<size(); i++){
        (*this)[i].v += v;
    }
};

void atomgroup::randomize_velocities(flt T){
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m == 0 or isinf(a.m)) continue;
        a.v = randVec() * sqrt(T*NDIM/a.m);
    }
};

void atomgroup::resetForces(){
    for(uint i=0; i<size(); i++){
        (*this)[i].f = Vec();
    }
};

//~ void atomgroup::vverlet1(const flt dt){
    //~ for(uint i=0; i<size(); i++){
        //~ (*this)[i].x += (*this)[i].v * dt + (*this)[i].a * (dt*dt/2);
        //~ (*this)[i].v += (*this)[i].a * (dt/2);
    //~ }
//~ };

//~ void atomgroup::vverlet2(const flt dt){
    //~ for(uint i=0; i<size(); i++){
        //~ (*this)[i].v += (*this)[i].a * (dt/2);
    //~ }
//~ };

void LeesEdwardsBox::shear(flt dgamma, atomgroup &atoms){
    // TODO: is this right for non-square boxes?
    // Is gamma Δx / Lx or Δx / Ly?
    for(uint i=0; i<atoms.size(); i++){
        //flt dy = remainder(atoms[i].x[1], boxsize[1]);
        flt dy = atoms[i].x[1];
        atoms[i].x[0] += dy * dgamma;
    }

    gamma += dgamma;
};
<commit_msg>Fixed "isinf(curmass)" issue, pointed out by clang++<commit_after>#include "box.hpp"

Vec LeesEdwardsBox::diff(Vec r1, Vec r2){
    flt Ly = boxsize[1];
    flt dy = r1[1]-r2[1];
    int im = (int) round(dy / Ly);
    dy = dy - (im*Ly);

    flt Lx = boxsize[0];
    flt dx = r1[0] - r2[0];
    dx = dx - round((dx/Lx)-im*gamma)*Lx-im*gamma*Lx;

    #ifdef VEC2D
    return Vec(dx, dy);
    #endif
    #ifdef VEC3D
    flt dz = remainder(r1[2] - r2[2], boxsize[2]);
    return Vec(dx, dy, dz);
    #endif
};

array<int,NDIM> LeesEdwardsBox::box_round(Vec r1, Vec r2){
    Vec dr = r1 - r2;
    array<int,NDIM> boxes;
    boxes[1] = (int) round(dr[1] / boxsize[1]);
    boxes[0] = (int) round((dr[0]/boxsize[0])-boxes[1]*gamma);
    #ifdef VEC3D
    boxes[2] = (int) round(dr[2] / boxsize[2]);
    #endif
    return boxes;
};

Vec LeesEdwardsBox::diff(Vec r1, Vec r2, array<int,NDIM> boxes){
    Vec dr = r1 - r2;
    dr[0] -= (boxes[0] + boxes[1]*gamma)*boxsize[0];
    dr[1] -= boxes[1]*boxsize[1];
    #ifdef VEC3D
    dr[2] -= boxes[2]*boxsize[2];
    #endif
    return dr;
}

SCbox::SCbox(flt L, flt R) : L(L), R(R){};

flt SCbox::V(){
    #ifdef VEC2D
    return R*L + R*R*M_PI;
    #else
    flt endcap = R*R*M_PI;
    return endcap*L + endcap*R*4/3;
    #endif
};

Vec SCbox::dist(Vec r1){
    // Vector to nearest point on central line
    if(r1[0] < -L/2) r1[0] += L/2;
    else if(r1[0] > L/2) r1[0] -= L/2;
    else r1[0] = 0;
    return r1;
};

Vec SCbox::edgedist(Vec r1){
    // Vector to nearest edge
    if(r1[0] < -L/2) r1[0] += L/2;
    else if(r1[0] > L/2) r1[0] -= L/2;
    else r1[0] = 0;

    flt dmag = r1.mag(); // distance to center
    if(dmag == 0){
        #ifdef VEC2D
        return Vec(0, R);
        #else
        return Vec(0, R, 0);
        #endif
    }
    return r1 * ((R-dmag)/dmag);
}

bool SCbox::inside(Vec r1, flt buffer){
    if(r1[0] < -L/2) r1[0] += L/2;
    else if(r1[0] > L/2) r1[0] -= L/2;
    else r1[0] = 0;
    flt newR = R - buffer;
    return r1.sq() < newR*newR;
};

Vec SCbox::randLoc(flt min_dist_to_wall){
    if(min_dist_to_wall >= R) return Vec();
    Vec v;
    flt Rmin = R - min_dist_to_wall;
    flt Rminsq = pow(Rmin, 2.0);
    while(true){
        v = randVecBoxed();
        v[0] -= 0.5;
        v[0] *= (L + 2*Rmin);

        v[1] -= 0.5;
        v[1] *= 2*Rmin;

        #ifndef VEC2D
        v[2] -= 0.5;
        v[2] *= 2*Rmin;
        #endif

        flt distsq = pow(v[1],2);
        if(abs(v[0]) >= L/2.0) distsq += pow(abs(v[0]) - L/2.0, 2.0);

        #ifndef VEC2D
        distsq += pow(v[2],2);
        #endif

        if(distsq <= Rminsq) break;
    };
    return v;
};

Vec atomgroup::com() const{
    Vec v = Vec();
    for(unsigned int i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        flt curmass = (*this)[i].m;
        v += (*this)[i].x * curmass;
    }
    return v / mass();
};

flt atomgroup::mass() const{
    flt m = 0;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        m += (*this)[i].m;
    }
    return m;
};

Vec atomgroup::comv() const {
    return momentum() / mass();
};

Vec atomgroup::momentum() const{
    Vec tot = Vec();
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        flt curmass = a.m;
        tot += a.v * curmass;
    }
    return tot;
};

flt atomgroup::gyradius() const{
    Vec avgr = Vec();
    for(uint i = 0; i<size(); i++){
        avgr += (*this)[i].x;
    }
    avgr /= size(); // now avgr is the average location, akin to c.o.m.
    flt Rgsq = 0;
    for(uint i = 0; i<size(); i++){
        Rgsq += ((*this)[i].x - avgr).sq();
    }

    return sqrt(Rgsq/size());
};

#ifdef VEC3D
Vec atomgroup::angmomentum(const Vec &loc, Box &box) const{
    Vec tot = Vec();
    for(uint i=0; i<size(); i++){
        flt curmass = (*this)[i].m;
        if(curmass <= 0 or isinf(curmass)) continue;
        Vec newloc = box.diff((*this)[i].x, loc);
        tot += newloc.cross((*this)[i].v) * curmass; // r x v m = r x p
    }
    return tot;
};
#elif defined VEC2D
flt atomgroup::angmomentum(const Vec &loc, Box &box) const{
    flt tot = 0;
    Vec newloc;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        newloc = box.diff(a.x, loc);
        tot += newloc.cross(a.v) * a.m; // r x v m = r x p
    }
    return tot;
};
#endif

#ifdef VEC3D
flt atomgroup::moment(const Vec &loc, const Vec &axis, Box &box) const{
    if (axis.sq() == 0) return 0;
    flt tot = 0;
    Vec newloc;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        newloc = box.diff(a.x, loc).perpto(axis);
        tot += newloc.dot(newloc) * a.m;
    }
    return tot;
};

Matrix<flt> atomgroup::moment(const Vec &loc, Box &box) const{
    Matrix<flt> I;
    for(uint i=0; i<size(); i++){
        flt curmass = (*this)[i].m;
        if(curmass <= 0 or isinf(curmass)) continue;
        Vec r = box.diff((*this)[i].x, loc);
        flt x = r.getx(), y = r.gety(), z = r.getz();
        I[0][0] += curmass * (y*y + z*z);
        I[1][1] += curmass * (x*x + z*z);
        I[2][2] += curmass * (x*x + y*y);
        I[0][1] -= curmass * (x*y);
        I[0][2] -= curmass * (x*z);
        I[1][2] -= curmass * (y*z);
    }
    I[1][0] = I[0][1];
    I[2][0] = I[0][2];
    I[2][1] = I[1][2];
    return I;
};

Vec atomgroup::omega(const Vec &loc, Box &box) const{
    Matrix<flt> Inv = moment(loc, box).SymmetricInverse();
    return Inv * (angmomentum(loc, box));
};

void atomgroup::addOmega(Vec w, Vec loc, Box &box){
    for(uint i=0; i<size(); i++){
        Vec r = box.diff((*this)[i].x, loc);
        (*this)[i].v -= r.cross(w);
    }
};
#elif defined VEC2D
flt atomgroup::moment(const Vec &loc, Box &box) const{
    flt tot = 0;
    Vec newloc;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        newloc = box.diff(a.x, loc);
        tot += newloc.dot(newloc) * a.m;
    }
    return tot;
};

void atomgroup::addOmega(flt w, Vec loc, Box &box){
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m <= 0 or isinf(a.m)) continue;
        Vec r = box.diff(a.x, loc);
        a.v -= r.perp().norm()*w;
    }
};
#endif

flt atomgroup::kinetic(const Vec &originvelocity) const{
    flt totE = 0;
    Vec curv;
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m == 0 or isinf(a.m)) continue;
        curv = a.v - originvelocity;
        totE += a.m/2 * curv.dot(curv);
    }
    return totE;
};

void atomgroup::addv(Vec v){
    for(uint i=0; i<size(); i++){
        (*this)[i].v += v;
    }
};

void atomgroup::randomize_velocities(flt T){
    for(uint i=0; i<size(); i++){
        atom& a = (*this)[i];
        if(a.m == 0 or isinf(a.m)) continue;
        a.v = randVec() * sqrt(T*NDIM/a.m);
    }
};

void atomgroup::resetForces(){
    for(uint i=0; i<size(); i++){
        (*this)[i].f = Vec();
    }
};

//~ void atomgroup::vverlet1(const flt dt){
    //~ for(uint i=0; i<size(); i++){
        //~ (*this)[i].x += (*this)[i].v * dt + (*this)[i].a * (dt*dt/2);
        //~ (*this)[i].v += (*this)[i].a * (dt/2);
    //~ }
//~ };

//~ void atomgroup::vverlet2(const flt dt){
    //~ for(uint i=0; i<size(); i++){
        //~ (*this)[i].v += (*this)[i].a * (dt/2);
    //~ }
//~ };

void LeesEdwardsBox::shear(flt dgamma, atomgroup &atoms){
    // TODO: is this right for non-square boxes?
    // Is gamma Δx / Lx or Δx / Ly?
    for(uint i=0; i<atoms.size(); i++){
        //flt dy = remainder(atoms[i].x[1], boxsize[1]);
        flt dy = atoms[i].x[1];
        atoms[i].x[0] += dy * dgamma;
    }

    gamma += dgamma;
};
<|endoftext|>