text:
#include "windowing/WindowData.h"

#include "common/Exception.hpp"
#include "common/Types.h"
#include "common/UuidUtility.h"

#include "logic/camera/CameraTypes.h"
#include "logic/camera/CameraHelpers.h"

#include <glm/glm.hpp>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>

#include <spdlog/spdlog.h>
#include <spdlog/fmt/ostr.h>

#include <boost/range.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/filtered.hpp>

#undef min
#undef max

namespace
{

Layout createFourUpLayout()
{
    using namespace camera;

    const UiControls uiControls( true );

    const auto noRotationSyncGroup = std::nullopt;
    const auto noTranslationSyncGroup = std::nullopt;
    const auto noZoomSyncGroup = std::nullopt;

    const auto zoomSyncGroupUid = generateRandomUuid();

    Layout layout( false );

    auto zoomGroup = layout.cameraZoomSyncGroups().try_emplace( zoomSyncGroupUid ).first;

    ViewOffsetSetting offsetSetting;
    offsetSetting.m_offsetMode = ViewOffsetMode::None;

    {
        // top right
        auto view = std::make_shared<View>(
                    glm::vec4{ 0.0f, 0.0f, 1.0f, 1.0f },
                    offsetSetting,
                    CameraType::Coronal,
                    ViewRenderMode::Image,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, zoomSyncGroupUid );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
        zoomGroup->second.push_back( viewUid );
    }
    {
        // top left
        auto view = std::make_shared<View>(
                    glm::vec4{ -1.0f, 0.0f, 1.0f, 1.0f },
                    offsetSetting,
                    CameraType::Sagittal,
                    ViewRenderMode::Image,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, zoomSyncGroupUid );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
        zoomGroup->second.push_back( viewUid );
    }
    {
        // bottom left
        auto view = std::make_shared<View>(
                    glm::vec4{ -1.0f, -1.0f, 1.0f, 1.0f },
                    offsetSetting,
                    CameraType::ThreeD,
                    ViewRenderMode::Disabled,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, noZoomSyncGroup );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
        zoomGroup->second.push_back( viewUid );
    }
    {
        // bottom right
        auto view = std::make_shared<View>(
                    glm::vec4{ 0.0f, -1.0f, 1.0f, 1.0f },
                    offsetSetting,
                    CameraType::Axial,
                    ViewRenderMode::Image,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, zoomSyncGroupUid );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
        zoomGroup->second.push_back( viewUid );
    }

    return layout;
}

Layout createTriLayout()
{
    using namespace camera;

    const UiControls uiControls( true );

    const auto noRotationSyncGroup = std::nullopt;
    const auto noTranslationSyncGroup = std::nullopt;
    const auto noZoomSyncGroup = std::nullopt;
    const auto zoomSyncGroupUid = generateRandomUuid();

    Layout layout( false );

    auto zoomGroup = layout.cameraZoomSyncGroups().try_emplace( zoomSyncGroupUid ).first;

    ViewOffsetSetting offsetSetting;
    offsetSetting.m_offsetMode = ViewOffsetMode::None;

    {
        // left
        auto view = std::make_shared<View>(
                    glm::vec4{ -1.0f, -1.0f, 1.5f, 2.0f },
                    offsetSetting,
                    CameraType::Axial,
                    ViewRenderMode::Image,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, noZoomSyncGroup );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
    }
    {
        // bottom right
        auto view = std::make_shared<View>(
                    glm::vec4{ 0.5f, -1.0f, 0.5f, 1.0f },
                    offsetSetting,
                    CameraType::Coronal,
                    ViewRenderMode::Image,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, zoomSyncGroupUid );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
        zoomGroup->second.push_back( viewUid );
    }
    {
        // top right
        auto view = std::make_shared<View>(
                    glm::vec4{ 0.5f, 0.0f, 0.5f, 1.0f },
                    offsetSetting,
                    CameraType::Sagittal,
                    ViewRenderMode::Image,
                    IntensityProjectionMode::None,
                    uiControls,
                    noRotationSyncGroup, noTranslationSyncGroup, zoomSyncGroupUid );

        const auto viewUid = generateRandomUuid();
        layout.views().emplace( viewUid, std::move( view ) );
        zoomGroup->second.push_back( viewUid );
    }

    return layout;
}

Layout createTriTopBottomLayout( size_t numRows )
{
    using namespace camera;

    const UiControls uiControls( true );

    const auto axiRotationSyncGroupUid = generateRandomUuid();
    const auto corRotationSyncGroupUid = generateRandomUuid();
    const auto sagRotationSyncGroupUid = generateRandomUuid();

    const auto axiTranslationSyncGroupUid = generateRandomUuid();
    const auto corTranslationSyncGroupUid = generateRandomUuid();
    const auto sagTranslationSyncGroupUid = generateRandomUuid();

    const auto axiZoomSyncGroupUid = generateRandomUuid();
    const auto corZoomSyncGroupUid = generateRandomUuid();
    const auto sagZoomSyncGroupUid = generateRandomUuid();

    Layout layout( false );

    auto axiRotGroup = layout.cameraRotationSyncGroups().try_emplace( axiRotationSyncGroupUid ).first;
    auto corRotGroup = layout.cameraRotationSyncGroups().try_emplace( corRotationSyncGroupUid ).first;
    auto sagRotGroup = layout.cameraRotationSyncGroups().try_emplace( sagRotationSyncGroupUid ).first;

    auto axiTransGroup = layout.cameraTranslationSyncGroups().try_emplace( axiTranslationSyncGroupUid ).first;
    auto corTransGroup = layout.cameraTranslationSyncGroups().try_emplace( corTranslationSyncGroupUid ).first;
    auto sagTransGroup = layout.cameraTranslationSyncGroups().try_emplace( sagTranslationSyncGroupUid ).first;

    // Should zoom be synchronized across columns or across rows?
    auto axiZoomGroup = layout.cameraZoomSyncGroups().try_emplace( axiZoomSyncGroupUid ).first;
    auto corZoomGroup = layout.cameraZoomSyncGroups().try_emplace( corZoomSyncGroupUid ).first;
    auto sagZoomGroup = layout.cameraZoomSyncGroups().try_emplace( sagZoomSyncGroupUid ).first;

    ViewOffsetSetting offsetSetting;
    offsetSetting.m_offsetMode = ViewOffsetMode::None;

    for ( size_t r = 0; r < numRows; ++r )
    {
        const float height = 2.0f / static_cast<float>( numRows );
        const float bottom = 1.0f - ( static_cast<float>( r + 1 ) ) * height;

        {
            // axial
            auto view = std::make_shared<View>(
                        glm::vec4{ -1.0f, bottom, 2.0f/3.0f, height },
                        offsetSetting,
                        CameraType::Axial,
                        ViewRenderMode::Image,
                        IntensityProjectionMode::None,
                        uiControls,
                        axiRotationSyncGroupUid,
                        axiTranslationSyncGroupUid,
                        axiZoomSyncGroupUid );

            view->setPreferredDefaultRenderedImages( { r } );

            const auto viewUid = generateRandomUuid();
            layout.views().emplace( viewUid, std::move( view ) );

            axiRotGroup->second.push_back( viewUid );
            axiTransGroup->second.push_back( viewUid );
            axiZoomGroup->second.push_back( viewUid );
        }

        {
            // coronal
            auto view = std::make_shared<View>(
                        glm::vec4{ -1.0f/3.0f, bottom, 2.0f/3.0f, height },
                        offsetSetting,
                        CameraType::Coronal,
                        ViewRenderMode::Image,
                        IntensityProjectionMode::None,
                        uiControls,
                        corRotationSyncGroupUid, corTranslationSyncGroupUid, corZoomSyncGroupUid );

            view->setPreferredDefaultRenderedImages( { r } );

            const auto viewUid = generateRandomUuid();
            layout.views().emplace( viewUid, std::move( view ) );

            corRotGroup->second.push_back( viewUid );
            corTransGroup->second.push_back( viewUid );
            corZoomGroup->second.push_back( viewUid );
        }
        {
            // sagittal
            auto view = std::make_shared<View>(
                        glm::vec4{ 1.0f/3.0f, bottom, 2.0f/3.0f, height },
                        offsetSetting,
                        CameraType::Sagittal,
                        ViewRenderMode::Image,
                        IntensityProjectionMode::None,
                        uiControls,
                        sagRotationSyncGroupUid, sagTranslationSyncGroupUid, sagZoomSyncGroupUid );

            view->setPreferredDefaultRenderedImages( { r } );

            const auto viewUid = generateRandomUuid();
            layout.views().emplace( viewUid, std::move( view ) );

            sagRotGroup->second.push_back( viewUid );
            sagTransGroup->second.push_back( viewUid );
            sagZoomGroup->second.push_back( viewUid );
        }
    }

    return layout;
}

Layout createGridLayout(
        size_t width,
        size_t height,
        bool offsetViews,
        bool isLightbox,
        const camera::CameraType& cameraType )
{
    static const camera::ViewRenderMode s_shaderType = camera::ViewRenderMode::Image;
    static const camera::IntensityProjectionMode s_ipMode = camera::IntensityProjectionMode::None;

    Layout layout( isLightbox );

    if ( isLightbox )
    {
        layout.setCameraType( cameraType );
        layout.setRenderMode( s_shaderType );
        layout.setIntensityProjectionMode( s_ipMode );

        // Lightbox layouts prefer to render reference image only by default:
        layout.setPreferredDefaultRenderedImages( { 0 } );
    }

    const auto rotationSyncGroupUid = generateRandomUuid();
    const auto translationSyncGroupUid = generateRandomUuid();
    const auto zoomSyncGroupUid = generateRandomUuid();

    auto rotGroup = layout.cameraRotationSyncGroups().try_emplace( rotationSyncGroupUid ).first;
    auto transGroup = layout.cameraTranslationSyncGroups().try_emplace( translationSyncGroupUid ).first;
    auto zoomGroup = layout.cameraZoomSyncGroups().try_emplace( zoomSyncGroupUid ).first;

    const float w = 2.0f / static_cast<float>( width );
    const float h = 2.0f / static_cast<float>( height );

    size_t count = 0;

    ViewOffsetSetting offsetSetting;
    offsetSetting.m_offsetMode = ViewOffsetMode::RelativeToRefImageScrolls;

    for ( size_t j = 0; j < height; ++j )
    {
        for ( size_t i = 0; i < width; ++i )
        {
            const float l = -1.0f + static_cast<float>( i ) * w;
            const float b = -1.0f + static_cast<float>( j ) * h;

            const int counter = static_cast<int>( width * j + i );

            offsetSetting.m_relativeOffsetSteps = ( offsetViews )
                    ? ( counter - static_cast<int>( width * height ) / 2 )
                    : 0;

            auto view = std::make_shared<View>(
                        glm::vec4{ l, b, w, h },
                        offsetSetting,
                        cameraType,
                        s_shaderType,
                        s_ipMode,
                        UiControls( ! isLightbox ),
                        rotationSyncGroupUid,
                        translationSyncGroupUid,
                        zoomSyncGroupUid );

            if ( ! isLightbox )
            {
                // Make each view render a different image by default:
                view->setPreferredDefaultRenderedImages( { count } );
            }

            const auto viewUid = generateRandomUuid();
            layout.views().emplace( viewUid, std::move( view ) );

            // Synchronize rotations, translations, and zooms for all views in the layout:
            rotGroup->second.push_back( viewUid );
            transGroup->second.push_back( viewUid );
            zoomGroup->second.push_back( viewUid );

            ++count;
        }
    }

    return layout;
}

} // anonymous

WindowData::WindowData()
    :
      m_viewport( 0, 0, 800, 800 ),
      m_windowPos( 0, 0 ),
      m_windowSize( 800, 800 ),

      m_layouts(),
      m_currentLayout( 0 ),
      m_activeViewUid( std::nullopt )
{
    setupViews();
    setCurrentLayoutIndex( 0 );
}

