<commit_before>#include "joblistwidget.h"

WARNINGS_DISABLE
#include <QAbstractItemView>
#include <QKeyEvent>
#include <QList>
#include <QListWidgetItem>
#include <QMessageBox>
#include <QRegExp>
#include <Qt>
WARNINGS_ENABLE

#include "messages/archiverestoreoptions.h"

#include "debug.h"
#include "joblistwidgetitem.h"
#include "persistentmodel/job.h"
#include "restoredialog.h"

JobListWidget::JobListWidget(QWidget *parent)
    : QListWidget(parent), _filter(new QRegExp)
{
    _filter->setCaseSensitivity(Qt::CaseInsensitive);
    _filter->setPatternSyntax(QRegExp::Wildcard);
    connect(this, &QListWidget::itemActivated, [this](QListWidgetItem *item) {
        emit displayJobDetails(static_cast<JobListWidgetItem *>(item)->job());
    });
}

JobListWidget::~JobListWidget()
{
    clear();
    delete _filter;
}

void JobListWidget::backupSelectedItems()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    QMessageBox::StandardButton confirm =
        QMessageBox::question(this, tr("Confirm action"),
                              tr("Initiate backup for the %1 selected job(s)?")
                                  .arg(selectedItems().count()));
    if(confirm != QMessageBox::Yes)
        return;

    for(QListWidgetItem *item : selectedItems())
    {
        if(item->isSelected())
        {
            JobPtr job = static_cast<JobListWidgetItem *>(item)->job();
            emit   backupJob(job);
        }
    }
}

void JobListWidget::selectJob(JobPtr job)
{
    // Bail (if applicable).
    if(!job)
    {
        DEBUG << "Null JobPtr passed.";
        return;
    }

    for(int i = 0; i < count(); ++i)
    {
        JobListWidgetItem *jobItem = static_cast<JobListWidgetItem *>(item(i));
        if(jobItem && (jobItem->job()->objectKey() == job->objectKey()))
        {
            clearSelection();
            setCurrentItem(jobItem);
            scrollToItem(currentItem(), QAbstractItemView::EnsureVisible);
            break;
        }
    }
}

void JobListWidget::inspectJobByRef(const QString &jobRef)
{
    // Bail (if applicable).
    if(jobRef.isEmpty())
        return;

    for(int i = 0; i < count(); ++i)
    {
        JobListWidgetItem *jobItem = static_cast<JobListWidgetItem *>(item(i));
        if(jobItem && (jobItem->job()->objectKey() == jobRef))
            emit displayJobDetails(jobItem->job());
    }
}

void JobListWidget::backupAllJobs()
{
    for(int i = 0; i < count(); ++i)
    {
        JobPtr job = static_cast<JobListWidgetItem *>(item(i))->job();
        emit   backupJob(job);
    }
}

void JobListWidget::backupItem()
{
    // Bail (if applicable).
    if(!sender())
        return;

    JobPtr job = qobject_cast<JobListWidgetItem *>(sender())->job();
    if(job)
        emit backupJob(job);
}

void JobListWidget::inspectItem()
{
    // Bail (if applicable).
    if(!sender())
        return;

    emit displayJobDetails(qobject_cast<JobListWidgetItem *>(sender())->job());
}

void JobListWidget::restoreItem()
{
    // Bail (if applicable).
    if(!sender())
        return;

    JobPtr job = qobject_cast<JobListWidgetItem *>(sender())->job();

    // Bail (if applicable).
    if(job->archives().isEmpty())
        return;

    ArchivePtr     archive       = job->archives().first();
    RestoreDialog *restoreDialog = new RestoreDialog(this, archive);
    connect(restoreDialog, &RestoreDialog::accepted, [this, restoreDialog] {
        emit restoreArchive(restoreDialog->archive(),
                            restoreDialog->getOptions());
    });
    restoreDialog->show();
}

void JobListWidget::deleteItem()
{
    execDeleteJob(qobject_cast<JobListWidgetItem *>(sender()));
}

void JobListWidget::execDeleteJob(JobListWidgetItem *jobItem)
{
    // Bail (if applicable).
    if(!jobItem)
    {
        DEBUG << "Null JobListWidgetItem passed.";
        return;
    }

    JobPtr job = jobItem->job();

    QMessageBox::StandardButton confirm =
        QMessageBox::question(this, tr("Confirm action"),
                              tr("Are you sure you want to delete job \"%1\" "
                                 "(this cannot be undone)?")
                                  .arg(job->name()));
    if(confirm != QMessageBox::Yes)
        return;

    bool purgeArchives = false;
    if(!job->archives().isEmpty())
    {
        QMessageBox::StandardButton delArchives =
            QMessageBox::question(this, tr("Confirm action"),
                                  tr("Also delete %1 archives "
                                     "belonging to this job "
                                     "(this cannot be undone)?")
                                      .arg(job->archives().count()));
        if(delArchives == QMessageBox::Yes)
            purgeArchives = true;
    }
    emit deleteJob(job, purgeArchives);
    delete jobItem;
    emit countChanged(count(), visibleItemsCount());
}

int JobListWidget::visibleItemsCount()
{
    int count = 0;
    for(QListWidgetItem *item : findItems("*", Qt::MatchWildcard))
    {
        if(item && !item->isHidden())
            count++;
    }
    return count;
}

void JobListWidget::setJobs(const QMap<QString, JobPtr> &jobs)
{
    setUpdatesEnabled(false);
    clear();
    for(const JobPtr &job : jobs)
    {
        addJob(job);
    }
    setUpdatesEnabled(true);
}

void JobListWidget::addJob(JobPtr job)
{
    // Bail (if applicable).
    if(!job)
    {
        DEBUG << "Null JobPtr passed.";
        return;
    }

    JobListWidgetItem *item = new JobListWidgetItem(job);
    connect(item, &JobListWidgetItem::requestBackup, this,
            &JobListWidget::backupItem);
    connect(item, &JobListWidgetItem::requestInspect, this,
            &JobListWidget::inspectItem);
    connect(item, &JobListWidgetItem::requestRestore, this,
            &JobListWidget::restoreItem);
    connect(item, &JobListWidgetItem::requestDelete, this,
            &JobListWidget::deleteItem);
    insertItem(count(), item);
    setItemWidget(item, item->widget());
    item->setHidden(!job->name().contains(*_filter));
    emit countChanged(count(), visibleItemsCount());
}

void JobListWidget::inspectSelectedItem()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    emit displayJobDetails(
        static_cast<JobListWidgetItem *>(selectedItems().first())->job());
}

void JobListWidget::restoreSelectedItem()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    JobPtr job =
        static_cast<JobListWidgetItem *>(selectedItems().first())->job();

    // Bail (if applicable).
    if(job->archives().isEmpty())
        return;

    ArchivePtr     archive       = job->archives().first();
    RestoreDialog *restoreDialog = new RestoreDialog(this, archive);
    connect(restoreDialog, &RestoreDialog::accepted, [this, restoreDialog] {
        emit restoreArchive(restoreDialog->archive(),
                            restoreDialog->getOptions());
    });
    restoreDialog->show();
}

void JobListWidget::deleteSelectedItem()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    execDeleteJob(static_cast<JobListWidgetItem *>(selectedItems().first()));
}

void JobListWidget::setFilter(const QString &regex)
{
    setUpdatesEnabled(false);
    clearSelection();
    _filter->setPattern(regex);
    for(int i = 0; i < count(); ++i)
    {
        JobListWidgetItem *jobItem = static_cast<JobListWidgetItem *>(item(i));
        if(jobItem)
        {
            if(jobItem->job()->name().contains(*_filter))
                jobItem->setHidden(false);
            else
                jobItem->setHidden(true);
        }
    }
    setUpdatesEnabled(true);
    emit countChanged(count(), visibleItemsCount());
}

void JobListWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Delete:
        deleteSelectedItem();
        break;
    case Qt::Key_Escape:
        if(!selectedItems().isEmpty())
            clearSelection();
        else
            QListWidget::keyPressEvent(event);
        break;
    default:
        QListWidget::keyPressEvent(event);
    }
}
<commit_msg>JobListWidget: comments<commit_after>#include "joblistwidget.h"

WARNINGS_DISABLE
#include <QAbstractItemView>
#include <QKeyEvent>
#include <QList>
#include <QListWidgetItem>
#include <QMessageBox>
#include <QRegExp>
#include <Qt>
WARNINGS_ENABLE

#include "messages/archiverestoreoptions.h"

#include "debug.h"
#include "joblistwidgetitem.h"
#include "persistentmodel/job.h"
#include "restoredialog.h"

JobListWidget::JobListWidget(QWidget *parent)
    : QListWidget(parent), _filter(new QRegExp)
{
    // Set up filtering job names.
    _filter->setCaseSensitivity(Qt::CaseInsensitive);
    _filter->setPatternSyntax(QRegExp::Wildcard);

    // Connection for showing info about a Job.
    connect(this, &QListWidget::itemActivated, [this](QListWidgetItem *item) {
        emit displayJobDetails(static_cast<JobListWidgetItem *>(item)->job());
    });
}

JobListWidget::~JobListWidget()
{
    clear();
    delete _filter;
}

void JobListWidget::backupSelectedItems()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    // Confirm that the user wants to create new archive(s).
    QMessageBox::StandardButton confirm =
        QMessageBox::question(this, tr("Confirm action"),
                              tr("Initiate backup for the %1 selected job(s)?")
                                  .arg(selectedItems().count()));
    if(confirm != QMessageBox::Yes)
        return;

    // Create a new archive for each selected Job.
    for(QListWidgetItem *item : selectedItems())
    {
        if(item->isSelected())
        {
            JobPtr job = static_cast<JobListWidgetItem *>(item)->job();
            emit   backupJob(job);
        }
    }
}

void JobListWidget::selectJob(JobPtr job)
{
    // Bail (if applicable).
    if(!job)
    {
        DEBUG << "Null JobPtr passed.";
        return;
    }

    // Find the item representing the Job, and select it.
    for(int i = 0; i < count(); ++i)
    {
        JobListWidgetItem *jobItem = static_cast<JobListWidgetItem *>(item(i));
        if(jobItem && (jobItem->job()->objectKey() == job->objectKey()))
        {
            clearSelection();
            setCurrentItem(jobItem);
            scrollToItem(currentItem(), QAbstractItemView::EnsureVisible);
            break;
        }
    }
}

