<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBicubicImageFilter.h"
#include "SkBitmap.h"
#include "SkBitmapDevice.h"
#include "SkBitmapSource.h"
#include "SkBlurImageFilter.h"
#include "SkCanvas.h"
#include "SkColorFilterImageFilter.h"
#include "SkColorMatrixFilter.h"
#include "SkDeviceImageFilterProxy.h"
#include "SkDisplacementMapEffect.h"
#include "SkDropShadowImageFilter.h"
#include "SkFlattenableBuffers.h"
#include "SkLightingImageFilter.h"
#include "SkMatrixConvolutionImageFilter.h"
#include "SkMergeImageFilter.h"
#include "SkMorphologyImageFilter.h"
#include "SkOffsetImageFilter.h"
#include "SkPicture.h"
#include "SkRect.h"
#include "SkTileImageFilter.h"
#include "SkXfermodeImageFilter.h"
#include "Test.h"

#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#include "SkGpuDevice.h"
#endif

static const int kBitmapSize = 4;

namespace {

class MatrixTestImageFilter : public SkImageFilter {
public:
    MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
      : SkImageFilter(0), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
    }

    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
                               SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
        REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
        return true;
    }

    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)

protected:
    explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0) {
        fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
        buffer.readMatrix(&fExpectedMatrix);
    }

    virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
        buffer.writeFunctionPtr(fReporter);
        buffer.writeMatrix(fExpectedMatrix);
    }

private:
    skiatest::Reporter* fReporter;
    SkMatrix fExpectedMatrix;
};

}

static void make_small_bitmap(SkBitmap& bitmap) {
    bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
    SkCanvas canvas(bitmap);
    canvas.clear(0x00000000);
    SkPaint darkPaint;
    darkPaint.setColor(0xFF804020);
    SkPaint lightPaint;
    lightPaint.setColor(0xFF244484);
    const int i = kBitmapSize / 4;
    for (int y = 0; y < kBitmapSize; y += i) {
        for (int x = 0; x < kBitmapSize; x += i) {
            canvas.save();
            canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
            canvas.drawRect(SkRect::MakeXYWH(0, 0,
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), darkPaint);
            canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
                                             0,
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), lightPaint);
            canvas.drawRect(SkRect::MakeXYWH(0,
                                             SkIntToScalar(i),
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), lightPaint);
            canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
                                             SkIntToScalar(i),
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), darkPaint);
            canvas.restore();
        }
    }
}

static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
    SkScalar s = amount;
    SkScalar matrix[20] = { s, 0, 0, 0, 0,
                            0, s, 0, 0, 0,
                            0, 0, s, 0, 0,
                            0, 0, 0, s, 0 };
    SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
    return SkColorFilterImageFilter::Create(filter, input);
}

static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
    SkScalar matrix[20];
    memset(matrix, 0, 20 * sizeof(SkScalar));
    matrix[0] = matrix[5] = matrix[10] = 0.2126f;
    matrix[1] = matrix[6] = matrix[11] = 0.7152f;
    matrix[2] = matrix[7] = matrix[12] = 0.0722f;
    matrix[18] = 1.0f;
    SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
    return SkColorFilterImageFilter::Create(filter, input, cropRect);
}

DEF_TEST(ImageFilter, reporter) {
    {
        // Check that two non-clipping color matrices concatenate into a single filter.
        SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
        SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
        REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
    }

    {
        // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
        SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
        SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
        REPORTER_ASSERT(reporter, NULL != halfBrightness->getInput(0));
    }

    {
        // Check that a color filter image filter without a crop rect can be
        // expressed as a color filter.
        SkAutoTUnref<SkImageFilter> gray(make_grayscale());
        REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
    }

    {
        // Check that a color filter image filter with a crop rect cannot
        // be expressed as a color filter.
        SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
        SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
        REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
    }

    {
        // Tests pass by not asserting
        SkBitmap bitmap, result;
        make_small_bitmap(bitmap);
        result.allocN32Pixels(kBitmapSize, kBitmapSize);

        {
            // This tests for :
            // 1 ) location at (0,0,1)
            SkPoint3 location(0, 0, SK_Scalar1);
            // 2 ) location and target at same value
            SkPoint3 target(location.fX, location.fY, location.fZ);
            // 3 ) large negative specular exponent value
            SkScalar specularExponent = -1000;

            SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
            SkPaint paint;
            paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
                    location, target, specularExponent, 180,
                    0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
                    bmSrc))->unref();
            SkCanvas canvas(result);
            SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
                                      SkIntToScalar(kBitmapSize));
            canvas.drawRect(r, paint);
        }

        {
            // This tests for scale bringing width to 0
            SkSize scale = SkSize::Make(-0.001f, SK_Scalar1);
            SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
            SkAutoTUnref<SkBicubicImageFilter> bicubic(
                SkBicubicImageFilter::CreateMitchell(scale, bmSrc));
            SkBitmapDevice device(bitmap);
            SkDeviceImageFilterProxy proxy(&device);
            SkIPoint loc = SkIPoint::Make(0, 0);
            // An empty input should early return and return false
            SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeEmpty());
            REPORTER_ASSERT(reporter,
                            !bicubic->filterImage(&proxy, bitmap, ctx, &result, &loc));
        }
    }
}

static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
    // Check that all filters offset to their absolute crop rect,
    // unaffected by the input crop rect.
    // Tests pass by not asserting.
    SkBitmap bitmap;
    bitmap.allocN32Pixels(100, 100);
    bitmap.eraseARGB(0, 0, 0, 0);
    SkDeviceImageFilterProxy proxy(device);

    SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
    SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
    SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));

    SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
    SkPoint3 location(0, 0, SK_Scalar1);
    SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
    SkScalar kernel[9] = {
        SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
        SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
        SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
    };
    SkISize kernelSize = SkISize::Make(3, 3);
    SkScalar gain = SK_Scalar1, bias = 0;

    SkImageFilter* filters[] = {
        SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
        SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
                                        SkDisplacementMapEffect::kB_ChannelSelectorType,
                                        40.0f, input.get(), input.get(), &cropRect),
        SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
        SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input.get(), &cropRect),
        SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
        SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
        SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
        SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
        SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
        SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
        SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
        SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
        SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
        SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
    };

    for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
        SkImageFilter* filter = filters[i];
        SkBitmap result;
        SkIPoint offset;
        SkString str;
        str.printf("filter %d", static_cast<int>(i));
        SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest());
        REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset), str.c_str());
        REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
    }

    for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
        SkSafeUnref(filters[i]);
    }
}

DEF_TEST(ImageFilterCropRect, reporter) {
    SkBitmap temp;
    temp.allocN32Pixels(100, 100);
    SkBitmapDevice device(temp);
    test_crop_rects(&device, reporter);
}

DEF_TEST(ImageFilterMatrixTest, reporter) {
    SkBitmap temp;
    temp.allocN32Pixels(100, 100);
    SkBitmapDevice device(temp);
    SkCanvas canvas(&device);
    canvas.scale(SkIntToScalar(2), SkIntToScalar(2));

    SkMatrix expectedMatrix = canvas.getTotalMatrix();

    SkPicture picture;
    SkCanvas* recordingCanvas = picture.beginRecording(100, 100,
        SkPicture::kOptimizeForClippedPlayback_RecordingFlag);

    SkPaint paint;
    SkAutoTUnref<MatrixTestImageFilter> imageFilter(
        new MatrixTestImageFilter(reporter, expectedMatrix));
    paint.setImageFilter(imageFilter.get());
    SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(
        SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
    recordingCanvas->saveLayer(NULL, &paint, saveFlags);
    SkPaint solidPaint;
    solidPaint.setColor(0xFFFFFFFF);
    recordingCanvas->save();
    recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
    recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
    recordingCanvas->restore(); // scale
    recordingCanvas->restore(); // saveLayer
    picture.endRecording();

    canvas.drawPicture(picture);
}

void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
    SkCanvas canvas(device);

    SkBitmap bitmap;
    bitmap.allocN32Pixels(100, 100);
    bitmap.eraseARGB(0, 0, 0, 0);

    // Check that a blur with an insane radius does not crash or assert.
    SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));

    SkPaint paint;
    paint.setImageFilter(blur);
    canvas.drawSprite(bitmap, 0, 0, &paint);
}

DEF_TEST(HugeBlurImageFilter, reporter) {
    SkBitmap temp;
    temp.allocN32Pixels(100, 100);
    SkBitmapDevice device(temp);
    test_huge_blur(&device, reporter);
}

#if SK_SUPPORT_GPU
DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
    GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
                                                         SkImageInfo::MakeN32Premul(100, 100),
                                                         0));
    test_crop_rects(device, reporter);
}

DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
    GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
                                                         SkImageInfo::MakeN32Premul(100, 100),
                                                         0));
    test_huge_blur(device, reporter);
}
#endif
<commit_msg>Fix Mac Debug clang build.<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBicubicImageFilter.h"
#include "SkBitmap.h"
#include "SkBitmapDevice.h"
#include "SkBitmapSource.h"
#include "SkBlurImageFilter.h"
#include "SkCanvas.h"
#include "SkColorFilterImageFilter.h"
#include "SkColorMatrixFilter.h"
#include "SkDeviceImageFilterProxy.h"
#include "SkDisplacementMapEffect.h"
#include "SkDropShadowImageFilter.h"
#include "SkFlattenableBuffers.h"
#include "SkLightingImageFilter.h"
#include "SkMatrixConvolutionImageFilter.h"
#include "SkMergeImageFilter.h"
#include "SkMorphologyImageFilter.h"
#include "SkOffsetImageFilter.h"
#include "SkPicture.h"
#include "SkRect.h"
#include "SkTileImageFilter.h"
#include "SkXfermodeImageFilter.h"
#include "Test.h"

#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#include "SkGpuDevice.h"
#endif

static const int kBitmapSize = 4;

namespace {

class MatrixTestImageFilter : public SkImageFilter {
public:
    MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
      : SkImageFilter(0), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
    }

    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
                               SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
        REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
        return true;
    }

    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)

protected:
    explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0) {
        fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
        buffer.readMatrix(&fExpectedMatrix);
    }

    virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
        buffer.writeFunctionPtr(fReporter);
        buffer.writeMatrix(fExpectedMatrix);
    }

private:
    skiatest::Reporter* fReporter;
    SkMatrix fExpectedMatrix;
};

}

static void make_small_bitmap(SkBitmap& bitmap) {
    bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
    SkCanvas canvas(bitmap);
    canvas.clear(0x00000000);
    SkPaint darkPaint;
    darkPaint.setColor(0xFF804020);
    SkPaint lightPaint;
    lightPaint.setColor(0xFF244484);
    const int i = kBitmapSize / 4;
    for (int y = 0; y < kBitmapSize; y += i) {
        for (int x = 0; x < kBitmapSize; x += i) {
            canvas.save();
            canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
            canvas.drawRect(SkRect::MakeXYWH(0, 0,
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), darkPaint);
            canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
                                             0,
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), lightPaint);
            canvas.drawRect(SkRect::MakeXYWH(0,
                                             SkIntToScalar(i),
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), lightPaint);
            canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
                                             SkIntToScalar(i),
                                             SkIntToScalar(i),
                                             SkIntToScalar(i)), darkPaint);
            canvas.restore();
        }
    }
}

static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
    SkScalar s = amount;
    SkScalar matrix[20] = { s, 0, 0, 0, 0,
                            0, s, 0, 0, 0,
                            0, 0, s, 0, 0,
                            0, 0, 0, s, 0 };
    SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
    return SkColorFilterImageFilter::Create(filter, input);
}