void WindowData::setupViews()
{
    m_layouts.emplace_back( createFourUpLayout() );
    m_layouts.emplace_back( createTriLayout() );
    m_layouts.emplace_back( createGridLayout ( 1, 1, false, false, camera::CameraType::Axial ) );
    updateAllViews();
}

void WindowData::addGridLayout( size_t width, size_t height, bool offsetViews, bool isLightbox )
{
    m_layouts.emplace_back( createGridLayout( width, height, offsetViews, isLightbox, camera::CameraType::Axial ) );
    updateAllViews();
}

void WindowData::addLightboxLayoutForImage( size_t numSlices )
{
    static constexpr bool k_offsetViews = true;
    static constexpr bool k_isLightbox = true;

    const int w = static_cast<int>( std::sqrt( numSlices + 1 ) );
    const auto div = std::div( static_cast<int>( numSlices ), w );
    const int h = div.quot + ( div.rem > 0 ? 1 : 0 );

    addGridLayout( static_cast<size_t>( w ), static_cast<size_t>( h ),
                   k_offsetViews, k_isLightbox );
}

void WindowData::addAxCorSagLayout( size_t numImages )
{
    m_layouts.emplace_back( createTriTopBottomLayout( numImages ) );
    updateAllViews();
}

void WindowData::removeLayout( size_t index )
{
    if ( index >= m_layouts.size() ) return;

    m_layouts.erase( std::begin( m_layouts ) + static_cast<long>( index ) );
}

void WindowData::setDefaultRenderedImagesForLayout(
        Layout& layout, uuid_range_t orderedImageUids )
{
    static constexpr bool s_filterAgainstDefaults = true;

    std::list<uuids::uuid> renderedImages;
    std::list<uuids::uuid> metricImages;

    size_t count = 0;

    for ( const auto& uid : orderedImageUids )
    {
        renderedImages.push_back( uid );

        if ( count < 2 )
        {
            // By default, compute the metric using the first two images:
            metricImages.push_back( uid );
            ++count;
        }
    }

    if ( layout.isLightbox() )
    {
        layout.setRenderedImages( renderedImages, s_filterAgainstDefaults );
        layout.setMetricImages( metricImages );
        return;
    }

    for ( auto& view : layout.views() )
    {
        if ( ! view.second ) continue;
        view.second->setRenderedImages( renderedImages, s_filterAgainstDefaults );
        view.second->setMetricImages( metricImages );
    }
}

void WindowData::setDefaultRenderedImagesForAllLayouts( uuid_range_t orderedImageUids )
{
    static constexpr bool s_filterAgainstDefaults = true;

    std::list<uuids::uuid> renderedImages;
    std::list<uuids::uuid> metricImages;

    size_t count = 0;

    for ( const auto& uid : orderedImageUids )
    {
        renderedImages.push_back( uid );

        if ( count < 2 )
        {
            // By default, compute the metric using the first two images:
            metricImages.push_back( uid );
            ++count;
        }
    }

    for ( auto& layout : m_layouts )
    {
        if ( layout.isLightbox() )
        {
            layout.setRenderedImages( renderedImages, s_filterAgainstDefaults );
            layout.setMetricImages( metricImages );
            continue;
        }

        for ( auto& view : layout.views() )
        {
            if ( ! view.second ) continue;
            view.second->setRenderedImages( renderedImages, s_filterAgainstDefaults );
            view.second->setMetricImages( metricImages );
        }
    }
}

void WindowData::updateImageOrdering( uuid_range_t orderedImageUids )
{
    for ( auto& layout : m_layouts )
    {
        if ( layout.isLightbox() )
        {
            layout.updateImageOrdering( orderedImageUids );
            continue;
        }

        for ( auto& view : layout.views() )
        {
            if ( ! view.second ) continue;
            view.second->updateImageOrdering( orderedImageUids );
        }
    }
}

void WindowData::recenterAllViews(
        const glm::vec3& worldCenter,
        const glm::vec3& worldFov,
        bool resetZoom,
        bool resetObliqueOrientation )
{
    for ( auto& layout : m_layouts )
    {
        for ( auto& view : layout.views() )
        {
            if ( view.second )
            {
                recenterView( *view.second, worldCenter, worldFov, resetZoom, resetObliqueOrientation );
            }
        }
    }
}

void WindowData::recenterView(
        const uuids::uuid& viewUid,
        const glm::vec3& worldCenter,
        const glm::vec3& worldFov,
        bool resetZoom,
        bool resetObliqueOrientation )
{
    if ( View* view = getView( viewUid ) )
    {
        recenterView( *view, worldCenter, worldFov, resetZoom, resetObliqueOrientation );
    }
}

void WindowData::recenterView(
        View& view,
        const glm::vec3& worldCenter,
        const glm::vec3& worldFov,
        bool resetZoom,
        bool resetObliqueOrientation )
{
    if ( resetZoom )
    {
        camera::resetZoom( view.camera() );
    }

    if ( resetObliqueOrientation && ( camera::CameraType::Oblique == view.cameraType() ) )
    {
        // Reset the view orientation for oblique views:
        camera::resetViewTransformation( view.camera() );
    }

    camera::positionCameraForWorldTargetAndFov( view.camera(), worldFov, worldCenter );
}

uuid_range_t WindowData::currentViewUids() const
{
    return ( m_layouts.at( m_currentLayout ).views() | boost::adaptors::map_keys );
}

const View* WindowData::getCurrentView( const uuids::uuid& uid ) const
{
    const auto& views = m_layouts.at( m_currentLayout ).views();
    auto it = views.find( uid );
    if ( std::end( views ) != it )
    {
        if ( it->second ) return it->second.get();
    }
    return nullptr;
}

View* WindowData::getCurrentView( const uuids::uuid& uid )
{
    auto& views = m_layouts.at( m_currentLayout ).views();
    auto it = views.find( uid );
    if ( std::end( views ) != it )
    {
        if ( it->second ) return it->second.get();
    }
    return nullptr;
}

const View* WindowData::getView( const uuids::uuid& uid ) const
{
    for ( const auto& layout : m_layouts )
    {
        auto it = layout.views().find( uid );
        if ( std::end( layout.views() ) != it )
        {
            if ( it->second ) return it->second.get();
        }
    }
    return nullptr;
}

View* WindowData::getView( const uuids::uuid& uid )
{
    for ( const auto& layout : m_layouts )
    {
        auto it = layout.views().find( uid );
        if ( std::end( layout.views() ) != it )
        {
            if ( it->second ) return it->second.get();
        }
    }
    return nullptr;
}

std::optional<uuids::uuid>
WindowData::currentViewUidAtCursor( const glm::vec2& windowPos ) const
{
    if ( m_layouts.empty() ) return std::nullopt;

    const glm::vec2 winClipPos = camera::windowNdc_T_window( m_viewport, windowPos );

    for ( const auto& view : m_layouts.at( m_currentLayout ).views() )
    {
        if ( ! view.second ) continue;
        const glm::vec4& winClipVp = view.second->windowClipViewport();

        if ( ( winClipVp[0] <= winClipPos.x ) &&
             ( winClipPos.x < winClipVp[0] + winClipVp[2] ) &&
             ( winClipVp[1] <= winClipPos.y ) &&
             ( winClipPos.y < winClipVp[1] + winClipVp[3] ) )
        {
            return view.first;
        }
    }

    return std::nullopt;
}

std::optional<uuids::uuid> WindowData::activeViewUid() const
{
    return m_activeViewUid;
}

void WindowData::setActiveViewUid( const std::optional<uuids::uuid>& uid )
{
    m_activeViewUid = uid;
}

size_t WindowData::numLayouts() const
{
    return m_layouts.size();
}

size_t WindowData::currentLayoutIndex() const
{
    return m_currentLayout;
}

const Layout* WindowData::layout( size_t index ) const
{
    if ( index < m_layouts.size() )
    {
        return &( m_layouts.at( index ) );
    }
    return nullptr;
}

const Layout& WindowData::currentLayout() const
{
    return m_layouts.at( m_currentLayout );
}

Layout& WindowData::currentLayout()
{
    return m_layouts.at( m_currentLayout );
}

void WindowData::setCurrentLayoutIndex( size_t index )
{
    if ( index >= m_layouts.size() ) return;
    m_currentLayout = index;
}

void WindowData::cycleCurrentLayout( int step )
{
    const int i = static_cast<int>( currentLayoutIndex() );
    const int N = static_cast<int>( numLayouts() );

    setCurrentLayoutIndex( static_cast<size_t>( ( N + i + step ) % N ) );
}

const Viewport& WindowData::viewport() const
{
    return m_viewport;
}

void WindowData::setViewport( float left, float bottom, float width, float height )
{
    m_viewport.setLeft( left );
    m_viewport.setBottom( bottom );
    m_viewport.setWidth( width );
    m_viewport.setHeight( height );
    updateAllViews();
}

void WindowData::setDeviceScaleRatio( const glm::vec2& scale )
{
    spdlog::trace( "Setting device scale ratio to {}x{}", scale.x, scale.y );
    m_viewport.setDevicePixelRatio( scale );
    updateAllViews();
}

void WindowData::setWindowPos( int posX, int posY )
{
    m_windowPos = glm::ivec2{ posX, posY };
}

const glm::ivec2& WindowData::getWindowPos() const
{
    return m_windowPos;
}

void WindowData::setWindowSize( int width, int height )
{
    m_windowSize = glm::ivec2{ width, height };
}

const glm::ivec2& WindowData::getWindowSize() const
{
    return m_windowSize;
}

uuid_range_t WindowData::cameraRotationGroupViewUids(
        const uuids::uuid& syncGroupUid ) const
{
    const auto& currentLayout = m_layouts.at( m_currentLayout );
    const auto it = currentLayout.cameraRotationSyncGroups().find( syncGroupUid );
    if ( std::end( currentLayout.cameraRotationSyncGroups() ) != it ) return it->second;
    return {};
}

uuid_range_t WindowData::cameraTranslationGroupViewUids(
        const uuids::uuid& syncGroupUid ) const
{
    const auto& currentLayout = m_layouts.at( m_currentLayout );
    const auto it = currentLayout.cameraTranslationSyncGroups().find( syncGroupUid );
    if ( std::end( currentLayout.cameraTranslationSyncGroups() ) != it ) return it->second;
    return {};
}

uuid_range_t WindowData::cameraZoomGroupViewUids(
        const uuids::uuid& syncGroupUid ) const
{
    const auto& currentLayout = m_layouts.at( m_currentLayout );
    const auto it = currentLayout.cameraZoomSyncGroups().find( syncGroupUid );
    if ( std::end( currentLayout.cameraZoomSyncGroups() ) != it ) return it->second;
    return {};
}

void WindowData::applyImageSelectionToAllCurrentViews(
        const uuids::uuid& referenceViewUid )
{
    static constexpr bool s_filterAgainstDefaults = false;

    const View* referenceView = getCurrentView( referenceViewUid );
    if ( ! referenceView ) return;

    const auto renderedImages = referenceView->renderedImages();
    const auto metricImages = referenceView->metricImages();

    for ( auto& viewUid : currentViewUids() )
    {
        View* view = getCurrentView( viewUid );
        if ( ! view ) continue;

        view->setRenderedImages( renderedImages, s_filterAgainstDefaults );
        view->setMetricImages( metricImages );
    }
}

void WindowData::applyViewRenderModeAndProjectionToAllCurrentViews(
        const uuids::uuid& referenceViewUid )
{
    const View* referenceView = getCurrentView( referenceViewUid );
    if ( ! referenceView ) return;

    const auto renderMode = referenceView->renderMode();
    const auto ipMode = referenceView->intensityProjectionMode();

    for ( auto& viewUid : currentViewUids() )
    {
        View* view = getCurrentView( viewUid );
        if ( ! view ) continue;

        if ( camera::CameraType::ThreeD != view->cameraType() )
        {
            // Don't allow changing render mode of 3D views
            view->setRenderMode( renderMode );
        }

        view->setIntensityProjectionMode( ipMode );
    }
}