void JobListWidget::inspectJobByRef(const QString &jobRef)
{
    // Bail (if applicable).
    if(jobRef.isEmpty())
        return;

    // Find the item representing the Job, and display its details.
    for(int i = 0; i < count(); ++i)
    {
        JobListWidgetItem *jobItem = static_cast<JobListWidgetItem *>(item(i));
        if(jobItem && (jobItem->job()->objectKey() == jobRef))
            emit displayJobDetails(jobItem->job());
    }
}

void JobListWidget::backupAllJobs()
{
    // Start a new archive for all jobs.
    for(int i = 0; i < count(); ++i)
    {
        JobPtr job = static_cast<JobListWidgetItem *>(item(i))->job();
        emit   backupJob(job);
    }
}

void JobListWidget::backupItem()
{
    // Bail (if applicable).
    if(!sender())
        return;

    // Start a new archive for this job.
    JobPtr job = qobject_cast<JobListWidgetItem *>(sender())->job();
    if(job)
        emit backupJob(job);
}

void JobListWidget::inspectItem()
{
    // Bail (if applicable).
    if(!sender())
        return;

    // Display details about the job.
    emit displayJobDetails(qobject_cast<JobListWidgetItem *>(sender())->job());
}

void JobListWidget::restoreItem()
{
    // Bail (if applicable).
    if(!sender())
        return;

    // Get the Job.
    JobPtr job = qobject_cast<JobListWidgetItem *>(sender())->job();

    // Bail (if applicable).
    if(job->archives().isEmpty())
        return;

    // Get the latest archive belonging to the Job.
    ArchivePtr archive = job->archives().first();

    // Launch the RestoreDialog.
    RestoreDialog *restoreDialog = new RestoreDialog(this, archive);
    connect(restoreDialog, &RestoreDialog::accepted, [this, restoreDialog] {
        emit restoreArchive(restoreDialog->archive(),
                            restoreDialog->getOptions());
    });
    restoreDialog->show();
}

void JobListWidget::deleteItem()
{
    execDeleteJob(qobject_cast<JobListWidgetItem *>(sender()));
}

void JobListWidget::execDeleteJob(JobListWidgetItem *jobItem)
{
    // Bail (if applicable).
    if(!jobItem)
    {
        DEBUG << "Null JobListWidgetItem passed.";
        return;
    }

    // Get the Job.
    JobPtr job = jobItem->job();

    // Confirm that the user wants to delete the Job.
    QMessageBox::StandardButton confirm =
        QMessageBox::question(this, tr("Confirm action"),
                              tr("Are you sure you want to delete job \"%1\" "
                                 "(this cannot be undone)?")
                                  .arg(job->name()));
    if(confirm != QMessageBox::Yes)
        return;

    // Confirm if the user wants to remove archives as well.
    bool purgeArchives = false;
    if(!job->archives().isEmpty())
    {
        QMessageBox::StandardButton delArchives =
            QMessageBox::question(this, tr("Confirm action"),
                                  tr("Also delete %1 archives "
                                     "belonging to this job "
                                     "(this cannot be undone)?")
                                      .arg(job->archives().count()));
        if(delArchives == QMessageBox::Yes)
            purgeArchives = true;
    }

    // Begin deleting the job (and possibly archives as well).
    emit deleteJob(job, purgeArchives);
    delete jobItem;

    // Notify about the number of visible items.
    emit countChanged(count(), visibleItemsCount());
}

int JobListWidget::visibleItemsCount()
{
    int count = 0;
    for(QListWidgetItem *item : findItems("*", Qt::MatchWildcard))
    {
        if(item && !item->isHidden())
            count++;
    }
    return count;
}

void JobListWidget::setJobs(const QMap<QString, JobPtr> &jobs)
{
    setUpdatesEnabled(false);
    clear();
    for(const JobPtr &job : jobs)
    {
        addJob(job);
    }
    setUpdatesEnabled(true);
}

void JobListWidget::addJob(JobPtr job)
{
    // Bail (if applicable).
    if(!job)
    {
        DEBUG << "Null JobPtr passed.";
        return;
    }

    // Create new item.
    JobListWidgetItem *item = new JobListWidgetItem(job);
    connect(item, &JobListWidgetItem::requestBackup, this,
            &JobListWidget::backupItem);
    connect(item, &JobListWidgetItem::requestInspect, this,
            &JobListWidget::inspectItem);
    connect(item, &JobListWidgetItem::requestRestore, this,
            &JobListWidget::restoreItem);
    connect(item, &JobListWidgetItem::requestDelete, this,
            &JobListWidget::deleteItem);

    // Add it to the end of the list.
    insertItem(count(), item);
    setItemWidget(item, item->widget());

    // Check it against the name filter.
    item->setHidden(!job->name().contains(*_filter));

    // Notify about the number of visible items.
    emit countChanged(count(), visibleItemsCount());
}

void JobListWidget::inspectSelectedItem()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    // Display details about the first of the selected items.
    emit displayJobDetails(
        static_cast<JobListWidgetItem *>(selectedItems().first())->job());
}

void JobListWidget::restoreSelectedItem()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    // Get the first Job amongst the selected items.
    JobPtr job =
        static_cast<JobListWidgetItem *>(selectedItems().first())->job();

    // Bail (if applicable).
    if(job->archives().isEmpty())
        return;

    // Get the latest archive belonging to the Job.
    ArchivePtr archive = job->archives().first();

    // Launch the RestoreDialog.
    RestoreDialog *restoreDialog = new RestoreDialog(this, archive);
    connect(restoreDialog, &RestoreDialog::accepted, [this, restoreDialog] {
        emit restoreArchive(restoreDialog->archive(),
                            restoreDialog->getOptions());
    });
    restoreDialog->show();
}

void JobListWidget::deleteSelectedItem()
{
    // Bail (if applicable).
    if(selectedItems().isEmpty())
        return;

    // Delete the first of the selected items.
    execDeleteJob(static_cast<JobListWidgetItem *>(selectedItems().first()));
}

void JobListWidget::setFilter(const QString &regex)
{
    setUpdatesEnabled(false);

    // Set up filter.
    clearSelection();
    _filter->setPattern(regex);

    // Check jobs against filter.
    for(int i = 0; i < count(); ++i)
    {
        JobListWidgetItem *jobItem = static_cast<JobListWidgetItem *>(item(i));
        if(jobItem)
        {
            if(jobItem->job()->name().contains(*_filter))
                jobItem->setHidden(false);
            else
                jobItem->setHidden(true);
        }
    }
    setUpdatesEnabled(true);

    // Notify about the number of visible items.
    emit countChanged(count(), visibleItemsCount());
}

void JobListWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Delete:
        deleteSelectedItem();
        break;
    case Qt::Key_Escape:
        if(!selectedItems().isEmpty())
            clearSelection();
        else
            QListWidget::keyPressEvent(event);
        break;
    default:
        QListWidget::keyPressEvent(event);
    }
}
<|endoftext|>


<commit_before>#include "pong/state.hpp"

#include <Box2D/Box2D.h>

#include "pong/game.hpp"
#include "pong/defs.hpp"

namespace pong {

sf::RectangleShape createRectangleShape(float width, float height) {
    sf::RectangleShape shape;
    shape.setOrigin(width / 2, height / 2);
    shape.setSize(sf::Vector2f(width, height));
    shape.setFillColor(sf::Color::White);
    return shape;
}

void syncBodyToTransformable(b2Body* body, sf::Transformable& transformable) {
    b2Vec2 position = body->GetPosition();
    float angle = body->GetAngle();
    transformable.setPosition(position.x * PIXELS_PER_METER,
                              position.y * PIXELS_PER_METER);
    transformable.setRotation(angle);
}

void DefaultState::enter(Game* game) {
    game_ = game;
}

void DefaultState::handleInput(const sf::Event& event) {
    if (event.type == sf::Event::Closed) {
        game_->exit();
    }
}

void GameState::enter(Game* game) {
    DefaultState::enter(game);

    create();
}

void GameState::create() {
    setupGameWorld();
    setupInputHandlers();
}

void GameState::setupGameWorld() {
    gameWorld_.create();
    gameWorld_.setScoreListener(this);
    gameWorld_.start();

#ifndef NDEBUG
    setupDebugDraw();
#endif /* ifndef NDEBUG */
}

void GameState::setupDebugDraw() {
    debugDraw_.reset(new SFMLDebugDraw(game_->window(), pong::PIXELS_PER_METER));
    gameWorld_.setDebugDraw(debugDraw_.get());
    debugDraw_->SetFlags(b2Draw::e_shapeBit);
}

void GameState::setupInputHandlers() {
    setupPlayerOneInputHandler();
    setupPlayerTwoInputHandler();
}

void GameState::setupPlayerOneInputHandler() {
    b2Body* leftRaquet = gameWorld_.leftRaquet();
    b2Vec2 upVelocity(0.0f, RAQUET_BASE_SPEED);
    b2Vec2 downVelocity(0.0f, -RAQUET_BASE_SPEED);

    RaquetInputHandler* leftHandler = new RaquetInputHandler(leftRaquet);
    leftHandler->bindKey(sf::Keyboard::W, InputHandler::UP);
    leftHandler->bindKey(sf::Keyboard::S, InputHandler::DOWN);

    Command* command = new MoveRaquetCommand(leftRaquet, upVelocity);
    leftHandler->bindCommand(InputHandler::UP, command);
    command = new MoveRaquetCommand(leftRaquet, downVelocity);
    leftHandler->bindCommand(InputHandler::DOWN, command);

    inputHandlers_[PLAYER_1].reset(leftHandler);
}

void GameState::setupPlayerTwoInputHandler() {
    b2Body* leftRaquet = gameWorld_.rightRaquet();
    b2Vec2 upVelocity(0.0f, RAQUET_BASE_SPEED);
    b2Vec2 downVelocity(0.0f, -RAQUET_BASE_SPEED);

    RaquetInputHandler* rightHandler = new RaquetInputHandler(leftRaquet);
    rightHandler->bindKey(sf::Keyboard::Up, InputHandler::UP);
    rightHandler->bindKey(sf::Keyboard::Down, InputHandler::DOWN);

    Command* command = new MoveRaquetCommand(leftRaquet, upVelocity);
    rightHandler->bindCommand(InputHandler::UP, command);
    command = new MoveRaquetCommand(leftRaquet, downVelocity);
    rightHandler->bindCommand(InputHandler::DOWN, command);

    inputHandlers_[PLAYER_2].reset(rightHandler);
}

void GameState::exit() {
}

void GameState::handleInput(const sf::Event& event) {
    if (event.type == sf::Event::KeyReleased) {
        if (event.key.code == sf::Keyboard::R) {
            create();
        }
    } else {
        DefaultState::handleInput(event);
    }
}

void GameState::update() {
    for (auto& handler : inputHandlers_) {
        Command* command = handler->handleInput();
        command->execute();
    }

    gameWorld_.update();
}

void GameState::render(sf::RenderTarget& renderTarget) {
#ifndef NDEBUG
    gameWorld_.drawDebugData();
#endif /* ifndef NDEBUG  */
}

void GameState::leftScored(GameWorld& gameWorld) {
    gameWorld.resetBall();
}

void GameState::rightScored(GameWorld& gameWorld) {
    gameWorld.resetBall();
}

} /* namespace pong */
<commit_msg>Add pause button<commit_after>#include "pong/state.hpp"