static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
    SkScalar matrix[20];
    memset(matrix, 0, 20 * sizeof(SkScalar));
    matrix[0] = matrix[5] = matrix[10] = 0.2126f;
    matrix[1] = matrix[6] = matrix[11] = 0.7152f;
    matrix[2] = matrix[7] = matrix[12] = 0.0722f;
    matrix[18] = 1.0f;
    SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
    return SkColorFilterImageFilter::Create(filter, input, cropRect);
}

DEF_TEST(ImageFilter, reporter) {
    {
        // Check that two non-clipping color matrices concatenate into a single filter.
        SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
        SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
        REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
    }

    {
        // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
        SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
        SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
        REPORTER_ASSERT(reporter, NULL != halfBrightness->getInput(0));
    }

    {
        // Check that a color filter image filter without a crop rect can be
        // expressed as a color filter.
        SkAutoTUnref<SkImageFilter> gray(make_grayscale());
        REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
    }

    {
        // Check that a color filter image filter with a crop rect cannot
        // be expressed as a color filter.
        SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
        SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
        REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
    }

    {
        // Tests pass by not asserting
        SkBitmap bitmap, result;
        make_small_bitmap(bitmap);
        result.allocN32Pixels(kBitmapSize, kBitmapSize);

        {
            // This tests for :
            // 1 ) location at (0,0,1)
            SkPoint3 location(0, 0, SK_Scalar1);
            // 2 ) location and target at same value
            SkPoint3 target(location.fX, location.fY, location.fZ);
            // 3 ) large negative specular exponent value
            SkScalar specularExponent = -1000;

            SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
            SkPaint paint;
            paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
                    location, target, specularExponent, 180,
                    0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
                    bmSrc))->unref();
            SkCanvas canvas(result);
            SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
                                      SkIntToScalar(kBitmapSize));
            canvas.drawRect(r, paint);
        }

        {
            // This tests for scale bringing width to 0
            SkSize scale = SkSize::Make(-0.001f, SK_Scalar1);
            SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
            SkAutoTUnref<SkBicubicImageFilter> bicubic(
                SkBicubicImageFilter::CreateMitchell(scale, bmSrc));
            SkBitmapDevice device(bitmap);
            SkDeviceImageFilterProxy proxy(&device);
            SkIPoint loc = SkIPoint::Make(0, 0);
            // An empty input should early return and return false
            SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeEmpty());
            REPORTER_ASSERT(reporter,
                            !bicubic->filterImage(&proxy, bitmap, ctx, &result, &loc));
        }
    }
}

static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
    // Check that all filters offset to their absolute crop rect,
    // unaffected by the input crop rect.
    // Tests pass by not asserting.
    SkBitmap bitmap;
    bitmap.allocN32Pixels(100, 100);
    bitmap.eraseARGB(0, 0, 0, 0);
    SkDeviceImageFilterProxy proxy(device);

    SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
    SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
    SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));

    SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
    SkPoint3 location(0, 0, SK_Scalar1);
    SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
    SkScalar kernel[9] = {
        SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
        SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
        SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
    };
    SkISize kernelSize = SkISize::Make(3, 3);
    SkScalar gain = SK_Scalar1, bias = 0;

    SkImageFilter* filters[] = {
        SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
        SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
                                        SkDisplacementMapEffect::kB_ChannelSelectorType,
                                        40.0f, input.get(), input.get(), &cropRect),
        SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
        SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input.get(), &cropRect),
        SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
        SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
        SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
        SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
        SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
        SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
        SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
        SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
        SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
        SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
    };

    for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
        SkImageFilter* filter = filters[i];
        SkBitmap result;
        SkIPoint offset;
        SkString str;
        str.printf("filter %d", static_cast<int>(i));
        SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest());
        REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset), str.c_str());
        REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
    }

    for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
        SkSafeUnref(filters[i]);
    }
}

DEF_TEST(ImageFilterCropRect, reporter) {
    SkBitmap temp;
    temp.allocN32Pixels(100, 100);
    SkBitmapDevice device(temp);
    test_crop_rects(&device, reporter);
}

DEF_TEST(ImageFilterMatrixTest, reporter) {
    SkBitmap temp;
    temp.allocN32Pixels(100, 100);
    SkBitmapDevice device(temp);
    SkCanvas canvas(&device);
    canvas.scale(SkIntToScalar(2), SkIntToScalar(2));

    SkMatrix expectedMatrix = canvas.getTotalMatrix();

    SkPicture picture;
    SkCanvas* recordingCanvas = picture.beginRecording(100, 100,
        SkPicture::kOptimizeForClippedPlayback_RecordingFlag);

    SkPaint paint;
    SkAutoTUnref<MatrixTestImageFilter> imageFilter(
        new MatrixTestImageFilter(reporter, expectedMatrix));
    paint.setImageFilter(imageFilter.get());
    SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(
        SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
    recordingCanvas->saveLayer(NULL, &paint, saveFlags);
    SkPaint solidPaint;
    solidPaint.setColor(0xFFFFFFFF);
    recordingCanvas->save();
    recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
    recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
    recordingCanvas->restore(); // scale
    recordingCanvas->restore(); // saveLayer
    picture.endRecording();

    canvas.drawPicture(picture);
}

static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
    SkCanvas canvas(device);

    SkBitmap bitmap;
    bitmap.allocN32Pixels(100, 100);
    bitmap.eraseARGB(0, 0, 0, 0);

    // Check that a blur with an insane radius does not crash or assert.
    SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));

    SkPaint paint;
    paint.setImageFilter(blur);
    canvas.drawSprite(bitmap, 0, 0, &paint);
}

DEF_TEST(HugeBlurImageFilter, reporter) {
    SkBitmap temp;
    temp.allocN32Pixels(100, 100);
    SkBitmapDevice device(temp);
    test_huge_blur(&device, reporter);
}

#if SK_SUPPORT_GPU
DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
    GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
                                                         SkImageInfo::MakeN32Premul(100, 100),
                                                         0));
    test_crop_rects(device, reporter);
}

DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
    GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
                                                         SkImageInfo::MakeN32Premul(100, 100),
                                                         0));
    test_huge_blur(device, reporter);
}
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015, Julien Bernard
 *
 * 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 "Assets.h"

#include <cassert>

#include <boost/filesystem.hpp>

#include "Log.h"

namespace fs = boost::filesystem;

namespace game {

  void AssetManager::addSearchDir(std::string path) {
    Log::info(Log::RESOURCES, "Added a new search directory: %s\n", path.c_str());
    m_searchdirs.emplace_back(std::move(path));
  }

  std::string AssetManager::getAbsolutePath(const std::string& relative_path) {
    fs::path file(relative_path);

    for (fs::path base : m_searchdirs) {
      fs::path absolute_path = base / file;

      if (fs::is_regular_file(absolute_path)) {
        Log::info(Log::RESOURCES, "Found a resource file: %s\n", absolute_path.string().c_str());
        return absolute_path.string();
      }
    }

    Log::error(Log::RESOURCES, "Could not find the following file: %s\n", relative_path.c_str());
    return std::string();
  }

}
<commit_msg>handle absolute filenames for assets<commit_after>/*
 * Copyright (c) 2014-2015, Julien Bernard
 *
 * 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 "Assets.h"

#include <cassert>

#include <boost/filesystem.hpp>

#include "Log.h"

namespace fs = boost::filesystem;

namespace game {

  void AssetManager::addSearchDir(std::string path) {
    Log::info(Log::RESOURCES, "Added a new search directory: %s\n", path.c_str());
    m_searchdirs.emplace_back(std::move(path));
  }

  std::string AssetManager::getAbsolutePath(const std::string& relative_path) {
    fs::path file(relative_path);

    if (file.is_absolute()) {
      return relative_path;
    }

    for (fs::path base : m_searchdirs) {
      fs::path absolute_path = base / file;

      if (fs::is_regular_file(absolute_path)) {
        Log::info(Log::RESOURCES, "Found a resource file: %s\n", absolute_path.string().c_str());
        return absolute_path.string();
      }
    }

    Log::error(Log::RESOURCES, "Could not find the following file: %s\n", relative_path.c_str());
    return std::string();
  }

}
<|endoftext|>


<commit_before>#include "contest.h"

extern "C"
{
#include "cutie.h"
}

CONTEST_SUITE(cutie_suite_test)
CONTEST_CASE(test_parser)
{
  std::vector<std::string> programs;
  programs.push_back("(define a 10)");
  programs.push_back("(set! a 10)");
  programs.push_back("(1 ' set! 10) 10)");

  for (std::string ps : programs) {
    const char *p = ps.c_str();
    Error err;
    Atom sexpr;
    err = read_expr((const char*)p, (const char**)&p, &sexpr);
    CONTEST_TRUE(!ERROR_RAISED(err));
  }
}

CONTEST_CASE(test_parser_input)
{
  std::vector<std::string> programs;
  programs.push_back(")£$(1 ' set! 10) 10)");

  for (std::string ps : programs) {
    const char *p = ps.c_str();
    Atom sexpr;
    Error err = read_expr((const char*)p, (const char**)&p, &sexpr);
    CONTEST_TRUE(ERROR_RAISED(err));
  }
}

namespace {
Error builtin_square(Atom args, Atom *result)
{
  if (nilp(args))
    return ERROR(Error::Error_Args, "Requires one arguments.");

  Atom a = car(args);
  if (a.type != Atom::ATOM_INTEGER)
    return ERROR(Error::Error_Args, "Argument must be integer");

  *result = make_integer(a.value.integer * a.value.integer);
  return ERROR_OK();
}
}

CONTEST_CASE(make_new_builtin)
{
  Atom env = setup_env();
  env_set(env, make_symbol("TEST-FUNC"), make_builtin(builtin_square));

  Atom sexpr, result;

  const char *p = "(test-func 12)";
  Error err = read_expr(p, &p, &sexpr);
  CONTEST_TRUE(!ERROR_RAISED(err));

  err = eval_expr(sexpr, env, &result);
  CONTEST_TRUE(!ERROR_RAISED(err));
  CONTEST_EQUAL(result.value.integer, (long)144);
}

CONTEST_SUITE_END
<commit_msg>Fixed test.<commit_after>#include "contest.h"

extern "C"
{
#include "cutie.h"
}

CONTEST_SUITE(cutie_suite_test)
CONTEST_CASE(test_parser)
{
  std::vector<std::string> programs;
  programs.push_back("(define a 10)");
  programs.push_back("(set! a 10)");
  programs.push_back("(1 ' set! 10) 10)");

  for (std::string ps : programs) {
    const char *p = ps.c_str();
    Error err;
    Atom sexpr;
    err = read_expr((const char*)p, (const char**)&p, &sexpr);
    CONTEST_TRUE(!ERROR_RAISED(err));
  }
}

CONTEST_CASE(test_parser_input)
{
  std::vector<std::string> programs;
  programs.push_back(")£$(1 ' set! 10) 10)");

  for (std::string ps : programs) {
    const char *p = ps.c_str();
    Atom sexpr;
    Error err = read_expr((const char*)p, (const char**)&p, &sexpr);
    CONTEST_TRUE(ERROR_RAISED(err));
  }
}

namespace {
Error builtin_square(Atom args, Atom *result)
{
  if (nilp(args))
    return ERROR(Error::Error_Args, "Requires one arguments.");

  Atom a = car(args);
  if (a.type != AtomType::ATOM_INTEGER)
    return ERROR(Error::Error_Args, "Argument must be integer");

  *result = make_integer(a.value.integer * a.value.integer);
  return ERROR_OK();
}
}

CONTEST_CASE(make_new_builtin)
{
  Atom env = setup_env();
  env_set(env, make_symbol("TEST-FUNC"), make_builtin(builtin_square));

  Atom sexpr, result;

  const char *p = "(test-func 12)";
  Error err = read_expr(p, &p, &sexpr);
  CONTEST_TRUE(!ERROR_RAISED(err));

  err = eval_expr(sexpr, env, &result);
  CONTEST_TRUE(!ERROR_RAISED(err));
  CONTEST_EQUAL(result.value.integer, (long)144);
}

CONTEST_SUITE_END
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <chrono>
#include <random>

#define ETL_COUNTERS
//#define ETL_COUNTERS_VERBOSE

// Use GPU pool to limit allocations
#define ETL_GPU_POOL

#define IF_DEBUG if(false)

#include "etl/etl.hpp"

typedef std::chrono::high_resolution_clock timer_clock;
typedef std::chrono::milliseconds milliseconds;

float fake = 0;

/*
 *
 * Current values are (alloc/release/gpu_to_cpu/cpu_to_gpu):
 *
 * No pool
 * Simple: 13 /  13 /   0 /   2 (Optimal!)
 * Basic:  25 /  25 /   0 /   3 (Optimal!)
 * Sub:   163 / 163 / 160 / 480
 * ML:    179 / 179 /  10 /  19
 *
 * GPU pool
 * Simple:  4 / 0 /   0 /   2 (Optimal!)
 * Basic:   2 / 0 /   0 /   3 (Optimal!)
 * Sub:     4 / 0 / 160 / 480
 * ML:     40 / 0 /  10 /  19
 */