std::vector<uuids::uuid> WindowData::findCurrentViewsWithNormal(
        const glm::vec3& worldNormal ) const
{
    // Angle threshold (in degrees) for checking whether two vectors are parallel
    static constexpr float sk_parallelThreshold_degrees = 0.1f;

    std::vector<uuids::uuid> viewUids;

    for ( auto& viewUid : currentViewUids() )
    {
        const View* view = getCurrentView( viewUid );
        if ( ! view ) continue;

        const glm::vec3 viewBackDir = camera::worldDirection( view->camera(), Directions::View::Back );

        if ( camera::areVectorsParallel( worldNormal, viewBackDir, sk_parallelThreshold_degrees ) )
        {
            viewUids.push_back( viewUid );
        }
    }

    return viewUids;
}

uuids::uuid WindowData::findLargestCurrentView() const
{
    uuids::uuid largestViewUid = currentViewUids().front();

    const View* largestView = getCurrentView( largestViewUid );

    if ( ! largestView )
    {
        spdlog::error( "The current layout has no views" );
        throw_debug( "The current layout has no views" )
    }

    float largestArea = largestView->windowClipViewport()[2] * largestView->windowClipViewport()[3];

    for ( auto& viewUid : currentViewUids() )
    {
        const View* view = getCurrentView( viewUid );
        if ( ! view ) continue;

        const float area = view->windowClipViewport()[2] * view->windowClipViewport()[3];

        if ( area > largestArea )
        {
            largestArea = area;
            largestViewUid = viewUid;
        }
    }

    return largestViewUid;
}

void WindowData::recomputeCameraAspectRatios()
{
    for ( auto& layout : m_layouts )
    {
        for ( auto& view : layout.views() )
        {
            if ( auto v = view.second )
            {
                // The view camera's aspect ratio is the product of the main window's
                // aspect ratio and the view's aspect ratio:
                const float h = v->windowClipViewport()[3];

                if ( glm::epsilonEqual( h, 0.0f, glm::epsilon<float>() ) )
                {
                    spdlog::error( "View {} has zero height: setting it to 1.", view.first );
                    v->setWindowClipViewport( glm::vec4{ glm::vec3{ v->windowClipViewport() }, 1.0f } );
                }

                const float viewAspect = v->windowClipViewport()[2] / v->windowClipViewport()[3];
                v->camera().setAspectRatio( m_viewport.aspectRatio() * viewAspect );
            }
        }
    }
}

void WindowData::updateAllViews()
{
    recomputeCameraAspectRatios();
}

max_stars_repo_name: halfmvsq/antropy

max_issues_repo_name: halfmvsq/antropy

max_forks_repo_name: halfmvsq/antropy


text:
//
// Created by zzhou on 07.08.20.
//

#include "spconv_utils/nms_ops.h"
#include "spconv_utils/nms.cuh"
#include "spconv_utils/box_iou.h"
#include <boost/geometry.hpp>
#include <iostream>

namespace spconv {
namespace py = pybind11;

constexpr int const threadsPerBlock = sizeof(unsigned long long) * 8;

template <typename DType>
std::vector<int> non_max_suppression_cpu(py::array_t<DType> boxes,
                                         py::array_t<int> order,
                                         DType thresh,
                                         DType eps)
{
    auto ndets = boxes.shape(0);
    auto boxes_r = boxes.template unchecked<2>();
    auto order_r = order.template unchecked<1>();
    auto suppressed = zeros<int>({int(ndets)});
    auto suppressed_rw = suppressed.template mutable_unchecked<1>();
    auto area = zeros<DType>({int(ndets)});
    auto area_rw = area.template mutable_unchecked<1>();
    // get areas
    for (int i = 0; i < ndets; ++i) {
        area_rw(i) = (boxes_r(i, 2) - boxes_r(i, 0) + eps) *
                     (boxes_r(i, 3) - boxes_r(i, 1) + eps);
    }
    std::vector<int> keep;
    int i, j;
    DType xx1, xx2, w, h, inter, ovr;
    for (int _i = 0; _i < ndets; ++_i) {
        i = order_r(_i);
        if (suppressed_rw(i) == 1)
            continue;
        keep.push_back(i);
        for (int _j = _i + 1; _j < ndets; ++_j) {
            j = order_r(_j);
            if (suppressed_rw(j) == 1)
                continue;
            xx2 = std::min(boxes_r(i, 2), boxes_r(j, 2));
            xx1 = std::max(boxes_r(i, 0), boxes_r(j, 0));
            w = xx2 - xx1 + eps;
            if (w > 0) {
                xx2 = std::min(boxes_r(i, 3), boxes_r(j, 3));
                xx1 = std::max(boxes_r(i, 1), boxes_r(j, 1));
                h = xx2 - xx1 + eps;
                if (h > 0) {
                    inter = w * h;
                    ovr = inter / (area_rw(i) + area_rw(j) - inter);
                    if (ovr >= thresh)
                        suppressed_rw(j) = 1;
                }
            }
        }
    }
    return keep;
}

template <typename DType>
std::vector<int> rotate_non_max_suppression_cpu(py::array_t<DType> box_corners,
                                                py::array_t<int> order,
                                                py::array_t<DType> standup_iou,
                                                DType thresh) {
    auto ndets = box_corners.shape(0);
    auto box_corners_r = box_corners.template unchecked<3>();
    auto order_r = order.template unchecked<1>();
    auto suppressed = zeros<int>({int(ndets)});
    auto suppressed_rw = suppressed.template mutable_unchecked<1>();
    auto standup_iou_r = standup_iou.template unchecked<2>();
    std::vector<int> keep;
    int i, j;

    namespace bg = boost::geometry;
    typedef bg::model::point<DType, 2, bg::cs::cartesian> point_t;
    typedef bg::model::polygon<point_t> polygon_t;
    polygon_t poly, qpoly;
    std::vector<polygon_t> poly_inter, poly_union;
    DType inter_area, union_area, overlap;

    for (int _i = 0; _i < ndets; ++_i) {
        i = order_r(_i);
        if (suppressed_rw(i) == 1)
            continue;
        keep.push_back(i);
        for (int _j = _i + 1; _j < ndets; ++_j) {
            j = order_r(_j);
            if (suppressed_rw(j) == 1)
                continue;
            if (standup_iou_r(i, j) <= 0.0)
                continue;
            // std::cout << "pre_poly" << std::endl;
            try {
                bg::append(poly,
                           point_t(box_corners_r(i, 0, 0), box_corners_r(i, 0, 1)));
                bg::append(poly,
                           point_t(box_corners_r(i, 1, 0), box_corners_r(i, 1, 1)));
                bg::append(poly,
                           point_t(box_corners_r(i, 2, 0), box_corners_r(i, 2, 1)));
                bg::append(poly,
                           point_t(box_corners_r(i, 3, 0), box_corners_r(i, 3, 1)));
                bg::append(poly,
                           point_t(box_corners_r(i, 0, 0), box_corners_r(i, 0, 1)));
                bg::append(qpoly,
                           point_t(box_corners_r(j, 0, 0), box_corners_r(j, 0, 1)));
                bg::append(qpoly,
                           point_t(box_corners_r(j, 1, 0), box_corners_r(j, 1, 1)));
                bg::append(qpoly,
                           point_t(box_corners_r(j, 2, 0), box_corners_r(j, 2, 1)));
                bg::append(qpoly,
                           point_t(box_corners_r(j, 3, 0), box_corners_r(j, 3, 1)));
                bg::append(qpoly,
                           point_t(box_corners_r(j, 0, 0), box_corners_r(j, 0, 1)));
                bg::intersection(poly, qpoly, poly_inter);
            } catch (const std::exception &e) {
                std::cout << "box i corners:" << std::endl;
                for (int k = 0; k < 4; ++k) {
                    std::cout << box_corners_r(i, k, 0) << " " << box_corners_r(i, k, 1)
                              << std::endl;
                }
                std::cout << "box j corners:" << std::endl;
                for (int k = 0; k < 4; ++k) {
                    std::cout << box_corners_r(j, k, 0) << " " << box_corners_r(j, k, 1)
                              << std::endl;
                }
                // throw e;
                continue;
            }
            // std::cout << "post_poly" << std::endl;
            // std::cout << "post_intsec" << std::endl;
            if (!poly_inter.empty()) {
                inter_area = bg::area(poly_inter.front());
                // std::cout << "pre_union" << " " << inter_area << std::endl;
                bg::union_(poly, qpoly, poly_union);
                /*
                if (poly_union.empty()){
                    std::cout << "intsec area:" << " " << inter_area << std::endl;
                    std::cout << "box i corners:" << std::endl;
                    for(int k = 0; k < 4; ++k){
                        std::cout << box_corners_r(i, k, 0) << " " << box_corners_r(i,
                k, 1) << std::endl;
                    }
                    std::cout << "box j corners:" <<  std::endl;
                    for(int k = 0; k < 4; ++k){
                        std::cout << box_corners_r(j, k, 0) << " " << box_corners_r(j,
                k, 1) << std::endl;
                    }
                }*/
                // std::cout << "post_union" << poly_union.empty() << std::endl;
                if (!poly_union.empty()) { // ignore invalid box
                    union_area = bg::area(poly_union.front());
                    // std::cout << "post union area" << std::endl;
                    // std::cout << union_area << "debug" << std::endl;
                    overlap = inter_area / union_area;
                    if (overlap >= thresh)
                        suppressed_rw(j) = 1;
                    poly_union.clear();
                }
            }
            poly.clear();
            qpoly.clear();
            poly_inter.clear();
        }
    }
    return keep;
}

template <typename DType>
int non_max_suppression(py::array_t<DType> boxes,
                        py::array_t<int> keep_out,
                        DType nms_overlap_thresh,
                        int device_id)
{

    py::buffer_info info = boxes.request();
    auto boxes_ptr = static_cast<DType *>(info.ptr);
    py::buffer_info info_k = keep_out.request();
    auto keep_out_ptr = static_cast<int *>(info_k.ptr);

    return _nms_gpu<DType, threadsPerBlock>(keep_out_ptr, boxes_ptr,
                                            boxes.shape(0), boxes.shape(1),
                                            nms_overlap_thresh, device_id);
}

// Explicitly instantiate templates
template std::vector<int> non_max_suppression_cpu<double>(
        py::array_t<double> boxes,
        py::array_t<int> order,
        double thresh,
        double eps);

template std::vector<int> non_max_suppression_cpu<float>(
        py::array_t<float> boxes,
        py::array_t<int> order,
        float thresh,
        float eps);

template std::vector<int> rotate_non_max_suppression_cpu<double>(
        py::array_t<double> box_corners,
        py::array_t<int> order,
        py::array_t<double> standup_iou,
        double thresh);

template std::vector<int> rotate_non_max_suppression_cpu<float>(
        py::array_t<float> box_corners,
        py::array_t<int> order,
        py::array_t<float> standup_iou,
        float thresh);

template int non_max_suppression<double>(
        py::array_t<double> boxes,
        py::array_t<int> keep_out,
        double nms_overlap_thresh,
        int device_id);

template int non_max_suppression<float>(
        py::array_t<float> boxes,
        py::array_t<int> keep_out,
        float nms_overlap_thresh,
        int device_id);

}  // namespace spconv

ext: cpp


text:
/*
 * modeller.cc
 *
 *  Copyright (C) 2013 Diamond Light Source
 *
 *  Author: James Parkhurst
 *
 *  This code is distributed under the BSD license, a copy of which is
 *  included in the root directory of this package.
 */
#include <boost/python.hpp>
#include <boost/python/def.hpp>
#include <dials/algorithms/background/simple/modeller.h>

