<commit_before>/*
 * Copyright (c) 2012 Christoph Schulz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "zxing.h"
#include "image.h"
#include "util.h"
#include <zxing/LuminanceSource.h>
#include <zxing/Binarizer.h>
#include <zxing/BinaryBitmap.h>
#include <zxing/common/HybridBinarizer.h>
#include <zxing/common/HybridBinarizer.h>
#include <zxing/Result.h>
#include <zxing/ReaderException.h>
#include <zxing/MultiFormatReader.h>
#include <zxing/multi/GenericMultipleBarcodeReader.h>
#include <sstream>

using namespace v8;
using namespace node;

class PixSource : public zxing::LuminanceSource
{
public:
    PixSource(Pix* pix, bool take = false);
    ~PixSource();

    int getWidth() const;
    int getHeight() const;
    unsigned char* getRow(int y, unsigned char* row);
    unsigned char* getMatrix();

    bool isCropSupported() const;
    zxing::Ref<zxing::LuminanceSource> crop(int left, int top, int width, int height);
    bool isRotateSupported() const;
    zxing::Ref<zxing::LuminanceSource> rotateCounterClockwise();
    int getStraightLine(unsigned char *line, int nLengthMax, int x1,int y1,int x2,int y2);

private:
    PIX* pix_;
};

PixSource::PixSource(Pix* pix, bool take)
{
    if (take) {
        assert(pix->d == 8);
        pix_ = pix;
    } else {
        pix_ = pixConvertTo8(pix, 0);
    }
}

PixSource::~PixSource()
{
    pixDestroy(&pix_);
}

int PixSource::getWidth() const
{
    return pix_->w;
}

int PixSource::getHeight() const
{
    return pix_->h;
}

unsigned char* PixSource::getRow(int y, unsigned char* row)
{
    row = row ? row : new unsigned char[pix_->w];
    if (static_cast<uint32_t>(y) < pix_->h) {
        uint32_t *line = pix_->data + (pix_->wpl * y);
        unsigned char *r = row;
        for (uint32_t x = 0; x < pix_->w; ++x) {
            *r = GET_DATA_BYTE(line, x);
            ++r;
        }
    }
    return row;
}

unsigned char* PixSource::getMatrix()
{
    unsigned char* matrix = new unsigned char[pix_->w * pix_->h];
    unsigned char* m = matrix;
    uint32_t *line = pix_->data;
    for (uint32_t y = 0; y < pix_->h; ++y) {
        for (uint32_t x = 0; x < pix_->w; ++x) {
            *m = GET_DATA_BYTE(line, x);
            ++m;
        }
        line += pix_->wpl;
    }
    return matrix;
}

bool PixSource::isRotateSupported() const
{
    return true;
}

zxing::Ref<zxing::LuminanceSource> PixSource::rotateCounterClockwise()
{
    // Rotate 90 degree counterclockwise.
    if (pix_->w != 0 && pix_->h != 0) {
        Pix *rotatedPix = pixRotate90(pix_, -1);
        return zxing::Ref<PixSource>(new PixSource(rotatedPix, true));
    } else {
        return zxing::Ref<PixSource>(new PixSource(pix_));
    }
}

bool PixSource::isCropSupported() const
{
    return true;
}

zxing::Ref<zxing::LuminanceSource> PixSource::crop(int left, int top, int width, int height)
{
    BOX *box = boxCreate(left, top, width, height);
    PIX *croppedPix = pixClipRectangle(pix_, box, 0);
    boxDestroy(&box);
    return zxing::Ref<PixSource>(new PixSource(croppedPix, true));
}

//TODO: clean this code someday (more or less copied).
int PixSource::getStraightLine(unsigned char *line, int nLengthMax, int x1,int y1,int x2,int y2)
{
  int width = pix_->w;
  int height = pix_->h;
  int x,y,xDiff,yDiff,xDiffAbs,yDiffAbs,nMigr,dX,dY;
  int cnt;
  int nLength = nLengthMax;
  int nMigrGlob;

  if(x1 < 0 || x1 >= 0 + width || x2 < 0 || x2 >= 0 + width
     || y1 < 0 || y1 >= height || y2 < 0 || y2 >= 0 + height)
    return 0;

  x = x1;
  y = y1;
  cnt = 0;
  xDiff = x2 - x1;
  yDiff = y2 - y1;
  xDiffAbs = std::abs(xDiff);
  yDiffAbs = std::abs(yDiff);
  dX = dY = 1;
  if (xDiff < 0)
    dX = -1;
  if (yDiff < 0)
    dY = -1;

  nMigrGlob = nLength / 2;

  unsigned char* matrix = getMatrix();

  // horizontal dimension greater than vertical?
  if (xDiffAbs > yDiffAbs) {
    nMigr = xDiffAbs / 2;
    // distributes regularly <nLength> points of the straight line to line[]:
    while(cnt < nLength) {
      while(cnt < nLength && nMigrGlob > 0) {
        line[cnt] = matrix[(0 + y) * width + 0 + x];
        nMigrGlob -= xDiffAbs;
        cnt++;
      }
      while(nMigrGlob <= 0) {
        nMigrGlob += nLength;
        x += dX;
        nMigr -= yDiffAbs;
        if (nMigr < 0) {
          nMigr += xDiffAbs;
          y += dY;
        }
      }
    }
  }
  else {
    // vertical dimension greater than horizontal:
    nMigr = yDiffAbs / 2;

    while(cnt < nLength) {
      while(cnt < nLength && nMigrGlob > 0) {
        line[cnt] = matrix[(0 + y) * width + 0 + x];
        nMigrGlob -= yDiffAbs;
        cnt++;
      }
      while(nMigrGlob <= 0) {
        nMigrGlob += nLength;
        y += dY;
        nMigr -= xDiffAbs;
        if (nMigr < 0) {
          nMigr += yDiffAbs;
          x += dX;
        }
      }
    }
  }

  // last point?
  if (cnt < nLengthMax) {
    line[cnt] = matrix[(0 + y) * width + 0 + x];
    cnt++;
  }

  delete matrix;

  return cnt;
}

void ZXing::Init(Handle<Object> target)
{
    Local<FunctionTemplate> constructor_template = FunctionTemplate::New(New);
    constructor_template->SetClassName(String::NewSymbol("ZXing"));
    constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
    Local<ObjectTemplate> proto = constructor_template->PrototypeTemplate();
    proto->SetAccessor(String::NewSymbol("image"), GetImage, SetImage);
    proto->SetAccessor(String::NewSymbol("tryHarder"), GetTryHarder, SetTryHarder);
    proto->Set(String::NewSymbol("findCode"),
               FunctionTemplate::New(FindCode)->GetFunction());
    proto->Set(String::NewSymbol("findCodes"),
               FunctionTemplate::New(FindCodes)->GetFunction());
    target->Set(String::NewSymbol("ZXing"),
                Persistent<Function>::New(constructor_template->GetFunction()));
}

Handle<Value> ZXing::New(const Arguments &args)
{
    HandleScope scope;
    Local<Object> image;
    if (args.Length() == 1 && Image::HasInstance(args[0])) {
        image = args[0]->ToObject();
    } else if (args.Length() != 0) {
        return THROW(TypeError, "cannot convert argument list to "
                     "() or "
                     "(image: Image)");
    }
    ZXing* obj = new ZXing();
    if (!image.IsEmpty()) {
        obj->image_ = Persistent<Object>::New(image->ToObject());
    }
    obj->Wrap(args.This());
    return args.This();
}

Handle<Value> ZXing::GetImage(Local<String> prop, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    return obj->image_;
}

void ZXing::SetImage(Local<String> prop, Local<Value> value, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    if (Image::HasInstance(value)) {
        if (!obj->image_.IsEmpty()) {
            obj->image_.Dispose();
            obj->image_.Clear();
        }
        obj->image_ = Persistent<Object>::New(value->ToObject());
    } else {
        THROW(TypeError, "value must be of type Image");
    }
}

Handle<Value> ZXing::GetTryHarder(Local<String> prop, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    return Boolean::New(obj->hints_.getTryHarder());
}

void ZXing::SetTryHarder(Local<String> prop, Local<Value> value, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    if (value->IsBoolean()) {
        obj->hints_.setTryHarder(value->BooleanValue());
    } else {
        THROW(TypeError, "value must be of type bool");
    }
}

Handle<Value> ZXing::FindCode(const Arguments &args)
{
    HandleScope scope;
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(args.This());
    try {
        zxing::Ref<PixSource> source(new PixSource(Image::Pixels(obj->image_)));
        zxing::Ref<zxing::Binarizer> binarizer(new zxing::HybridBinarizer(source));
        zxing::Ref<zxing::BinaryBitmap> binary(new zxing::BinaryBitmap(binarizer));
        zxing::Ref<zxing::Result> result(obj->reader_->decodeWithState(binary));
        Local<Object> object = Object::New();
        object->Set(String::NewSymbol("type"), String::New(zxing::barcodeFormatNames[result->getBarcodeFormat()]));
        object->Set(String::NewSymbol("data"), String::New(result->getText()->getText().c_str()));
        Local<Array> points = Array::New();
        for (size_t i = 0; i < result->getResultPoints().size(); ++i) {
            Local<Object> point = Object::New();
            point->Set(String::NewSymbol("x"), Number::New(result->getResultPoints()[i]->getX()));
            point->Set(String::NewSymbol("y"), Number::New(result->getResultPoints()[i]->getY()));
            points->Set(i, point);
        }
        object->Set(String::NewSymbol("points"), points);
        return scope.Close(object);
    } catch (const zxing::ReaderException& e) {
        if (strcmp(e.what(), "No code detected") == 0) {
            return scope.Close(Null());
        } else {
            return THROW(Error, e.what());
        }
    } catch (const zxing::IllegalArgumentException& e) {
        return THROW(Error, e.what());
    } catch (const zxing::Exception& e) {
        return THROW(Error, e.what());
    } catch (const std::exception& e) {
        return THROW(Error, e.what());
    } catch (...) {
        return THROW(Error, "Uncaught exception");
    }
}

Handle<Value> ZXing::FindCodes(const Arguments &args)
{
    HandleScope scope;
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(args.This());
    try {
        zxing::Ref<PixSource> source(new PixSource(Image::Pixels(obj->image_)));
        zxing::Ref<zxing::Binarizer> binarizer(new zxing::HybridBinarizer(source));
        zxing::Ref<zxing::BinaryBitmap> binary(new zxing::BinaryBitmap(binarizer));
        std::vector< zxing::Ref<zxing::Result> > result = obj->multiReader_->decodeMultiple(binary, obj->hints_);
        Local<Array> objects = Array::New();
        for (size_t i = 0; i < result.size(); ++i) {
            Local<Object> object = Object::New();
            object->Set(String::NewSymbol("type"), String::New(zxing::barcodeFormatNames[result[i]->getBarcodeFormat()]));
            object->Set(String::NewSymbol("data"), String::New(result[i]->getText()->getText().c_str()));
            Local<Array> points = Array::New();
            for (size_t j = 0; j < result[i]->getResultPoints().size(); ++j) {
                Local<Object> point = Object::New();
                point->Set(String::NewSymbol("x"), Number::New(result[i]->getResultPoints()[j]->getX()));
                point->Set(String::NewSymbol("y"), Number::New(result[i]->getResultPoints()[j]->getY()));
                points->Set(j, point);
            }
            object->Set(String::NewSymbol("points"), points);
            objects->Set(i, object);
        }
        return scope.Close(objects);
    } catch (const zxing::ReaderException& e) {
        if (strcmp(e.what(), "No code detected") == 0) {
            return scope.Close(Array::New());
        } else {
            return THROW(Error, e.what());
        }
    } catch (const zxing::IllegalArgumentException& e) {
        return THROW(Error, e.what());
    } catch (const zxing::Exception& e) {
        return THROW(Error, e.what());
    } catch (const std::exception& e) {
        return THROW(Error, e.what());
    } catch (...) {
        return THROW(Error, "Uncaught exception");
    }
}

ZXing::ZXing()
    : hints_(zxing::DecodeHints::DEFAULT_HINT), reader_(new zxing::MultiFormatReader),
      multiReader_(new zxing::multi::GenericMultipleBarcodeReader(*reader_))
{
    //TODO: implement getters/setters for hints
    //hints_.addFormat(...)
    reader_->setHints(hints_);
}

ZXing::~ZXing()
{
}
<commit_msg>Fix gcc compile error<commit_after>/*
 * Copyright (c) 2012 Christoph Schulz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "zxing.h"
#include "image.h"
#include "util.h"
#include <zxing/LuminanceSource.h>
#include <zxing/Binarizer.h>
#include <zxing/BinaryBitmap.h>
#include <zxing/common/HybridBinarizer.h>
#include <zxing/common/HybridBinarizer.h>
#include <zxing/Result.h>
#include <zxing/ReaderException.h>
#include <zxing/MultiFormatReader.h>
#include <zxing/multi/GenericMultipleBarcodeReader.h>
#include <cstdlib>
#include <sstream>

using namespace v8;
using namespace node;

class PixSource : public zxing::LuminanceSource
{
public:
    PixSource(Pix* pix, bool take = false);
    ~PixSource();

    int getWidth() const;
    int getHeight() const;
    unsigned char* getRow(int y, unsigned char* row);
    unsigned char* getMatrix();

    bool isCropSupported() const;
    zxing::Ref<zxing::LuminanceSource> crop(int left, int top, int width, int height);
    bool isRotateSupported() const;
    zxing::Ref<zxing::LuminanceSource> rotateCounterClockwise();
    int getStraightLine(unsigned char *line, int nLengthMax, int x1,int y1,int x2,int y2);

private:
    PIX* pix_;
};

PixSource::PixSource(Pix* pix, bool take)
{
    if (take) {
        assert(pix->d == 8);
        pix_ = pix;
    } else {
        pix_ = pixConvertTo8(pix, 0);
    }
}

PixSource::~PixSource()
{
    pixDestroy(&pix_);
}

int PixSource::getWidth() const
{
    return pix_->w;
}

int PixSource::getHeight() const
{
    return pix_->h;
}

unsigned char* PixSource::getRow(int y, unsigned char* row)
{
    row = row ? row : new unsigned char[pix_->w];
    if (static_cast<uint32_t>(y) < pix_->h) {
        uint32_t *line = pix_->data + (pix_->wpl * y);
        unsigned char *r = row;
        for (uint32_t x = 0; x < pix_->w; ++x) {
            *r = GET_DATA_BYTE(line, x);
            ++r;
        }
    }
    return row;
}

unsigned char* PixSource::getMatrix()
{
    unsigned char* matrix = new unsigned char[pix_->w * pix_->h];
    unsigned char* m = matrix;
    uint32_t *line = pix_->data;
    for (uint32_t y = 0; y < pix_->h; ++y) {
        for (uint32_t x = 0; x < pix_->w; ++x) {
            *m = GET_DATA_BYTE(line, x);
            ++m;
        }
        line += pix_->wpl;
    }
    return matrix;
}

bool PixSource::isRotateSupported() const
{
    return true;
}

zxing::Ref<zxing::LuminanceSource> PixSource::rotateCounterClockwise()
{
    // Rotate 90 degree counterclockwise.
    if (pix_->w != 0 && pix_->h != 0) {
        Pix *rotatedPix = pixRotate90(pix_, -1);
        return zxing::Ref<PixSource>(new PixSource(rotatedPix, true));
    } else {
        return zxing::Ref<PixSource>(new PixSource(pix_));
    }
}

bool PixSource::isCropSupported() const
{
    return true;
}

zxing::Ref<zxing::LuminanceSource> PixSource::crop(int left, int top, int width, int height)
{
    BOX *box = boxCreate(left, top, width, height);
    PIX *croppedPix = pixClipRectangle(pix_, box, 0);
    boxDestroy(&box);
    return zxing::Ref<PixSource>(new PixSource(croppedPix, true));
}

//TODO: clean this code someday (more or less copied).
int PixSource::getStraightLine(unsigned char *line, int nLengthMax, int x1,int y1,int x2,int y2)
{
  int width = pix_->w;
  int height = pix_->h;
  int x,y,xDiff,yDiff,xDiffAbs,yDiffAbs,nMigr,dX,dY;
  int cnt;
  int nLength = nLengthMax;
  int nMigrGlob;

  if(x1 < 0 || x1 >= 0 + width || x2 < 0 || x2 >= 0 + width
     || y1 < 0 || y1 >= height || y2 < 0 || y2 >= 0 + height)
    return 0;

  x = x1;
  y = y1;
  cnt = 0;
  xDiff = x2 - x1;
  yDiff = y2 - y1;
  xDiffAbs = std::abs(xDiff);
  yDiffAbs = std::abs(yDiff);
  dX = dY = 1;
  if (xDiff < 0)
    dX = -1;
  if (yDiff < 0)
    dY = -1;

  nMigrGlob = nLength / 2;

  unsigned char* matrix = getMatrix();

  // horizontal dimension greater than vertical?
  if (xDiffAbs > yDiffAbs) {
    nMigr = xDiffAbs / 2;
    // distributes regularly <nLength> points of the straight line to line[]:
    while(cnt < nLength) {
      while(cnt < nLength && nMigrGlob > 0) {
        line[cnt] = matrix[(0 + y) * width + 0 + x];
        nMigrGlob -= xDiffAbs;
        cnt++;
      }
      while(nMigrGlob <= 0) {
        nMigrGlob += nLength;
        x += dX;
        nMigr -= yDiffAbs;
        if (nMigr < 0) {
          nMigr += xDiffAbs;
          y += dY;
        }
      }
    }
  }
  else {
    // vertical dimension greater than horizontal:
    nMigr = yDiffAbs / 2;

    while(cnt < nLength) {
      while(cnt < nLength && nMigrGlob > 0) {
        line[cnt] = matrix[(0 + y) * width + 0 + x];
        nMigrGlob -= yDiffAbs;
        cnt++;
      }
      while(nMigrGlob <= 0) {
        nMigrGlob += nLength;
        y += dY;
        nMigr -= xDiffAbs;
        if (nMigr < 0) {
          nMigr += yDiffAbs;
          x += dX;
        }
      }
    }
  }

  // last point?
  if (cnt < nLengthMax) {
    line[cnt] = matrix[(0 + y) * width + 0 + x];
    cnt++;
  }

  delete matrix;

  return cnt;
}

void ZXing::Init(Handle<Object> target)
{
    Local<FunctionTemplate> constructor_template = FunctionTemplate::New(New);
    constructor_template->SetClassName(String::NewSymbol("ZXing"));
    constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
    Local<ObjectTemplate> proto = constructor_template->PrototypeTemplate();
    proto->SetAccessor(String::NewSymbol("image"), GetImage, SetImage);
    proto->SetAccessor(String::NewSymbol("tryHarder"), GetTryHarder, SetTryHarder);
    proto->Set(String::NewSymbol("findCode"),
               FunctionTemplate::New(FindCode)->GetFunction());
    proto->Set(String::NewSymbol("findCodes"),
               FunctionTemplate::New(FindCodes)->GetFunction());
    target->Set(String::NewSymbol("ZXing"),
                Persistent<Function>::New(constructor_template->GetFunction()));
}

Handle<Value> ZXing::New(const Arguments &args)
{
    HandleScope scope;
    Local<Object> image;
    if (args.Length() == 1 && Image::HasInstance(args[0])) {
        image = args[0]->ToObject();
    } else if (args.Length() != 0) {
        return THROW(TypeError, "cannot convert argument list to "
                     "() or "
                     "(image: Image)");
    }
    ZXing* obj = new ZXing();
    if (!image.IsEmpty()) {
        obj->image_ = Persistent<Object>::New(image->ToObject());
    }
    obj->Wrap(args.This());
    return args.This();
}

Handle<Value> ZXing::GetImage(Local<String> prop, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    return obj->image_;
}

void ZXing::SetImage(Local<String> prop, Local<Value> value, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    if (Image::HasInstance(value)) {
        if (!obj->image_.IsEmpty()) {
            obj->image_.Dispose();
            obj->image_.Clear();
        }
        obj->image_ = Persistent<Object>::New(value->ToObject());
    } else {
        THROW(TypeError, "value must be of type Image");
    }
}

Handle<Value> ZXing::GetTryHarder(Local<String> prop, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    return Boolean::New(obj->hints_.getTryHarder());
}

void ZXing::SetTryHarder(Local<String> prop, Local<Value> value, const AccessorInfo &info)
{
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(info.This());
    if (value->IsBoolean()) {
        obj->hints_.setTryHarder(value->BooleanValue());
    } else {
        THROW(TypeError, "value must be of type bool");
    }
}

Handle<Value> ZXing::FindCode(const Arguments &args)
{
    HandleScope scope;
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(args.This());
    try {
        zxing::Ref<PixSource> source(new PixSource(Image::Pixels(obj->image_)));
        zxing::Ref<zxing::Binarizer> binarizer(new zxing::HybridBinarizer(source));
        zxing::Ref<zxing::BinaryBitmap> binary(new zxing::BinaryBitmap(binarizer));
        zxing::Ref<zxing::Result> result(obj->reader_->decodeWithState(binary));
        Local<Object> object = Object::New();
        object->Set(String::NewSymbol("type"), String::New(zxing::barcodeFormatNames[result->getBarcodeFormat()]));
        object->Set(String::NewSymbol("data"), String::New(result->getText()->getText().c_str()));
        Local<Array> points = Array::New();
        for (size_t i = 0; i < result->getResultPoints().size(); ++i) {
            Local<Object> point = Object::New();
            point->Set(String::NewSymbol("x"), Number::New(result->getResultPoints()[i]->getX()));
            point->Set(String::NewSymbol("y"), Number::New(result->getResultPoints()[i]->getY()));
            points->Set(i, point);
        }
        object->Set(String::NewSymbol("points"), points);
        return scope.Close(object);
    } catch (const zxing::ReaderException& e) {
        if (strcmp(e.what(), "No code detected") == 0) {
            return scope.Close(Null());
        } else {
            return THROW(Error, e.what());
        }
    } catch (const zxing::IllegalArgumentException& e) {
        return THROW(Error, e.what());
    } catch (const zxing::Exception& e) {
        return THROW(Error, e.what());
    } catch (const std::exception& e) {
        return THROW(Error, e.what());
    } catch (...) {
        return THROW(Error, "Uncaught exception");
    }
}

Handle<Value> ZXing::FindCodes(const Arguments &args)
{
    HandleScope scope;
    ZXing* obj = ObjectWrap::Unwrap<ZXing>(args.This());
    try {
        zxing::Ref<PixSource> source(new PixSource(Image::Pixels(obj->image_)));
        zxing::Ref<zxing::Binarizer> binarizer(new zxing::HybridBinarizer(source));
        zxing::Ref<zxing::BinaryBitmap> binary(new zxing::BinaryBitmap(binarizer));
        std::vector< zxing::Ref<zxing::Result> > result = obj->multiReader_->decodeMultiple(binary, obj->hints_);
        Local<Array> objects = Array::New();
        for (size_t i = 0; i < result.size(); ++i) {
            Local<Object> object = Object::New();
            object->Set(String::NewSymbol("type"), String::New(zxing::barcodeFormatNames[result[i]->getBarcodeFormat()]));
            object->Set(String::NewSymbol("data"), String::New(result[i]->getText()->getText().c_str()));
            Local<Array> points = Array::New();
            for (size_t j = 0; j < result[i]->getResultPoints().size(); ++j) {
                Local<Object> point = Object::New();
                point->Set(String::NewSymbol("x"), Number::New(result[i]->getResultPoints()[j]->getX()));
                point->Set(String::NewSymbol("y"), Number::New(result[i]->getResultPoints()[j]->getY()));
                points->Set(j, point);
            }
            object->Set(String::NewSymbol("points"), points);
            objects->Set(i, object);
        }
        return scope.Close(objects);
    } catch (const zxing::ReaderException& e) {
        if (strcmp(e.what(), "No code detected") == 0) {
            return scope.Close(Array::New());
        } else {
            return THROW(Error, e.what());
        }
    } catch (const zxing::IllegalArgumentException& e) {
        return THROW(Error, e.what());
    } catch (const zxing::Exception& e) {
        return THROW(Error, e.what());
    } catch (const std::exception& e) {
        return THROW(Error, e.what());
    } catch (...) {
        return THROW(Error, "Uncaught exception");
    }
}

ZXing::ZXing()
    : hints_(zxing::DecodeHints::DEFAULT_HINT), reader_(new zxing::MultiFormatReader),
      multiReader_(new zxing::multi::GenericMultipleBarcodeReader(*reader_))
{
    //TODO: implement getters/setters for hints
    //hints_.addFormat(...)
    reader_->setHints(hints_);
}

ZXing::~ZXing()
{
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2016, imec
 * All rights reserved.
 */