void simple() {
    std::cout << "Simple" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();

    {
        etl::dyn_matrix<float, 2> A(4096, 4096);
        etl::dyn_matrix<float, 2> B(4096, 4096);
        etl::dyn_matrix<float, 2> C(4096, 4096);

        A = 1e-4 >> etl::sequence_generator<float>(1.0);
        B = 1e-4 >> etl::sequence_generator<float>(1.0);
        C = 1e-4 >> etl::sequence_generator<float>(1.0);

        for (size_t i = 0; i < 10; ++i) {
            C = A * B;
            fake += etl::mean(C);
        }

        std::cout << "   Result: " << fake << std::endl;
        std::cout << "Should be: 2.8826e+10" << std::endl;
    }

    etl::dump_counters();
}

void basic() {
    std::cout << "Basic" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();

    {
        etl::dyn_matrix<float, 2> A(4096, 4096);
        etl::dyn_matrix<float, 2> B(4096, 4096);
        etl::dyn_matrix<float, 2> C(4096, 4096);
        etl::dyn_matrix<float, 2> D(4096, 4096);
        etl::dyn_matrix<float, 2> E(4096, 4096);

        A = 1e-4 >> etl::sequence_generator<float>(1.0);
        B = 1e-4 >> etl::sequence_generator<float>(1.0);
        C = 1e-4 >> etl::sequence_generator<float>(1.0);
        D = 1e-4 >> etl::sequence_generator<float>(1.0);
        E = 1e-4 >> etl::sequence_generator<float>(1.0);

        for (size_t i = 0; i < 10; ++i) {
            IF_DEBUG std::cout << i << ":0 C = A * B * E" << std::endl;
            C = A * B * E;
            IF_DEBUG std::cout << i << ":1 D = A * trans(A)" << std::endl;
            D = A * trans(A);
            IF_DEBUG std::cout << i << ":2 D *= 1.1" << std::endl;
            D *= 1.1;
            IF_DEBUG std::cout << i << ":3 E = D" << std::endl;
            E = D;
            IF_DEBUG std::cout << i << ":4 D += C" << std::endl;
            D += C;
            IF_DEBUG std::cout << i << ":5 fake += etl::mean(D)" << std::endl;
            fake += etl::mean(D);
            IF_DEBUG std::cout << i << ":6 end" << std::endl;
        }

        std::cout << "   Result: " << fake << std::endl;
        std::cout << "Should be: 3.36933e+23" << std::endl;
    }

    etl::dump_counters();
}

void sub() {
    std::cout << "Sub" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();
    {
        etl::dyn_matrix<float, 3> A(16, 2048, 2048);
        etl::dyn_matrix<float, 3> B(16, 2048, 2048);
        etl::dyn_matrix<float, 3> C(16, 2048, 2048);
        etl::dyn_matrix<float, 3> D(16, 2048, 2048);

        A = etl::normal_generator<float>(1.0, 0.0);
        B = etl::normal_generator<float>(1.0, 0.0);
        C = etl::normal_generator<float>(1.0, 0.0);
        D = etl::normal_generator<float>(1.0, 0.0);

        for (size_t i = 0; i < 10; ++i) {
            for (size_t k = 0; k < 16; ++k) {
                C(k) = A(k) * B(k) * B(k);
                D(k) += C(k);
                D(k) *= 1.1;
                fake += etl::mean(D(k));
            }
        }
    }

    etl::dump_counters();
}

// Simulate forward propagation in a neural network (with some ops as DLL)
void ml() {
    std::cout << "ML" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();

    {
        etl::dyn_matrix<float, 4> I(32, 3, 28, 28);
        etl::dyn_matrix<float, 2> L(32, 10);

        etl::dyn_matrix<float, 4> C1_W(16, 3, 3, 3);
        etl::dyn_matrix<float, 1> C1_B(16);
        etl::dyn_matrix<float, 4> C1_W_G(16, 3, 3, 3);
        etl::dyn_matrix<float, 1> C1_B_G(16);
        etl::dyn_matrix<float, 4> C1_O(32, 16, 28, 28);
        etl::dyn_matrix<float, 4> C1_E(32, 16, 28, 28);

        etl::dyn_matrix<float, 4> P1_O(32, 16, 14, 14);
        etl::dyn_matrix<float, 4> P1_E(32, 16, 14, 14);

        etl::dyn_matrix<float, 4> C2_W(16, 16, 3, 3);
        etl::dyn_matrix<float, 1> C2_B(16);
        etl::dyn_matrix<float, 4> C2_W_G(16, 16, 3, 3);
        etl::dyn_matrix<float, 1> C2_B_G(16);
        etl::dyn_matrix<float, 4> C2_O(32, 16, 14, 14);
        etl::dyn_matrix<float, 4> C2_E(32, 16, 14, 14);

        etl::dyn_matrix<float, 4> P2_O(32, 16, 7, 7);
        etl::dyn_matrix<float, 4> P2_E(32, 16, 7, 7);

        etl::dyn_matrix<float, 2> FC1_W(16 * 7 * 7, 500);
        etl::dyn_matrix<float, 1> FC1_B(500);
        etl::dyn_matrix<float, 2> FC1_W_G(16 * 7 * 7, 500);
        etl::dyn_matrix<float, 1> FC1_B_G(500);
        etl::dyn_matrix<float, 2> FC1_O(32, 500);
        etl::dyn_matrix<float, 2> FC1_E(32, 500);

        etl::dyn_matrix<float, 2> FC2_W(500, 10);
        etl::dyn_matrix<float, 1> FC2_B(10);
        etl::dyn_matrix<float, 2> FC2_W_G(500, 10);
        etl::dyn_matrix<float, 1> FC2_B_G(10);
        etl::dyn_matrix<float, 2> FC2_O(32, 10);
        etl::dyn_matrix<float, 2> FC2_E(32, 10);

        float eps = 0.1;

        for (size_t i = 0; i < 10; ++i) {
            // Forward Propagation
            C1_O = relu(bias_add_4d(etl::ml::convolution_forward<1, 1, 1, 1>(I, C1_W), C1_B));
            P1_O = etl::max_pool_2d<2, 2>(C1_O);

            C2_O = relu(bias_add_4d(etl::ml::convolution_forward<1, 1, 1, 1>(P1_O, C2_W), C2_B));
            P2_O = etl::max_pool_2d<2, 2>(C2_O);

            FC1_O = sigmoid(bias_add_2d(etl::reshape<32, 16 * 7 * 7>(P2_O) * FC1_W, FC1_B));
            FC2_O = sigmoid(bias_add_2d(FC1_O * FC2_W, FC2_B));

            // Backward propagation of the errors

            FC2_E = L - FC2_O;                                            // Errors of last layer  (!GPU)
            FC1_E = FC2_E * trans(FC2_W);                                 // Backpropagate FC2 -> FC1
            FC1_E = etl::ml::sigmoid_backward(FC1_O, FC1_E);              // Adapt errors of FC1
            etl::reshape<32, 16 * 7 * 7>(P2_E) = FC1_E * trans(FC1_W);    // FC1 -> MP2
            C2_E = etl::max_pool_upsample_2d<2, 2>(C2_O, P2_O, P2_E);     // MP2 -> C2
            C2_E = etl::ml::relu_backward(C2_O, C2_E);                    // Adapt errors of C2
            P1_E = etl::ml::convolution_backward<1, 1, 1, 1>(C2_E, C2_W); // C2 -> MP1
            C1_E = etl::max_pool_upsample_2d<2, 2>(C1_O, P1_O, P1_E);     // MP1 -> C1
            C1_E = etl::ml::relu_backward(C1_O, C1_E);                    // Adapt errors of C1

            // Compute the gradients

            C1_W_G = etl::ml::convolution_backward_filter<1, 1, 1, 1>(I, C1_E);
            C1_B_G = bias_batch_sum_4d(C1_E);

            C2_W_G = etl::ml::convolution_backward_filter<1, 1, 1, 1>(P1_O, C2_E);
            C2_B_G = bias_batch_sum_4d(C2_E);

            FC1_W_G = batch_outer(etl::reshape<32, 16 * 7 * 7>(P2_O), FC1_E);
            FC1_B_G = bias_batch_sum_2d(FC1_E);

            FC2_W_G = batch_outer(FC1_O, FC2_E);
            FC2_B_G = bias_batch_sum_2d(FC2_E);

            // Apply the gradients

            FC2_W += (eps / 32) * FC2_W_G;
            FC2_B += (eps / 32) * FC2_B_G;

            FC1_W += (eps / 32) * FC1_W_G;
            FC1_B += (eps / 32) * FC1_B_G;

            C2_W += (eps / 32) * C2_W_G;
            C2_B += (eps / 32) * C2_B_G;

            C1_W += (eps / 32) * C1_W_G;
            C1_B += (eps / 32) * C1_B_G;
        }
    }

    etl::dump_counters();
}

int main() {
    auto start_time = timer_clock::now();

    simple();
    basic();
    sub();
    ml();

    auto end_time = timer_clock::now();
    auto duration = std::chrono::duration_cast<milliseconds>(end_time - start_time);

    std::cout << "duration: " << duration.count() << "ms" << std::endl;

    etl::exit();

    return (int)fake;
}
<commit_msg>Update the values of the counters<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <chrono>
#include <random>

#define ETL_COUNTERS
//#define ETL_COUNTERS_VERBOSE

// Use GPU pool to limit allocations
#define ETL_GPU_POOL

#define IF_DEBUG if(false)

#include "etl/etl.hpp"

typedef std::chrono::high_resolution_clock timer_clock;
typedef std::chrono::milliseconds milliseconds;

float fake = 0;