#include <Box2D/Box2D.h>

#include "pong/game.hpp"
#include "pong/defs.hpp"

namespace pong {

sf::RectangleShape createRectangleShape(float width, float height) {
    sf::RectangleShape shape;
    shape.setOrigin(width / 2, height / 2);
    shape.setSize(sf::Vector2f(width, height));
    shape.setFillColor(sf::Color::White);
    return shape;
}

void syncBodyToTransformable(b2Body* body, sf::Transformable& transformable) {
    b2Vec2 position = body->GetPosition();
    float angle = body->GetAngle();
    transformable.setPosition(position.x * PIXELS_PER_METER,
                              position.y * PIXELS_PER_METER);
    transformable.setRotation(angle);
}

void DefaultState::enter(Game* game) {
    game_ = game;
}

void DefaultState::handleInput(const sf::Event& event) {
    if (event.type == sf::Event::Closed) {
        game_->exit();
    }
}

void GameState::enter(Game* game) {
    DefaultState::enter(game);

    create();
}

void GameState::create() {
    setupGameWorld();
    setupInputHandlers();
}

void GameState::setupGameWorld() {
    gameWorld_.create();
    gameWorld_.setScoreListener(this);
    gameWorld_.start();

#ifndef NDEBUG
    setupDebugDraw();
#endif /* ifndef NDEBUG */
}

void GameState::setupDebugDraw() {
    debugDraw_.reset(new SFMLDebugDraw(game_->window(), pong::PIXELS_PER_METER));
    gameWorld_.setDebugDraw(debugDraw_.get());
    debugDraw_->SetFlags(b2Draw::e_shapeBit);
}

void GameState::setupInputHandlers() {
    setupPlayerOneInputHandler();
    setupPlayerTwoInputHandler();
}

void GameState::setupPlayerOneInputHandler() {
    b2Body* leftRaquet = gameWorld_.leftRaquet();
    b2Vec2 upVelocity(0.0f, RAQUET_BASE_SPEED);
    b2Vec2 downVelocity(0.0f, -RAQUET_BASE_SPEED);

    RaquetInputHandler* leftHandler = new RaquetInputHandler(leftRaquet);
    leftHandler->bindKey(sf::Keyboard::W, InputHandler::UP);
    leftHandler->bindKey(sf::Keyboard::S, InputHandler::DOWN);

    Command* command = new MoveRaquetCommand(leftRaquet, upVelocity);
    leftHandler->bindCommand(InputHandler::UP, command);
    command = new MoveRaquetCommand(leftRaquet, downVelocity);
    leftHandler->bindCommand(InputHandler::DOWN, command);

    inputHandlers_[PLAYER_1].reset(leftHandler);
}

void GameState::setupPlayerTwoInputHandler() {
    b2Body* leftRaquet = gameWorld_.rightRaquet();
    b2Vec2 upVelocity(0.0f, RAQUET_BASE_SPEED);
    b2Vec2 downVelocity(0.0f, -RAQUET_BASE_SPEED);

    RaquetInputHandler* rightHandler = new RaquetInputHandler(leftRaquet);
    rightHandler->bindKey(sf::Keyboard::Up, InputHandler::UP);
    rightHandler->bindKey(sf::Keyboard::Down, InputHandler::DOWN);

    Command* command = new MoveRaquetCommand(leftRaquet, upVelocity);
    rightHandler->bindCommand(InputHandler::UP, command);
    command = new MoveRaquetCommand(leftRaquet, downVelocity);
    rightHandler->bindCommand(InputHandler::DOWN, command);

    inputHandlers_[PLAYER_2].reset(rightHandler);
}

void GameState::exit() {
}

void GameState::handleInput(const sf::Event& event) {
    if (event.type == sf::Event::KeyReleased) {
        if (event.key.code == sf::Keyboard::R) {
            create();
        } else if (event.key.code == sf::Keyboard::P) {
            gameWorld_.toggleRunning();
        }
    } else {
        DefaultState::handleInput(event);
    }
}

void GameState::update() {
    for (auto& handler : inputHandlers_) {
        Command* command = handler->handleInput();
        command->execute();
    }

    gameWorld_.update();
}

void GameState::render(sf::RenderTarget& renderTarget) {
#ifndef NDEBUG
    gameWorld_.drawDebugData();
#endif /* ifndef NDEBUG  */
}

void GameState::leftScored(GameWorld& gameWorld) {
    gameWorld.resetBall();
}

void GameState::rightScored(GameWorld& gameWorld) {
    gameWorld.resetBall();
}

} /* namespace pong */
<|endoftext|>


<commit_before>#include <iostream>
#include <random>
#include <chrono>
#include <map>
#include <string>
#include <json/json.hpp>

class Civilization {
  // I think this is the first time I've ever used friend without feeling bad
  friend std::ostream& operator<<(std::ostream&, const Civilization&);

  typedef std::normal_distribution<double> normal;
  typedef std::gamma_distribution<double> gamma;
  typedef std::uniform_real_distribution<double> uniform;
  typedef std::string string;
  typedef nlohmann::json json;
public:
  Civilization(time_t seed=std::chrono::system_clock::now().time_since_epoch().count()) :
    unitrand_(0.0, 1.0) {

    std::cout << "Using seed " << seed << std::endl;
    engine_.seed(seed);

    // burn card
    engine_.discard(1);

    GenCiv();
  }

  void GenCiv() {
    GenBasics();
    GenCriticalThinking();
    GenSpeech();
    GenGovernment();
    GenRelations();
    GenAppearance();

  }

  void GenBasics() {
    // god this is actually unbelievably fun
    normal intelligence_gen(100, 30);
    normal friendliness_gen(100, 80);
    normal emotionality_gen(100, 80);
    normal tribalism_gen(100,25);
    gamma age_gen(2, 8200);

    // no negative intelligence (despite some people I know)
    intelligence_ = Clamp(intelligence_gen(engine_), 0);
    friendliness_ = friendliness_gen(engine_);
    emotionality_ = emotionality_gen(engine_);
    tribalism_ = tribalism_gen(engine_);
    age_ = age_gen(engine_) + 2000;
  }

  void GenCriticalThinking() {
    if (intelligence_ > 70 || rand() < .05) {
      specifics_["critical_thinking"] = 1;
    }
    std::cout << engine_() << "\n" << engine_() << std::endl;
  }

  void GenSpeech() {

  }

  void GenGovernment() {

  }

  void GenRelations() {

  }

  void GenAppearance() {

  }

  double Clamp(double number, double min, double max=kLargeNumber) {
    if (number > max) {
      return max;
    } else if (number < min) {
      return min;
    } else {
      return number;
    }
  }

  double Rand() {
    return unitrand_(engine_);
  }

private:
  std::mt19937 engine_;
  uniform unitrand_;

  constexpr const static double kLargeNumber = 999999999999999;

  double intelligence_;
  double friendliness_;
  double emotionality_;
  double tribalism_;
  double age_;

  json specifics_;
};

std::ostream& operator<<(std::ostream &strm, const Civilization &civ) {
  return strm << "Civilization"
              << "\nintelligence: " << civ.intelligence_
              << "\nfriendliness: " << civ.friendliness_
              << "\nemotionality: " << civ.emotionality_
              << "\ntribalism:    " << civ.tribalism_
              << "\nage:          " << civ.age_ << "\n";
}

int main() {
  for (size_t i = 0; i < 10; ++i) {
    std::cout << Civilization() << std::endl;
  }

}
<commit_msg>Doesn't work yet hisssss<commit_after>#include <iostream>
#include <random>
#include <chrono>
#include <list>
#include <map>
#include <string>
#include <json/json.hpp>
#include <limits>
//#include <functional>

class CivAttribute {
protected:
  typedef std::string string;
  typedef nlohmann::json json;
  template <class T>
  using list = std::list<T>;
  template <class T, class V>
  using map = std::map<T, V>;

  using AttributeMap = map<string, CivAttribute>;
public:
  CivAttribute() {}

  virtual string GetName();

  virtual double OccurrenceProbability(AttributeMap current_tags) { return 0; }
  virtual bool DependenciesSatisfied(AttributeMap potential_tags) { return true; }
  virtual bool MutexesSatisfied(AttributeMap current_tags) { return true; }

  virtual list<string> GetParents() { return list<string>(); }
  virtual list<string> GetChildren() { return list<string>(); }
  virtual list<string> GetMutexes() { return list<string>(); }

  bool ContainsAll(AttributeMap att_map, list<string> attributes) {
    for (string att : attributes) {
      if (att_map.find(att) == att_map.end()) {
        return false;
      }
    }
    return true;
  }

  bool ContainsAny(AttributeMap att_map, list<string> attributes) {
    for (string att : attributes) {
      if (att_map.find(att) == att_map.end()) {
        return true;
      }
    }
    return false;
  }
};

class Eat : public CivAttribute {
public:

  Eat() {}

  string GetName() override { return "eat"; }

  double OccurrenceProbability(AttributeMap current_tags) override {
    return .5;
  }

  bool DependenciesSatisfied(AttributeMap potential_tags) override {
    return ContainsAll(potential_tags, GetParents());
  }

  bool MutexesSatisfied(AttributeMap current_tags) override {
    return !ContainsAny(current_tags, GetMutexes());
  }