#include <random>
#include <memory>
#include <cstdio>
#include <iostream>
#include <climits>
#include <stdexcept>
#include <cmath>

#include "error.h"
#include "bpmf.h"
#include "io.h"

static const bool measure_perf = false;

std::ostream *Sys::os;
std::ostream *Sys::dbgs;

int Sys::procid = -1;
int Sys::nprocs = -1;

int Sys::nsims;
int Sys::burnin;
int Sys::update_freq;
double Sys::alpha = 2.0;

std::string Sys::odirname = "";

bool Sys::permute = true;
bool Sys::verbose = false;

// verifies that A has the same non-zero structure as B
void assert_same_struct(SparseMatrixD &A, SparseMatrixD &B)
{
    assert(A.cols() == B.cols());
    assert(A.rows() == B.rows());
    for(int i=0; i<A.cols(); ++i) assert(A.col(i).nonZeros() == B.col(i).nonZeros());
}

//
// Does predictions for prediction matrix T
// Computes RMSE (Root Means Square Error)
//
void Sys::predict(Sys& other, bool all)
{
    int n = (iter < burnin) ? 0 : (iter - burnin);

    double se(0.0); // squared err
    double se_avg(0.0); // squared avg err
    int nump = 0; // number of predictions

    int lo = from();
    int hi = to();
    if (all) {
#ifdef BPMF_REDUCE
        Sys::cout() << "WARNING: predict all items in test set not available in BPMF_REDUCE mode" << std::endl;
#else
        lo = 0;
        hi = num();
#endif
    }

    #pragma omp parallel for reduction(+:se,se_avg,nump)
    for(int k = lo; k<hi; k++) {
        for (Eigen::SparseMatrix<double>::InnerIterator it(T,k); it; ++it)
        {
#ifdef BPMF_REDUCE
            if (it.row() >= other.to() || it.row() < other.from())
                continue;
#endif
            auto m = items().col(it.col());
            auto u = other.items().col(it.row());

            assert(m.norm() > 0.0);
            assert(u.norm() > 0.0);

            const double pred = m.dot(u) + mean_rating;
            se += sqr(it.value() - pred);

            // update average prediction
            double &avg = Pavg.coeffRef(it.row(), it.col());
            double delta = pred - avg;
            avg = (n == 0) ? pred : (avg + delta/n);
            double &m2 = Pm2.coeffRef(it.row(), it.col());
            m2 = (n == 0) ? 0 : m2 + delta * (pred - avg);
            se_avg += sqr(it.value() - avg);

            nump++;
        }
    }

    rmse = sqrt( se / num_predict );
    rmse_avg = sqrt( se_avg / num_predict );
    num_predict = nump;
}