/*
 *
 * Current values are (alloc/release/gpu_to_cpu/cpu_to_gpu):
 *
 * No pool
 * Simple: 13 /  13 /   0 /   2 (Optimal!)
 * Basic:  25 /  25 /   0 /   3 (Optimal!)
 * Sub:   163 / 163 / 160 / 480
 * ML:    179 / 179 /  10 /  19
 *
 * GPU pool
 * Simple:  4 / 0 /   0 /   2 (Optimal!)
 * Basic:   2 / 0 /   0 /   3 (Optimal!)
 * Sub:     4 / 0 / 160 / 480
 * ML:     40 / 8 /  90 /  91
 */

void simple() {
    std::cout << "Simple" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();

    {
        etl::dyn_matrix<float, 2> A(4096, 4096);
        etl::dyn_matrix<float, 2> B(4096, 4096);
        etl::dyn_matrix<float, 2> C(4096, 4096);

        A = 1e-4 >> etl::sequence_generator<float>(1.0);
        B = 1e-4 >> etl::sequence_generator<float>(1.0);
        C = 1e-4 >> etl::sequence_generator<float>(1.0);

        for (size_t i = 0; i < 10; ++i) {
            C = A * B;
            fake += etl::mean(C);
        }

        std::cout << "   Result: " << fake << std::endl;
        std::cout << "Should be: 2.8826e+10" << std::endl;
    }

    etl::dump_counters();
}

void basic() {
    std::cout << "Basic" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();

    {
        etl::dyn_matrix<float, 2> A(4096, 4096);
        etl::dyn_matrix<float, 2> B(4096, 4096);
        etl::dyn_matrix<float, 2> C(4096, 4096);
        etl::dyn_matrix<float, 2> D(4096, 4096);
        etl::dyn_matrix<float, 2> E(4096, 4096);

        A = 1e-4 >> etl::sequence_generator<float>(1.0);
        B = 1e-4 >> etl::sequence_generator<float>(1.0);
        C = 1e-4 >> etl::sequence_generator<float>(1.0);
        D = 1e-4 >> etl::sequence_generator<float>(1.0);
        E = 1e-4 >> etl::sequence_generator<float>(1.0);

        for (size_t i = 0; i < 10; ++i) {
            IF_DEBUG std::cout << i << ":0 C = A * B * E" << std::endl;
            C = A * B * E;
            IF_DEBUG std::cout << i << ":1 D = A * trans(A)" << std::endl;
            D = A * trans(A);
            IF_DEBUG std::cout << i << ":2 D *= 1.1" << std::endl;
            D *= 1.1;
            IF_DEBUG std::cout << i << ":3 E = D" << std::endl;
            E = D;
            IF_DEBUG std::cout << i << ":4 D += C" << std::endl;
            D += C;
            IF_DEBUG std::cout << i << ":5 fake += etl::mean(D)" << std::endl;
            fake += etl::mean(D);
            IF_DEBUG std::cout << i << ":6 end" << std::endl;
        }

        std::cout << "   Result: " << fake << std::endl;
        std::cout << "Should be: 3.36933e+23" << std::endl;
    }

    etl::dump_counters();
}

void sub() {
    std::cout << "Sub" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();
    {
        etl::dyn_matrix<float, 3> A(16, 2048, 2048);
        etl::dyn_matrix<float, 3> B(16, 2048, 2048);
        etl::dyn_matrix<float, 3> C(16, 2048, 2048);
        etl::dyn_matrix<float, 3> D(16, 2048, 2048);

        A = etl::normal_generator<float>(1.0, 0.0);
        B = etl::normal_generator<float>(1.0, 0.0);
        C = etl::normal_generator<float>(1.0, 0.0);
        D = etl::normal_generator<float>(1.0, 0.0);

        for (size_t i = 0; i < 10; ++i) {
            for (size_t k = 0; k < 16; ++k) {
                C(k) = A(k) * B(k) * B(k);
                D(k) += C(k);
                D(k) *= 1.1;
                fake += etl::mean(D(k));
            }
        }
    }

    etl::dump_counters();
}

// Simulate forward propagation in a neural network (with some ops as DLL)
void ml() {
    std::cout << "ML" << std::endl;

#ifdef ETL_CUDA
    etl::gpu_memory_allocator::clear();
#endif

    etl::reset_counters();

    {
        etl::dyn_matrix<float, 4> I(32, 3, 28, 28);
        etl::dyn_matrix<float, 2> L(32, 10);

        etl::dyn_matrix<float, 4> C1_W(16, 3, 3, 3);
        etl::dyn_matrix<float, 1> C1_B(16);
        etl::dyn_matrix<float, 4> C1_W_G(16, 3, 3, 3);
        etl::dyn_matrix<float, 1> C1_B_G(16);
        etl::dyn_matrix<float, 4> C1_O(32, 16, 28, 28);
        etl::dyn_matrix<float, 4> C1_E(32, 16, 28, 28);

        etl::dyn_matrix<float, 4> P1_O(32, 16, 14, 14);
        etl::dyn_matrix<float, 4> P1_E(32, 16, 14, 14);

        etl::dyn_matrix<float, 4> C2_W(16, 16, 3, 3);
        etl::dyn_matrix<float, 1> C2_B(16);
        etl::dyn_matrix<float, 4> C2_W_G(16, 16, 3, 3);
        etl::dyn_matrix<float, 1> C2_B_G(16);
        etl::dyn_matrix<float, 4> C2_O(32, 16, 14, 14);
        etl::dyn_matrix<float, 4> C2_E(32, 16, 14, 14);

        etl::dyn_matrix<float, 4> P2_O(32, 16, 7, 7);
        etl::dyn_matrix<float, 4> P2_E(32, 16, 7, 7);

        etl::dyn_matrix<float, 2> FC1_W(16 * 7 * 7, 500);
        etl::dyn_matrix<float, 1> FC1_B(500);
        etl::dyn_matrix<float, 2> FC1_W_G(16 * 7 * 7, 500);
        etl::dyn_matrix<float, 1> FC1_B_G(500);
        etl::dyn_matrix<float, 2> FC1_O(32, 500);
        etl::dyn_matrix<float, 2> FC1_E(32, 500);

        etl::dyn_matrix<float, 2> FC2_W(500, 10);
        etl::dyn_matrix<float, 1> FC2_B(10);
        etl::dyn_matrix<float, 2> FC2_W_G(500, 10);
        etl::dyn_matrix<float, 1> FC2_B_G(10);
        etl::dyn_matrix<float, 2> FC2_O(32, 10);
        etl::dyn_matrix<float, 2> FC2_E(32, 10);

        float eps = 0.1;

        for (size_t i = 0; i < 10; ++i) {
            // Forward Propagation
            C1_O = relu(bias_add_4d(etl::ml::convolution_forward<1, 1, 1, 1>(I, C1_W), C1_B));
            P1_O = etl::max_pool_2d<2, 2>(C1_O);

            C2_O = relu(bias_add_4d(etl::ml::convolution_forward<1, 1, 1, 1>(P1_O, C2_W), C2_B));
            P2_O = etl::max_pool_2d<2, 2>(C2_O);

            FC1_O = sigmoid(bias_add_2d(etl::reshape<32, 16 * 7 * 7>(P2_O) * FC1_W, FC1_B));
            FC2_O = sigmoid(bias_add_2d(FC1_O * FC2_W, FC2_B));

            // Backward propagation of the errors

            FC2_E = L - FC2_O;                                            // Errors of last layer  (!GPU)
            FC1_E = FC2_E * trans(FC2_W);                                 // Backpropagate FC2 -> FC1
            FC1_E = etl::ml::sigmoid_backward(FC1_O, FC1_E);              // Adapt errors of FC1
            etl::reshape<32, 16 * 7 * 7>(P2_E) = FC1_E * trans(FC1_W);    // FC1 -> MP2
            C2_E = etl::max_pool_upsample_2d<2, 2>(C2_O, P2_O, P2_E);     // MP2 -> C2
            C2_E = etl::ml::relu_backward(C2_O, C2_E);                    // Adapt errors of C2
            P1_E = etl::ml::convolution_backward<1, 1, 1, 1>(C2_E, C2_W); // C2 -> MP1
            C1_E = etl::max_pool_upsample_2d<2, 2>(C1_O, P1_O, P1_E);     // MP1 -> C1
            C1_E = etl::ml::relu_backward(C1_O, C1_E);                    // Adapt errors of C1

            // Compute the gradients

            C1_W_G = etl::ml::convolution_backward_filter<1, 1, 1, 1>(I, C1_E);
            C1_B_G = bias_batch_sum_4d(C1_E);

            C2_W_G = etl::ml::convolution_backward_filter<1, 1, 1, 1>(P1_O, C2_E);
            C2_B_G = bias_batch_sum_4d(C2_E);

            FC1_W_G = batch_outer(etl::reshape<32, 16 * 7 * 7>(P2_O), FC1_E);
            FC1_B_G = bias_batch_sum_2d(FC1_E);

            FC2_W_G = batch_outer(FC1_O, FC2_E);
            FC2_B_G = bias_batch_sum_2d(FC2_E);

            // Apply the gradients

            FC2_W += (eps / 32) * FC2_W_G;
            FC2_B += (eps / 32) * FC2_B_G;

            FC1_W += (eps / 32) * FC1_W_G;
            FC1_B += (eps / 32) * FC1_B_G;

            C2_W += (eps / 32) * C2_W_G;
            C2_B += (eps / 32) * C2_B_G;

            C1_W += (eps / 32) * C1_W_G;
            C1_B += (eps / 32) * C1_B_G;
        }
    }

    etl::dump_counters();
}

int main() {
    auto start_time = timer_clock::now();

    simple();
    basic();
    sub();
    ml();

    auto end_time = timer_clock::now();
    auto duration = std::chrono::duration_cast<milliseconds>(end_time - start_time);

    std::cout << "duration: " << duration.count() << "ms" << std::endl;

    etl::exit();

    return (int)fake;
}
<|endoftext|>


<commit_before>#include <QString>
#include <QUrl>
#include <QRegExp>
#include <QSharedPointer>
#include <QVector>
#include <QFileInfo>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QSettings>
#include <QSqlField>
#include "identity.h"
#include "kernel.h"
#include "resource.h"
#include "connectorinterface.h"
#include "catalogconnector.h"
#include "factory.h"
#include "abstractfactory.h"
#include "connectorfactory.h"
#include "catalogconnectorfactory.h"
#include "catalog.h"
#include "mastercatalog.h"
#include "operationExpression.h"
#include "ilwiscontext.h"

Ilwis::MasterCatalog *Ilwis::MasterCatalog::_masterCatalog = 0;

using namespace Ilwis;

MasterCatalog* Ilwis::mastercatalog() {
    if (Ilwis::MasterCatalog::_masterCatalog == 0) {
        Ilwis::MasterCatalog::_masterCatalog = new Ilwis::MasterCatalog();
        Ilwis::MasterCatalog::_masterCatalog->prepare();

    }
    return Ilwis::MasterCatalog::_masterCatalog;
}

MasterCatalog::MasterCatalog()
{
}

MasterCatalog::~MasterCatalog()
{
    qDeleteAll(_catalogs);
}

bool MasterCatalog::prepare()
{
    QSettings settings("52n","ilwis4");

    QString local = settings.value("localfilesystem",QVariant(sUNDEF)).toString();
    if ( local == sUNDEF) {
        QUrl res("file://");
        addContainer(res);
    }
    return true;
}

bool MasterCatalog::addContainer(const QUrl &location)
{
    if ( _catalogs.contains(location))
        return true;

    Resource resource(location, itCATALOG);
    auto *cfactory = kernel()->factory<CatalogConnectorFactory>("catalogconnectorfactory", resource);
    if (!cfactory) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"Connector Factory",location.toString());
    }
    auto connectors= cfactory->create(location);
    if ( connectors.size() == 0) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"Catalog connector", location.toString());
    }

    addItems({resource});
    for(CatalogConnector *conn: connectors) {
        _catalogs.insert(location, conn);
        conn->loadItems();
    }
    return true;
}