namespace dials { namespace algorithms { namespace background { namespace boost_python {

  using namespace boost::python;

  void export_modeller() {
    // An abstract class for background model
    class_<Model, boost::shared_ptr<Model>, boost::noncopyable>("Model", no_init)
      .def("value", &Model::value, (arg("z"), arg("y"), arg("x")))
      .def("params", &Model::params)
      .def("variances", &Model::variances);

    // An abtract class for background modeller
    class_<Modeller, boost::noncopyable>("Modeller", no_init)
      .def("create", &Modeller::create, (arg("data"), arg("mask")));

    // A constant 2d model
    class_<Constant2dModel, bases<Model> >("Constant2dModel", no_init)
      .def(init<af::shared<double>, af::shared<double> >((arg("a"), arg("va"))));

    // A constant 3d model
    class_<Constant3dModel, bases<Model> >("Constant3dModel", no_init)
      .def(init<double, double>((arg("a"), arg("va"))));

    // A linear 2d model
    class_<Linear2dModel, bases<Model> >("Linear2dModel", no_init)
      .def(init<af::shared<double>,
                af::shared<double>,
                af::shared<double>,
                af::shared<double>,
                af::shared<double>,
                af::shared<double> >(
        (arg("a"), arg("b"), arg("c"), arg("va"), arg("vb"), arg("vc"))));

    // A linear 3d model
    class_<Linear3dModel, bases<Model> >("Linear3dModel", no_init)
      .def(init<double, double, double, double, double, double, double, double>(
        (arg("a"),
         arg("b"),
         arg("c"),
         arg("d"),
         arg("va"),
         arg("vb"),
         arg("vc"),
         arg("vd"))));

    // The modeller classes
    class_<Constant2dModeller, bases<Modeller> >("Constant2dModeller");
    class_<Constant3dModeller, bases<Modeller> >("Constant3dModeller");
    class_<Linear2dModeller, bases<Modeller> >("Linear2dModeller");
    class_<Linear3dModeller, bases<Modeller> >("Linear3dModeller");
  }

}}}}  // namespace dials::algorithms::background::boost_python

ext: cc

max_stars_repo_name: TiankunZhou/dials

max_issues_repo_name: TiankunZhou/dials

max_forks_repo_name: TiankunZhou/dials


text:
////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2015 Andreas Brück
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

/** @file slot_macros.hpp */

#ifndef BOOST_OBJECT_SLOT_MACROS_HPP
#define BOOST_OBJECT_SLOT_MACROS_HPP

#include "detail/config.hpp"

#ifndef BOOST_OBJECT_DOXYGEN
#ifndef BOOST_OBJECT_NO_SLOT_MACROS

#include <boost/preprocessor/facilities/overload.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>

#define BOOST_OBJECT_BOUNDTO(IMPL) \
    ={this,&bobj::object_type::IMPL}

#define BOOST_OBJECT__EXPAND_SLOT_2(SLOT_TYPE,SLOT_NAME,SLOT_FUNC) \
    bobj::SLOT_TYPE< \
    typename boost::object::detail::detail::remove_member_pointer \
    <decltype(&bobj::object_type::SLOT_FUNC)>::type> \
    SLOT_NAME BOOST_OBJECT_BOUNDTO(SLOT_FUNC);

#define BOOST_OBJECT__EXPAND_SLOT_1(SLOT_TYPE,SLOT_NAME) \
    BOOST_OBJECT__EXPAND_SLOT_2(SLOT_TYPE,SLOT_NAME,_slot_##SLOT_NAME)

#define BOOST_OBJECT__EXPAND_SLOT_TMPL_2(SLOT_TYPE,SLOT_NAME,SLOT_FUNC) \
    typename bobj::template SLOT_TYPE< \
    typename boost::object::detail::detail::remove_member_pointer \
    <decltype(&bobj::object_type::SLOT_FUNC)>::type> \
    SLOT_NAME BOOST_OBJECT_BOUNDTO(SLOT_FUNC);

#define BOOST_OBJECT__EXPAND_SLOT_TMPL_1(SLOT_TYPE,SLOT_NAME) \
    BOOST_OBJECT__EXPAND_SLOT_TMPL_2(SLOT_TYPE,SLOT_NAME,_slot_##SLOT_NAME)

#ifdef BOOST_MSVC
#include <boost/preprocessor/facilities/empty.hpp>
#define BOOST_OBJECT__EXPAND_SLOT(SLOT_TYPE,EXPAND_VER,...) \
    BOOST_PP_CAT(BOOST_PP_OVERLOAD(BOOST_OBJECT__EXPAND_SLOT##EXPAND_VER \
    ,__VA_ARGS__) (SLOT_TYPE,__VA_ARGS__),BOOST_PP_EMPTY())
#else // BOOST_MSVC
#define BOOST_OBJECT__EXPAND_SLOT(SLOT_TYPE,EXPAND_VER,...) \
    BOOST_PP_OVERLOAD(BOOST_OBJECT__EXPAND_SLOT##EXPAND_VER,__VA_ARGS__) \
    (SLOT_TYPE,__VA_ARGS__)
#endif // BOOST_MSVC

#define BOOST_OBJECT_ASYNC_SLOT(...) \
    BOOST_OBJECT__EXPAND_SLOT(async_slot_t,_,__VA_ARGS__)
#define BOOST_OBJECT_DIRECT_SLOT(...) \
    BOOST_OBJECT__EXPAND_SLOT(direct_slot_t,_,__VA_ARGS__)
#define BOOST_OBJECT_AUTO_SLOT(...) \
    BOOST_OBJECT__EXPAND_SLOT(auto_slot_t,_,__VA_ARGS__)

#define BOOST_OBJECT_ASYNC_SLOT_TMPL(...) \
    BOOST_OBJECT__EXPAND_SLOT(async_slot_t,_TMPL_,__VA_ARGS__)
#define BOOST_OBJECT_DIRECT_SLOT_TMPL(...) \
    BOOST_OBJECT__EXPAND_SLOT(direct_slot_t,_TMPL_,__VA_ARGS__)
#define BOOST_OBJECT_AUTO_SLOT_TMPL(...) \
    BOOST_OBJECT__EXPAND_SLOT(auto_slot_t,_TMPL_,__VA_ARGS__)

#define BOOST_OBJECT__FOREACH_SLOT_ELEM(R,DATA,ELEM) DATA(ELEM)

#ifndef BOOST_OBJECT_NO_SHORT_SLOT_MACROS
#define async_slot(...) BOOST_OBJECT_ASYNC_SLOT(__VA_ARGS__)
#define async_slot_tmpl(...) BOOST_OBJECT_ASYNC_SLOT_TMPL(__VA_ARGS__)
#define direct_slot(...) BOOST_OBJECT_DIRECT_SLOT(__VA_ARGS__)
#define direct_slot_tmpl(...) BOOST_OBJECT_DIRECT_SLOT_TMPL(__VA_ARGS__)
#define auto_slot(...) BOOST_OBJECT_AUTO_SLOT(__VA_ARGS__)
#define auto_slot_tmpl(...) BOOST_OBJECT_AUTO_SLOT_TMPL(__VA_ARGS__)

#define boundto(IMPL) BOOST_OBJECT_BOUNDTO(IMPL)
#endif // BOOST_OBJECT_NO_SHORT_SLOT_MACROS

#endif // BOOST_OBJECT_NO_SLOT_MACROS

#else // BOOST_OBJECT_DOXYGEN

/**
 * Declare an asynchronous slot named @p NAME.
 * The slot implementation will be @p IMPL.
 *
 * If no parameter @p IMPL is provided, it will default to _slot_NAME
 *
 * Possible usage:
 * @code
 * BOOST_OBJECT_ASYNC_SLOT(foo)     // The slot implementation will be _slot_foo
 * BOOST_OBJECT_ASYNC_SLOT(foo,bar) // The slot implementation is bar
 * @endcode
 */
#define BOOST_OBJECT_ASYNC_SLOT(NAME,IMPL)

/**
 * Declare a direct slot named @p NAME.
 * The slot implementation will be @p IMPL.
 *
 * If no parameter @p IMPL is provided, it will default to _slot_NAME
 *
 * Possible usage:
 * @code
 * BOOST_OBJECT_DIRECT_SLOT(foo)     //The slot implementation will be _slot_foo
 * BOOST_OBJECT_DIRECT_SLOT(foo,bar) //The slot implementation is bar
 * @endcode
 */
#define BOOST_OBJECT_DIRECT_SLOT(NAME,IMPL)

/**
 * Declare an automatic slot named @p NAME.
 * The slot implementation will be @p IMPL.
 *
 * If no parameter @p IMPL is provided, it will default to _slot_NAME
 *
 * Possible usage:
 * @code
 * BOOST_OBJECT_AUTO_SLOT(foo)     //The slot implementation will be _slot_foo
 * BOOST_OBJECT_AUTO_SLOT(foo,bar) //The slot implementation is bar
 * @endcode
 */
#define BOOST_OBJECT_AUTO_SLOT(NAME,IMPL)

/**
 * Declare an asynchronous slot named @p NAME.
 * The slot implementation will be @p IMPL.
 *
 * If no parameter @p IMPL is provided, it will default to _slot_NAME
 *
 * Possible usage:
 * @code
 * async_slot(foo)     //The slot implementation will be _slot_foo
 * async_slot(foo,bar) //The slot implementation is bar
 * @endcode
 *
 * Define @a BOOST_OBJECT_NO_SHORT_SLOT_MACROS to disable this macro.
 */
#define async_slot(NAME,IMPL)

/**
 * Declare a direct slot named @p NAME.
 * The slot implementation will be @p IMPL.
 *
 * If no parameter @p IMPL is provided, it will default to _slot_NAME
 *
 * Possible usage:
 * @code
 * direct_slot(foo)     //The slot implementation will be _slot_foo
 * direct_slot(foo,bar) //The slot implementation is bar
 * @endcode
 *
 * Define @a BOOST_OBJECT_NO_SHORT_SLOT_MACROS to disable this macro.
 */
#define direct_slot(NAME,IMPL)

/**
 * Declare an automatic slot named @p NAME.
 * The slot implementation will be @p IMPL.
 *
 * If no parameter @p IMPL is provided, it will default to _slot_NAME
 *
 * Possible usage:
 * @code
 * auto_slot(foo)     //The slot implementation will be _slot_foo
 * auto_slot(foo,bar) //The slot implementation is bar
 * @endcode
 *
 * Define @a BOOST_OBJECT_NO_SHORT_SLOT_MACROS to disable this macro.
 */
#define auto_slot(NAME,IMPL)

#endif // BOOST_OBJECT_DOXYGEN

#endif // BOOST_OBJECT_SLOT_MACROS_HPP

ext: hpp

max_stars_repo_name: andreasbrueck/BoostObject

max_issues_repo_name: andreasbrueck/BoostObject

max_forks_repo_name: andreasbrueck/BoostObject


text: #include <boost/config/abi/msvc_suffix.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/******************************************************************************
**
** Copyright (C) 2009-2011 Kyle Lutz <kyle.r.lutz@gmail.com>
** All rights reserved.
**
** This file is a part of the chemkit project. For more information
** see <http://www.chemkit.org>.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in the
**     documentation and/or other materials provided with the distribution.
**   * Neither the name of the chemkit project nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
******************************************************************************/

// The substructure-search test checks the SubstructureQuery::matches() method
// against a variety of small molecules. Each one is tested against every other
// to ensure that substructure mappings are correctly detected.

#include "substructuresearchtest.h"

#include <boost/make_shared.hpp>

#include <chemkit/molecule.h>
#include <chemkit/moleculefile.h>
#include <chemkit/substructurequery.h>

void SubstructureSearchTest::initTestCase()
{
    m_benzene = new chemkit::Molecule("InChI=1/C6H6/c1-2-4-6-5-3-1/h1-6H", "inchi");
    QCOMPARE(m_benzene->formula(), std::string("C6H6"));
    m_butane = new chemkit::Molecule("InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3", "inchi");
    QCOMPARE(m_butane->formula(), std::string("C4H10"));
    m_cyclopropane = new chemkit::Molecule("InChI=1/C3H6/c1-2-3-1/h1-3H2", "inchi");
    QCOMPARE(m_cyclopropane->formula(), std::string("C3H6"));
    m_ethane = new chemkit::Molecule("InChI=1/C2H6/c1-2/h1-2H3", "inchi");
    QCOMPARE(m_ethane->formula(), std::string("C2H6"));
    m_ethanol = new chemkit::Molecule("InChI=1/C2H6O/c1-2-3/h3H,2H2,1H3", "inchi");
    QCOMPARE(m_ethanol->formula(), std::string("C2H6O"));
    m_indole = new chemkit::Molecule("InChI=1/C8H7N/c1-2-4-8-7(3-1)5-6-9-8/h1-6,9H", "inchi");
    QCOMPARE(m_indole->formula(), std::string("C8H7N"));
    m_methane = new chemkit::Molecule("InChI=1/CH4/h1H4", "inchi");
    QCOMPARE(m_methane->formula(), std::string("CH4"));
    m_methanol = new chemkit::Molecule("InChI=1/CH4O/c1-2/h2H,1H3", "inchi");
    QCOMPARE(m_methanol->formula(), std::string("CH4O"));
    m_propane = new chemkit::Molecule("InChI=1/C3H8/c1-3-2/h3H2,1-2H3", "inchi");
    QCOMPARE(m_propane->formula(), std::string("C3H8"));
    m_phenol = new chemkit::Molecule("InChI=1/C6H6O/c7-6-4-2-1-3-5-6/h1-5,7H", "inchi");
    QCOMPARE(m_phenol->formula(), std::string("C6H6O"));
}

void SubstructureSearchTest::cleanupTestCase()
{
    delete m_benzene;
    delete m_butane;
    delete m_cyclopropane;
    delete m_ethane;
    delete m_ethanol;
    delete m_indole;
    delete m_methane;
    delete m_methanol;
    delete m_phenol;
    delete m_propane;
}

void SubstructureSearchTest::benzene()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_benzene));
    QCOMPARE(query.matches(m_benzene), true);
    QCOMPARE(query.matches(m_butane), false);
    QCOMPARE(query.matches(m_cyclopropane), false);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), false);
    QCOMPARE(query.matches(m_indole), true);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), true);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::butane()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_butane));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), true);
    QCOMPARE(query.matches(m_cyclopropane), false);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), false);
    QCOMPARE(query.matches(m_indole), false);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), false);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::cyclopropane()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_cyclopropane));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), false);
    QCOMPARE(query.matches(m_cyclopropane), true);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), false);
    QCOMPARE(query.matches(m_indole), false);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), false);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::ethane()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_ethane));
    QCOMPARE(query.matches(m_benzene), true);
    QCOMPARE(query.matches(m_butane), true);
    QCOMPARE(query.matches(m_cyclopropane), true);
    QCOMPARE(query.matches(m_ethane), true);
    QCOMPARE(query.matches(m_ethanol), true);
    QCOMPARE(query.matches(m_indole), true);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), true);
    QCOMPARE(query.matches(m_propane), true);
}