//
// Prints sampling progress
//
void Sys::print(double items_per_sec, double ratings_per_sec, double norm_u, double norm_m) {
  char buf[1024];
  std::string phase = (iter < Sys::burnin) ? "Burnin" : "Sampling";
  sprintf(buf, "%d: %s iteration %d:\t RMSE: %3.4f\tavg RMSE: %3.4f\tFU(%6.2f)\tFM(%6.2f)\titems/sec: %6.2f\tratings/sec: %6.2fM\n",
                    Sys::procid, phase.c_str(), iter, rmse, rmse_avg, norm_u, norm_m, items_per_sec, ratings_per_sec / 1e6);
  Sys::cout() << buf;
}

//
// Constructor with that reads MTX files
//
Sys::Sys(std::string name, std::string fname, std::string probename)
    : name(name), iter(-1), assigned(false), dom(nprocs+1)
{

    read_matrix(fname, M);
    read_matrix(probename, T);

    auto rows = std::max(M.rows(), T.rows());
    auto cols = std::max(M.cols(), T.cols());
    M.conservativeResize(rows,cols);
    T.conservativeResize(rows,cols);
    Pm2 = Pavg = Torig = T; // reference ratings and predicted ratings
    assert(M.rows() == Pavg.rows());
    assert(M.cols() == Pavg.cols());
    assert(Sys::nprocs <= (int)Sys::max_procs);
}