ESPObject MasterCatalog::get(const QUrl &resource, IlwisTypes type) const
{
    quint64 id = resource2id(resource, type);
    return get(id);
}

ESPObject MasterCatalog::get(quint64 id) const
{
    if ( id != i64UNDEF) {
        auto iter = _lookup.find(id);
        if ( iter != _lookup.end())
            return iter.value();
    }
    return QExplicitlySharedDataPointer<IlwisObject>();
}

bool MasterCatalog::contains(const QUrl& url, IlwisTypes type) const{
    auto hash = Ilwis::qHash2(url, type);
    auto  iter = _knownHashes.find(hash);
    if ( iter != _knownHashes.end()) {
        auto id = resource2id(url, type);
        if ( id != i64UNDEF)
            return true;
    }
    return false;
}

bool MasterCatalog::removeItems(const QList<Resource> &items){
    for(const Resource &item : items) {
        auto iter = _knownHashes.find(Ilwis::qHash(item));
        if ( iter != _knownHashes.end()) {
            _knownHashes.erase(iter);
        }
        QString stmt = QString("DELETE FROM mastercatalog WHERE item = %1" ).arg(item.id());
        QSqlQuery db(kernel()->database());
        if(!db.exec(stmt)) {
            kernel()->issues()->logSql(db.lastError());
            return false;
        }
        stmt = QString("DELETE FROM catalogitemproperties WHERE item = %1").arg(item.id());
        if(!db.exec(stmt)) {
            kernel()->issues()->logSql(db.lastError());
            return false;
        }
    }

    return true;
}

bool MasterCatalog::addItems(const QList<Resource>& items)
{
    QSqlQuery queryItem, queryProperties;

    bool ok = queryItem.prepare("INSERT INTO mastercatalog VALUES(\
                  :itemid,:name,:code,:container,:resource,:type,:extendedtype, :size,:dimensions \
                  )" );
    if (!ok) {
        kernel()->issues()->logSql(queryItem.lastError());
        return false;

    }

    ok = queryProperties.prepare("INSERT INTO catalogitemproperties VALUES(\
                   :propertyvalue,:propertyname,:itemid\
                 )" );
    if (!ok) {
        kernel()->issues()->logSql(queryItem.lastError());
        return false;
    }

    for(const Resource &item : items) {
        if ( _lookup.contains(item.id()))
            continue;
        if ( mastercatalog()->contains(item.url(), item.ilwisType()))
            continue;

         _knownHashes.insert(Ilwis::qHash(item));
        item.store(queryItem, queryProperties);
    }

    return true;

}
quint64 MasterCatalog::resource2id(const QUrl &url, IlwisTypes tp) const
{
    auto query = QString("select itemid,type from mastercatalog where resource = '%1'").arg(url.toString());
    auto results = kernel()->database().exec(query);
    while ( results.next()) {
        auto rec = results.record();
        auto iid = rec.value(0).toLongLong();
        auto itype = rec.value(1).toLongLong();
        if ( (itype & tp) || tp == itUNKNOWN)
            return iid;
    }

    return i64UNDEF;

}

Resource MasterCatalog::id2Resource(quint64 iid) const {
    auto query = QString("select * from mastercatalog where itemid = %1").arg(iid);
    auto results = kernel()->database().exec(query);
    if ( results.next()) {
        auto rec = results.record();
        return Resource(rec);
    }
    return Resource();
}

quint64 MasterCatalog::name2id(const QString &name, IlwisTypes tp) const
{
    if ( name.left(10) == INTERNAL_PREFIX) { // internal objects are not in the catalog
        QString sid = name.mid(11);
        bool ok;
        quint64 id = sid.toLongLong(&ok);
        if (ok){
            ESPObject data = mastercatalog()->get(id);
            if ( data.data() != 0) {
                data->id();
            }
        }
    }
    Resource res = name2Resource(name,tp);
    return res.id();
}

IlwisTypes MasterCatalog::id2type(quint64 iid) const {
    QString query = QString("select type from mastercatalog where itemid = %1").arg(iid);
    QSqlQuery results = kernel()->database().exec(query);
    if ( results.next()) {
        return results.value(0).toLongLong();
    }
    return itUNKNOWN;
}

Resource MasterCatalog::name2Resource(const QString &name, IlwisTypes tp) const
{
    if ( tp == itUNKNOWN) {
        std::vector<IlwisTypes> types { itGRIDCOVERAGE, itFEATURECOVERAGE, itTABLE, itGEOREF, itCOORDSYSTEM, itDOMAIN};
        for(IlwisTypes type: types) {
            Resource res = name2Resource(name, type);
            if (res.isValid())
                return res.ilwisType();
        }

        return Resource();
    }
    auto resolvedName = name2url(name, tp);
    if (!resolvedName.isValid())
        return Resource();

    auto query = QString("select * from mastercatalog where resource = '%1' and (type & %2) != 0").arg(resolvedName.toString()).arg(tp);
    auto results = kernel()->database().exec(query);
    if ( results.next()) {
        auto rec = results.record();
        return Resource(rec);

    } else {
        query = QString("select propertyvalue from catalogitemproperties,mastercatalog \
                        where mastercatalog.resource='%1' and mastercatalog.itemid=catalogitemproperties.itemid\
                and (mastercatalog.extendedtype & %2) != 0").arg(resolvedName.toString()).arg(tp);
        auto viaExtType = kernel()->database().exec(query);
                //TODO this can probably be more efficient, later
        while ( viaExtType.next()){
            bool ok;
            auto propertyid = viaExtType.value(0).toLongLong(&ok);
            if (!ok) {
                kernel()->issues()->log(TR("Invalid catalog property, mastercatalog corrupted?"),IssueObject::itWarning);
            }
            auto type = id2type(propertyid);
            if ( type & tp)
                return id2Resource(propertyid);
        }
    }
    return Resource();
}

QUrl MasterCatalog::name2url(const QString &name, IlwisTypes tp) const{
    if ( name.contains(QRegExp("\\\\|/"))) { // is there already path info; then assume it is already a unique resource
        QUrl url(name);
        if ( url.scheme().size() > 1)
            return name;
        return QUrl::fromLocalFile(name).toString();
    }
    if ( name.indexOf("code=wkt:")==0) {
        auto code = name.right(name.size() - 5);
        auto wkt = code.mid(4);
        auto table = "projection";
        if ( tp & itELLIPSOID )
            table = "ellipsoid";
        else if ( tp & itGEODETICDATUM)
            table = "datum";
        auto query = QString("select code from %1 where wkt='%2'").arg(table, wkt);
        auto codes = kernel()->database().exec(query);
        if ( codes.next()) {
            return QString("ilwis://tables/%1?code=%2").arg(table,codes.value(0).toString());
        }else {
            kernel()->issues()->log(TR(ERR_FIND_SYSTEM_OBJECT_1).arg(wkt));
            return QUrl();
        }
    } else if ( name.indexOf("code=epsg:")== 0 ) {
        //TODO other tables then projectedcsy
        auto code = name.right(name.size() - 5);
        return QString("ilwis://tables/projectedcsy?code=%1").arg(code);

    } else if ( name.left(6) == "code=proj4:") {
        auto code = name.right(name.size() - 5);
        return QString("ilwis://projection/code=%1").arg(code);
    }
    if ( context()->workingCatalog()) {
        auto resolvedName = context()->workingCatalog()->resolve(name, tp);
        if ( resolvedName != sUNDEF)
            return resolvedName;
    }
    auto code = name;
    if ( code.indexOf("code=") == 0)
        code = code.mid(5);

    auto query = QString("select resource,type from mastercatalog where name = '%1' or code='%1'").arg(code);
    auto results = kernel()->database().exec(query);
    while ( results.next()) {
        auto rec = results.record();
        auto type = rec.value(1).toLongLong();
        if ( type & tp)
            return rec.value(0).toString();
    }
    return QUrl();

}

bool MasterCatalog::isRegistered(quint64 id) const
{
    return _lookup.contains(id);
}

bool MasterCatalog::unregister(quint64 id)
{
    QHash<quint64,ESPObject>::const_iterator iter = _lookup.find(id);
    if ( iter != _lookup.end()) {
        _lookup.remove(id);
    }

    return true;

}

std::list<Resource> MasterCatalog::select(const QUrl &res, const QString &selection) const
{
    QString rest = selection == "" ? "" : QString("and (%1)").arg(selection);
    QString query = QString("select * from mastercatalog where container = '%1' %2").arg(res.toString(), rest);
    QSqlQuery results = kernel()->database().exec(query);
    std::list<Resource> items;
    while( results.next()) {
        QSqlRecord rec = results.record();
        items.push_back(Resource(rec));
    }
    return items;

}

void MasterCatalog::registerObject(ESPObject &data)
{
    if ( data.data() == 0) {
        QHash<quint64,ESPObject>::iterator iter = _lookup.find(data->id());
        data = iter.value();
    } else {
        _lookup[data->id()] = data;

    }
}

<commit_msg>missing return statement<commit_after>#include <QString>
#include <QUrl>
#include <QRegExp>
#include <QSharedPointer>
#include <QVector>
#include <QFileInfo>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QSettings>
#include <QSqlField>
#include "identity.h"
#include "kernel.h"
#include "resource.h"
#include "connectorinterface.h"
#include "catalogconnector.h"
#include "factory.h"
#include "abstractfactory.h"
#include "connectorfactory.h"
#include "catalogconnectorfactory.h"
#include "catalog.h"
#include "mastercatalog.h"
#include "operationExpression.h"
#include "ilwiscontext.h"

Ilwis::MasterCatalog *Ilwis::MasterCatalog::_masterCatalog = 0;

using namespace Ilwis;

MasterCatalog* Ilwis::mastercatalog() {
    if (Ilwis::MasterCatalog::_masterCatalog == 0) {
        Ilwis::MasterCatalog::_masterCatalog = new Ilwis::MasterCatalog();
        Ilwis::MasterCatalog::_masterCatalog->prepare();

    }
    return Ilwis::MasterCatalog::_masterCatalog;
}

MasterCatalog::MasterCatalog()
{
}

MasterCatalog::~MasterCatalog()
{
    qDeleteAll(_catalogs);
}

bool MasterCatalog::prepare()
{
    QSettings settings("52n","ilwis4");

    QString local = settings.value("localfilesystem",QVariant(sUNDEF)).toString();
    if ( local == sUNDEF) {
        QUrl res("file://");
        addContainer(res);
    }
    return true;
}

bool MasterCatalog::addContainer(const QUrl &location)
{
    if ( _catalogs.contains(location))
        return true;

    Resource resource(location, itCATALOG);
    auto *cfactory = kernel()->factory<CatalogConnectorFactory>("catalogconnectorfactory", resource);
    if (!cfactory) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"Connector Factory",location.toString());
    }
    auto connectors= cfactory->create(location);
    if ( connectors.size() == 0) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"Catalog connector", location.toString());
    }

    addItems({resource});
    for(CatalogConnector *conn: connectors) {
        _catalogs.insert(location, conn);
        conn->loadItems();
    }
    return true;
}

ESPObject MasterCatalog::get(const QUrl &resource, IlwisTypes type) const
{
    quint64 id = resource2id(resource, type);
    return get(id);
}