void SubstructureSearchTest::ethanol()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_ethanol));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), false);
    QCOMPARE(query.matches(m_cyclopropane), false);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), true);
    QCOMPARE(query.matches(m_indole), false);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), true);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::indole()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_indole));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), false);
    QCOMPARE(query.matches(m_cyclopropane), false);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), false);
    QCOMPARE(query.matches(m_indole), true);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), false);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::methane()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_methane));
    QCOMPARE(query.matches(m_benzene), true);
    QCOMPARE(query.matches(m_butane), true);
    QCOMPARE(query.matches(m_cyclopropane), true);
    QCOMPARE(query.matches(m_ethane), true);
    QCOMPARE(query.matches(m_ethanol), true);
    QCOMPARE(query.matches(m_indole), true);
    QCOMPARE(query.matches(m_methane), true);
    QCOMPARE(query.matches(m_methanol), true);
    QCOMPARE(query.matches(m_phenol), true);
    QCOMPARE(query.matches(m_propane), true);
}

void SubstructureSearchTest::methanol()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_methanol));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), false);
    QCOMPARE(query.matches(m_cyclopropane), false);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), true);
    QCOMPARE(query.matches(m_indole), false);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), true);
    QCOMPARE(query.matches(m_phenol), true);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::phenol()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_phenol));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), false);
    QCOMPARE(query.matches(m_cyclopropane), false);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), false);
    QCOMPARE(query.matches(m_indole), false);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), true);
    QCOMPARE(query.matches(m_propane), false);
}

void SubstructureSearchTest::propane()
{
    chemkit::SubstructureQuery query(boost::make_shared<chemkit::Molecule>(*m_propane));
    QCOMPARE(query.matches(m_benzene), false);
    QCOMPARE(query.matches(m_butane), true);
    QCOMPARE(query.matches(m_cyclopropane), true);
    QCOMPARE(query.matches(m_ethane), false);
    QCOMPARE(query.matches(m_ethanol), false);
    QCOMPARE(query.matches(m_indole), true);
    QCOMPARE(query.matches(m_methane), false);
    QCOMPARE(query.matches(m_methanol), false);
    QCOMPARE(query.matches(m_phenol), false);
    QCOMPARE(query.matches(m_propane), true);
}