//
// Constructs Sys as transpose of existing Sys
//
Sys::Sys(std::string name, const SparseMatrixD &Mt, const SparseMatrixD &Pt) : name(name), iter(-1), assigned(false), dom(nprocs+1) {
    M = Mt.transpose();
    Pm2 = Pavg = T = Torig = Pt.transpose(); // reference ratings and predicted ratings
    assert(M.rows() == Pavg.rows());
    assert(M.cols() == Pavg.cols());
}

Sys::~Sys()
{
    if (measure_perf) {
        Sys::cout() << " --------------------\n";
        Sys::cout() << name << ": sampling times on " << procid << "\n";
        for(int i = from(); i<to(); ++i)
        {
            Sys::cout() << "\t" << nnz(i) << "\t" << sample_time.at(i) / nsims  << "\n";
        }
        Sys::cout() << " --------------------\n\n";
    }
}

bool Sys::has_prop_posterior() const
{
    return propMu.nonZeros() > 0;
}

void Sys::add_prop_posterior(std::string fnames)
{
    if (fnames.empty()) return;

    std::size_t pos = fnames.find_first_of(",");
    std::string mu_name = fnames.substr(0, pos);
    std::string lambda_name = fnames.substr(pos+1);

    read_matrix(mu_name, propMu);
    read_matrix(lambda_name, propLambda);

    assert(propMu.cols() == num());
    assert(propLambda.cols() == num());

    assert(propMu.rows() == num_latent);
    assert(propLambda.rows() == num_latent * num_latent);

}

//
// Intializes internal Matrices and Vectors
//
void Sys::init()
{
    //-- M
    assert(M.rows() > 0 && M.cols() > 0);
    mean_rating = M.sum() / M.nonZeros();
    items().setZero();
    sum.setZero();
    cov.setZero();
    norm = 0.;
    col_permutation.setIdentity(num());

#ifdef BPMF_REDUCE
    precMu = MatrixNXd::Zero(num_latent, num());
    precLambda = Eigen::MatrixXd::Zero(num_latent * num_latent, num());
#endif

    if (Sys::odirname.size())
    {
        aggrMu = Eigen::MatrixXd::Zero(num_latent, num());
        aggrLambda = Eigen::MatrixXd::Zero(num_latent * num_latent, num());
    }

    int count_larger_bp1 = 0;
    int count_larger_bp2 = 0;
    int count_sum = 0;
    for(int k = 0; k<M.cols(); k++) {
        int count = M.col(k).nonZeros();
        count_sum += count;
        if (count > breakpoint1) count_larger_bp1++;
        if (count > breakpoint2) count_larger_bp2++;
    }

    Sys::cout() << "mean rating: " << mean_rating << std::endl;
    Sys::cout() << "total number of ratings in train: " << M.nonZeros() << std::endl;
    Sys::cout() << "total number of ratings in test: " << T.nonZeros() << std::endl;
    Sys::cout() << "average ratings per row: " << (double)count_sum / (double)M.cols() << std::endl;
    Sys::cout() << "rows > break_point1: " << 100. * (double)count_larger_bp1 / (double)M.cols() << std::endl;
    Sys::cout() << "rows > break_point2: " << 100. * (double)count_larger_bp2 / (double)M.cols() << std::endl;
    Sys::cout() << "num " << name << ": " << num() << std::endl;
    if (has_prop_posterior())
    {
        Sys::cout() << "with propagated posterior" << std::endl;
    }

    if (measure_perf) sample_time.resize(num(), .0);
}

class PrecomputedLLT : public Eigen::LLT<MatrixNNd>
{
  public:
    void operator=(const MatrixNNd &m) { m_matrix = m; m_isInitialized = true; m_info = Eigen::Success; }
};

void Sys::preComputeMuLambda(const Sys &other)
{
    BPMF_COUNTER("preComputeMuLambda");
#pragma omp parallel for schedule(guided)
    for (int i = 0; i < num(); ++i)
    {
        VectorNd mu = VectorNd::Zero();
        MatrixNNd Lambda = MatrixNNd::Zero();
        computeMuLambda(i, other, mu, Lambda, true);
        precLambdaMatrix(i) = Lambda;
        precMu.col(i) = mu;
    }
}

void Sys::computeMuLambda(long idx, const Sys &other, VectorNd &rr, MatrixNNd &MM, bool local_only) const
{
    BPMF_COUNTER("computeMuLambda");
    for (SparseMatrixD::InnerIterator it(M, idx); it; ++it)
    {
        if (local_only && (it.row() < other.from() || it.row() >= other.to())) continue;
        auto col = other.items().col(it.row());
        MM.triangularView<Eigen::Upper>() += col * col.transpose();
        rr.noalias() += col * ((it.value() - mean_rating) * alpha);
    }
}

//
// Update ONE movie or one user
//
VectorNd Sys::sample(long idx, Sys &other)
{
    auto start = tick();
    rng.set_pos((idx+1) * num_latent * (iter+1));
    Sys::dbg() << "-- original start name: " << name << " iter: " << iter << " idx: " << idx << ": " << rng.counter << std::endl;

    VectorNd hp_mu;
    MatrixNNd hp_LambdaF;
    MatrixNNd hp_LambdaL;
    if (has_prop_posterior())
    {
        hp_mu = propMu.col(idx);
        hp_LambdaF = Eigen::Map<MatrixNNd>(propLambda.col(idx).data());
        hp_LambdaL =  hp_LambdaF.llt().matrixL();
    }
    else
    {
        hp_mu = hp.mu;
        hp_LambdaF = hp.LambdaF;
        hp_LambdaL = hp.LambdaL;
    }

    VectorNd rr = hp_LambdaF * hp.mu;                // vector num_latent x 1, we will use it in formula (14) from the paper
    MatrixNNd MM(MatrixNNd::Zero());
    PrecomputedLLT chol;                             // matrix num_latent x num_latent, chol="lambda_i with *" from formula (14)

#ifdef BPMF_REDUCE
    rr += precMu.col(idx);
    MM += precLambdaMatrix(idx);
#else
    computeMuLambda(idx, other, rr, MM, false);
#endif

    // copy upper -> lower part, matrix is symmetric.
    MM.triangularView<Eigen::Lower>() = MM.transpose();

    chol.compute(hp_LambdaF + alpha * MM);

    if(chol.info() != Eigen::Success) THROWERROR("Cholesky failed");

    // now we should calculate formula (14) from the paper
    // u_i for k-th iteration = Gaussian distribution N(u_i | mu_i with *, [lambda_i with *]^-1) =
    //                        = mu_i with * + s * [U]^-1,
    //                        where
    //                              s is a random vector with N(0, I),
    //                              mu_i with * is a vector num_latent x 1,
    //                              mu_i with * = [lambda_i with *]^-1 * rr,
    //                              lambda_i with * = L * U

    // Expression u_i = U \ (s + (L \ rr)) in Matlab looks for Eigen library like:

    chol.matrixL().solveInPlace(rr);                    // L*Y=rr => Y=L\rr, we store Y result again in rr vector
    rr += nrandn(num_latent);                           // rr=s+(L\rr), we store result again in rr vector
    chol.matrixU().solveInPlace(rr);                    // u_i=U\rr
    items().col(idx) = rr;                              // we save rr vector in items matrix (it is user features matrix)

    auto stop = tick();
    register_time(idx, 1e6 * (stop - start));
    //Sys::cout() << "  " << count << ": " << 1e6*(stop - start) << std::endl;

    assert(rr.norm() > .0);

    SHOW(rr.transpose());
    Sys::dbg() << "-- original done name: " << name << " iter: " << iter << " idx: " << idx << ": " << rng.counter << std::endl;

    return rr;
}

//
// update ALL movies / users in parallel
//
void Sys::sample(Sys &other)
{
    iter++;
    thread_vector<VectorNd>  sums(VectorNd::Zero()); // sum
    thread_vector<double>    norms(0.0); // squared norm
    thread_vector<MatrixNNd> prods(MatrixNNd::Zero()); // outer prod

    rng.set_pos(iter); // make this consistent
    sample_hp();
    SHOW(hp.mu.transpose());

#ifdef BPMF_REDUCE
    other.precMu.setZero();
    other.precLambda.setZero();
#endif

#pragma omp parallel for schedule(guided)
    for (int i = from(); i < to(); ++i)
    {
#pragma omp task
        {
            auto r = sample(i, other);

            MatrixNNd cov = (r * r.transpose());
            prods.local() += cov;
            sums.local() += r;
            norms.local() += r.squaredNorm();

            if (iter >= burnin && Sys::odirname.size())
            {
                aggrMu.col(i) += r;
                aggrLambda.col(i) += Eigen::Map<Eigen::VectorXd>(cov.data(), num_latent * num_latent);
            }

            send_item(i);
        }
    }
#pragma omp taskwait

#ifdef BPMF_REDUCE
    other.preComputeMuLambda(*this);
#endif

    VectorNd sum = sums.combine();
    MatrixNNd prod = prods.combine();
    norm = norms.combine();

    const int N = num();
    cov = (prod - (sum * sum.transpose() / N)) / (N-1);
}

void Sys::register_time(int i, double t)
{
    if (measure_perf) sample_time.at(i) += t;
}<commit_msg>WIP: only diagonal - no covariance<commit_after>/*
 * Copyright (c) 2014-2016, imec
 * All rights reserved.
 */

#include <random>
#include <memory>
#include <cstdio>
#include <iostream>
#include <climits>
#include <stdexcept>
#include <cmath>

#include "error.h"
#include "bpmf.h"
#include "io.h"