ESPObject MasterCatalog::get(quint64 id) const
{
    if ( id != i64UNDEF) {
        auto iter = _lookup.find(id);
        if ( iter != _lookup.end())
            return iter.value();
    }
    return QExplicitlySharedDataPointer<IlwisObject>();
}

bool MasterCatalog::contains(const QUrl& url, IlwisTypes type) const{
    auto hash = Ilwis::qHash2(url, type);
    auto  iter = _knownHashes.find(hash);
    if ( iter != _knownHashes.end()) {
        auto id = resource2id(url, type);
        if ( id != i64UNDEF)
            return true;
    }
    return false;
}

bool MasterCatalog::removeItems(const QList<Resource> &items){
    for(const Resource &item : items) {
        auto iter = _knownHashes.find(Ilwis::qHash(item));
        if ( iter != _knownHashes.end()) {
            _knownHashes.erase(iter);
        }
        QString stmt = QString("DELETE FROM mastercatalog WHERE item = %1" ).arg(item.id());
        QSqlQuery db(kernel()->database());
        if(!db.exec(stmt)) {
            kernel()->issues()->logSql(db.lastError());
            return false;
        }
        stmt = QString("DELETE FROM catalogitemproperties WHERE item = %1").arg(item.id());
        if(!db.exec(stmt)) {
            kernel()->issues()->logSql(db.lastError());
            return false;
        }
    }

    return true;
}

bool MasterCatalog::addItems(const QList<Resource>& items)
{
    QSqlQuery queryItem, queryProperties;

    bool ok = queryItem.prepare("INSERT INTO mastercatalog VALUES(\
                  :itemid,:name,:code,:container,:resource,:type,:extendedtype, :size,:dimensions \
                  )" );
    if (!ok) {
        kernel()->issues()->logSql(queryItem.lastError());
        return false;

    }

    ok = queryProperties.prepare("INSERT INTO catalogitemproperties VALUES(\
                   :propertyvalue,:propertyname,:itemid\
                 )" );
    if (!ok) {
        kernel()->issues()->logSql(queryItem.lastError());
        return false;
    }

    for(const Resource &item : items) {
        if ( _lookup.contains(item.id()))
            continue;
        if ( mastercatalog()->contains(item.url(), item.ilwisType()))
            continue;

         _knownHashes.insert(Ilwis::qHash(item));
        item.store(queryItem, queryProperties);
    }

    return true;

}
quint64 MasterCatalog::resource2id(const QUrl &url, IlwisTypes tp) const
{
    auto query = QString("select itemid,type from mastercatalog where resource = '%1'").arg(url.toString());
    auto results = kernel()->database().exec(query);
    while ( results.next()) {
        auto rec = results.record();
        auto iid = rec.value(0).toLongLong();
        auto itype = rec.value(1).toLongLong();
        if ( (itype & tp) || tp == itUNKNOWN)
            return iid;
    }

    return i64UNDEF;

}

Resource MasterCatalog::id2Resource(quint64 iid) const {
    auto query = QString("select * from mastercatalog where itemid = %1").arg(iid);
    auto results = kernel()->database().exec(query);
    if ( results.next()) {
        auto rec = results.record();
        return Resource(rec);
    }
    return Resource();
}

quint64 MasterCatalog::name2id(const QString &name, IlwisTypes tp) const
{
    if ( name.left(10) == INTERNAL_PREFIX) { // internal objects are not in the catalog
        QString sid = name.mid(11);
        bool ok;
        quint64 id = sid.toLongLong(&ok);
        if (ok){
            ESPObject data = mastercatalog()->get(id);
            if ( data.data() != 0) {
                return data->id();
            }
        }
    }
    Resource res = name2Resource(name,tp);
    return res.id();
}

IlwisTypes MasterCatalog::id2type(quint64 iid) const {
    QString query = QString("select type from mastercatalog where itemid = %1").arg(iid);
    QSqlQuery results = kernel()->database().exec(query);
    if ( results.next()) {
        return results.value(0).toLongLong();
    }
    return itUNKNOWN;
}

Resource MasterCatalog::name2Resource(const QString &name, IlwisTypes tp) const
{
    if ( tp == itUNKNOWN) {
        std::vector<IlwisTypes> types { itGRIDCOVERAGE, itFEATURECOVERAGE, itTABLE, itGEOREF, itCOORDSYSTEM, itDOMAIN};
        for(IlwisTypes type: types) {
            Resource res = name2Resource(name, type);
            if (res.isValid())
                return res.ilwisType();
        }

        return Resource();
    }
    auto resolvedName = name2url(name, tp);
    if (!resolvedName.isValid())
        return Resource();

    auto query = QString("select * from mastercatalog where resource = '%1' and (type & %2) != 0").arg(resolvedName.toString()).arg(tp);
    auto results = kernel()->database().exec(query);
    if ( results.next()) {
        auto rec = results.record();
        return Resource(rec);

    } else {
        query = QString("select propertyvalue from catalogitemproperties,mastercatalog \
                        where mastercatalog.resource='%1' and mastercatalog.itemid=catalogitemproperties.itemid\
                and (mastercatalog.extendedtype & %2) != 0").arg(resolvedName.toString()).arg(tp);
        auto viaExtType = kernel()->database().exec(query);
                //TODO this can probably be more efficient, later
        while ( viaExtType.next()){
            bool ok;
            auto propertyid = viaExtType.value(0).toLongLong(&ok);
            if (!ok) {
                kernel()->issues()->log(TR("Invalid catalog property, mastercatalog corrupted?"),IssueObject::itWarning);
            }
            auto type = id2type(propertyid);
            if ( type & tp)
                return id2Resource(propertyid);
        }
    }
    return Resource();
}

QUrl MasterCatalog::name2url(const QString &name, IlwisTypes tp) const{
    if ( name.contains(QRegExp("\\\\|/"))) { // is there already path info; then assume it is already a unique resource
        QUrl url(name);
        if ( url.scheme().size() > 1)
            return name;
        return QUrl::fromLocalFile(name).toString();
    }
    if ( name.indexOf("code=wkt:")==0) {
        auto code = name.right(name.size() - 5);
        auto wkt = code.mid(4);
        auto table = "projection";
        if ( tp & itELLIPSOID )
            table = "ellipsoid";
        else if ( tp & itGEODETICDATUM)
            table = "datum";
        auto query = QString("select code from %1 where wkt='%2'").arg(table, wkt);
        auto codes = kernel()->database().exec(query);
        if ( codes.next()) {
            return QString("ilwis://tables/%1?code=%2").arg(table,codes.value(0).toString());
        }else {
            kernel()->issues()->log(TR(ERR_FIND_SYSTEM_OBJECT_1).arg(wkt));
            return QUrl();
        }
    } else if ( name.indexOf("code=epsg:")== 0 ) {
        //TODO other tables then projectedcsy
        auto code = name.right(name.size() - 5);
        return QString("ilwis://tables/projectedcsy?code=%1").arg(code);

    } else if ( name.left(6) == "code=proj4:") {
        auto code = name.right(name.size() - 5);
        return QString("ilwis://projection/code=%1").arg(code);
    }
    if ( context()->workingCatalog()) {
        auto resolvedName = context()->workingCatalog()->resolve(name, tp);
        if ( resolvedName != sUNDEF)
            return resolvedName;
    }
    auto code = name;
    if ( code.indexOf("code=") == 0)
        code = code.mid(5);

    auto query = QString("select resource,type from mastercatalog where name = '%1' or code='%1'").arg(code);
    auto results = kernel()->database().exec(query);
    while ( results.next()) {
        auto rec = results.record();
        auto type = rec.value(1).toLongLong();
        if ( type & tp)
            return rec.value(0).toString();
    }
    return QUrl();

}

bool MasterCatalog::isRegistered(quint64 id) const
{
    return _lookup.contains(id);
}

bool MasterCatalog::unregister(quint64 id)
{
    QHash<quint64,ESPObject>::const_iterator iter = _lookup.find(id);
    if ( iter != _lookup.end()) {
        _lookup.remove(id);
    }

    return true;

}

std::list<Resource> MasterCatalog::select(const QUrl &res, const QString &selection) const
{
    QString rest = selection == "" ? "" : QString("and (%1)").arg(selection);
    QString query = QString("select * from mastercatalog where container = '%1' %2").arg(res.toString(), rest);
    QSqlQuery results = kernel()->database().exec(query);
    std::list<Resource> items;
    while( results.next()) {
        QSqlRecord rec = results.record();
        items.push_back(Resource(rec));
    }
    return items;

}

void MasterCatalog::registerObject(ESPObject &data)
{
    if ( data.data() == 0) {
        QHash<quint64,ESPObject>::iterator iter = _lookup.find(data->id());
        data = iter.value();
    } else {
        _lookup[data->id()] = data;

    }
}

<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE "test_eigen"

#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif

#include <mill/math/Matrix.hpp>
#include <mill/math/Vector.hpp>
#include <mill/math/EigenSolver.hpp>

#include <random>
#include <iostream>
constexpr static unsigned int seed = 32479327;
constexpr static std::size_t N = 1000;

inline double
determinant(const mill::Matrix<double, 3, 3>& mat)
{
    return mat(0,0) * mat(1,1) * mat(2,2) +
           mat(1,0) * mat(2,1) * mat(0,2) +
           mat(2,0) * mat(0,1) * mat(1,2) -
           mat(0,0) * mat(2,1) * mat(1,2) -
           mat(2,0) * mat(1,1) * mat(0,2) -
           mat(1,0) * mat(0,1) * mat(2,2);
}

BOOST_AUTO_TEST_CASE(eigenvalues)
{
    std::mt19937 mt(seed);
    std::uniform_real_distribution<double> uni(0., 1.0);
    mill::JacobiEigenSolver solver;
    for(std::size_t test_times=0; test_times<N; ++test_times)
    {
        mill::Matrix<double, 3, 3> mat;
        double det = 0.;
        while(det == 0.)
        {
            for(std::size_t i=0; i<3; ++i)
                for(std::size_t j=i; j<3; ++j)
                    if(i==j)
                        mat(i,j) = uni(mt);
                    else
                        mat(i,j) = mat(j,i) = uni(mt);
            det = determinant(mat);
        }

        auto ev = solver.solve(mat);

        for(std::size_t i=0; i<3; ++i)
        {
            mill::Matrix<double, 3, 3> M = mat;

            for(std::size_t j=0; j<3; ++j)
                M(j, j) -= ev.at(i).first;

            const mill::Vector<double, 3> vec = M * ev.at(i).second;
            BOOST_CHECK_SMALL(vec[0], 1e-6);
            BOOST_CHECK_SMALL(vec[1], 1e-6);
            BOOST_CHECK_SMALL(vec[2], 1e-6);
        }
    }
}

<commit_msg>:white_check_mark: add test for eigenvalues of dynamic matrix<commit_after>#define BOOST_TEST_MODULE "test_eigen"

#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif

#include <mill/math/Matrix.hpp>
#include <mill/math/Vector.hpp>
#include <mill/math/EigenSolver.hpp>

#include <random>
#include <iostream>
constexpr static unsigned int seed = 32479327;
constexpr static std::size_t N = 1000;

inline double
determinant(const mill::Matrix<double, 3, 3>& mat)
{
    return mat(0,0) * mat(1,1) * mat(2,2) +
           mat(1,0) * mat(2,1) * mat(0,2) +
           mat(2,0) * mat(0,1) * mat(1,2) -
           mat(0,0) * mat(2,1) * mat(1,2) -
           mat(2,0) * mat(1,1) * mat(0,2) -
           mat(1,0) * mat(0,1) * mat(2,2);
}