  list<string> GetMutexes() override {
    return list<string>();
  }

  list<string> GetParents() override {
    return parents_;
  }

  list<string> GetChildren() override {
    return children_;
  }

  list<string> parents_ = {};
  list<string> children_ = {"choke", "fork"};
};

class Drink : public CivAttribute {
public:

  Drink() {}

  string GetName() override { return "drink"; }

  double OccurrenceProbability(AttributeMap current_tags) override {
    return .5;
  }

  bool DependenciesSatisfied(AttributeMap potential_tags) override {
    return ContainsAll(potential_tags, GetParents());
  }

  bool MutexesSatisfied(AttributeMap current_tags) override {
    return !ContainsAny(current_tags, GetMutexes());
  }

  list<string> GetMutexes() override {
    return list<string>();
  }

  list<string> GetParents() override {
    return parents_;
  }

  list<string> GetChildren() override {
    return children_;
  }

  list<string> parents_ = {};
  list<string> children_ = {"choke"};
};

class Choke : public CivAttribute {
public:

  Choke() {}

  string GetName() override { return "choke"; }

  double OccurrenceProbability(AttributeMap current_tags) override {
    return .5;
  }

  bool DependenciesSatisfied(AttributeMap potential_tags) override {
    return ContainsAll(potential_tags, GetParents());
  }

  bool MutexesSatisfied(AttributeMap current_tags) override {
    return !ContainsAny(current_tags, GetMutexes());
  }

  list<string> GetMutexes() override {
    return list<string>();
  }

  list<string> GetParents() override {
    return parents_;
  }

  list<string> GetChildren() override {
    return children_;
  }

  list<string> parents_ = {"eat", "drink"};
  list<string> children_ = {};
};

class Fork : public CivAttribute {
public:

  Fork() {};

  string GetName() override { return "fork"; }

  double OccurrenceProbability(AttributeMap current_tags) override {
    return .5;
  }

  bool DependenciesSatisfied(AttributeMap potential_tags) override {
    return ContainsAll(potential_tags, GetParents());
  }

  bool MutexesSatisfied(AttributeMap current_tags) override {
    return !ContainsAny(current_tags, GetMutexes());
  }

  list<string> GetMutexes() override {
    return list<string>();
  }

  list<string> GetParents() override {
    return parents_;
  }

  list<string> GetChildren() override {
    return children_;
  }

  list<string> parents_ = {"eat"};
  list<string> children_ = {};
};

class Civilization {
  // I think this is the first time I've ever used friend without feeling bad
  friend std::ostream& operator<<(std::ostream&, const Civilization&);

  typedef std::normal_distribution<double> normal;
  typedef std::gamma_distribution<double> gamma;
  typedef std::uniform_real_distribution<double> uniform_real;
  typedef std::uniform_int_distribution<int> uniform_int;
  typedef std::string string;
  typedef nlohmann::json json;
public:
  Civilization(time_t seed=std::chrono::system_clock::now().time_since_epoch().count()) :
    unitrand_(0.0, 1.0) {

    std::cout << "Using seed " << seed << std::endl;
    engine_.seed(seed);

    // burn card
    engine_.discard(1);

    GenCiv();
  }

  void GenCiv() {
    GenBasics();
    GenCriticalThinking();

  }

  void GenBasics() {
    // god this is actually unbelievably fun
    normal intelligence_gen(100, 30);
    normal friendliness_gen(100, 80);
    normal emotionality_gen(100, 80);
    normal tribalism_gen(100,25);
    normal disgust_gen(100, 25);
    gamma age_gen(2, 8200);

    // no negative intelligence (despite some people I know)
    intelligence_ = Clamp(intelligence_gen(engine_), 0);
    friendliness_ = friendliness_gen(engine_);
    emotionality_ = emotionality_gen(engine_);
    tribalism_ = tribalism_gen(engine_);
    disgust_ = disgust_gen(engine_);
    age_ = age_gen(engine_) + 2000;
  }

  void GenCriticalThinking() {
    if (intelligence_ > 70 || rand() < .05) {
      specifics_["critical_thinking"] = 1;

    }

    potential_attributes_["eat"] = Eat();
    potential_attributes_["drink"] = Drink();
    potential_attributes_["choke"] = Choke();
    potential_attributes_["fork"] = Fork();

    //while (!potential_attributes_.empty()) {
    //   int idx = RandInt(0, potential_attributes_.size());
    //}

    for (int i = 0; i < 100; ++i) {
      std::cout << RandInt(0, 10) << std::endl;
    }

    std::cout << engine_() << "\n" << engine_() << std::endl;
  }

  double Clamp(double number, double min, double max=kLargeNumber) {
    if (number > max) {
      return max;
    } else if (number < min) {
      return min;
    } else {
      return number;
    }
  }

  double Rand() {
    return unitrand_(engine_);
  }

  double RandInt(int low, int high) {
    return uniform_int(low, high-1)(engine_);
  }

private:
  std::mt19937 engine_;
  uniform_real unitrand_;

  constexpr const static double kLargeNumber = 999999999999999;

  double intelligence_;
  double friendliness_;
  double emotionality_;
  double tribalism_;
  double disgust_;
  double age_;

  json specifics_;

  std::map<string, CivAttribute> current_attributes_;
  std::map<string, CivAttribute> potential_attributes_;
};

std::ostream& operator<<(std::ostream &strm, const Civilization &civ) {
  return strm << "Civilization"
              << "\nintelligence: " << civ.intelligence_
              << "\nfriendliness: " << civ.friendliness_
              << "\nemotionality: " << civ.emotionality_
              << "\ntribalism:    " << civ.tribalism_
              << "\nage:          " << civ.age_ << "\n";
}

int main() {
  for (size_t i = 0; i < 10; ++i) {
    std::cout << Civilization() << std::endl;
  }

}
<|endoftext|>


<commit_before>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2016 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

/**
 * @file
 * @brief Implementation of the ADF variants.
 */

#include <xerus/algorithms/xals.h>

#include <xerus/indexedTensorMoveable.h>
#include <xerus/misc/basicArraySupport.h>

#ifdef _OPENMP
	#include <omp.h>
#endif

namespace xerus {

     class InternalSolver {
        const size_t d;

         std::vector<Tensor> leftStack;
         std::vector<Tensor> rightStack;

        TTTensor& x;
        const TTOperator& A;
        const TTTensor& b;

     public:
         InternalSolver(TTTensor& _x, const TTOperator& _A, const TTTensor& _b) : d(_x.degree()), x(_x), A(_A), b(_b) {

         }

         void solve() {

         }
     };

        void xals(TTTensor& _x, const TTOperator& _A, const TTTensor& _b)  {
            InternalSolver solver(_x, _A, _b);
            return solver.solve();
        }
}

<commit_msg>Further work on xALS<commit_after>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2016 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

/**
 * @file
 * @brief Implementation of the ADF variants.
 */

#include <xerus/algorithms/xals.h>
#include <xerus/basic.h>
#include <xerus/misc/internal.h>

#include <xerus/indexedTensorMoveable.h>
#include <xerus/misc/basicArraySupport.h>

#ifdef _OPENMP
	#include <omp.h>
#endif

namespace xerus {

     class InternalSolver {
        const size_t d;

         std::vector<Tensor> leftStack;
         std::vector<Tensor> rightStack;

         std::vector<Tensor> leftBStack;
         std::vector<Tensor> rightBStack;

        TTTensor& x;
        const TTOperator& A;
        const TTTensor& b;

        Tensor leftStackA,rightStackA;
        Tensor leftBStackB,rightBStackB;

     public:
         InternalSolver(TTTensor& _x, const TTOperator& _A, const TTTensor& _b) : d(_x.degree()),leftStack(d), rightStack(d), x(_x), A(_A), b(_b) {

         }

         void calc_left_stack(const size_t _position) {
             const Tensor& xi = x.get_component(_position);

             if(_position == 0) {
                 Tensor tmp;
                 Tensor A0 = A.get_component(_position);
                 A0.reinterpret_dimensions({A0.dimensions[1], A0.dimensions[2], A0.dimensions[3]});
                 contract(tmp, A0, true, xi, false, 1);
                 contract(leftStack[_position], A0, true, xi, false, 1);
             } else {
                 contract(leftStack[_position], leftStack[_position-1], x.component(_position), 1);
             }
         }

         void calc_right_stack(const size_t _position) {

         }

         double calc_residual_norm() {
             Index i,j;
             Tensor tmp;
             tmp(i&0) = A(i/2, j/2)*x(j&0);
             return frob_norm(tmp);
         }

         void solve() {
             const double solutionsNorm = frob_norm(b);
             std::vector<double> residuals(10, 1000.0);
			const size_t maxIterations = 1000;

			for(size_t iteration = 0; maxIterations == 0 || iteration < maxIterations; ++iteration) {
				x.move_core(0, true);

				// Rebuild right stack
				for(size_t corePosition = d-1; corePosition > 0; --corePosition) {
					calc_right_stack(corePosition);
				}

                residuals.push_back(calc_residual_norm()/solutionsNorm);
                if(residuals.back()/residuals[residuals.size()-10] > 0.99) {
                    LOG(ALS, "Residual decrease from " << std::scientific << residuals[10] << " to " << std::scientific << residuals.back() << " in " << residuals.size()-10 << " iterations.");
                    return; // We are done!
                }

				// Sweep Right -> Left
				for(size_t corePosition = 0; corePosition < x.degree(); ++corePosition) {
                    // Actual Work to do
					Tensor op, rhs;
                    if(corePosition == 0) {
                        leftStackA =  A.get_component(corePosition);
                        leftStackA.reinterpret_dimensions({leftStackA.dimensions[1], leftStackA.dimensions[2], leftStackA.dimensions[3]});

                        leftBStackB =  B.get_component(corePosition);
                        leftBStackB.reinterpret_dimensions({leftBStackB.dimensions[1], leftBStackB.dimensions[2]});
                    } else {
                        contract(leftStackA, leftStack[corePosition-1],  A.get_component(corePosition), 1);
                        contract(leftBStackB, leftBStack[corePosition-1],  b.get_component(corePosition), 1);
                    }
                    contract(op, leftStackA, rightStack[corePosition+1], 1);
                    contract(rhs, leftBStackB, rightBStack[corePosition+1], 1);

                    solve_least_squares(x.component(corePosition), op, rhs, 0);

					// If we have not yet reached the end of the sweep we need to take care of the core and update our stacks
					if(corePosition+1 < d) {
						x.move_core(corePosition+1, true);
						calc_left_stack(corePosition);
					}
				}

				// Sweep Right -> Left
				for(size_t corePosition = d-1; corePosition > 0; --corePosition) {
                    //Actual Work to do

					// If we have not yet reached the end of the sweep we need to take care of the core and update our stacks
					if(corePosition > 0) {
						x.move_core(corePosition-1, true);
						calc_right_stack(corePosition);
					}
				}

			}
         }

     };