static const bool measure_perf = false;

std::ostream *Sys::os;
std::ostream *Sys::dbgs;

int Sys::procid = -1;
int Sys::nprocs = -1;

int Sys::nsims;
int Sys::burnin;
int Sys::update_freq;
double Sys::alpha = 2.0;

std::string Sys::odirname = "";

bool Sys::permute = true;
bool Sys::verbose = false;

// verifies that A has the same non-zero structure as B
void assert_same_struct(SparseMatrixD &A, SparseMatrixD &B)
{
    assert(A.cols() == B.cols());
    assert(A.rows() == B.rows());
    for(int i=0; i<A.cols(); ++i) assert(A.col(i).nonZeros() == B.col(i).nonZeros());
}

//
// Does predictions for prediction matrix T
// Computes RMSE (Root Means Square Error)
//
void Sys::predict(Sys& other, bool all)
{
    int n = (iter < burnin) ? 0 : (iter - burnin);

    double se(0.0); // squared err
    double se_avg(0.0); // squared avg err
    int nump = 0; // number of predictions

    int lo = from();
    int hi = to();
    if (all) {
#ifdef BPMF_REDUCE
        Sys::cout() << "WARNING: predict all items in test set not available in BPMF_REDUCE mode" << std::endl;
#else
        lo = 0;
        hi = num();
#endif
    }

    #pragma omp parallel for reduction(+:se,se_avg,nump)
    for(int k = lo; k<hi; k++) {
        for (Eigen::SparseMatrix<double>::InnerIterator it(T,k); it; ++it)
        {
#ifdef BPMF_REDUCE
            if (it.row() >= other.to() || it.row() < other.from())
                continue;
#endif
            auto m = items().col(it.col());
            auto u = other.items().col(it.row());

            assert(m.norm() > 0.0);
            assert(u.norm() > 0.0);

            const double pred = m.dot(u) + mean_rating;
            se += sqr(it.value() - pred);

            // update average prediction
            double &avg = Pavg.coeffRef(it.row(), it.col());
            double delta = pred - avg;
            avg = (n == 0) ? pred : (avg + delta/n);
            double &m2 = Pm2.coeffRef(it.row(), it.col());
            m2 = (n == 0) ? 0 : m2 + delta * (pred - avg);
            se_avg += sqr(it.value() - avg);

            nump++;
        }
    }

    rmse = sqrt( se / num_predict );
    rmse_avg = sqrt( se_avg / num_predict );
    num_predict = nump;
}

//
// Prints sampling progress
//
void Sys::print(double items_per_sec, double ratings_per_sec, double norm_u, double norm_m) {
  char buf[1024];
  std::string phase = (iter < Sys::burnin) ? "Burnin" : "Sampling";
  sprintf(buf, "%d: %s iteration %d:\t RMSE: %3.4f\tavg RMSE: %3.4f\tFU(%6.2f)\tFM(%6.2f)\titems/sec: %6.2f\tratings/sec: %6.2fM\n",
                    Sys::procid, phase.c_str(), iter, rmse, rmse_avg, norm_u, norm_m, items_per_sec, ratings_per_sec / 1e6);
  Sys::cout() << buf;
}

//
// Constructor with that reads MTX files
//
Sys::Sys(std::string name, std::string fname, std::string probename)
    : name(name), iter(-1), assigned(false), dom(nprocs+1)
{

    read_matrix(fname, M);
    read_matrix(probename, T);

    auto rows = std::max(M.rows(), T.rows());
    auto cols = std::max(M.cols(), T.cols());
    M.conservativeResize(rows,cols);
    T.conservativeResize(rows,cols);
    Pm2 = Pavg = Torig = T; // reference ratings and predicted ratings
    assert(M.rows() == Pavg.rows());
    assert(M.cols() == Pavg.cols());
    assert(Sys::nprocs <= (int)Sys::max_procs);
}

//
// Constructs Sys as transpose of existing Sys
//
Sys::Sys(std::string name, const SparseMatrixD &Mt, const SparseMatrixD &Pt) : name(name), iter(-1), assigned(false), dom(nprocs+1) {
    M = Mt.transpose();
    Pm2 = Pavg = T = Torig = Pt.transpose(); // reference ratings and predicted ratings
    assert(M.rows() == Pavg.rows());
    assert(M.cols() == Pavg.cols());
}

Sys::~Sys()
{
    if (measure_perf) {
        Sys::cout() << " --------------------\n";
        Sys::cout() << name << ": sampling times on " << procid << "\n";
        for(int i = from(); i<to(); ++i)
        {
            Sys::cout() << "\t" << nnz(i) << "\t" << sample_time.at(i) / nsims  << "\n";
        }
        Sys::cout() << " --------------------\n\n";
    }
}

bool Sys::has_prop_posterior() const
{
    return propMu.nonZeros() > 0;
}

void Sys::add_prop_posterior(std::string fnames)
{
    if (fnames.empty()) return;

    std::size_t pos = fnames.find_first_of(",");
    std::string mu_name = fnames.substr(0, pos);
    std::string lambda_name = fnames.substr(pos+1);

    read_matrix(mu_name, propMu);
    read_matrix(lambda_name, propLambda);

    assert(propMu.cols() == num());
    assert(propLambda.cols() == num());

    assert(propMu.rows() == num_latent);
    assert(propLambda.rows() == num_latent * num_latent);

}

//
// Intializes internal Matrices and Vectors
//
void Sys::init()
{
    //-- M
    assert(M.rows() > 0 && M.cols() > 0);
    mean_rating = M.sum() / M.nonZeros();
    items().setZero();
    sum.setZero();
    cov.setZero();
    norm = 0.;
    col_permutation.setIdentity(num());

#ifdef BPMF_REDUCE
    precMu = MatrixNXd::Zero(num_latent, num());
    precLambda = Eigen::MatrixXd::Zero(num_latent * num_latent, num());
#endif

    if (Sys::odirname.size())
    {
        aggrMu = Eigen::MatrixXd::Zero(num_latent, num());
        aggrLambda = Eigen::MatrixXd::Zero(num_latent * num_latent, num());
    }

    int count_larger_bp1 = 0;
    int count_larger_bp2 = 0;
    int count_sum = 0;
    for(int k = 0; k<M.cols(); k++) {
        int count = M.col(k).nonZeros();
        count_sum += count;
        if (count > breakpoint1) count_larger_bp1++;
        if (count > breakpoint2) count_larger_bp2++;
    }

    Sys::cout() << "mean rating: " << mean_rating << std::endl;
    Sys::cout() << "total number of ratings in train: " << M.nonZeros() << std::endl;
    Sys::cout() << "total number of ratings in test: " << T.nonZeros() << std::endl;
    Sys::cout() << "average ratings per row: " << (double)count_sum / (double)M.cols() << std::endl;
    Sys::cout() << "rows > break_point1: " << 100. * (double)count_larger_bp1 / (double)M.cols() << std::endl;
    Sys::cout() << "rows > break_point2: " << 100. * (double)count_larger_bp2 / (double)M.cols() << std::endl;
    Sys::cout() << "num " << name << ": " << num() << std::endl;
    if (has_prop_posterior())
    {
        Sys::cout() << "with propagated posterior" << std::endl;
    }

    if (measure_perf) sample_time.resize(num(), .0);
}

class PrecomputedLLT : public Eigen::LLT<MatrixNNd>
{
  public:
    void operator=(const MatrixNNd &m) { m_matrix = m; m_isInitialized = true; m_info = Eigen::Success; }
};

void Sys::preComputeMuLambda(const Sys &other)
{
    BPMF_COUNTER("preComputeMuLambda");
#pragma omp parallel for schedule(guided)
    for (int i = 0; i < num(); ++i)
    {
        VectorNd mu = VectorNd::Zero();
        MatrixNNd Lambda = MatrixNNd::Zero();
        computeMuLambda(i, other, mu, Lambda, true);
        precLambdaMatrix(i) = Lambda;
        precMu.col(i) = mu;
    }
}

void Sys::computeMuLambda(long idx, const Sys &other, VectorNd &rr, MatrixNNd &MM, bool local_only) const
{
    BPMF_COUNTER("computeMuLambda");
    for (SparseMatrixD::InnerIterator it(M, idx); it; ++it)
    {
        if (local_only && (it.row() < other.from() || it.row() >= other.to())) continue;
        auto col = other.items().col(it.row());
        MM.triangularView<Eigen::Upper>() += col * col.transpose();
        rr.noalias() += col * ((it.value() - mean_rating) * alpha);
    }
}