BOOST_AUTO_TEST_CASE(eigenvalues)
{
    std::mt19937 mt(seed);
    std::uniform_real_distribution<double> uni(0., 1.0);
    mill::JacobiEigenSolver solver;
    for(std::size_t test_times=0; test_times<N; ++test_times)
    {
        mill::Matrix<double, 3, 3> mat;
        double det = 0.;
        while(det == 0.)
        {
            for(std::size_t i=0; i<3; ++i)
                for(std::size_t j=i; j<3; ++j)
                    if(i==j)
                        mat(i,j) = uni(mt);
                    else
                        mat(i,j) = mat(j,i) = uni(mt);
            det = determinant(mat);
        }

        auto ev = solver.solve(mat);

        for(std::size_t i=0; i<3; ++i)
        {
            mill::Matrix<double, 3, 3> M = mat;

            for(std::size_t j=0; j<3; ++j)
                M(j, j) -= ev.at(i).first;

            const mill::Vector<double, 3> vec = M * ev.at(i).second;
            BOOST_CHECK_SMALL(vec[0], 1e-6);
            BOOST_CHECK_SMALL(vec[1], 1e-6);
            BOOST_CHECK_SMALL(vec[2], 1e-6);
        }
    }
}

BOOST_AUTO_TEST_CASE(eigenvalues_dynamic)
{
    std::mt19937 mt(seed);
    std::uniform_real_distribution<double> uni(0.0, 1.0);
    mill::JacobiEigenSolver solver;

    for(std::size_t test_times=0; test_times<N; ++test_times)
    {
        mill::Matrix<double, mill::DYNAMIC, mill::DYNAMIC> mat({10u, 10u});
        for(std::size_t i=0; i<mat.col(); ++i)
        {
            for(std::size_t j=i; j<mat.row(); ++j)
            {
                if(i == j)
                {
                    mat(i, j) = uni(mt);
                }
                else
                {
                    mat(i, j) = mat(j, i) = uni(mt);
                }
            }
        }

        auto ev = solver.solve(mat);
        for(std::size_t i=0; i<mat.row(); ++i)
        {
            auto M = mat;

            for(std::size_t j=0; j<mat.row(); ++j)
            {
                M(j, j) -= ev.at(i).first;
            }

            const auto vec = M * ev.at(i).second;
            BOOST_CHECK(vec.len() == M.row());
            BOOST_CHECK(vec.row() == M.row());
            BOOST_CHECK(vec.col() == 1);
            for(std::size_t j=0; j<vec.len(); ++j)
            {
                BOOST_CHECK_SMALL(vec[j], 1e-5);
            }
        }
    }
}
<|endoftext|>


<commit_before>#include <L3GD20.h>
#include <Wire.h>
#include <math.h>

// Defines ////////////////////////////////////////////////////////////////
#define _MULTI_REGISTER_GYRO_READ

// The Arduino two-wire interface uses a 7-bit number for the address,
// and sets the last bit correctly based on reads and writes
#define L3GD20_ADDR_SEL_LOW	0x6a
#define L3GD20_ADDR_SEL_HIGH	0x6b

// Public Methods //////////////////////////////////////////////////////////////

L3GD20::L3GD20()
{
	I2CAddr = L3GD20_ADDR_SEL_HIGH;
}

uint8_t L3GD20::setSELState(uint8_t SELState)
{
	uint8_t ReturnValue = 0;

	if(0 == SELState)
	{
		I2CAddr = L3GD20_ADDR_SEL_LOW;
	}
	else if(1 == SELState)
	{
		I2CAddr = L3GD20_ADDR_SEL_HIGH;
	}

	return ReturnValue;
}

// Turns on the L3GD20's gyro and places it in normal mode.
void L3GD20::enableDefault(void)
{
	// 0x0F = 0b00001111
	// Normal power mode, all axes enabled
	writeReg(L3GD20_CTRL_REG1, 0x0F);
}

// Writes a gyro register
void L3GD20::writeReg(uint8_t reg, uint8_t value)
{
	Wire.beginTransmission(I2CAddr);
	Wire.write(reg);
	Wire.write(value);
	Wire.endTransmission();
}

// Reads a gyro register
uint8_t L3GD20::readReg(uint8_t reg)
{
	uint8_t value;

	Wire.beginTransmission(I2CAddr);
	Wire.write(reg);
	Wire.endTransmission();
	Wire.requestFrom(I2CAddr, 1);

	while(!Wire.available());

	value = Wire.read();
	Wire.endTransmission();

	return value;
}

// Reads the 3 gyro channels
void L3GD20::readGyro(int16_t *pX, int16_t *pY, int16_t *pZ)
{
	Wire.beginTransmission(I2CAddr);

#ifdef _MULTI_REGISTER_GYRO_READ
	// assert the MSB of the address to get the gyro
	// to do slave-transmit subaddress updating.
	Wire.write(L3GD20_OUT_X_L | (1 << 7));
	Wire.endTransmission();
	Wire.requestFrom(I2CAddr, 6);

	while (Wire.available() < 6);

	uint8_t xla = Wire.read();
	uint8_t xha = Wire.read();
	uint8_t yla = Wire.read();
	uint8_t yha = Wire.read();
	uint8_t zla = Wire.read();
	uint8_t zha = Wire.read();

#else

	uint8_t xla = readReg(L3GD20_OUT_X_L);
	uint8_t xha = readReg(L3GD20_OUT_X_H);
	uint8_t yla = readReg(L3GD20_OUT_Y_L);
	uint8_t yha = readReg(L3GD20_OUT_Y_H);
	uint8_t zla = readReg(L3GD20_OUT_Z_L);
	uint8_t zha = readReg(L3GD20_OUT_Z_H);

#endif	//_AUTO_ADDRESS_UPDATE

	*pX = (int16_t)(xha << 8 | xla);
	*pY = (int16_t)(yha << 8 | yla);
	*pZ = (int16_t)(zha << 8 | zla);
}

void L3GD20::readTemperature(int8_t *pTemperature)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_OUT_TEMP);

	*pTemperature = (int8_t)RegisterValue;
}

void L3GD20::setFullScaleRange(uint8_t FullScaleRange)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_CTRL_REG4);

	RegisterValue &= ~(0x30);
	RegisterValue |= ((FullScaleRange & 0x03) << 4);

	writeReg(L3GD20_CTRL_REG4, RegisterValue);
}

void L3GD20::setBandwidth(uint8_t Bandwidth)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_CTRL_REG1);

	RegisterValue &= ~(0x30);
	RegisterValue |= ((Bandwidth & 0x03) << 4);

	writeReg(L3GD20_CTRL_REG1, RegisterValue);
}

void L3GD20::setOutputDataRate(uint8_t DataRate)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_CTRL_REG1);

	RegisterValue &= ~(0xC0);
	RegisterValue |= ((DataRate & 0x03) << 6);

	writeReg(L3GD20_CTRL_REG1, RegisterValue);
}

<commit_msg>whitespace and dead include cleanup<commit_after>#include <L3GD20.h>
#include <Wire.h>

// Defines ////////////////////////////////////////////////////////////////
#define _MULTI_REGISTER_GYRO_READ

// The Arduino two-wire interface uses a 7-bit number for the address,
// and sets the last bit correctly based on reads and writes
#define L3GD20_ADDR_SEL_LOW	0x6a
#define L3GD20_ADDR_SEL_HIGH	0x6b

// Public Methods //////////////////////////////////////////////////////////////

L3GD20::L3GD20()
{
	I2CAddr = L3GD20_ADDR_SEL_HIGH;
}

uint8_t L3GD20::setSELState(uint8_t SELState)
{
	uint8_t ReturnValue = 0;

	if(0 == SELState)
	{
		I2CAddr = L3GD20_ADDR_SEL_LOW;
	}
	else if(1 == SELState)
	{
		I2CAddr = L3GD20_ADDR_SEL_HIGH;
	}

	return ReturnValue;
}

// Turns on the L3GD20's gyro and places it in normal mode.
void L3GD20::enableDefault(void)
{
	// 0x0F = 0b00001111
	// Normal power mode, all axes enabled
	writeReg(L3GD20_CTRL_REG1, 0x0F);
}

// Writes a gyro register
void L3GD20::writeReg(uint8_t reg, uint8_t value)
{
	Wire.beginTransmission(I2CAddr);
	Wire.write(reg);
	Wire.write(value);
	Wire.endTransmission();
}

// Reads a gyro register
uint8_t L3GD20::readReg(uint8_t reg)
{
	uint8_t value;

	Wire.beginTransmission(I2CAddr);
	Wire.write(reg);
	Wire.endTransmission();
	Wire.requestFrom(I2CAddr, 1);

	while(!Wire.available());

	value = Wire.read();
	Wire.endTransmission();

	return value;
}

// Reads the 3 gyro channels
void L3GD20::readGyro(int16_t *pX, int16_t *pY, int16_t *pZ)
{
	Wire.beginTransmission(I2CAddr);

#ifdef _MULTI_REGISTER_GYRO_READ
	// assert the MSB of the address to get the gyro
	// to do slave-transmit subaddress updating.
	Wire.write(L3GD20_OUT_X_L | (1 << 7));
	Wire.endTransmission();
	Wire.requestFrom(I2CAddr, 6);

	while (Wire.available() < 6);

	uint8_t xla = Wire.read();
	uint8_t xha = Wire.read();
	uint8_t yla = Wire.read();
	uint8_t yha = Wire.read();
	uint8_t zla = Wire.read();
	uint8_t zha = Wire.read();

#else

	uint8_t xla = readReg(L3GD20_OUT_X_L);
	uint8_t xha = readReg(L3GD20_OUT_X_H);
	uint8_t yla = readReg(L3GD20_OUT_Y_L);
	uint8_t yha = readReg(L3GD20_OUT_Y_H);
	uint8_t zla = readReg(L3GD20_OUT_Z_L);
	uint8_t zha = readReg(L3GD20_OUT_Z_H);

#endif	//_AUTO_ADDRESS_UPDATE

	*pX = (int16_t)(xha << 8 | xla);
	*pY = (int16_t)(yha << 8 | yla);
	*pZ = (int16_t)(zha << 8 | zla);
}

void L3GD20::readTemperature(int8_t *pTemperature)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_OUT_TEMP);

	*pTemperature = (int8_t)RegisterValue;
}

void L3GD20::setFullScaleRange(uint8_t FullScaleRange)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_CTRL_REG4);

	RegisterValue &= ~(0x30);
	RegisterValue |= ((FullScaleRange & 0x03) << 4);

	writeReg(L3GD20_CTRL_REG4, RegisterValue);
}

void L3GD20::setBandwidth(uint8_t Bandwidth)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_CTRL_REG1);

	RegisterValue &= ~(0x30);
	RegisterValue |= ((Bandwidth & 0x03) << 4);

	writeReg(L3GD20_CTRL_REG1, RegisterValue);
}

void L3GD20::setOutputDataRate(uint8_t DataRate)
{
	uint8_t RegisterValue;

	RegisterValue = readReg(L3GD20_CTRL_REG1);

	RegisterValue &= ~(0xC0);
	RegisterValue |= ((DataRate & 0x03) << 6);

	writeReg(L3GD20_CTRL_REG1, RegisterValue);
}

<|endoftext|>


<commit_before>#ifndef SJTU_LCTREE_HPP
#define SJTU_LCTREE_HPP

#include "TBase.hpp"
#include "LCTNode.hpp"