        void xals(TTTensor& _x, const TTOperator& _A, const TTTensor& _b)  {
            InternalSolver solver(_x, _A, _b);
            return solver.solve();
        }
}

<|endoftext|>


<commit_before>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2016 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

/**
 * @file
 * @brief Implementation of the ADF variants.
 */

#include <xerus/algorithms/xals.h>
#include <xerus/basic.h>
#include <xerus/misc/internal.h>

#include <xerus/indexedTensorMoveable.h>
#include <xerus/misc/basicArraySupport.h>

#ifdef _OPENMP
	#include <omp.h>
#endif

namespace xerus {

     class InternalSolver {
        const size_t d;

         std::vector<Tensor> leftStack;
         std::vector<Tensor> rightStack;

         std::vector<Tensor> leftBStack;
         std::vector<Tensor> rightBStack;

        TTTensor& x;
        const TTOperator& A;
        const TTTensor& b;

        Tensor leftStackA,rightStackA;
        Tensor leftBStackB,rightBStackB;

     public:
         InternalSolver(TTTensor& _x, const TTOperator& _A, const TTTensor& _b) : d(_x.degree()),leftStack(d), rightStack(d), x(_x), A(_A), b(_b) {

         }

         void calc_left_stack(const size_t _position) {
             const Tensor& xi = x.get_component(_position);

             if(_position == 0) {
                 Tensor tmp;
                 Tensor A0 = A.get_component(_position);
                 A0.reinterpret_dimensions({A0.dimensions[1], A0.dimensions[2], A0.dimensions[3]});
                 contract(tmp, A0, true, xi, false, 1);
                 contract(leftStack[_position], A0, true, xi, false, 1);
             } else {
                 contract(leftStack[_position], leftStack[_position-1], x.component(_position), 1);
             }
         }

         void calc_right_stack(const size_t _position) {

         }

         double calc_residual_norm() {
             Index i,j;
             Tensor tmp;
             tmp(i&0) = A(i/2, j/2)*x(j&0);
             return frob_norm(tmp);
         }

         void solve() {
             const double solutionsNorm = frob_norm(b);
             std::vector<double> residuals(10, 1000.0);
			const size_t maxIterations = 1000;

			for(size_t iteration = 0; maxIterations == 0 || iteration < maxIterations; ++iteration) {
				x.move_core(0, true);

				// Rebuild right stack
				for(size_t corePosition = d-1; corePosition > 0; --corePosition) {
					calc_right_stack(corePosition);
				}

                residuals.push_back(calc_residual_norm()/solutionsNorm);
                if(residuals.back()/residuals[residuals.size()-10] > 0.99) {
                    LOG(ALS, "Residual decrease from " << std::scientific << residuals[10] << " to " << std::scientific << residuals.back() << " in " << residuals.size()-10 << " iterations.");
                    return; // We are done!
                }

				// Sweep Right -> Left
				for(size_t corePosition = 0; corePosition < x.degree(); ++corePosition) {
                    // Actual Work to do
					Tensor op, rhs;
                    if(corePosition == 0) {
                        leftStackA =  A.get_component(corePosition);
                        leftStackA.reinterpret_dimensions({leftStackA.dimensions[1], leftStackA.dimensions[2], leftStackA.dimensions[3]});

                        leftBStackB =  B.get_component(corePosition);
                        leftBStackB.reinterpret_dimensions({leftBStackB.dimensions[1], leftBStackB.dimensions[2]});
                    } else {
                        contract(leftStackA, leftStack[corePosition-1],  A.get_component(corePosition), 1);
                        contract(leftBStackB, leftBStack[corePosition-1],  b.get_component(corePosition), 1);
                    }
                    contract(op, leftStackA, rightStack[corePosition+1], 1);
                    contract(rhs, leftBStackB, rightBStack[corePosition+1], 1);

                    solve_least_squares(x.component(corePosition), op, rhs, 0);

					// If we have not yet reached the end of the sweep we need to take care of the core and update our stacks
					if(corePosition+1 < d) {
						x.move_core(corePosition+1, true);
						calc_left_stack(corePosition);
					}
				}

				// Sweep Right -> Left
				for(size_t corePosition = d-1; corePosition > 0; --corePosition) {
                    //Actual Work to do

					// If we have not yet reached the end of the sweep we need to take care of the core and update our stacks
					if(corePosition > 0) {
						x.move_core(corePosition-1, true);
						calc_right_stack(corePosition);
					}
				}

			}
         }

     };

        void xals(TTTensor& _x, const TTOperator& _A, const TTTensor& _b)  {
            InternalSolver solver(_x, _A, _b);
            return solver.solve();
        }
}

<commit_msg>Fixed typo<commit_after>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2016 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

/**
 * @file
 * @brief Implementation of the ADF variants.
 */

#include <xerus/algorithms/xals.h>
#include <xerus/basic.h>
#include <xerus/misc/internal.h>

#include <xerus/indexedTensorMoveable.h>
#include <xerus/misc/basicArraySupport.h>

#ifdef _OPENMP
	#include <omp.h>
#endif

namespace xerus {

     class InternalSolver {
        const size_t d;

         std::vector<Tensor> leftStack;
         std::vector<Tensor> rightStack;

         std::vector<Tensor> leftBStack;
         std::vector<Tensor> rightBStack;

        TTTensor& x;
        const TTOperator& A;
        const TTTensor& b;

        Tensor leftStackA,rightStackA;
        Tensor leftBStackB,rightBStackB;

     public:
         InternalSolver(TTTensor& _x, const TTOperator& _A, const TTTensor& _b) : d(_x.degree()),leftStack(d), rightStack(d), x(_x), A(_A), b(_b) {

         }

         void calc_left_stack(const size_t _position) {
             const Tensor& xi = x.get_component(_position);

             if(_position == 0) {
                 Tensor tmp;
                 Tensor A0 = A.get_component(_position);
                 A0.reinterpret_dimensions({A0.dimensions[1], A0.dimensions[2], A0.dimensions[3]});
                 contract(tmp, A0, true, xi, false, 1);
                 contract(leftStack[_position], A0, true, xi, false, 1);
             } else {
                 contract(leftStack[_position], leftStack[_position-1], x.component(_position), 1);
             }
         }

         void calc_right_stack(const size_t _position) {

         }

         double calc_residual_norm() {
             Index i,j;
             Tensor tmp;
             tmp(i&0) = A(i/2, j/2)*x(j&0);
             return frob_norm(tmp);
         }

         void solve() {
             const double solutionsNorm = frob_norm(b);
             std::vector<double> residuals(10, 1000.0);
			const size_t maxIterations = 1000;

			for(size_t iteration = 0; maxIterations == 0 || iteration < maxIterations; ++iteration) {
				x.move_core(0, true);

				// Rebuild right stack
				for(size_t corePosition = d-1; corePosition > 0; --corePosition) {
					calc_right_stack(corePosition);
				}

                residuals.push_back(calc_residual_norm()/solutionsNorm);
                if(residuals.back()/residuals[residuals.size()-10] > 0.99) {
                    LOG(ALS, "Residual decrease from " << std::scientific << residuals[10] << " to " << std::scientific << residuals.back() << " in " << residuals.size()-10 << " iterations.");
                    return; // We are done!
                }

				// Sweep Right -> Left
				for(size_t corePosition = 0; corePosition < x.degree(); ++corePosition) {
                    // Actual Work to do
					Tensor op, rhs;
                    if(corePosition == 0) {
                        leftStackA =  A.get_component(corePosition);
                        leftStackA.reinterpret_dimensions({leftStackA.dimensions[1], leftStackA.dimensions[2], leftStackA.dimensions[3]});

                        leftBStackB =  b.get_component(corePosition);
                        leftBStackB.reinterpret_dimensions({leftBStackB.dimensions[1], leftBStackB.dimensions[2]});
                    } else {
                        contract(leftStackA, leftStack[corePosition-1],  A.get_component(corePosition), 1);
                        contract(leftBStackB, leftBStack[corePosition-1],  b.get_component(corePosition), 1);
                    }
                    contract(op, leftStackA, rightStack[corePosition+1], 1);
                    contract(rhs, leftBStackB, rightBStack[corePosition+1], 1);

                    solve_least_squares(x.component(corePosition), op, rhs, 0);

					// If we have not yet reached the end of the sweep we need to take care of the core and update our stacks
					if(corePosition+1 < d) {
						x.move_core(corePosition+1, true);
						calc_left_stack(corePosition);
					}
				}

				// Sweep Right -> Left
				for(size_t corePosition = d-1; corePosition > 0; --corePosition) {
                    //Actual Work to do

					// If we have not yet reached the end of the sweep we need to take care of the core and update our stacks
					if(corePosition > 0) {
						x.move_core(corePosition-1, true);
						calc_right_stack(corePosition);
					}
				}

			}
         }

     };

        void xals(TTTensor& _x, const TTOperator& _A, const TTTensor& _b)  {
            InternalSolver solver(_x, _A, _b);
            return solver.solve();
        }
}

<|endoftext|>


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

#ifdef CS_TARGETPLATFORM_RPI

#include <CSBackend/Platform/RPi/Core/Base/DispmanWindow.h>
#include <CSBackend/Platform/RPi/Core/Base/SystemInfoFactory.h>

#include <ChilliSource/Core/Base/StandardMacros.h>
#include <ChilliSource/Core/Base/AppConfig.h>
#include <ChilliSource/Core/Base/Application.h>
#include <ChilliSource/Core/Base/LifecycleManager.h>
#include <ChilliSource/Core/Base/SystemInfo.h>
#include <ChilliSource/Core/Container/VectorUtils.h>