//
// Update ONE movie or one user
//
VectorNd Sys::sample(long idx, Sys &other)
{
    auto start = tick();
    rng.set_pos((idx+1) * num_latent * (iter+1));
    Sys::dbg() << "-- original start name: " << name << " iter: " << iter << " idx: " << idx << ": " << rng.counter << std::endl;

    VectorNd hp_mu;
    MatrixNNd hp_LambdaF;
    MatrixNNd hp_LambdaL;
    if (has_prop_posterior())
    {
        hp_mu = propMu.col(idx);
        hp_LambdaF = Eigen::Map<MatrixNNd>(propLambda.col(idx).data());
        hp_LambdaL =  hp_LambdaF.llt().matrixL();
    }
    else
    {
        hp_mu = hp.mu;
        hp_LambdaF = hp.LambdaF;
        hp_LambdaL = hp.LambdaL;
    }

    VectorNd rr = hp_LambdaF * hp.mu;                // vector num_latent x 1, we will use it in formula (14) from the paper
    MatrixNNd MM(MatrixNNd::Zero());
    PrecomputedLLT chol;                             // matrix num_latent x num_latent, chol="lambda_i with *" from formula (14)

#ifdef BPMF_REDUCE
    rr += precMu.col(idx);
    MM += precLambdaMatrix(idx);
#else
    computeMuLambda(idx, other, rr, MM, false);
#endif

#ifdef BPMF_NO_COVARIANCE
    // only keep diagonal --
    MM = MM.diagonal().asDiagonal();
#else
    // copy upper -> lower part, matrix is symmetric.
    MM.triangularView<Eigen::Lower>() = MM.transpose();
#endif

    chol.compute(hp_LambdaF + alpha * MM);

    if(chol.info() != Eigen::Success) THROWERROR("Cholesky failed");

    // now we should calculate formula (14) from the paper
    // u_i for k-th iteration = Gaussian distribution N(u_i | mu_i with *, [lambda_i with *]^-1) =
    //                        = mu_i with * + s * [U]^-1,
    //                        where
    //                              s is a random vector with N(0, I),
    //                              mu_i with * is a vector num_latent x 1,
    //                              mu_i with * = [lambda_i with *]^-1 * rr,
    //                              lambda_i with * = L * U

    // Expression u_i = U \ (s + (L \ rr)) in Matlab looks for Eigen library like:

    chol.matrixL().solveInPlace(rr);                    // L*Y=rr => Y=L\rr, we store Y result again in rr vector
    rr += nrandn(num_latent);                           // rr=s+(L\rr), we store result again in rr vector
    chol.matrixU().solveInPlace(rr);                    // u_i=U\rr
    items().col(idx) = rr;                              // we save rr vector in items matrix (it is user features matrix)

    auto stop = tick();
    register_time(idx, 1e6 * (stop - start));
    //Sys::cout() << "  " << count << ": " << 1e6*(stop - start) << std::endl;

    assert(rr.norm() > .0);

    SHOW(rr.transpose());
    Sys::dbg() << "-- original done name: " << name << " iter: " << iter << " idx: " << idx << ": " << rng.counter << std::endl;

    return rr;
}

//
// update ALL movies / users in parallel
//
void Sys::sample(Sys &other)
{
    iter++;
    thread_vector<VectorNd>  sums(VectorNd::Zero()); // sum
    thread_vector<double>    norms(0.0); // squared norm
    thread_vector<MatrixNNd> prods(MatrixNNd::Zero()); // outer prod

    rng.set_pos(iter); // make this consistent
    sample_hp();
    SHOW(hp.mu.transpose());

#ifdef BPMF_REDUCE
    other.precMu.setZero();
    other.precLambda.setZero();
#endif

#pragma omp parallel for schedule(guided)
    for (int i = from(); i < to(); ++i)
    {
#pragma omp task
        {
            auto r = sample(i, other);

            MatrixNNd cov = (r * r.transpose());
            prods.local() += cov;
            sums.local() += r;
            norms.local() += r.squaredNorm();

            if (iter >= burnin && Sys::odirname.size())
            {
                aggrMu.col(i) += r;
                aggrLambda.col(i) += Eigen::Map<Eigen::VectorXd>(cov.data(), num_latent * num_latent);
            }

            send_item(i);
        }
    }
#pragma omp taskwait

#ifdef BPMF_REDUCE
    other.preComputeMuLambda(*this);
#endif

    VectorNd sum = sums.combine();
    MatrixNNd prod = prods.combine();
    norm = norms.combine();

    const int N = num();
    cov = (prod - (sum * sum.transpose() / N)) / (N-1);
}

void Sys::register_time(int i, double t)
{
    if (measure_perf) sample_time.at(i) += t;
}<|endoftext|>


<commit_before>#pragma once
#include <eosio/chain/block_state.hpp>
#include <eosio/chain/trace.hpp>
#include <eosio/chain/genesis_state.hpp>
#include <chainbase/pinnable_mapped_file.hpp>
#include <boost/signals2/signal.hpp>

#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/account_object.hpp>
#include <eosio/chain/snapshot.hpp>
#include <eosio/chain/protocol_feature_manager.hpp>

namespace chainbase {
   class database;
}
namespace boost { namespace asio {
   class thread_pool;
}}

namespace eosio { namespace chain {

   class authorization_manager;

   namespace resource_limits {
      class resource_limits_manager;
   };

   struct controller_impl;
   using chainbase::database;
   using chainbase::pinnable_mapped_file;
   using boost::signals2::signal;

   class dynamic_global_property_object;
   class global_property_object;
   class permission_object;
   class account_object;
   using resource_limits::resource_limits_manager;
   using apply_handler = std::function<void(apply_context&)>;
   using unapplied_transactions_type = map<transaction_id_type, transaction_metadata_ptr, sha256_less>;

   class fork_database;

   enum class db_read_mode {
      SPECULATIVE,
      HEAD,
      READ_ONLY,
      IRREVERSIBLE
   };

   enum class validation_mode {
      FULL,
      LIGHT
   };

   class controller {
      public:

         struct config {
            flat_set<account_name>   sender_bypass_whiteblacklist;
            flat_set<account_name>   actor_whitelist;
            flat_set<account_name>   actor_blacklist;
            flat_set<account_name>   contract_whitelist;
            flat_set<account_name>   contract_blacklist;
            flat_set< pair<account_name, action_name> > action_blacklist;
            flat_set<public_key_type> key_blacklist;
            path                     blocks_dir             =  chain::config::default_blocks_dir_name;
            path                     state_dir              =  chain::config::default_state_dir_name;
            uint64_t                 state_size             =  chain::config::default_state_size;
            uint64_t                 state_guard_size       =  chain::config::default_state_guard_size;
            uint64_t                 reversible_cache_size  =  chain::config::default_reversible_cache_size;
            uint64_t                 reversible_guard_size  =  chain::config::default_reversible_guard_size;
            uint32_t                 sig_cpu_bill_pct       =  chain::config::default_sig_cpu_bill_pct;
            uint16_t                 thread_pool_size       =  chain::config::default_controller_thread_pool_size;
            bool                     read_only              =  false;
            bool                     force_all_checks       =  false;
            bool                     disable_replay_opts    =  false;
            bool                     contracts_console      =  false;
            bool                     allow_ram_billing_in_notify = false;
            bool                     disable_all_subjective_mitigations = false; //< for testing purposes only

            genesis_state            genesis;
            wasm_interface::vm_type  wasm_runtime = chain::config::default_wasm_runtime;

            db_read_mode             read_mode              = db_read_mode::SPECULATIVE;
            validation_mode          block_validation_mode  = validation_mode::FULL;

            pinnable_mapped_file::map_mode db_map_mode      = pinnable_mapped_file::map_mode::mapped;
            vector<string>           db_hugepage_paths;

            flat_set<account_name>   resource_greylist;
            flat_set<account_name>   trusted_producers;
            uint32_t                 greylist_limit         = chain::config::maximum_elastic_resource_multiplier;
         };

         enum class block_status {
            irreversible = 0, ///< this block has already been applied before by this node and is considered irreversible
            validated   = 1, ///< this is a complete block signed by a valid producer and has been previously applied by this node and therefore validated but it is not yet irreversible
            complete   = 2, ///< this is a complete block signed by a valid producer but is not yet irreversible nor has it yet been applied by this node
            incomplete  = 3, ///< this is an incomplete block (either being produced by a producer or speculatively produced by a node)
         };

         explicit controller( const config& cfg );
         controller( const config& cfg, protocol_feature_set&& pfs );
         ~controller();

         void add_indices();
         void startup( std::function<bool()> shutdown, const snapshot_reader_ptr& snapshot = nullptr );

         void preactivate_feature( const digest_type& feature_digest );

         vector<digest_type> get_preactivated_protocol_features()const;

         void validate_protocol_features( const vector<digest_type>& features_to_activate )const;

         /**
          *  Starts a new pending block session upon which new transactions can
          *  be pushed.
          *
          *  Will only activate protocol features that have been pre-activated.
          */
         void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0 );

         /**
          * Starts a new pending block session upon which new transactions can
          * be pushed.
          */
         void start_block( block_timestamp_type time,
                           uint16_t confirm_block_count,
                           const vector<digest_type>& new_protocol_feature_activations );

         void abort_block();

         /**
          *  These transactions were previously pushed by have since been unapplied, recalling push_transaction
          *  with the transaction_metadata_ptr will remove them from the source of this data IFF it succeeds.
          *
          *  The caller is responsible for calling drop_unapplied_transaction on a failing transaction that
          *  they never intend to retry
          *
          *  @return map of transactions which have been unapplied
          */
         unapplied_transactions_type& get_unapplied_transactions();

         /**
          *
          */
         transaction_trace_ptr push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us = 0 );

         /**
          * Attempt to execute a specific transaction in our deferred trx database
          *
          */
         transaction_trace_ptr push_scheduled_transaction( const transaction_id_type& scheduled, fc::time_point deadline, uint32_t billed_cpu_time_us = 0 );