namespace sjtu{

template<class T, class A, class M>
class LCTree : public TBase<T, A, M>{
private:
	LCTNode<T, A, M>* access(LCTNode<T, A, M> *u);
	void add(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void del(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void isSplayRoot(LCTNode<T, A, M> *u);

protected:
	static void rotate(LCTNode<T, A, M> *u, int c);
	static void zig(LCTNode<T, A, M> *u);
	static void zag(LCTNode<T, A, M> *u);
	static LCTNode<T, A, M>* getSplayRoot(LCTNode<T, A, M> *u);
	static void splay(LCTNode<T, A, M> *u);
	void link(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void cut(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void modifyChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v, const T &value);
	T queryChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void modifySubtree(LCTNode<T, A, M> *u, const T &value);
	void querySubtree(LCTNode<T, A, M> *u);
	LCTNode<T, A, M> * setRoot(LCTNode<T, A, M> *u);

};

#include "source/LCTree.cpp"

template<class T, class A, class M>
void LCTree<T, A, M>::add(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	if (u == nullptr || v == nullptr) return;
	(u -> subtree).insert(AuxNode<T, A, M>(v, rand()));
}

template<class T, class A, class M>
void LCTree<T, A, M>::del(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	if (u == nullptr || v == nullptr) return;
	(u -> subtree).erase(AuxNode<T, A, M>(v, rand()));
}

template<class T, class A, class M>
void LCTree<T, A, M>::rotate(LCTNode<T, A, M> *u, int c) {
	LCTNode<T, A, M> *v = u->father;
	v->child[c ^ 1] = u->child[c];
	if (u->child[c] != nullptr) {
		u->child[c]->father = v;
	}
	u->father = v->father;
	if (v->father->child[0] == v) {
		u->father->child[0] = u;
	} else if (v->father->child[1] == v) {
		u->father->child[1] = u;
	}
	v->father = u;
	u->child[c] = v;
}

template<class T, class A, class M>
void LCTree<T, A, M>::zig(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 0);
}

template<class T, class A, class M>
void LCTree<T, A, M>::zag(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 1);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::getSplayRoot(LCTNode<T, A, M> *u) {
	while (!LCTree<T, A, M>::isSplayRoot(u)) {
		u = u->father;
	}
	return u;
}

template<class T, class A, class M>
void LCTree<T, A, M>::isSplayRoot(LCTNode<T, A, M> *u) {
	return u->father == nullptr || (u->father->child[0] != u && u->father->child[1] != u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::splay(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M> * uRoot = LCTree<T, A, M>::getSplayRoot(u);
	del(uRoot->father, uRoot);

	while (!isSplayRoot(u)) {
		LCTNode<T, A, M> *v = u->father;
		if (isSplayRoot(v)) {
			v->update();
			u->update();
			if (v->child[0] == u) {
				LCTree<T, A, M>::zig(u);
			} else {
				LCTree<T, A, M>::zag(u);
			}
		} else {
			LCTNode<T, A, M> *w = v->father;
			w->update();
			v->update();
			u->update();
			if (w->child[0] == v) {
				if (v->child[0] == u) {
					LCTree<T, A, M>::zig(v);
					LCTree<T, A, M>::zig(u);
				} else {
					LCTree<T, A, M>::zag(u);
					LCTree<T, A, M>::zig(u);
				}
			} else {
				if (v->child[1] == u) {
					LCTree<T, A, M>::zag(v);
					LCTree<T, A, M>::zag(u);
				} else {
					LCTree<T, A, M>::zig(u);
					LCTree<T, A, M>::zag(u);
				}
			}
		}
	}
	LCTree<T, A, M>::update(u);
	add(u->father, u);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::access(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M>* v = nullptr;
	for ( ; u != nullptr; u = u->father) {
		LCTree<T, A, M>::splay(u);
		LCTree<T, A, M>::del(u, v);
		LCTree<T, A, M>::add(u, u->child[1]);
		if (u->child[1] != nullptr) {
			u->sum -= u->child[1]->sum;
		}
		u->child[1] = v;
		u->sum += v->sum;
		v = u;
		v->update();
	}
	return v;
}

template<class T, class A, class M>
LCTNode<T, A, M> * LCTree<T, A, M>::setRoot(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M> * tmp = LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	LCTNode<T, A, M> *p = u;
	while (p -> child[0] != nullptr) {
		p = p -> child[0];
	}
	tmp->reverse ^= true;
	LCTree<T, A, M>::splay(u);
	return p;
}

template<class T, class A, class M>
void LCTree<T, A, M>::link(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	u->father = v;
	add(v, u);
	LCTree<T, A, M>::access(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::cut(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->child[0]->father = nullptr;
	v->child[0] = nullptr;
	update(v);
}

template<class T, class A, class M>
void LCTree<T, A, M>::modifyChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v, const T &value) {
	LCTNode<T, A, M> tmp = LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->makeTagChain(value);
	LCTree<T, A, M>::setRoot(tmp);
}

template<class T, class A, class M>
T LCTree<T, A, M>::queryChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTNode<T, A, M> tmp = LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	T ret = v->sumChain;
	LCTree<T, A, M>::setRoot(tmp);
	return ret;
}

template<class T, class A, class M>
void LCTree<T, A, M>::modifySubtree(LCTNode<T, A, M> *u, const T &value) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	u->makeTagTree(value);
	u->update();
	LCTree<T, A, M>::splay(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::querySubtree(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	return add(u->sumSubtree, u->data);
}

}

#endif
<commit_msg>Changed.<commit_after>#ifndef SJTU_LCTREE_HPP
#define SJTU_LCTREE_HPP

#include "TBase.hpp"
#include "LCTNode.hpp"

namespace sjtu{

template<class T, class A, class M>
class LCTree : public TBase<T, A, M>{
private:
	LCTNode<T, A, M>* access(LCTNode<T, A, M> *u);
	void add(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void del(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void isSplayRoot(LCTNode<T, A, M> *u);

protected:
	static void rotate(LCTNode<T, A, M> *u, int c);
	static void zig(LCTNode<T, A, M> *u);
	static void zag(LCTNode<T, A, M> *u);
	static LCTNode<T, A, M>* getSplayRoot(LCTNode<T, A, M> *u);
	static void splay(LCTNode<T, A, M> *u);
	void link(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void cut(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void modifyChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v, const T &value);
	T queryChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v);
	void modifySubtree(LCTNode<T, A, M> *u, const T &value);
	void querySubtree(LCTNode<T, A, M> *u);
	LCTNode<T, A, M> * setRoot(LCTNode<T, A, M> *u);

};

#include "source/LCTree.cpp"

template<class T, class A, class M>
void LCTree<T, A, M>::add(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	if (u == nullptr || v == nullptr) return;
	(u -> subtree).insert(AuxNode<T, A, M>(v, rand()));
}

template<class T, class A, class M>
void LCTree<T, A, M>::del(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	if (u == nullptr || v == nullptr) return;
	(u -> subtree).erase(AuxNode<T, A, M>(v, rand()));
}

template<class T, class A, class M>
void LCTree<T, A, M>::rotate(LCTNode<T, A, M> *u, int c) {
	LCTNode<T, A, M> *v = u->father;
	v->child[c ^ 1] = u->child[c];
	if (u->child[c] != nullptr) {
		u->child[c]->father = v;
	}
	u->father = v->father;
	if (v->father->child[0] == v) {
		u->father->child[0] = u;
	} else if (v->father->child[1] == v) {
		u->father->child[1] = u;
	}
	v->father = u;
	u->child[c] = v;
}

template<class T, class A, class M>
void LCTree<T, A, M>::zig(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 0);
}

template<class T, class A, class M>
void LCTree<T, A, M>::zag(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::rotate(u, 1);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::getSplayRoot(LCTNode<T, A, M> *u) {
	while (!LCTree<T, A, M>::isSplayRoot(u)) {
		u = u->father;
	}
	return u;
}

template<class T, class A, class M>
void LCTree<T, A, M>::isSplayRoot(LCTNode<T, A, M> *u) {
	return u->father == nullptr || (u->father->child[0] != u && u->father->child[1] != u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::splay(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M> * uRoot = LCTree<T, A, M>::getSplayRoot(u);
	del(uRoot->father, uRoot);

	while (!isSplayRoot(u)) {
		LCTNode<T, A, M> *v = u->father;
		if (isSplayRoot(v)) {
			v->update();
			u->update();
			if (v->child[0] == u) {
				LCTree<T, A, M>::zig(u);
			} else {
				LCTree<T, A, M>::zag(u);
			}
		} else {
			LCTNode<T, A, M> *w = v->father;
			w->update();
			v->update();
			u->update();
			if (w->child[0] == v) {
				if (v->child[0] == u) {
					LCTree<T, A, M>::zig(v);
					LCTree<T, A, M>::zig(u);
				} else {
					LCTree<T, A, M>::zag(u);
					LCTree<T, A, M>::zig(u);
				}
			} else {
				if (v->child[1] == u) {
					LCTree<T, A, M>::zag(v);
					LCTree<T, A, M>::zag(u);
				} else {
					LCTree<T, A, M>::zig(u);
					LCTree<T, A, M>::zag(u);
				}
			}
		}
	}
	LCTree<T, A, M>::update(u);
	add(u->father, u);
}

template<class T, class A, class M>
LCTNode<T, A, M>* LCTree<T, A, M>::access(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M>* v = nullptr;
	for ( ; u != nullptr; u = u->father) {
		LCTree<T, A, M>::splay(u);
		LCTree<T, A, M>::del(u, v);
		LCTree<T, A, M>::add(u, u->child[1]);
		if (u->child[1] != nullptr) {
			u->sum -= u->child[1]->sum;
		}
		u->child[1] = v;
		u->sum += v->sum;
		v = u;
		v->update();
	}
	return v;
}

template<class T, class A, class M>
LCTNode<T, A, M> * LCTree<T, A, M>::setRoot(LCTNode<T, A, M> *u) {
	LCTNode<T, A, M> * tmp = LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	LCTNode<T, A, M> *p = u;
	while (p -> child[0] != nullptr) {
		p = p -> child[0];
	}
	tmp->reverse ^= true;
	LCTree<T, A, M>::splay(u);
	return p;
}

template<class T, class A, class M>
void LCTree<T, A, M>::link(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	u->father = v;
	add(v, u);
	LCTree<T, A, M>::access(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::cut(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->child[0]->father = nullptr;
	v->child[0] = nullptr;
	update(v);
}

template<class T, class A, class M>
void LCTree<T, A, M>::modifyChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v, const T &value) {
	LCTNode<T, A, M> tmp = LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	v->makeTagChain(value);
	LCTree<T, A, M>::setRoot(tmp);
}

template<class T, class A, class M>
T LCTree<T, A, M>::queryChain(LCTNode<T, A, M> *u, LCTNode<T, A, M> *v) {
	LCTNode<T, A, M> tmp = LCTree<T, A, M>::setRoot(u);
	LCTree<T, A, M>::access(v);
	LCTree<T, A, M>::splay(v);
	T ret = v->sumChain;
	LCTree<T, A, M>::setRoot(tmp);
	return ret;
}

template<class T, class A, class M>
void LCTree<T, A, M>::modifySubtree(LCTNode<T, A, M> *u, const T &value) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	u->makeTagTree(value);
	u->update();
	LCTree<T, A, M>::splay(u);
}

template<class T, class A, class M>
void LCTree<T, A, M>::querySubtree(LCTNode<T, A, M> *u) {
	LCTree<T, A, M>::access(u);
	LCTree<T, A, M>::splay(u);
	return add(u->sumTree, u->data);
}

}

#endif
<|endoftext|>