namespace CSBackend
{
	namespace RPi
	{
		//----------------------------------------------------------------------------------
		void DispmanWindow::Run() noexcept
		{
			//The display setup we use mimics Minecraft on the Raspberry Pi. Essentially we use a dispman display
			//to take advantage of hardware acceleration but we layer that on top of an X window which we use to listen
			//for events and to allow the user to control the size of the dispman display.

			//Create an XWindow which will act as a backing to our main display
			m_xdisplay = XOpenDisplay(NULL);
			if(m_xdisplay == nullptr)
			{
				printf("[ChilliSource] Failed to create X11 display. Exiting");
				return;
			}

			m_xwindow = XCreateSimpleWindow(m_xdisplay, XDefaultRootWindow(m_xdisplay), 0, 0, 200, 200, 0, 0, 0);
			XMapWindow(m_xdisplay, m_xwindow);
			XFlush(m_xdisplay);

			// Start interfacing with Raspberry Pi.
			if(!m_bcmInitialised)
			{
				bcm_host_init();
				m_bcmInitialised = true;
			}

			// TODO: Get attributes from Config
			static const EGLint attributeList[] =
			{
				EGL_RED_SIZE, 8,
				EGL_GREEN_SIZE, 8,
				EGL_BLUE_SIZE, 8,
				EGL_ALPHA_SIZE, 8,
				EGL_DEPTH_SIZE, 16,
				EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
				EGL_NONE
			};

			// Set up OpenGL context version
			static const EGLint contextAttributeList[] =
			{
				EGL_CONTEXT_CLIENT_VERSION, 2,
				EGL_NONE
			};

			// Get EGL display & initialize it
			m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
			eglInitialize(m_eglDisplay, NULL, NULL);

			// Set up config
			eglChooseConfig(m_eglDisplay, attributeList, &m_eglConfig, 1, &m_eglConfigNum);

			// Bind to OpenGL ES 2.0
			eglBindAPI(EGL_OPENGL_ES_API);

			// Create context
			m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttributeList);

			// Get display size (TODO: from config/X windowing system?)
			u32 displayWidth, displayHeight;
			graphics_get_display_size(0, &displayWidth, &displayHeight);
			m_windowSize.x = (s32)displayWidth;
			m_windowSize.y = (s32)displayHeight;

			// Set up blit rects.
			m_dstRect.x = 0;
			m_dstRect.y = 0;
			m_dstRect.width = m_windowSize.x;
			m_dstRect.height = m_windowSize.y;

			m_srcRect.x = 0;
			m_srcRect.y = 0;
			m_srcRect.width = m_windowSize.x << 16;
			m_srcRect.height = m_windowSize.y << 16;

			// Set up dispmanx
			m_displayManagerDisplay = vc_dispmanx_display_open(0);
			m_displayManagerUpdate = vc_dispmanx_update_start(0);
			m_displayManagerElement = vc_dispmanx_element_add(m_displayManagerUpdate, m_displayManagerDisplay, 0, &m_dstRect, 0, &m_srcRect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0);

			// Set up native window. TODO: Attach to X? Size to X Window?
			m_nativeWindow.element = m_displayManagerElement;
			m_nativeWindow.width = m_windowSize.x;
			m_nativeWindow.height = m_windowSize.y;

			// Instruct VC chip to use this display manager to sync
			vc_dispmanx_update_submit_sync(m_displayManagerUpdate);

			// Set up EGL surface
			m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, &m_nativeWindow, NULL);

			// Connect context to surface
			eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);

			// MAIN LOOP BEGINS HERE
			// Set up LifecycleManager
			ChilliSource::ApplicationUPtr app = ChilliSource::ApplicationUPtr(CreateApplication(SystemInfoFactory::CreateSystemInfo()));
			m_lifecycleManager = ChilliSource::LifecycleManagerUPtr(new ChilliSource::LifecycleManager(app.get()));

			// Load appconfig
			auto appConfig = app->GetAppConfig();

			m_lifecycleManager->Resume();
			m_lifecycleManager->Foreground();

			m_isRunning = true;

			while(m_isRunning == true)
			{
				//TODO: Handle backgrounding/foregrounding on window focus
				// Get X Events

				//Update, render and then flip display buffer
				m_lifecycleManager->SystemUpdate();
				m_lifecycleManager->Render();
				eglSwapBuffers(m_eglDisplay, m_eglSurface);

				if(m_quitScheduled)
				{
					Quit();
				}
			}
		}

		//-----------------------------------------------------------------------------------
		std::vector<ChilliSource::Integer2> DispmanWindow::GetSupportedResolutions() const noexcept
		{
			//TODO: Find out if we can query the BCM or dispman for supported resolutions
			return std::vector<ChilliSource::Integer2> { m_windowSize };
		}

		//-----------------------------------------------------------------------------------
		void DispmanWindow::Quit() noexcept
		{
			m_lifecycleManager->Suspend();
			m_lifecycleManager.reset();

			m_isRunning = false;
		}

		//-----------------------------------------------------------------------------------
		DispmanWindow::~DispmanWindow()
		{
			if(m_bcmInitialised)
			{
				bcm_host_deinit();
			}

			if(m_xdisplay)
			{
				XDestroyWindow(m_xdisplay, m_xwindow);
				XCloseDisplay(m_xdisplay);
			}
		}
	}
}

#endif
<commit_msg>Adding events to X window that we need to listen to<commit_after>//
//  The MIT License (MIT)
//
//  Copyright (c) 2017 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#ifdef CS_TARGETPLATFORM_RPI

#include <CSBackend/Platform/RPi/Core/Base/DispmanWindow.h>
#include <CSBackend/Platform/RPi/Core/Base/SystemInfoFactory.h>

#include <ChilliSource/Core/Base/StandardMacros.h>
#include <ChilliSource/Core/Base/AppConfig.h>
#include <ChilliSource/Core/Base/Application.h>
#include <ChilliSource/Core/Base/LifecycleManager.h>
#include <ChilliSource/Core/Base/SystemInfo.h>
#include <ChilliSource/Core/Container/VectorUtils.h>

namespace CSBackend
{
	namespace RPi
	{
		//----------------------------------------------------------------------------------
		void DispmanWindow::Run() noexcept
		{
			//The display setup we use mimics Minecraft on the Raspberry Pi. Essentially we use a dispman display
			//to take advantage of hardware acceleration but we layer that on top of an X window which we use to listen
			//for events and to allow the user to control the size of the dispman display.

			//Create an XWindow which will act as a backing to our main display
			m_xdisplay = XOpenDisplay(NULL);
			if(m_xdisplay == nullptr)
			{
				printf("[ChilliSource] Failed to create X11 display. Exiting");
				return;
			}
			m_xwindow = XCreateSimpleWindow(m_xdisplay, XDefaultRootWindow(m_xdisplay), 0, 0, 200, 200, 0, 0, 0);
			XMapWindow(m_xdisplay, m_xwindow);
			//All the events we need to listen for
			XSelectInput(m_xdisplay, m_xwindow, PointerMotionMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | FocusChangeMask);
			XFlush(m_xdisplay);

			// Start interfacing with Raspberry Pi.
			if(!m_bcmInitialised)
			{
				bcm_host_init();
				m_bcmInitialised = true;
			}

			// TODO: Get attributes from Config
			static const EGLint attributeList[] =
			{
				EGL_RED_SIZE, 8,
				EGL_GREEN_SIZE, 8,
				EGL_BLUE_SIZE, 8,
				EGL_ALPHA_SIZE, 8,
				EGL_DEPTH_SIZE, 16,
				EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
				EGL_NONE
			};

			// Set up OpenGL context version
			static const EGLint contextAttributeList[] =
			{
				EGL_CONTEXT_CLIENT_VERSION, 2,
				EGL_NONE
			};

			// Get EGL display & initialize it
			m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
			eglInitialize(m_eglDisplay, NULL, NULL);

			// Set up config
			eglChooseConfig(m_eglDisplay, attributeList, &m_eglConfig, 1, &m_eglConfigNum);

			// Bind to OpenGL ES 2.0
			eglBindAPI(EGL_OPENGL_ES_API);

			// Create context
			m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttributeList);

			// Get display size (TODO: from config/X windowing system?)
			u32 displayWidth, displayHeight;
			graphics_get_display_size(0, &displayWidth, &displayHeight);
			m_windowSize.x = (s32)displayWidth;
			m_windowSize.y = (s32)displayHeight;

			// Set up blit rects.
			m_dstRect.x = 0;
			m_dstRect.y = 0;
			m_dstRect.width = m_windowSize.x;
			m_dstRect.height = m_windowSize.y;

			m_srcRect.x = 0;
			m_srcRect.y = 0;
			m_srcRect.width = m_windowSize.x << 16;
			m_srcRect.height = m_windowSize.y << 16;

			// Set up dispmanx
			m_displayManagerDisplay = vc_dispmanx_display_open(0);
			m_displayManagerUpdate = vc_dispmanx_update_start(0);
			m_displayManagerElement = vc_dispmanx_element_add(m_displayManagerUpdate, m_displayManagerDisplay, 0, &m_dstRect, 0, &m_srcRect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0);

			// Set up native window. TODO: Attach to X? Size to X Window?
			m_nativeWindow.element = m_displayManagerElement;
			m_nativeWindow.width = m_windowSize.x;
			m_nativeWindow.height = m_windowSize.y;

			// Instruct VC chip to use this display manager to sync
			vc_dispmanx_update_submit_sync(m_displayManagerUpdate);

			// Set up EGL surface
			m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, &m_nativeWindow, NULL);