         block_state_ptr finalize_block( const std::function<signature_type( const digest_type& )>& signer_callback );
         void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback );
         void commit_block();
         void pop_block();

         std::future<block_state_ptr> create_block_state_future( const signed_block_ptr& b );
         void push_block( std::future<block_state_ptr>& block_state_future );

         boost::asio::io_context& get_thread_pool();

         const chainbase::database& db()const;

         const fork_database& fork_db()const;

         const account_object&                 get_account( account_name n )const;
         const global_property_object&         get_global_properties()const;
         const dynamic_global_property_object& get_dynamic_global_properties()const;
         const resource_limits_manager&        get_resource_limits_manager()const;
         resource_limits_manager&              get_mutable_resource_limits_manager();
         const authorization_manager&          get_authorization_manager()const;
         authorization_manager&                get_mutable_authorization_manager();
         const protocol_feature_manager&       get_protocol_feature_manager()const;

         const flat_set<account_name>&   get_actor_whitelist() const;
         const flat_set<account_name>&   get_actor_blacklist() const;
         const flat_set<account_name>&   get_contract_whitelist() const;
         const flat_set<account_name>&   get_contract_blacklist() const;
         const flat_set< pair<account_name, action_name> >& get_action_blacklist() const;
         const flat_set<public_key_type>& get_key_blacklist() const;

         void   set_actor_whitelist( const flat_set<account_name>& );
         void   set_actor_blacklist( const flat_set<account_name>& );
         void   set_contract_whitelist( const flat_set<account_name>& );
         void   set_contract_blacklist( const flat_set<account_name>& );
         void   set_action_blacklist( const flat_set< pair<account_name, action_name> >& );
         void   set_key_blacklist( const flat_set<public_key_type>& );

         uint32_t             head_block_num()const;
         time_point           head_block_time()const;
         block_id_type        head_block_id()const;
         account_name         head_block_producer()const;
         const block_header&  head_block_header()const;
         block_state_ptr      head_block_state()const;

         uint32_t             fork_db_head_block_num()const;
         block_id_type        fork_db_head_block_id()const;
         time_point           fork_db_head_block_time()const;
         account_name         fork_db_head_block_producer()const;

         uint32_t             fork_db_pending_head_block_num()const;
         block_id_type        fork_db_pending_head_block_id()const;
         time_point           fork_db_pending_head_block_time()const;
         account_name         fork_db_pending_head_block_producer()const;

         time_point              pending_block_time()const;
         account_name            pending_block_producer()const;
         public_key_type         pending_block_signing_key()const;
         optional<block_id_type> pending_producer_block_id()const;

         const vector<transaction_receipt>& get_pending_trx_receipts()const;

         const producer_schedule_type&    active_producers()const;
         const producer_schedule_type&    pending_producers()const;
         optional<producer_schedule_type> proposed_producers()const;

         uint32_t last_irreversible_block_num() const;
         block_id_type last_irreversible_block_id() const;

         signed_block_ptr fetch_block_by_number( uint32_t block_num )const;
         signed_block_ptr fetch_block_by_id( block_id_type id )const;

         block_state_ptr fetch_block_state_by_number( uint32_t block_num )const;
         block_state_ptr fetch_block_state_by_id( block_id_type id )const;

         block_id_type get_block_id_for_num( uint32_t block_num )const;

         sha256 calculate_integrity_hash()const;
         void write_snapshot( const snapshot_writer_ptr& snapshot )const;

         bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const;
         void check_actor_list( const flat_set<account_name>& actors )const;
         void check_contract_list( account_name code )const;
         void check_action_list( account_name code, action_name action )const;
         void check_key_list( const public_key_type& key )const;
         bool is_building_block()const;
         bool is_producing_block()const;

         bool is_ram_billing_in_notify_allowed()const;

         void add_resource_greylist(const account_name &name);
         void remove_resource_greylist(const account_name &name);
         bool is_resource_greylisted(const account_name &name) const;
         const flat_set<account_name> &get_resource_greylist() const;

         void validate_expiration( const transaction& t )const;
         void validate_tapos( const transaction& t )const;
         void validate_db_available_size() const;
         void validate_reversible_available_size() const;

         bool is_protocol_feature_activated( const digest_type& feature_digest )const;
         bool is_builtin_activated( builtin_protocol_feature_t f )const;

         bool is_known_unexpired_transaction( const transaction_id_type& id) const;

         int64_t set_proposed_producers( vector<producer_key> producers );

         bool light_validation_allowed(bool replay_opts_disabled_by_policy) const;
         bool skip_auth_check()const;
         bool skip_db_sessions( )const;
         bool skip_db_sessions( block_status bs )const;
         bool skip_trx_checks()const;

         bool contracts_console()const;

         chain_id_type get_chain_id()const;

         db_read_mode get_read_mode()const;
         validation_mode get_validation_mode()const;

         void set_subjective_cpu_leeway(fc::microseconds leeway);
         void set_greylist_limit( uint32_t limit );
         uint32_t get_greylist_limit()const;

         void add_to_ram_correction( account_name account, uint64_t ram_bytes );
         bool all_subjective_mitigations_disabled()const;

         static fc::optional<uint64_t> convert_exception_to_error_code( const fc::exception& e );

         signal<void(const signed_block_ptr&)>         pre_accepted_block;
         signal<void(const block_state_ptr&)>          accepted_block_header;
         signal<void(const block_state_ptr&)>          accepted_block;
         signal<void(const block_state_ptr&)>          irreversible_block;
         signal<void(const transaction_metadata_ptr&)> accepted_transaction;
         signal<void(std::tuple<const transaction_trace_ptr&, const signed_transaction&>)> applied_transaction;
         signal<void(const int&)>                      bad_alloc;

         /*
         signal<void()>                                  pre_apply_block;
         signal<void()>                                  post_apply_block;
         signal<void()>                                  abort_apply_block;
         signal<void(const transaction_metadata_ptr&)>   pre_apply_transaction;
         signal<void(const transaction_trace_ptr&)>      post_apply_transaction;
         signal<void(const transaction_trace_ptr&)>  pre_apply_action;
         signal<void(const transaction_trace_ptr&)>  post_apply_action;
         */

         const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const;
         wasm_interface& get_wasm_interface();

         optional<abi_serializer> get_abi_serializer( account_name n, const fc::microseconds& max_serialization_time )const {
            if( n.good() ) {
               try {
                  const auto& a = get_account( n );
                  abi_def abi;
                  if( abi_serializer::to_abi( a.abi, abi ))
                     return abi_serializer( abi, max_serialization_time );
               } FC_CAPTURE_AND_LOG((n))
            }
            return optional<abi_serializer>();
         }

         template<typename T>
         fc::variant to_variant_with_abi( const T& obj, const fc::microseconds& max_serialization_time ) {
            fc::variant pretty_output;
            abi_serializer::to_variant( obj, pretty_output,
                                        [&]( account_name n ){ return get_abi_serializer( n, max_serialization_time ); },
                                        max_serialization_time);
            return pretty_output;
         }

      private:
         friend class apply_context;
         friend class transaction_context;

         chainbase::database& mutable_db()const;

         std::unique_ptr<controller_impl> my;

   };

} }  /// eosio::chain

FC_REFLECT( eosio::chain::controller::config,
            (actor_whitelist)
            (actor_blacklist)
            (contract_whitelist)
            (contract_blacklist)
            (blocks_dir)
            (state_dir)
            (state_size)
            (reversible_cache_size)
            (read_only)
            (force_all_checks)
            (disable_replay_opts)
            (contracts_console)
            (genesis)
            (wasm_runtime)
            (resource_greylist)
            (trusted_producers)
          )
<commit_msg>remove unnecessary reflection of controller::config<commit_after>#pragma once
#include <eosio/chain/block_state.hpp>
#include <eosio/chain/trace.hpp>
#include <eosio/chain/genesis_state.hpp>
#include <chainbase/pinnable_mapped_file.hpp>
#include <boost/signals2/signal.hpp>

#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/account_object.hpp>
#include <eosio/chain/snapshot.hpp>
#include <eosio/chain/protocol_feature_manager.hpp>

namespace chainbase {
   class database;
}
namespace boost { namespace asio {
   class thread_pool;
}}

namespace eosio { namespace chain {

   class authorization_manager;

   namespace resource_limits {
      class resource_limits_manager;
   };

   struct controller_impl;
   using chainbase::database;
   using chainbase::pinnable_mapped_file;
   using boost::signals2::signal;

   class dynamic_global_property_object;
   class global_property_object;
   class permission_object;
   class account_object;
   using resource_limits::resource_limits_manager;
   using apply_handler = std::function<void(apply_context&)>;
   using unapplied_transactions_type = map<transaction_id_type, transaction_metadata_ptr, sha256_less>;

   class fork_database;

   enum class db_read_mode {
      SPECULATIVE,
      HEAD,
      READ_ONLY,
      IRREVERSIBLE
   };

   enum class validation_mode {
      FULL,
      LIGHT
   };

   class controller {
      public:

         struct config {
            flat_set<account_name>   sender_bypass_whiteblacklist;
            flat_set<account_name>   actor_whitelist;
            flat_set<account_name>   actor_blacklist;
            flat_set<account_name>   contract_whitelist;
            flat_set<account_name>   contract_blacklist;
            flat_set< pair<account_name, action_name> > action_blacklist;
            flat_set<public_key_type> key_blacklist;
            path                     blocks_dir             =  chain::config::default_blocks_dir_name;
            path                     state_dir              =  chain::config::default_state_dir_name;
            uint64_t                 state_size             =  chain::config::default_state_size;
            uint64_t                 state_guard_size       =  chain::config::default_state_guard_size;
            uint64_t                 reversible_cache_size  =  chain::config::default_reversible_cache_size;
            uint64_t                 reversible_guard_size  =  chain::config::default_reversible_guard_size;
            uint32_t                 sig_cpu_bill_pct       =  chain::config::default_sig_cpu_bill_pct;
            uint16_t                 thread_pool_size       =  chain::config::default_controller_thread_pool_size;
            bool                     read_only              =  false;
            bool                     force_all_checks       =  false;
            bool                     disable_replay_opts    =  false;
            bool                     contracts_console      =  false;
            bool                     allow_ram_billing_in_notify = false;
            bool                     disable_all_subjective_mitigations = false; //< for testing purposes only

            genesis_state            genesis;
            wasm_interface::vm_type  wasm_runtime = chain::config::default_wasm_runtime;