// This test utilizes a protein molecule from the 'alphabet.mol2' file. The
// protein consists of a single chain containing one of each of the twenty
// amino acids. Once loaded, various amino acid side chain molecules are
// created and then checked against the protein molecule to ensure that they
// are found as substructures.
void SubstructureSearchTest::protein()
{
    // read file
    chemkit::MoleculeFile file("../../../data/alphabet.mol2");
    bool ok = file.read();
    if(!ok)
        qDebug() << file.errorString().c_str();
    QVERIFY(ok);

    // load and verify the protein molecule
    const boost::shared_ptr<chemkit::Molecule> &molecule = file.molecule();
    QVERIFY(molecule != 0);
    QCOMPARE(molecule->atomCount(), size_t(324));

    // create query object
    chemkit::SubstructureQuery query;
    query.setFlags(chemkit::SubstructureQuery::CompareAromaticity);

    // indole in tryptophan
    query.setMolecule("InChI=1/C8H7N/c1-2-4-8-7(3-1)5-6-9-8/h1-6,9H", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // phenol ring in tyrosine
    query.setMolecule("InChI=1/C6H6O/c7-6-4-2-1-3-5-6/h1-5,7H", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // proline ring
    query.setMolecule("InChI=1/C4H9N/c1-2-4-5-3-1/h5H,1-4H2", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // guanidine in arginine
    query.setMolecule("InChI=1/CH5N3/c2-1(3)4/h(H5,2,3,4)/f/h2H,3-4H2", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // lysine chain
    query.setMolecule("InChI=1/C5H13N/c1-2-3-4-5-6/h2-6H2,1H3", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // isoleucine residue
    query.setMolecule("InChI=1/C6H13NO/c1-3-5(2)6(7)4-8/h4-6H,3,7H2,1-2H3", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // cysteine side chain
    query.setMolecule("InChI=1/C2H6S/c1-2-3/h3H,2H2,1H3", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);

    // methionine chain
    query.setMolecule("InChI=1/C4H10S/c1-3-4-5-2/h3-4H2,1-2H3", "inchi");
    QCOMPARE(query.matches(molecule.get()), true);
}

QTEST_APPLESS_MAIN(SubstructureSearchTest)

max_stars_repo_name: quizzmaster/chemkit

max_issues_repo_name: soplwang/chemkit

max_forks_repo_name: soplwang/chemkit


text:
#pragma once

#include <map>
#include <vector>

#include <boost/any.hpp>

#include "AMDiS_fwd.hpp"
#include "FixVec.hpp"
#include "Flag.hpp"

namespace AMDiS
{
  /**
   * \ingroup Assembler
   *
   * \brief
   * Base class for SecondOrderAssembler, FirstOrderAssembler,
   * ZeroOrderAssembler. The task of a SubAssembler is to assemble a list of
   * terms of a special order and add their contributions to a DOFMatrix or a
   * DOFVector. An Assembler can consist of up to four SubAssemblers: one
   * SecondOrderAssembler for second order terms, one ZeroOrderAssembler for
   * terms of order zero, and two FirstOrderAssemblers. One for terms with
   * derivatives of the basis functions connected to to row DOFs and one for
   * those connected to the column DOFs.
   */
  class SubAssembler
  {
  public:
    /// Creates a SubAssembler belonging to assembler for the terms of given
    /// order of Operator op. If order is equal to one, type spezifies what kind
    /// of FirstOrderType are to assemble. During construction of a SubAssembler
    /// the needs and properties of the terms are considered.
    SubAssembler(Operator* op,
                 Assembler* assembler,
                 Quadrature* quadrat,
                 int order,
                 bool optimized,
                 FirstOrderType type = GRD_PHI);

    /// Destructor.
    ~SubAssembler() {}

    /// Calculates the element matrix for elInfo and adds it to mat. Memory for
    /// mat must be provided by the caller.
    void calculateElementMatrix(ElInfo const* elInfo,
                                ElementMatrix& mat)
    {
      calculateElementMatrixImpl(elInfo, mat);
    }

    /// Calculates the element vector for elInfo and adds it to vec. Memory for
    /// vec must be provided by the caller.
    void calculateElementVector(ElInfo const* elInfo,
                                DenseVector<double>& vec)
    {
      calculateElementVectorImpl(elInfo, vec);
    }

    /// Called once for each ElInfo when \ref calculateElementMatrix() or
    /// \ref calculateElementVector() is called for the first time for this
    /// Element.
    // TODO: remove multi-mesh!
    void initElement(const ElInfo* smallElInfo,
                     const ElInfo* largeElInfo = NULL,
                     Quadrature* quad = NULL)
    {
      initImpl(smallElInfo, largeElInfo, quad);
    }

    /// Returns \ref terms
    std::vector<OperatorTerm*>* getTerms()
    {
      return &terms;
    }

    /// Returns \ref quadrature.
    Quadrature* getQuadrature()
    {
      return quadrature;
    }

    /// Returns \ref psiFast.
    const FastQuadrature* getPsiFast() const
    {
      return psiFast;
    }

    // Returns \ref phiFast.
    const FastQuadrature* getPhiFast() const
    {
      return phiFast;
    }

    /// Returns \ref name.
    std::string getName() const
    {
      return name;
    }

    /// Sets \ref quadrature to q.
    void setQuadrature(Quadrature* q)
    {
      quadrature = q;
    }

    /// Creates a vector with the world coordinates of the quadrature points
    /// of \ref quadrature on the element of elInfo.
    /// Used by \ref OperatorTerm::initElement().
    void getCoordsAtQPs(ElInfo const* elInfo,
                        Quadrature* quad,
                        DenseVector<WorldVector<double>>& coordsAtQPs);

    /// DOFVector dv evaluated at quadrature points.
    /// Used by \ref OperatorTerm::initElement().
    template <class T>
    void getVectorAtQPs(DOFVectorBase<T> const* dv,
                        ElInfo const* elInfo,
                        Quadrature* quad,
                        DenseVector<T>& vecAtQPs);

    /// Gradients of DOFVector dv evaluated at quadrature points.
    /// Used by \ref OperatorTerm::initElement().
    template <class T>
    void getGradientsAtQPs(DOFVectorBase<T> const* dv,
                           ElInfo const* elInfo,
                           Quadrature* quad,
                           DenseVector<Gradient_t<T>>& grdAtQPs);

    /// The comp'th component of the derivative of DOFVector dv evaluated at
    /// quadrature points. Used by \ref OperatorTerm::initElement().
    /// Attention: not caching at the moment! Using cache if gradients for read
    /// but not for write.
    template <class T>
    void getDerivativeAtQPs(DOFVectorBase<T> const* dv,
                            ElInfo const* elInfo,
                            Quadrature* quad,
                            int comp,
                            DenseVector<T>& grdAtQPs);

  private:
    // must be implemented by derived class
    virtual void calculateElementMatrixImpl(ElInfo const* elInfo,
                                            ElementMatrix& mat) = 0;

    // must be implemented by derived class.
    virtual void calculateElementVectorImpl(ElInfo const* elInfo,
                                            DenseVector<double>& vec) = 0;

    // calls initElement for all OperatorTerms
    virtual void initImpl(ElInfo const* smallElInfo,
                          ElInfo const* largeElInfo,
                          Quadrature* quad);

  protected:
    /// Updates \ref psiFast and \ref phiFast.
    FastQuadrature* updateFastQuadrature(FastQuadrature* quadFast,
                                         BasisFunction const* psi,
                                         Flag updateFlag);

  protected:
    /// Problem dimension
    int dim;

    /// Row FiniteElemSpace.
    FiniteElemSpace const* rowFeSpace;

    /// Column FiniteElemSpace.
    FiniteElemSpace const* colFeSpace;

    /// Number of rows of the element matrix and length of the element
    /// vector. Is equal to the number of row basis functions
    int nRow;

    /// Number of columns of the element matrix. Is equal to the number
    /// of column basis functions
    int nCol;

    // TODO: try to remove boost::any
    /// Used for \ref getVectorAtQPs() and \ref getGradientsAtQPs().
    struct ValuesAtQPs
    {
      ValuesAtQPs()
        : valid(false), quad(NULL)
      {}
      ValuesAtQPs(boost::any values_, bool valid_, Quadrature* quad_=NULL)
        : values(values_), valid(valid_), quad(quad_)
      {}

      boost::any values; // used for DenseVector<T>
      bool valid;
      Quadrature* quad;
    };

    std::map<DOFIndexedBase const*, ValuesAtQPs*> cachedValuesAtQPs;
    std::map<DOFIndexedBase const*, ValuesAtQPs*> cachedGradientsAtQPs;

    /// Set and updated by \ref initElement() for each ElInfo.
    /// coordsAtQPs[i] points to the coordinates of the i-th quadrature point.
    DenseVector<WorldVector<double>> cacheCoordsAtQPs;

    /// Used for \ref getCoordsAtQPs().
    bool coordsValid;

    /// Used for \ref getCoordsAtQP(). Stores the number of allocated
    /// WorldVectors.
    int coordsNumAllocated;

    /// Quadrature object to be used for assembling.
    Quadrature* quadrature;

    /// FastQuadrature for row basis functions
    FastQuadrature* psiFast;

    /// FastQuadrature for column basis functions
    FastQuadrature* phiFast;

    /// Flag that specifies whether the element matrix is symmetric.
    bool symmetric;

    /// List of all terms with a contribution to this SubAssembler
    std::vector<OperatorTerm*> terms;

    ///
    bool opt;

    ///
    bool firstCall;

    /// Name of the assembler. Is used to print information about
    /// used assembler.
    std::string name;
  };

} // end namespace AMDiS

#include "SubAssembler.hh"


text:
/**
 * @file tests/serialization.hpp
 * @author Ryan Curtin
 *
 * Miscellaneous utility functions for serialization tests.
 *
 * mlpack is free software; you may redistribute it and/or modify it under the
 * terms of the 3-clause BSD license.  You should have received a copy of the
 * 3-clause BSD license along with mlpack.  If not, see
 * http://www.opensource.org/licenses/BSD-3-Clause for more information.
 */
#ifndef MLPACK_TESTS_SERIALIZATION_HPP
#define MLPACK_TESTS_SERIALIZATION_HPP

#include <cereal/archives/json.hpp>
#include <cereal/archives/portable_binary.hpp>
#include <cereal/archives/xml.hpp>
#include <cereal/archives/binary.hpp>
#include <mlpack/core.hpp>

#include <mlpack/core/cereal/array_wrapper.hpp>
#include <mlpack/core/cereal/pointer_wrapper.hpp>

#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"

namespace mlpack {

// Test function for loading and saving Armadillo objects.
template<typename CubeType,
         typename IArchiveType,
         typename OArchiveType>
void TestArmadilloSerialization(arma::Cube<CubeType>& x)
{
  // First save it.
  // Use type_info name to get unique file name for serialization test files.
  std::string fileName = FilterFileName(typeid(IArchiveType).name());
  std::ofstream ofs(fileName, std::ios::binary);
  bool success = true;

  {
    OArchiveType o(ofs);
    o(CEREAL_NVP(x));
  }

  BOOST_REQUIRE_EQUAL(success, true);
  ofs.close();

  // Now load it.
  arma::Cube<CubeType> orig(x);
  success = true;
  std::ifstream ifs(fileName, std::ios::binary);

  {
    IArchiveType i(ifs);
    i(CEREAL_NVP(x));
  }
  ifs.close();

  remove(fileName.c_str());

  BOOST_REQUIRE_EQUAL(success, true);

  BOOST_REQUIRE_EQUAL(x.n_rows, orig.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_cols, orig.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_elem_slice, orig.n_elem_slice);
  BOOST_REQUIRE_EQUAL(x.n_slices, orig.n_slices);
  BOOST_REQUIRE_EQUAL(x.n_elem, orig.n_elem);

  for (size_t slice = 0; slice != x.n_slices; ++slice)
  {
    const auto& origSlice = orig.slice(slice);
    const auto& xSlice = x.slice(slice);
    for (size_t i = 0; i < x.n_cols; ++i)
    {
      for (size_t j = 0; j < x.n_rows; ++j)
      {
        if (double(origSlice(j, i)) == 0.0)
          BOOST_REQUIRE_SMALL(double(xSlice(j, i)), 1e-8);
        else
          BOOST_REQUIRE_CLOSE(double(origSlice(j, i)), double(xSlice(j, i)),
              1e-8);
      }
    }
  }
}

// Test all serialization strategies.
template<typename CubeType>
void TestAllArmadilloSerialization(arma::Cube<CubeType>& x)
{
  TestArmadilloSerialization<CubeType, cereal::XMLInputArchive,
      cereal::XMLOutputArchive>(x);
  TestArmadilloSerialization<CubeType, cereal::JSONInputArchive,
      cereal::JSONOutputArchive>(x);
  TestArmadilloSerialization<CubeType, cereal::BinaryInputArchive,
      cereal::BinaryOutputArchive>(x);
}

// Test function for loading and saving Armadillo objects.
template<typename MatType,
         typename IArchiveType,
         typename OArchiveType>
void TestArmadilloSerialization(MatType& x)
{
  // First save it.
  std::string fileName = FilterFileName(typeid(IArchiveType).name());
  std::ofstream ofs(fileName, std::ios::binary);
  bool success = true;

  {
    OArchiveType o(ofs);
    o(CEREAL_NVP(x));
  }

  BOOST_REQUIRE_EQUAL(success, true);
  ofs.close();

  // Now load it.
  MatType orig(x);
  success = true;
  std::ifstream ifs(fileName, std::ios::binary);

  {
    IArchiveType i(ifs);
    i(CEREAL_NVP(x));
  }
  ifs.close();

  remove(fileName.c_str());

  BOOST_REQUIRE_EQUAL(success, true);

  BOOST_REQUIRE_EQUAL(x.n_rows, orig.n_rows);
  BOOST_REQUIRE_EQUAL(x.n_cols, orig.n_cols);
  BOOST_REQUIRE_EQUAL(x.n_elem, orig.n_elem);

  for (size_t i = 0; i < x.n_cols; ++i)
    for (size_t j = 0; j < x.n_rows; ++j)
      if (double(orig(j, i)) == 0.0)
        BOOST_REQUIRE_SMALL(double(x(j, i)), 1e-8);
      else
        BOOST_REQUIRE_CLOSE(double(orig(j, i)), double(x(j, i)), 1e-8);
}

// Test all serialization strategies.
template<typename MatType>
void TestAllArmadilloSerialization(MatType& x)
{
  TestArmadilloSerialization<MatType, cereal::XMLInputArchive,
      cereal::XMLOutputArchive>(x);
  TestArmadilloSerialization<MatType, cereal::JSONInputArchive,
      cereal::JSONOutputArchive>(x);
  TestArmadilloSerialization<MatType, cereal::BinaryInputArchive,
      cereal::BinaryOutputArchive>(x);
}

// Save and load an mlpack object.
// The re-loaded copy is placed in 'newT'.
template<typename T, typename IArchiveType, typename OArchiveType>
void SerializeObject(T& t, T& newT)
{
  std::string fileName = FilterFileName(typeid(T).name());
  std::ofstream ofs(fileName, std::ios::binary);
  bool success = true;

  {
    OArchiveType o(ofs);
    T& x(t);
    o(CEREAL_NVP(x));
  }
  ofs.close();

  BOOST_REQUIRE_EQUAL(success, true);

  std::ifstream ifs(fileName, std::ios::binary);

  {
    IArchiveType i(ifs);
    T& x(newT);
    i(CEREAL_NVP(x));
  }
  ifs.close();

  remove(fileName.c_str());

  BOOST_REQUIRE_EQUAL(success, true);
}

// Test mlpack serialization with all three archive types.
template<typename T>
void SerializeObjectAll(T& t, T& xmlT, T& jsonT, T& binaryT)
{
  SerializeObject<T, cereal::XMLInputArchive,
      cereal::XMLOutputArchive>(t, xmlT);
  SerializeObject<T, cereal::JSONInputArchive,
      cereal::JSONOutputArchive>(t, jsonT);
  SerializeObject<T, cereal::BinaryInputArchive,
      cereal::BinaryOutputArchive>(t, binaryT);
}

// Save and load a non-default-constructible mlpack object.
template<typename T, typename IArchiveType, typename OArchiveType>
void SerializePointerObject(T* t, T*& newT)
{
  std::string fileName = FilterFileName(typeid(T).name());
  std::ofstream ofs(fileName, std::ios::binary);
  bool success = true;

  {
    OArchiveType o(ofs);
    o(CEREAL_POINTER(t));
  }
  ofs.close();

  BOOST_REQUIRE_EQUAL(success, true);

  std::ifstream ifs(fileName, std::ios::binary);

  {
    IArchiveType i(ifs);
    i(CEREAL_POINTER(newT));
  }
  ifs.close();

  remove(fileName.c_str());

  BOOST_REQUIRE_EQUAL(success, true);
}

template<typename T>
void SerializePointerObjectAll(T* t, T*& xmlT, T*& jsonT, T*& binaryT)
{
  SerializePointerObject<T, cereal::JSONInputArchive,
      cereal::JSONOutputArchive>(t, jsonT);
  SerializePointerObject<T, cereal::BinaryInputArchive,
      cereal::BinaryOutputArchive>(t, binaryT);
  SerializePointerObject<T, cereal::XMLInputArchive,
      cereal::XMLOutputArchive>(t, xmlT);
}

// Utility function to check the equality of two Armadillo matrices.
void CheckMatrices(const arma::mat& x,
                   const arma::mat& xmlX,
                   const arma::mat& jsonX,
                   const arma::mat& binaryX);

void CheckMatrices(const arma::Mat<size_t>& x,
                   const arma::Mat<size_t>& xmlX,
                   const arma::Mat<size_t>& jsonX,
                   const arma::Mat<size_t>& binaryX);

void CheckMatrices(const arma::cube& x,
                   const arma::cube& xmlX,
                   const arma::cube& jsonX,
                   const arma::cube& binaryX);

} // namespace mlpack

#endif

max_stars_repo_name: NippunSharma/mlpack

max_issues_repo_name: NippunSharma/mlpack

max_forks_repo_name: NippunSharma/mlpack


text:
//----------------------------------------------------------------------------//

/*
 * Copyright (c) 2009 Sony Pictures Imageworks Inc
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.  Neither the name of Sony Pictures Imageworks nor the
 * names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

//----------------------------------------------------------------------------//

/*! \file SparseFieldIO.cpp
  \brief Contains implementations of the SparseFieldIO class.
*/

//----------------------------------------------------------------------------//

#include <boost/intrusive_ptr.hpp>

#include "SparseFieldIO.h"
#include "Types.h"

//----------------------------------------------------------------------------//

using namespace boost;
using namespace std;

//----------------------------------------------------------------------------//

FIELD3D_NAMESPACE_OPEN

//----------------------------------------------------------------------------//
// Field3D namespaces
//----------------------------------------------------------------------------//

using namespace Exc;
using namespace Hdf5Util;

//----------------------------------------------------------------------------//
// Static members
//----------------------------------------------------------------------------//

const int         SparseFieldIO::k_versionNumber(1);
const std::string SparseFieldIO::k_versionAttrName("version");
const std::string SparseFieldIO::k_extentsStr("extents");
const std::string SparseFieldIO::k_dataWindowStr("data_window");
const std::string SparseFieldIO::k_componentsStr("components");
const std::string SparseFieldIO::k_dataStr("data");
const std::string SparseFieldIO::k_blockOrderStr("block_order");
const std::string SparseFieldIO::k_numBlocksStr("num_blocks");
const std::string SparseFieldIO::k_blockResStr("block_res");
const std::string SparseFieldIO::k_bitsPerComponentStr("bits_per_component");
const std::string SparseFieldIO::k_numOccupiedBlocksStr("num_occupied_blocks");

//----------------------------------------------------------------------------//

FieldBase::Ptr
SparseFieldIO::read(hid_t layerGroup, const std::string &filename,
                    const std::string &layerPath,
                    DataTypeEnum typeEnum)
{
  Box3i extents, dataW;
  int components;
  int blockOrder;
  int numBlocks;
  V3i blockRes;

  if (layerGroup == -1) {
    Msg::print(Msg::SevWarning, "Bad layerGroup.");
    return FieldBase::Ptr();
  }

  int version;
  if (!readAttribute(layerGroup, k_versionAttrName, 1, version))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_versionAttrName);

  if (version != k_versionNumber)
    throw UnsupportedVersionException("SparseField version not supported: " +
                                      lexical_cast<std::string>(version));

  if (!readAttribute(layerGroup, k_extentsStr, 6, extents.min.x))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_extentsStr);

  if (!readAttribute(layerGroup, k_dataWindowStr, 6, dataW.min.x))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_dataWindowStr);

  if (!readAttribute(layerGroup, k_componentsStr, 1, components))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_componentsStr);

  // Read block order
  if (!readAttribute(layerGroup, k_blockOrderStr, 1, blockOrder))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_blockOrderStr);

  // Read number of blocks total
  if (!readAttribute(layerGroup, k_numBlocksStr, 1, numBlocks))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_numBlocksStr);

  // Read block resolution in each dimension
  if (!readAttribute(layerGroup, k_blockResStr, 3, blockRes.x))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_blockResStr);

  // ... Check that it matches the # reported by summing the active blocks

  int numCalculatedBlocks = blockRes.x * blockRes.y * blockRes.z;
  if (numCalculatedBlocks != numBlocks)
    throw FileIntegrityException("Incorrect block count in SparseFieldIO::read");

  // Call the appropriate read function based on the data type ---

  FieldBase::Ptr result;

  int occupiedBlocks;
  if (!readAttribute(layerGroup, k_numOccupiedBlocksStr, 1, occupiedBlocks))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_numOccupiedBlocksStr);

  // Check the data type ---

  int bits;
  if (!readAttribute(layerGroup, k_bitsPerComponentStr, 1, bits))
    throw MissingAttributeException("Couldn't find attribute: " +
                                    k_bitsPerComponentStr);

  bool isHalf = false;
  bool isFloat = false;
  bool isDouble = false;

  switch (bits) {
  case 16:
    isHalf = true;
    break;
  case 64:
    isDouble = true;
    break;
  case 32:
  default:
    isFloat = true;
  }

  // Finally, read the data ---

  if (components == 1) {
    if (isHalf && typeEnum == DataTypeHalf) {
      SparseField<half>::Ptr field(new SparseField<half>);
      field->setSize(extents, dataW);
      field->setBlockOrder(blockOrder);
      readData<half>(layerGroup, numBlocks, filename, layerPath, field);
      result = field;
    } else if (isFloat && typeEnum == DataTypeFloat) {
      SparseField<float>::Ptr field(new SparseField<float>);
      field->setSize(extents, dataW);
      field->setBlockOrder(blockOrder);
      readData<float>(layerGroup, numBlocks, filename, layerPath, field);
      result = field;
    } else if (isDouble && typeEnum == DataTypeDouble) {
      SparseField<double>::Ptr field(new SparseField<double>);
      field->setSize(extents, dataW);
      field->setBlockOrder(blockOrder);
      readData<double>(layerGroup, numBlocks, filename, layerPath, field);
      result = field;
    }
  } else if (components == 3) {
    if (isHalf && typeEnum == DataTypeVecHalf) {
      SparseField<V3h>::Ptr field(new SparseField<V3h>);
      field->setSize(extents, dataW);
      field->setBlockOrder(blockOrder);
      readData<V3h>(layerGroup, numBlocks, filename, layerPath, field);
      result = field;
    } else if (isFloat && typeEnum == DataTypeVecFloat) {
      SparseField<V3f>::Ptr field(new SparseField<V3f>);
      field->setSize(extents, dataW);
      field->setBlockOrder(blockOrder);
      readData<V3f>(layerGroup, numBlocks, filename, layerPath, field);
      result = field;
    } else if (isDouble && typeEnum == DataTypeVecDouble) {
      SparseField<V3d>::Ptr field(new SparseField<V3d>);
      field->setSize(extents, dataW);
      field->setBlockOrder(blockOrder);
      readData<V3d>(layerGroup, numBlocks, filename, layerPath, field);
      result = field;
    }
  }

  return result;
}