			// Connect context to surface
			eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);

			// MAIN LOOP BEGINS HERE
			// Set up LifecycleManager
			ChilliSource::ApplicationUPtr app = ChilliSource::ApplicationUPtr(CreateApplication(SystemInfoFactory::CreateSystemInfo()));
			m_lifecycleManager = ChilliSource::LifecycleManagerUPtr(new ChilliSource::LifecycleManager(app.get()));

			// Load appconfig
			auto appConfig = app->GetAppConfig();

			m_lifecycleManager->Resume();
			m_lifecycleManager->Foreground();

			m_isRunning = true;

			while(m_isRunning == true)
			{
				//TODO: Handle backgrounding/foregrounding on window focus
				// Get X Events

				//Update, render and then flip display buffer
				m_lifecycleManager->SystemUpdate();
				m_lifecycleManager->Render();
				eglSwapBuffers(m_eglDisplay, m_eglSurface);

				if(m_quitScheduled)
				{
					Quit();
				}
			}
		}

		//-----------------------------------------------------------------------------------
		std::vector<ChilliSource::Integer2> DispmanWindow::GetSupportedResolutions() const noexcept
		{
			//TODO: Find out if we can query the BCM or dispman for supported resolutions
			return std::vector<ChilliSource::Integer2> { m_windowSize };
		}

		//-----------------------------------------------------------------------------------
		void DispmanWindow::Quit() noexcept
		{
			m_lifecycleManager->Suspend();
			m_lifecycleManager.reset();

			m_isRunning = false;
		}

		//-----------------------------------------------------------------------------------
		DispmanWindow::~DispmanWindow()
		{
			if(m_bcmInitialised)
			{
				bcm_host_deinit();
			}

			if(m_xdisplay)
			{
				XDestroyWindow(m_xdisplay, m_xwindow);
				XCloseDisplay(m_xdisplay);
			}
		}
	}
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Georgia Institute of Technology
 *
 * 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.
 */

/**
 * @file    test_reductions.cpp
 * @author  Patrick Flick <patrick.flick@gmail.com>
 * @brief   GTest Unit Tests for mxx reductions
 */

#include <mpi.h>
#include <gtest/gtest.h>

#include <mxx/comm.hpp>
#include <mxx/reduction.hpp>

// test internal details of custom ops

TEST(MxxImpl, CustomOp) {
    // test C++ functors (postive tests)
    {
        std::plus<int> x;
        mxx::custom_op<int> o(x);
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_SUM, o.get_op());
    }
    {
        std::multiplies<double> x;
        mxx::custom_op<double> o(x);
        EXPECT_EQ(MPI_DOUBLE, o.get_type());
        EXPECT_EQ(MPI_PROD, o.get_op());
    }
    {
        std::bit_or<char> x;
        mxx::custom_op<char> o(x);
        EXPECT_EQ(MPI_CHAR, o.get_type());
        EXPECT_EQ(MPI_BOR, o.get_op());
    }
    {
        std::bit_xor<long> x;
        mxx::custom_op<long> o(x);
        EXPECT_EQ(MPI_LONG, o.get_type());
        EXPECT_EQ(MPI_BXOR, o.get_op());
    }
    {
        std::bit_and<unsigned char> x;
        mxx::custom_op<unsigned char> o(x);
        EXPECT_EQ(MPI_UNSIGNED_CHAR, o.get_type());
        EXPECT_EQ(MPI_BAND, o.get_op());
    }
    {
        std::logical_or<unsigned int> x;
        mxx::custom_op<unsigned int> o(x);
        EXPECT_EQ(MPI_UNSIGNED, o.get_type());
        EXPECT_EQ(MPI_LOR, o.get_op());
    }
    {
        std::logical_and<unsigned short> x;
        mxx::custom_op<unsigned short> o(x);
        EXPECT_EQ(MPI_UNSIGNED_SHORT, o.get_type());
        EXPECT_EQ(MPI_LAND, o.get_op());
    }
    // test std::min and std::max
    {
        mxx::custom_op<float> o(static_cast<const float&(*)(const float&, const float&)>(&std::min<float>));
        EXPECT_EQ(MPI_FLOAT, o.get_type());
        EXPECT_EQ(MPI_MIN, o.get_op());
    }
    {
        mxx::custom_op<int> o(static_cast<const int&(*)(const int&, const int&)>(&std::max<int>));
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_MAX, o.get_op());
    }
    {
        mxx::max<int> x;
        mxx::custom_op<int> o(x);
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_MAX, o.get_op());
    }
    {
        mxx::min<int> x;
        mxx::custom_op<int> o(x);
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_MIN, o.get_op());
    }
}

template <typename T>
struct mymax {
    T operator()(const T x, T& y){
        if (x > y)
            return x;
        else
            return y;
    }
};

int mymin(int x, int y) {
    if (x < y)
        return x;
    else
        return y;
}

// scatter of size 1
TEST(MxxReduce, ReduceOne) {
    mxx::comm c = mxx::comm();

    // test min
    int x = -13*(c.size() - c.rank());
    int y = mxx::reduce(x, c.size()/2, mxx::min<int>(), c);
    if (c.rank() == c.size()/2) {
        ASSERT_EQ(-13*c.size(), y);
    } else {
        ASSERT_EQ(0, y);
    }
    // test sum
    int z = mxx::reduce(3, 0, std::plus<int>(), c);
    if (c.rank() == 0) {
        ASSERT_EQ(3*c.size(), z);
    } else {
        ASSERT_EQ(0, z);
    }
    // test lambda op
    int g = mxx::reduce(2, c.size()-1, [](int i, int j){return i+j;});
    if (c.rank() == c.size()-1) {
        ASSERT_EQ(2*c.size(), g);
    } else {
        ASSERT_EQ(0, g);
    }
    // test functor
    float m = mxx::reduce(1.3333f*c.rank(), 0, mymax<float>(), c);
    if (c.rank() == 0) {
        ASSERT_EQ(1.3333f*(c.size()-1), m);
    } else {
        ASSERT_EQ(0, m);
    }
    // test own function pointer
    int v = c.rank() + 1;
    int u = mxx::reduce(v, 0, mymin, c);
    if (c.rank() == 0) {
        ASSERT_EQ(1, u);
    } else {
        ASSERT_EQ(0, u);
    }
}

TEST(MxxReduce, ReduceVec) {
    mxx::comm c;
    int n = 13;
    std::vector<int> v(n);

    for (int i = 0; i < n; ++i) {
        v[i] = c.rank() + i;
    }

    int ranksum = (c.size() * (c.size()-1)) / 2;

    std::vector<int> w = mxx::reduce(v, c.size()/2, c);
    if (c.rank() == c.size()/2) {
        ASSERT_EQ(n, (int)w.size());
        for (int i = 0; i < n; ++i) {
            ASSERT_EQ(ranksum + i*c.size(), w[i]);
        }
    } else {
        ASSERT_EQ(0u, w.size());
    }
}

TEST(MxxReduce, AllReduceVec) {
    mxx::comm c;

    int n = 10; // numbers per rank

    std::vector<int> v(n);
    for (int i = 0; i < n; ++i) {
        v[i] = i;
    }

    std::vector<int> w = mxx::allreduce(v);
    ASSERT_EQ(n, (int)w.size());
    for (int i = 0; i < n; ++i) {
        ASSERT_EQ(c.size()*i, w[i]);
    }

    w = mxx::allreduce(v, [](int x, int y) { return x+y; }, c.split(c.rank() % 2));
    int mysize = c.size() / 2;
    if (c.size() % 2 == 1 && c.rank() % 2 == 0)
        ++mysize;
    ASSERT_EQ(mysize, c.split(c.rank() % 2).size());
    ASSERT_EQ(n, (int)w.size());
    for (int i = 0; i < n; ++i) {
        ASSERT_EQ(mysize*i, w[i]);
    }
}

TEST(MxxReduce, Scan) {
    mxx::comm c;

    int r = c.rank()*2;
    int g = mxx::scan(r);
    ASSERT_EQ(c.rank()*(c.rank()+1), g);
    int m = mxx::exscan(r, mxx::max<int>());
    if (r != 0) {
        ASSERT_EQ((c.rank()-1)*2, m);
    }
    int m2 = mxx::exscan(r, mxx::max<int>(), c.split(c.rank() % 3));
    if (c.rank() >= 3) {
        ASSERT_EQ((c.rank()-3)*2, m2);
    }
}

TEST(MxxReduce, GlobalReduce) {
    mxx::comm c;

    // test reduce with zero elements for some processes
    size_t n = 0;
    int presize = 0;
    if (c.rank() % 2 == 0) {
        n = (c.rank()/2+1);
        presize = n*(n-1)/2;
    }
    std::vector<long> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = presize + i + 1;
    }
    long totalsum = mxx::global_reduce(local, [](int x, int y){ return x+y; }, c);
    int nonzero_size = (c.size()+1)/2;
    int num_els = nonzero_size*(nonzero_size+1)/2;
    ASSERT_EQ(num_els*(num_els+1)/2, totalsum);
}

TEST(MxxReduce, GlobalScan) {
    mxx::comm c;
    // test reduce with zero elements for some processes
    size_t n = 0;
    int presize = 0;
    if (c.rank() % 2 == 0) {
        n = (c.rank()/2+1);
        presize = n*(n-1)/2;
    }
    std::vector<int> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = presize + i + 1;
    }
    // test inplace scan
    std::vector<int> local_cpy(local);
    mxx::global_scan_inplace(local_cpy.begin(), local_cpy.end(), c);
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]+1)/2, local_cpy[i]);
    }
    // test scan
    //std::vector<int> result(local.size());
    std::vector<int> result = mxx::global_scan(local, [](int x, int y) {return x+y;});
    ASSERT_EQ(local.size(), result.size());
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]+1)/2, result[i]);
    }
}

TEST(MxxReduce, GlobalExScan) {
    mxx::comm c;
    // test reduce with zero elements for some processes
    size_t n = 0;
    int presize = 0;
    if (c.rank() % 2 == 0) {
        n = (c.rank()/2+1);
        presize = n*(n-1)/2;
    }
    std::vector<int> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = presize + i + 1;
    }
    // test inplace exscan
    std::vector<int> local_cpy(local);
    mxx::global_exscan_inplace(local_cpy, std::plus<int>(), c);
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]-1)/2, local_cpy[i]);
    }
    // test exscan
    std::vector<int> result = mxx::global_exscan(local);
    ASSERT_EQ(local.size(), result.size());
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]-1)/2, result[i]);
    }
}

TEST(MxxReduce, MinMaxLoc) {
    mxx::comm c;

    std::pair<double, int> maxloc = mxx::max_element(3.1*c.rank(), c);
    ASSERT_EQ(c.size()-1, maxloc.second);
    ASSERT_EQ(3.1*(c.size()-1), maxloc.first);

    std::pair<int, int> minloc = mxx::min_element(c.rank()+13);
    ASSERT_EQ(13, minloc.first);
    ASSERT_EQ(0, minloc.second);
}

// TODO: test for simple all_of/some_of etc reductions
<commit_msg>Added a test that was failing before the fix in b55a0b6d033f90a75dec5132e380e8c05404d9e4.<commit_after>/*
 * Copyright 2015 Georgia Institute of Technology
 *
 * 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.
 */