            db_read_mode             read_mode              = db_read_mode::SPECULATIVE;
            validation_mode          block_validation_mode  = validation_mode::FULL;

            pinnable_mapped_file::map_mode db_map_mode      = pinnable_mapped_file::map_mode::mapped;
            vector<string>           db_hugepage_paths;

            flat_set<account_name>   resource_greylist;
            flat_set<account_name>   trusted_producers;
            uint32_t                 greylist_limit         = chain::config::maximum_elastic_resource_multiplier;
         };

         enum class block_status {
            irreversible = 0, ///< this block has already been applied before by this node and is considered irreversible
            validated   = 1, ///< this is a complete block signed by a valid producer and has been previously applied by this node and therefore validated but it is not yet irreversible
            complete   = 2, ///< this is a complete block signed by a valid producer but is not yet irreversible nor has it yet been applied by this node
            incomplete  = 3, ///< this is an incomplete block (either being produced by a producer or speculatively produced by a node)
         };

         explicit controller( const config& cfg );
         controller( const config& cfg, protocol_feature_set&& pfs );
         ~controller();

         void add_indices();
         void startup( std::function<bool()> shutdown, const snapshot_reader_ptr& snapshot = nullptr );

         void preactivate_feature( const digest_type& feature_digest );

         vector<digest_type> get_preactivated_protocol_features()const;

         void validate_protocol_features( const vector<digest_type>& features_to_activate )const;

         /**
          *  Starts a new pending block session upon which new transactions can
          *  be pushed.
          *
          *  Will only activate protocol features that have been pre-activated.
          */
         void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0 );

         /**
          * Starts a new pending block session upon which new transactions can
          * be pushed.
          */
         void start_block( block_timestamp_type time,
                           uint16_t confirm_block_count,
                           const vector<digest_type>& new_protocol_feature_activations );

         void abort_block();

         /**
          *  These transactions were previously pushed by have since been unapplied, recalling push_transaction
          *  with the transaction_metadata_ptr will remove them from the source of this data IFF it succeeds.
          *
          *  The caller is responsible for calling drop_unapplied_transaction on a failing transaction that
          *  they never intend to retry
          *
          *  @return map of transactions which have been unapplied
          */
         unapplied_transactions_type& get_unapplied_transactions();

         /**
          *
          */
         transaction_trace_ptr push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us = 0 );

         /**
          * Attempt to execute a specific transaction in our deferred trx database
          *
          */
         transaction_trace_ptr push_scheduled_transaction( const transaction_id_type& scheduled, fc::time_point deadline, uint32_t billed_cpu_time_us = 0 );

         block_state_ptr finalize_block( const std::function<signature_type( const digest_type& )>& signer_callback );
         void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback );
         void commit_block();
         void pop_block();

         std::future<block_state_ptr> create_block_state_future( const signed_block_ptr& b );
         void push_block( std::future<block_state_ptr>& block_state_future );

         boost::asio::io_context& get_thread_pool();

         const chainbase::database& db()const;

         const fork_database& fork_db()const;

         const account_object&                 get_account( account_name n )const;
         const global_property_object&         get_global_properties()const;
         const dynamic_global_property_object& get_dynamic_global_properties()const;
         const resource_limits_manager&        get_resource_limits_manager()const;
         resource_limits_manager&              get_mutable_resource_limits_manager();
         const authorization_manager&          get_authorization_manager()const;
         authorization_manager&                get_mutable_authorization_manager();
         const protocol_feature_manager&       get_protocol_feature_manager()const;

         const flat_set<account_name>&   get_actor_whitelist() const;
         const flat_set<account_name>&   get_actor_blacklist() const;
         const flat_set<account_name>&   get_contract_whitelist() const;
         const flat_set<account_name>&   get_contract_blacklist() const;
         const flat_set< pair<account_name, action_name> >& get_action_blacklist() const;
         const flat_set<public_key_type>& get_key_blacklist() const;

         void   set_actor_whitelist( const flat_set<account_name>& );
         void   set_actor_blacklist( const flat_set<account_name>& );
         void   set_contract_whitelist( const flat_set<account_name>& );
         void   set_contract_blacklist( const flat_set<account_name>& );
         void   set_action_blacklist( const flat_set< pair<account_name, action_name> >& );
         void   set_key_blacklist( const flat_set<public_key_type>& );

         uint32_t             head_block_num()const;
         time_point           head_block_time()const;
         block_id_type        head_block_id()const;
         account_name         head_block_producer()const;
         const block_header&  head_block_header()const;
         block_state_ptr      head_block_state()const;

         uint32_t             fork_db_head_block_num()const;
         block_id_type        fork_db_head_block_id()const;
         time_point           fork_db_head_block_time()const;
         account_name         fork_db_head_block_producer()const;

         uint32_t             fork_db_pending_head_block_num()const;
         block_id_type        fork_db_pending_head_block_id()const;
         time_point           fork_db_pending_head_block_time()const;
         account_name         fork_db_pending_head_block_producer()const;

         time_point              pending_block_time()const;
         account_name            pending_block_producer()const;
         public_key_type         pending_block_signing_key()const;
         optional<block_id_type> pending_producer_block_id()const;

         const vector<transaction_receipt>& get_pending_trx_receipts()const;

         const producer_schedule_type&    active_producers()const;
         const producer_schedule_type&    pending_producers()const;
         optional<producer_schedule_type> proposed_producers()const;

         uint32_t last_irreversible_block_num() const;
         block_id_type last_irreversible_block_id() const;

         signed_block_ptr fetch_block_by_number( uint32_t block_num )const;
         signed_block_ptr fetch_block_by_id( block_id_type id )const;

         block_state_ptr fetch_block_state_by_number( uint32_t block_num )const;
         block_state_ptr fetch_block_state_by_id( block_id_type id )const;

         block_id_type get_block_id_for_num( uint32_t block_num )const;

         sha256 calculate_integrity_hash()const;
         void write_snapshot( const snapshot_writer_ptr& snapshot )const;

         bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const;
         void check_actor_list( const flat_set<account_name>& actors )const;
         void check_contract_list( account_name code )const;
         void check_action_list( account_name code, action_name action )const;
         void check_key_list( const public_key_type& key )const;
         bool is_building_block()const;
         bool is_producing_block()const;

         bool is_ram_billing_in_notify_allowed()const;

         void add_resource_greylist(const account_name &name);
         void remove_resource_greylist(const account_name &name);
         bool is_resource_greylisted(const account_name &name) const;
         const flat_set<account_name> &get_resource_greylist() const;

         void validate_expiration( const transaction& t )const;
         void validate_tapos( const transaction& t )const;
         void validate_db_available_size() const;
         void validate_reversible_available_size() const;

         bool is_protocol_feature_activated( const digest_type& feature_digest )const;
         bool is_builtin_activated( builtin_protocol_feature_t f )const;

         bool is_known_unexpired_transaction( const transaction_id_type& id) const;

         int64_t set_proposed_producers( vector<producer_key> producers );

         bool light_validation_allowed(bool replay_opts_disabled_by_policy) const;
         bool skip_auth_check()const;
         bool skip_db_sessions( )const;
         bool skip_db_sessions( block_status bs )const;
         bool skip_trx_checks()const;

         bool contracts_console()const;

         chain_id_type get_chain_id()const;

         db_read_mode get_read_mode()const;
         validation_mode get_validation_mode()const;

         void set_subjective_cpu_leeway(fc::microseconds leeway);
         void set_greylist_limit( uint32_t limit );
         uint32_t get_greylist_limit()const;

         void add_to_ram_correction( account_name account, uint64_t ram_bytes );
         bool all_subjective_mitigations_disabled()const;

         static fc::optional<uint64_t> convert_exception_to_error_code( const fc::exception& e );

         signal<void(const signed_block_ptr&)>         pre_accepted_block;
         signal<void(const block_state_ptr&)>          accepted_block_header;
         signal<void(const block_state_ptr&)>          accepted_block;
         signal<void(const block_state_ptr&)>          irreversible_block;
         signal<void(const transaction_metadata_ptr&)> accepted_transaction;
         signal<void(std::tuple<const transaction_trace_ptr&, const signed_transaction&>)> applied_transaction;
         signal<void(const int&)>                      bad_alloc;

         /*
         signal<void()>                                  pre_apply_block;
         signal<void()>                                  post_apply_block;
         signal<void()>                                  abort_apply_block;
         signal<void(const transaction_metadata_ptr&)>   pre_apply_transaction;
         signal<void(const transaction_trace_ptr&)>      post_apply_transaction;
         signal<void(const transaction_trace_ptr&)>  pre_apply_action;
         signal<void(const transaction_trace_ptr&)>  post_apply_action;
         */

         const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const;
         wasm_interface& get_wasm_interface();

         optional<abi_serializer> get_abi_serializer( account_name n, const fc::microseconds& max_serialization_time )const {
            if( n.good() ) {
               try {
                  const auto& a = get_account( n );
                  abi_def abi;
                  if( abi_serializer::to_abi( a.abi, abi ))
                     return abi_serializer( abi, max_serialization_time );
               } FC_CAPTURE_AND_LOG((n))
            }
            return optional<abi_serializer>();
         }

         template<typename T>
         fc::variant to_variant_with_abi( const T& obj, const fc::microseconds& max_serialization_time ) {
            fc::variant pretty_output;
            abi_serializer::to_variant( obj, pretty_output,
                                        [&]( account_name n ){ return get_abi_serializer( n, max_serialization_time ); },
                                        max_serialization_time);
            return pretty_output;
         }

      private:
         friend class apply_context;
         friend class transaction_context;

         chainbase::database& mutable_db()const;

         std::unique_ptr<controller_impl> my;

   };

} }  /// eosio::chain
<|endoftext|>