//----------------------------------------------------------------------------//

bool
SparseFieldIO::write(hid_t layerGroup, FieldBase::Ptr field)
{
  if (layerGroup == -1) {
    Msg::print(Msg::SevWarning, "Bad layerGroup.");
    return false;
  }

  // Add version attribute
  if (!writeAttribute(layerGroup, k_versionAttrName,
                    1, k_versionNumber)) {
    Msg::print(Msg::SevWarning, "Error adding version attribute.");
    return false;
  }

  SparseField<half>::Ptr halfField =
    field_dynamic_cast<SparseField<half> >(field);
  SparseField<float>::Ptr floatField =
    field_dynamic_cast<SparseField<float> >(field);
  SparseField<double>::Ptr doubleField =
    field_dynamic_cast<SparseField<double> >(field);
  SparseField<V3h>::Ptr vecHalfField =
    field_dynamic_cast<SparseField<V3h> >(field);
  SparseField<V3f>::Ptr vecFloatField =
    field_dynamic_cast<SparseField<V3f> >(field);
  SparseField<V3d>::Ptr vecDoubleField =
    field_dynamic_cast<SparseField<V3d> >(field);

  bool success = true;
  if (halfField) {
    success = writeInternal<half>(layerGroup, halfField);
  } else if (floatField) {
    success = writeInternal<float>(layerGroup, floatField);
  } else if (doubleField) {
    success = writeInternal<double>(layerGroup, doubleField);
  } else if (vecHalfField) {
    success = writeInternal<V3h>(layerGroup, vecHalfField);
  } else if (vecFloatField) {
    success = writeInternal<V3f>(layerGroup, vecFloatField);
  } else if (vecDoubleField) {
    success = writeInternal<V3d>(layerGroup, vecDoubleField);
  } else {
    throw WriteLayerException("SparseFieldIO::write does not support the given "
                              "SparseField template parameter");
  }

  return success;
}

//----------------------------------------------------------------------------//

FIELD3D_NAMESPACE_SOURCE_CLOSE

//----------------------------------------------------------------------------//


text:
/*
 * Copyright (c) 2013 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <qi/clock.hpp>
#include <qi/log.hpp>
#include <qi/os.hpp>
#include <qi/atomic.hpp>
#include <boost/thread.hpp>
#include <boost/chrono/ceil.hpp>

#ifndef BOOST_THREAD_USES_CHRONO
// needed for boost < 1.50
#include <boost/thread/thread_time.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#endif
qiLogCategory("qi.clock");

namespace chrono = boost::chrono;

namespace qi {

  /* Have the static variable we need inside the function so that we
   * give correct results at initialization time, but also force
   * initialization so that timestamp 0 corresponds to program start time.
   */
  static SteadyClock::time_point _unused_base = SteadyClock::now();

  SteadyClock::time_point SteadyClock::now()
  {
    static bool initialized = false;
    static qi::Duration base;
    if (!initialized)
    {
      base = chrono::steady_clock::now().time_since_epoch();
      initialized = true;
    }
    return time_point(chrono::steady_clock::now().time_since_epoch() - base);
  }

  Clock::time_point Clock::now()
  {
    return time_point(chrono::steady_clock::now().time_since_epoch());
  }

  using uint32ms = chrono::duration<uint32_t, boost::milli>;

  uint32_t Clock::toUint32ms(const time_point &t) throw()
  {
    return chrono::duration_cast<uint32ms>(t.time_since_epoch()).count();
  }

  int32_t Clock::toInt32ms(const time_point &t) throw()
  {
    return static_cast<int32_t>(toUint32ms(t));
  }

  Clock::time_point Clock::fromUint32ms(uint32_t t_ms,
                                        Clock::time_point guess,
                                        Expect expect) throw()
  {
    // ms: a duration type with ms precision, but no overflow problem
    using ms = chrono::milliseconds;
    using time_point_ms = chrono::time_point<Clock, ms>;
    // overflow period
    static const ms period(ms(uint32ms::max()) - ms(uint32ms::min()) + ms(uint32ms(1)));
    uint32ms guess_ms = chrono::duration_cast<uint32ms>(guess.time_since_epoch());
    // convert to ms intead of using Clock::duration to avoid sub-ms noise
    time_point_ms origin(chrono::time_point_cast<ms>(guess)
                         - chrono::duration_cast<ms>(guess_ms));

    static const uint32_t half_period = uint32ms(period/2).count();
    switch (expect)
    {
    case Expect_SoonerOrLater: // guess - period/2 < result <= guess + period/2
      if (t_ms > guess_ms.count() && t_ms - guess_ms.count() > half_period)
        origin -= period;
      else if (t_ms < guess_ms.count() && guess_ms.count() - t_ms >= half_period)
        origin += period;
      break;
    case Expect_Later: // guess <= result < guess + period
      if (guess_ms.count() > t_ms)
        // the 32 bits clock has overflown between guess and t
        origin += period;
      break;
    case Expect_Sooner: // guess - period < result <= guess
      if (t_ms > guess_ms.count())
        // the 32 bits clock has overflown between t and guess
        origin -= period;
      break;
    }
    return origin + uint32ms(t_ms);
  }

  Clock::time_point Clock::fromInt32ms(int32_t t_ms,
                                       Clock::time_point guess,
                                       Expect expect) throw()
  {
    return Clock::fromUint32ms(static_cast<uint32_t>(t_ms), guess, expect);
  }

  SystemClock::time_point SystemClock::now()
  {
    return SystemClock::time_point(
        chrono::system_clock::now().time_since_epoch());
  }

  std::time_t SystemClock::to_time_t(const SystemClock::time_point &t) throw()
  {
    return chrono::system_clock::to_time_t(
        chrono::system_clock::time_point(
            chrono::duration_cast<chrono::system_clock::duration>(
                t.time_since_epoch())));
  }

  SystemClock::time_point SystemClock::from_time_t(const std::time_t &t) throw()
  {
    return time_point(
        chrono::system_clock::from_time_t(t).time_since_epoch());
  }

  void sleepFor(const SteadyClock::duration &d)
  {
#ifdef BOOST_THREAD_USES_CHRONO
    boost::this_thread::sleep_for(d);
#else
# ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
    boost::this_thread::sleep(boost::posix_time::nanoseconds(d.count()));
# else
    using us = chrono::microseconds;
    boost::this_thread::sleep(
          boost::posix_time::microseconds(chrono::ceil<us>(d).count()));
# endif
#endif
  }

  void sleepUntil(const SteadyClockTimePoint& t)
  {
    sleepFor(t - SteadyClock::now());
  }

  void sleepUntil(const ClockTimePoint& t)
  {
    sleepFor(t - Clock::now());
  }

  void sleepUntil(const SystemClockTimePoint &t)
  {
#ifdef BOOST_THREAD_USES_CHRONO
    boost::this_thread::sleep_until(t);
#else
    static const boost::gregorian::date epoch(1970, boost::date_time::Jan, 1);
# ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
    boost::this_thread::sleep(boost::system_time(epoch,
      boost::posix_time::nanoseconds(t.time_since_epoch().count())));
# else
    using us = chrono::microseconds;
    boost::this_thread::sleep(boost::system_time(epoch,
      boost::posix_time::microseconds(
        chrono::ceil<us>(t.time_since_epoch()).count())));
# endif
#endif
  }

  std::string toISO8601String(const SystemClockTimePoint &t)
  {
    std::time_t tt = SystemClock::to_time_t(t);
    char buff[18];
    std::strftime(buff, sizeof(buff), "%Y-%m-%dT%H%M%S", std::gmtime(&tt));
    // deal with milliseconds and timezone
    qi::MilliSeconds subseconds =
        boost::chrono::time_point_cast<qi::MilliSeconds>(t) -
        boost::chrono::time_point_cast<qi::Seconds>(t);
    std::ostringstream ss;
    ss << buff << ".";
    ss.width(3);
    ss.fill('0');
    ss << std::right << subseconds.count() << 'Z';
    return ss.str();
  }
}