/**
 * @file    test_reductions.cpp
 * @author  Patrick Flick <patrick.flick@gmail.com>
 * @brief   GTest Unit Tests for mxx reductions
 */

#include <mpi.h>
#include <gtest/gtest.h>

#include <mxx/comm.hpp>
#include <mxx/reduction.hpp>

// test internal details of custom ops

TEST(MxxImpl, CustomOp) {
    // test C++ functors (postive tests)
    {
        std::plus<int> x;
        mxx::custom_op<int> o(x);
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_SUM, o.get_op());
    }
    {
        std::multiplies<double> x;
        mxx::custom_op<double> o(x);
        EXPECT_EQ(MPI_DOUBLE, o.get_type());
        EXPECT_EQ(MPI_PROD, o.get_op());
    }
    {
        std::bit_or<char> x;
        mxx::custom_op<char> o(x);
        EXPECT_EQ(MPI_CHAR, o.get_type());
        EXPECT_EQ(MPI_BOR, o.get_op());
    }
    {
        std::bit_xor<long> x;
        mxx::custom_op<long> o(x);
        EXPECT_EQ(MPI_LONG, o.get_type());
        EXPECT_EQ(MPI_BXOR, o.get_op());
    }
    {
        std::bit_and<unsigned char> x;
        mxx::custom_op<unsigned char> o(x);
        EXPECT_EQ(MPI_UNSIGNED_CHAR, o.get_type());
        EXPECT_EQ(MPI_BAND, o.get_op());
    }
    {
        std::logical_or<unsigned int> x;
        mxx::custom_op<unsigned int> o(x);
        EXPECT_EQ(MPI_UNSIGNED, o.get_type());
        EXPECT_EQ(MPI_LOR, o.get_op());
    }
    {
        std::logical_and<unsigned short> x;
        mxx::custom_op<unsigned short> o(x);
        EXPECT_EQ(MPI_UNSIGNED_SHORT, o.get_type());
        EXPECT_EQ(MPI_LAND, o.get_op());
    }
    // test std::min and std::max
    {
        mxx::custom_op<float> o(static_cast<const float&(*)(const float&, const float&)>(&std::min<float>));
        EXPECT_EQ(MPI_FLOAT, o.get_type());
        EXPECT_EQ(MPI_MIN, o.get_op());
    }
    {
        mxx::custom_op<int> o(static_cast<const int&(*)(const int&, const int&)>(&std::max<int>));
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_MAX, o.get_op());
    }
    {
        mxx::max<int> x;
        mxx::custom_op<int> o(x);
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_MAX, o.get_op());
    }
    {
        mxx::min<int> x;
        mxx::custom_op<int> o(x);
        EXPECT_EQ(MPI_INT, o.get_type());
        EXPECT_EQ(MPI_MIN, o.get_op());
    }
}

template <typename T>
struct mymax {
    T operator()(const T x, T& y){
        if (x > y)
            return x;
        else
            return y;
    }
};

int mymin(int x, int y) {
    if (x < y)
        return x;
    else
        return y;
}

// scatter of size 1
TEST(MxxReduce, ReduceOne) {
    mxx::comm c = mxx::comm();

    // test min
    int x = -13*(c.size() - c.rank());
    int y = mxx::reduce(x, c.size()/2, mxx::min<int>(), c);
    if (c.rank() == c.size()/2) {
        ASSERT_EQ(-13*c.size(), y);
    } else {
        ASSERT_EQ(0, y);
    }
    // test sum
    int z = mxx::reduce(3, 0, std::plus<int>(), c);
    if (c.rank() == 0) {
        ASSERT_EQ(3*c.size(), z);
    } else {
        ASSERT_EQ(0, z);
    }
    // test lambda op
    int g = mxx::reduce(2, c.size()-1, [](int i, int j){return i+j;});
    if (c.rank() == c.size()-1) {
        ASSERT_EQ(2*c.size(), g);
    } else {
        ASSERT_EQ(0, g);
    }
    // test functor
    float m = mxx::reduce(1.3333f*c.rank(), 0, mymax<float>(), c);
    if (c.rank() == 0) {
        ASSERT_EQ(1.3333f*(c.size()-1), m);
    } else {
        ASSERT_EQ(0, m);
    }
    // test own function pointer
    int v = c.rank() + 1;
    int u = mxx::reduce(v, 0, mymin, c);
    if (c.rank() == 0) {
        ASSERT_EQ(1, u);
    } else {
        ASSERT_EQ(0, u);
    }
}

TEST(MxxReduce, ReduceVec) {
    mxx::comm c;
    int n = 13;
    std::vector<int> v(n);

    for (int i = 0; i < n; ++i) {
        v[i] = c.rank() + i;
    }

    int ranksum = (c.size() * (c.size()-1)) / 2;

    std::vector<int> w = mxx::reduce(v, c.size()/2, c);
    if (c.rank() == c.size()/2) {
        ASSERT_EQ(n, (int)w.size());
        for (int i = 0; i < n; ++i) {
            ASSERT_EQ(ranksum + i*c.size(), w[i]);
        }
    } else {
        ASSERT_EQ(0u, w.size());
    }
}

TEST(MxxReduce, AllReduceVec) {
    mxx::comm c;

    int n = 10; // numbers per rank

    std::vector<int> v(n);
    for (int i = 0; i < n; ++i) {
        v[i] = i;
    }

    std::vector<int> w = mxx::allreduce(v);
    ASSERT_EQ(n, (int)w.size());
    for (int i = 0; i < n; ++i) {
        ASSERT_EQ(c.size()*i, w[i]);
    }

    w = mxx::allreduce(v, [](int x, int y) { return x+y; }, c.split(c.rank() % 2));
    int mysize = c.size() / 2;
    if (c.size() % 2 == 1 && c.rank() % 2 == 0)
        ++mysize;
    ASSERT_EQ(mysize, c.split(c.rank() % 2).size());
    ASSERT_EQ(n, (int)w.size());
    for (int i = 0; i < n; ++i) {
        ASSERT_EQ(mysize*i, w[i]);
    }
}

TEST(MxxReduce, Scan) {
    mxx::comm c;

    int r = c.rank()*2;
    int g = mxx::scan(r);
    ASSERT_EQ(c.rank()*(c.rank()+1), g);
    int m = mxx::exscan(r, mxx::max<int>());
    if (r != 0) {
        ASSERT_EQ((c.rank()-1)*2, m);
    }
    int m2 = mxx::exscan(r, mxx::max<int>(), c.split(c.rank() % 3));
    if (c.rank() >= 3) {
        ASSERT_EQ((c.rank()-3)*2, m2);
    }
}

TEST(MxxReduce, GlobalReduce) {
    mxx::comm c;

    // test reduce with zero elements for some processes
    size_t n = 0;
    int presize = 0;
    if (c.rank() % 2 == 0) {
        n = (c.rank()/2+1);
        presize = n*(n-1)/2;
    }
    std::vector<long> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = presize + i + 1;
    }
    long totalsum = mxx::global_reduce(local, [](int x, int y){ return x+y; }, c);
    int nonzero_size = (c.size()+1)/2;
    int num_els = nonzero_size*(nonzero_size+1)/2;
    ASSERT_EQ(num_els*(num_els+1)/2, totalsum);
}

TEST(MxxReduce, GlobalScan) {
    mxx::comm c;
    // test scan with zero elements for some processes
    size_t n = 0;
    int presize = 0;
    if (c.rank() % 2 == 0) {
        n = (c.rank()/2+1);
        presize = n*(n-1)/2;
    }
    std::vector<int> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = presize + i + 1;
    }
    // test inplace scan
    std::vector<int> local_cpy(local);
    mxx::global_scan_inplace(local_cpy.begin(), local_cpy.end(), c);
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]+1)/2, local_cpy[i]);
    }
    // test scan
    //std::vector<int> result(local.size());
    std::vector<int> result = mxx::global_scan(local, [](int x, int y) {return x+y;});
    ASSERT_EQ(local.size(), result.size());
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]+1)/2, result[i]);
    }
}

TEST(MxxReduce, GlobalScanMin) {
    mxx::comm c;
    // test scan with min and an array of positive
    // elements sorted in ascending order
    size_t n = c.size();
    std::vector<int> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = (c.rank()*n)+i+1;
    }
    // test inplace scan
    std::vector<int> local_cpy(local);
    mxx::global_scan_inplace(local_cpy.begin(), local_cpy.end(), mxx::min<int>(), c);
    for (size_t i = 0; i < n; ++i) {
        // 1 is both the first as well as the minimum element
        ASSERT_EQ(1, local_cpy[i]);
    }
    // test scan
    std::vector<int> result = mxx::global_scan(local, mxx::min<int>(), c);
    ASSERT_EQ(local.size(), result.size());
    for (size_t i = 0; i < n; ++i) {
        // 1 is both the first as well as the minimum element
        ASSERT_EQ(1, result[i]);
    }
}

TEST(MxxReduce, GlobalExScan) {
    mxx::comm c;
    // test reduce with zero elements for some processes
    size_t n = 0;
    int presize = 0;
    if (c.rank() % 2 == 0) {
        n = (c.rank()/2+1);
        presize = n*(n-1)/2;
    }
    std::vector<int> local(n);
    for (size_t i = 0; i < n; ++i) {
        local[i] = presize + i + 1;
    }
    // test inplace exscan
    std::vector<int> local_cpy(local);
    mxx::global_exscan_inplace(local_cpy, std::plus<int>(), c);
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]-1)/2, local_cpy[i]);
    }
    // test exscan
    std::vector<int> result = mxx::global_exscan(local);
    ASSERT_EQ(local.size(), result.size());
    for (size_t i = 0; i < n; ++i) {
        ASSERT_EQ(local[i]*(local[i]-1)/2, result[i]);
    }
}

TEST(MxxReduce, MinMaxLoc) {
    mxx::comm c;

    std::pair<double, int> maxloc = mxx::max_element(3.1*c.rank(), c);
    ASSERT_EQ(c.size()-1, maxloc.second);
    ASSERT_EQ(3.1*(c.size()-1), maxloc.first);

    std::pair<int, int> minloc = mxx::min_element(c.rank()+13);
    ASSERT_EQ(13, minloc.first);
    ASSERT_EQ(0, minloc.second);
}

// TODO: test for simple all_of/some_of etc reductions
<|endoftext|>