max_stars_repo_name: arntanguy/libqi

max_issues_repo_name: arntanguy/libqi

max_forks_repo_name: arntanguy/libqi


text:
#ifndef INDEX_PARTITIONING_SOCKET_HPP
#define INDEX_PARTITIONING_SOCKET_HPP

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <cstdlib>
#include <iostream>

#include "socket_exception.hpp"

namespace query_server {
    using boost::asio::ip::tcp;

    class SocketServer;

    class Socket {
    public:
        unsigned int receive_message(void *buffer, std::size_t buffer_size) {
            unsigned int message_size;

            this->read_n_bytes(&message_size, sizeof(unsigned int));

            if (message_size > buffer_size) {
                throw SocketMessageSizeException();
            }

            this->read_n_bytes(buffer, message_size);
            return message_size;
        }

        void send_message(const void *data, unsigned int size_in_bytes) {
            this->write_n_bytes(&size_in_bytes, sizeof(unsigned int));
            this->write_n_bytes(data, size_in_bytes);
        }

        unsigned int receive_message(std::stringstream &ss) {
            unsigned int message_size;

            this->read_n_bytes(&message_size, sizeof(unsigned int));
            this->read_n_bytes(ss, message_size);
            return message_size;
        }

        void send_message(const std::string &str) {
            unsigned long message_size = str.size();
            if (message_size > static_cast<unsigned int>(-1)) {
                throw SocketMessageSizeException();
            }
            this->send_message(str.c_str(), static_cast<unsigned int>(message_size));
        }

        void close() {
            this->_sock.close();
        }

        void shutdown() {
            this->_sock.shutdown(tcp::socket::shutdown_both);
        }

    protected:
        Socket(boost::asio::io_service *io_service, const char *ip, unsigned short port) : _sock(*io_service) {
            tcp::endpoint endpoint = Socket::get_endpoint(ip, port);
            tcp::resolver resolver(*io_service);
            boost::asio::connect(this->_sock, resolver.resolve(endpoint));
        }

        Socket(boost::asio::io_service *io_service, tcp::acceptor &acceptor) : _sock(*io_service) {
            acceptor.accept(this->_sock);
        }

        static
        tcp::endpoint get_endpoint(const char *ip, unsigned short port) {
            return tcp::endpoint(boost::asio::ip::address::from_string(ip), port);
        }

        friend class SocketServer;

    private:
        static inline
        void
        custom_throw_error(boost::system::system_error const& e) {
            namespace error_ns = boost::asio::error;
            const boost::system::error_code &error = e.code();

            if (error == error_ns::eof || error == error_ns::connection_reset || error == error_ns::broken_pipe ||
                error == error_ns::not_connected)
                throw SocketConnectionClosedByPeerException(); // Connection closed cleanly by peer.
            throw SocketException(e.what()); // Some other error.
        }

        void
        read_n_bytes(
                void *buffer,
                std::size_t size_in_bytes
        ) {
            try {
                boost::asio::read(this->_sock, boost::asio::buffer(buffer, size_in_bytes));
            } catch (boost::system::system_error const& e) {
                custom_throw_error(e);
            } catch ( ... ) {
                throw SocketException("Unhandled exception in boost::asio::read");
            }
        }

        void
        read_n_bytes(
                std::stringstream &ss,
                std::size_t size_in_bytes
        ) {
            try {
                boost::asio::streambuf streambuf;
                boost::asio::read(this->_sock, streambuf, boost::asio::transfer_exactly(size_in_bytes));

                ss << &streambuf;
            } catch (boost::system::system_error const& e) {
                custom_throw_error(e);
            } catch ( ... ) {
                throw SocketException("Unhandled exception in boost::asio::read");
            }
        }

        void
        write_n_bytes(
                const void *data,
                std::size_t size_in_bytes
        ) {
            try {
                boost::asio::write(this->_sock, boost::asio::buffer(data, size_in_bytes));
            } catch (boost::system::system_error const& e) {
                custom_throw_error(e);
            } catch ( ... ) {
                throw SocketException("Unhandled exception in boost::asio::write");
            }
        }

    private:
        tcp::socket _sock;
    };

    class SocketServer {
    public:
        SocketServer(boost::asio::io_service *io_service, const char *ip, unsigned short port)
                : _io_service(io_service),
                  _acceptor(tcp::acceptor(*this->_io_service, Socket::get_endpoint(ip, port))) {}

        Socket *acceptConnection() {
            return new Socket(this->_io_service, this->_acceptor);
        }

        void close() {
            this->_acceptor.close();
        }

    private:
        boost::asio::io_service *_io_service;
        tcp::acceptor _acceptor;
    };

    class SocketClient : public Socket {
    public:
        SocketClient(boost::asio::io_service *io_service, const char *ip, unsigned short port)
                : Socket(io_service, ip, port) {}
    };
}

#endif //INDEX_PARTITIONING_SOCKET_HPP


text:
/* -*- Mode:C++; c-file-style:"bsd"; indent-tabs-mode:nil; -*- */
/**
 * Copyright 2020 Washington University in St. Louis
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <../src/api.hpp>

#include <ndn-cxx/face.hpp>
#include <ndn-cxx/encoding/buffer-stream.hpp>
#include <ndn-cxx/mgmt/nfd/face-status.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/security/validator-null.hpp>
#include <ndn-cxx/util/segment-fetcher.hpp>

#include <boost/asio.hpp>

#include <unordered_map>
#include <iostream>

// global variable to support debug
int DEBUG = 0;

enum class Status
{
    Good,
    Bad
};

struct TutorialEvent
{
    double latitude;
    double longitude;
    Status status;

    TutorialEvent(double lat, double lon, Status stat) :
        latitude(lat), longitude(lon), status(stat)
    { }
};

namespace ndn
{

typedef std::unordered_map<uint64_t, std::vector<Name>> NotificationMap;

class NotificationProducer
{
public:
    NotificationProducer(char* programName)
        : m_programName(programName)
    { }

    void
    usage()
    {
        std::cout << "\n Usage:\n " << m_programName <<
            ""
            " [-h] -f filters_file -n name [-d debug_mode]\n"
            " Register and push event notifications.\n"
            "\n"
            " \t-h - print this message and exit\n"
            " \t-f - configuration file \n"
            " \t-n - name of producer publishing events\n"
            " \t-d - sets the debug mode, 1 - debug on, 0 - debug off (default)\n"
            "\n";
        exit(1);
    }

    void setEntityName(std::string entityName)
    {
        m_entityName = entityName;
    }

    void
    setFile(std::string file)
    {
        m_fileName = file;
        if (DEBUG)
            std::cout << "set file name to " << m_fileName << std::endl;
    }

    void init()
    {
        if (m_notificationHandler != nullptr)
        {
            std::cout << "Trying to initialize notification handler, but it already exists." << std::endl;
            return;
        }

        m_notificationHandler = std::make_shared<notificationLib::api>(m_face,
                                                                       notificationLib::api::DEFAULT_NAME,
                                                                       notificationLib::api::DEFAULT_VALIDATOR);
        m_notificationHandler->init(m_fileName,
                                    std::bind(&NotificationProducer::onNotificationUpdateWithTime, this, _1, _2));
    }

    void
    generate()
    {
        std::random_device rd;
        std::mt19937 gen( rd() );
        std::uniform_real_distribution<> latDist(-90.0, 90.0);
        std::uniform_real_distribution<> longDist(-180.0, 180.0);

        while (true)
        {
            m_face.processEvents( time::seconds(1) );

            // generate a random event
            TutorialEvent event { latDist(gen), longDist(gen), Status(std::rand() % 2) };

            // create our event by adding additional named components
            Name eventName("/test/event/");
            eventName.append(m_entityName);
            eventName.append( std::to_string(event.latitude) );
            eventName.append( std::to_string(event.longitude) );
            eventName.append( std::to_string(static_cast<int>(event.status)) );

            // add our event to an eventList
            std::vector<Name> eventList;
            eventList.push_back(eventName);

            // publish the event list under the notify namespace
            std::cout << "sending event = " << eventName << std::endl;
            m_notificationHandler->notify("/wustl/test/service", eventList);

            sleep(1);
        }
    }

    void
    onNotificationUpdateWithTime (uint64_t receivedTime, const NotificationMap& notiMap)
    {
        for (auto& map_itr : notiMap)
        {
            for (auto& noti : map_itr.second)
            {
                std::cout << "application received notification: " << noti << std::endl;
            }
        }
    }

private:
    std::shared_ptr<notificationLib::api> m_notificationHandler;

    Face m_face;
    KeyChain m_keyChain;
    security::ValidatorNull m_validator;

    std::string m_programName;
    std::string m_fileName;
    std::string m_entityName;
};

} // namespace ndn

int
main(int argc, char* argv[])
{
    ndn::NotificationProducer producer(argv[0]);
    int option;
    bool fileSet = false;
    bool nameSet = false;

    while ((option = getopt(argc, argv, "hf:n:d:")) != -1)
    {
        switch (option)
        {
        case 'f':
            producer.setFile((std::string)(optarg));
            fileSet = true;
            break;
        case 'n':
            producer.setEntityName((std::string)(optarg));
            nameSet = true;
            break;
        case 'h':
            producer.usage();
            break;
        case 'd':
            DEBUG = atoi(optarg);
            break;
        default:
            producer.usage();
            break;
        }
    }

    argc -= optind;
    argv += optind;

    if(!fileSet) {
        producer.usage();
        return 1;
    }

    if(!nameSet) {
        producer.usage();
        return 2;
    }

    producer.init();
    producer.generate();
    return 0;
}