<commit_before>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "Pipeline.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "DockerUtilities.h"
#include "EmdFormat.h"
#include "ModuleManager.h"
#include "Operator.h"
#include "PipelineExecutor.h"
#include "Utilities.h"

#include <QMetaEnum>

#include <pqApplicationCore.h>
#include <pqSettings.h>
#include <pqView.h>
#include <vtkSMViewProxy.h>
#include <vtkTrivialProducer.h>

namespace tomviz {

PipelineSettings::PipelineSettings()
{
  m_settings = pqApplicationCore::instance()->settings();
}

void PipelineSettings::setExecutionMode(Pipeline::ExecutionMode executor)
{
  auto metaEnum = QMetaEnum::fromType<Pipeline::ExecutionMode>();
  setExecutionMode(QString(metaEnum.valueToKey(executor)));
}

void PipelineSettings::setExecutionMode(const QString& executor)
{
  m_settings->setValue("pipeline/mode", executor);
}

Pipeline::ExecutionMode PipelineSettings::executionMode()
{
  if (!m_settings->contains("pipeline/mode")) {
    return Pipeline::ExecutionMode::Threaded;
  }
  auto metaEnum = QMetaEnum::fromType<Pipeline::ExecutionMode>();

  return static_cast<Pipeline::ExecutionMode>(metaEnum.keyToValue(
    m_settings->value("pipeline/mode").toString().toLatin1().data()));
}

QString PipelineSettings::dockerImage()
{
  return m_settings->value("pipeline/docker.image").toString();
}

bool PipelineSettings::dockerPull()
{
  return m_settings->value("pipeline/docker.pull", true).toBool();
}

bool PipelineSettings::dockerRemove()
{
  return m_settings->value("pipeline/docker.remove", true).toBool();
}

void PipelineSettings::setDockerImage(const QString& image)
{
  m_settings->setValue("pipeline/docker.image", image);
}

void PipelineSettings::setDockerPull(bool pull)
{
  m_settings->setValue("pipeline/docker.pull", pull);
}

void PipelineSettings::setDockerRemove(bool remove)
{
  m_settings->setValue("pipeline/docker.remove", remove);
}

Pipeline::Pipeline(DataSource* dataSource, QObject* parent) : QObject(parent)
{
  m_data = dataSource;
  m_data->setParent(this);

  addDataSource(dataSource);

  PipelineSettings settings;
  auto executor = settings.executionMode();
  setExecutionMode(executor);
}

Pipeline::~Pipeline() = default;

void Pipeline::execute()
{
  execute(m_data);
}

void Pipeline::startedEditingOp(Operator* op)
{
  ++m_editingOperators;
  op->setEditing();
}

void Pipeline::finishedEditingOp(Operator* op)
{
  if (op->isModified()) {
    op->resetState();
  } else {
    op->setComplete();
  }

  if (m_editingOperators > 0) {
    --m_editingOperators;
    if (m_editingOperators == 0 && !isRunning()) {
      execute(op->dataSource());
    }
  }
}

void Pipeline::execute(DataSource* ds, Operator* start)
{
  if (paused()) {
    return;
  }

  if (ds == nullptr) {
    ds = m_data;
  }

  if (beingEdited(ds)) {
    return;
  }

  Operator* firstModifiedOperator;
  if (!isModified(ds, &firstModifiedOperator)) {
    return;
  }

  m_operatorsDeleted = false;

  emit started();

  auto operators = ds->operators();
  if (operators.isEmpty()) {
    emit finished();
    return;
  }
  int startIndex = 0;
  // We currently only support running the last operator or the entire pipeline.
  if (start == nullptr) {
    start = firstModifiedOperator;
  }
  if (start == ds->operators().last() && start->isNew()) {
    // See if we have any canceled operators in the pipeline, if so we have to
    // re-run the anyway pipeline.
    bool haveCanceled = false;
    for (auto itr = operators.begin(); *itr != start; ++itr) {
      auto currentOp = *itr;
      if (currentOp->isCanceled()) {
        currentOp->resetState();
        haveCanceled = true;
        break;
      }
    }

    if (!haveCanceled) {
      startIndex = operators.indexOf(start);
      // Use transformed data source
      ds = transformedDataSource(ds);
    }
  }

  m_executor->execute(ds->dataObject(), operators, startIndex);
}

bool Pipeline::beingEdited(DataSource* ds) const
{
  // If any operators in the pipeline are in editing state,
  // don't execute the pipeline
  if (ds == nullptr) {
    return false;
  }
  auto operators = ds->operators();
  for (auto itr = operators.begin(); itr != operators.end(); ++itr) {
    auto currentOp = *itr;
    if (currentOp->isEditing()) {
      return true;
    }
    // Also check if the operators in a branch are being edited.
    if (beingEdited(currentOp->childDataSource())) {
      return true;
    }
  }
  return false;
}

bool Pipeline::isModified(DataSource* datasource, Operator** start) const
{
  // If the m_operatorsDeleted flag is tripped
  // (i.e. if one or more operator were deleted since the last execution)
  // we should execute the pipeline even if no operators are in a modified state
  if (m_operatorsDeleted) {
    return true;
  }
  // If no operators are in a modified state,
  // there is no need to execute the pipeline
  if (datasource == nullptr) {
    return false;
  }
  auto operators = datasource->operators();
  for (auto itr = operators.begin(); itr != operators.end(); ++itr) {
    auto currentOp = *itr;
    if (currentOp->isModified()) {
      *start = currentOp;
      return true;
    }
    // Also check if the operators in a branch are being edited.
    if (isModified(currentOp->childDataSource(), start)) {
      return true;
    }
  }
  return false;
}

void Pipeline::branchFinished(DataSource* start, vtkDataObject* newData)
{
  // We only add the transformed child data source if the last operator
  // doesn't already have an explicit child data source i.e.
  // hasChildDataSource is true.
  auto lastOp = start->operators().last();
  if (!lastOp->hasChildDataSource()) {
    DataSource* newChildDataSource = nullptr;
    if (lastOp->childDataSource() == nullptr) {
      newChildDataSource = new DataSource("Output");
      newChildDataSource->setPersistenceState(
        tomviz::DataSource::PersistenceState::Transient);
      newChildDataSource->setForkable(false);
      newChildDataSource->setParent(this);
      lastOp->setChildDataSource(newChildDataSource);
      auto rootDataSource = dataSource();
      // connect signal to flow units and spacing to child data source.
      connect(dataSource(), &DataSource::dataPropertiesChanged,
              [rootDataSource, newChildDataSource]() {
                // Only flow the properties if no user modifications have been
                // made.
                if (!newChildDataSource->unitsModified()) {
                  newChildDataSource->setUnits(rootDataSource->getUnits(),
                                               false);
                  double spacing[3];
                  rootDataSource->getSpacing(spacing);
                  newChildDataSource->setSpacing(spacing, false);
                }
              });
    }

    lastOp->childDataSource()->setData(newData);
    lastOp->childDataSource()->dataModified();

    if (newChildDataSource != nullptr) {
      emit lastOp->newChildDataSource(newChildDataSource);
      // Move modules from root data source.
      bool oldMoveObjectsEnabled =
        ActiveObjects::instance().moveObjectsEnabled();
      ActiveObjects::instance().setMoveObjectsMode(false);
      auto view = ActiveObjects::instance().activeView();
      foreach (Module* module, ModuleManager::instance().findModules<Module*>(
                                 dataSource(), nullptr)) {
        // TODO: We should really copy the module properties as well.
        auto newModule = ModuleManager::instance().createAndAddModule(
          module->label(), newChildDataSource, view);
        // Copy over properties using the serialization code.
        newModule->deserialize(module->serialize());
        ModuleManager::instance().removeModule(module);
      }
      ActiveObjects::instance().setMoveObjectsMode(oldMoveObjectsEnabled);
    }
  }
}

void Pipeline::pause()
{
  m_paused = true;
}

bool Pipeline::paused() const
{
  return m_paused;
}

void Pipeline::resume(bool run)
{
  m_paused = false;
  if (run) {
    execute();
  }
}

void Pipeline::resume(DataSource* at)
{
  m_paused = false;
  execute(at);
}

void Pipeline::cancel(std::function<void()> canceled)
{
  m_executor->cancel(canceled);
}

bool Pipeline::isRunning()
{
  return m_executor->isRunning();
}

DataSource* Pipeline::findTransformedDataSource(DataSource* dataSource)
{
  auto op = findTransformedDataSourceOperator(dataSource);
  if (op != nullptr) {
    return op->childDataSource();
  }

  return nullptr;
}

Operator* Pipeline::findTransformedDataSourceOperator(DataSource* dataSource)
{
  if (dataSource == nullptr) {
    return nullptr;
  }

  auto operators = dataSource->operators();
  for (auto itr = operators.rbegin(); itr != operators.rend(); ++itr) {
    auto op = *itr;
    if (op->childDataSource() != nullptr) {
      auto child = op->childDataSource();
      // If the child has operators we need to go deeper
      if (!child->operators().isEmpty()) {
        return findTransformedDataSourceOperator(child);
      }

      return op;
    }
  }

  return nullptr;
}

void Pipeline::addDataSource(DataSource* dataSource)
{
  connect(dataSource, &DataSource::operatorAdded,
          [this](Operator* op) { execute(op->dataSource(), op); });
  // Wire up transformModified to execute pipeline
  connect(dataSource, &DataSource::operatorAdded, [this](Operator* op) {
    // Extract out source and execute all.
    connect(op, &Operator::transformModified, this, [this]() { execute(); });

    // Ensure that new child data source signals are correctly wired up.
    connect(op,
            static_cast<void (Operator::*)(DataSource*)>(
              &Operator::newChildDataSource),
            [this](DataSource* ds) { addDataSource(ds); });

    // We need to ensure we move add datasource to the end of the branch
    auto operators = op->dataSource()->operators();
    if (operators.size() > 1) {
      auto transformedDataSourceOp =
        findTransformedDataSourceOperator(op->dataSource());
      if (transformedDataSourceOp != nullptr) {
        auto transformedDataSource = transformedDataSourceOp->childDataSource();
        transformedDataSourceOp->setChildDataSource(nullptr);
        op->setChildDataSource(transformedDataSource);
        emit operatorAdded(op, transformedDataSource);
      } else {
        emit operatorAdded(op);
      }
    } else {
      emit operatorAdded(op);
    }
  });
  // Wire up operatorRemoved. TODO We need to check the branch of the
  // pipeline we are currently executing.
  connect(dataSource, &DataSource::operatorRemoved, [this](Operator* op) {
    // If an operator has been removed, there's a chance that none of the
    // remaining operators are in a modified state.
    // But the pipeline should still be executed to reflect changes
    if (!op->isNew()) {
      m_operatorsDeleted = true;
    }
    // Do we need to move the transformed data source, !hasChildDataSource as we
    // don't want to move "explicit" child data sources.
    if (!op->hasChildDataSource() && op->childDataSource() != nullptr) {
      auto transformedDataSource = op->childDataSource();
      auto operators = op->dataSource()->operators();
      // We have an operator to move it to.
      if (!operators.isEmpty()) {
        auto newOp = operators.last();
        op->setChildDataSource(nullptr);
        newOp->setChildDataSource(transformedDataSource);
        emit newOp->dataSourceMoved(transformedDataSource);
      }
      // Clean it up
      else {
        transformedDataSource->removeAllOperators();
        transformedDataSource->deleteLater();
      }
    }

    // If pipeline is running see if we can safely remove the operator
    if (isRunning()) {
      // If we can't safely cancel the execution then trigger the rerun of the
      // pipeline.
      if (!m_executor->cancel(op)) {
        execute(op->dataSource());
      }
    } else {
      // Trigger the pipeline to run
      execute(op->dataSource());
    }
  });
}

void Pipeline::addDefaultModules(DataSource* dataSource)
{
  // Note: In the future we can pull this out into a setting.
  QStringList defaultModules = { "Outline", "Orthogonal Slice" };
  bool oldMoveObjectsEnabled = ActiveObjects::instance().moveObjectsEnabled();
  ActiveObjects::instance().setMoveObjectsMode(false);
  auto view = ActiveObjects::instance().activeView();

  if (view == nullptr || !view->IsA("vtkSMRenderViewProxy")) {
    return;
  }

  Module* module = nullptr;
  foreach (QString name, defaultModules) {
    module =
      ModuleManager::instance().createAndAddModule(name, dataSource, view);
  }
  ActiveObjects::instance().setActiveModule(module);
  ActiveObjects::instance().setMoveObjectsMode(oldMoveObjectsEnabled);

  auto pqview = tomviz::convert<pqView*>(view);
  pqview->resetDisplay();
  pqview->render();
}

Pipeline::ImageFuture::ImageFuture(Operator* op, vtkImageData* imageData,
                                   PipelineWorker::Future* future,
                                   QObject* parent)
  : QObject(parent), m_operator(op), m_imageData(imageData), m_future(future)
{

  if (m_future != nullptr) {
    connect(m_future, &PipelineWorker::Future::finished, this,
            &Pipeline::ImageFuture::finished);
    connect(m_future, &PipelineWorker::Future::canceled, this,
            &Pipeline::ImageFuture::canceled);
  }
}

Pipeline::ImageFuture::~ImageFuture()
{
  if (m_future != nullptr) {
    m_future->deleteLater();
  }
}

Pipeline::ImageFuture* Pipeline::getCopyOfImagePriorTo(Operator* op)
{
  return m_executor->getCopyOfImagePriorTo(op);
}

DataSource* Pipeline::transformedDataSource(DataSource* ds)
{
  if (ds == nullptr) {
    ds = dataSource();
  }

  auto transformed = findTransformedDataSource(ds);
  if (transformed != nullptr) {
    return transformed;
  }

  // Default to dataSource at being of pipeline
  return ds;
}

void Pipeline::setExecutionMode(ExecutionMode executor)
{
  m_executionMode = executor;
  if (executor == ExecutionMode::Docker) {
    m_executor.reset(new DockerPipelineExecutor(this));
  } else {
    m_executor.reset(new ThreadPipelineExecutor(this));
  }
}

} // namespace tomviz
<commit_msg>Use Slice instead of OrthogonalSlice in default modules<commit_after>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "Pipeline.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "DockerUtilities.h"
#include "EmdFormat.h"
#include "ModuleManager.h"
#include "Operator.h"
#include "PipelineExecutor.h"
#include "Utilities.h"

#include <QMetaEnum>

#include <pqApplicationCore.h>
#include <pqSettings.h>
#include <pqView.h>
#include <vtkSMViewProxy.h>
#include <vtkTrivialProducer.h>

namespace tomviz {

PipelineSettings::PipelineSettings()
{
  m_settings = pqApplicationCore::instance()->settings();
}

void PipelineSettings::setExecutionMode(Pipeline::ExecutionMode executor)
{
  auto metaEnum = QMetaEnum::fromType<Pipeline::ExecutionMode>();
  setExecutionMode(QString(metaEnum.valueToKey(executor)));
}

void PipelineSettings::setExecutionMode(const QString& executor)
{
  m_settings->setValue("pipeline/mode", executor);
}

Pipeline::ExecutionMode PipelineSettings::executionMode()
{
  if (!m_settings->contains("pipeline/mode")) {
    return Pipeline::ExecutionMode::Threaded;
  }
  auto metaEnum = QMetaEnum::fromType<Pipeline::ExecutionMode>();

  return static_cast<Pipeline::ExecutionMode>(metaEnum.keyToValue(
    m_settings->value("pipeline/mode").toString().toLatin1().data()));
}

QString PipelineSettings::dockerImage()
{
  return m_settings->value("pipeline/docker.image").toString();
}

bool PipelineSettings::dockerPull()
{
  return m_settings->value("pipeline/docker.pull", true).toBool();
}

bool PipelineSettings::dockerRemove()
{
  return m_settings->value("pipeline/docker.remove", true).toBool();
}

void PipelineSettings::setDockerImage(const QString& image)
{
  m_settings->setValue("pipeline/docker.image", image);
}

void PipelineSettings::setDockerPull(bool pull)
{
  m_settings->setValue("pipeline/docker.pull", pull);
}

void PipelineSettings::setDockerRemove(bool remove)
{
  m_settings->setValue("pipeline/docker.remove", remove);
}

Pipeline::Pipeline(DataSource* dataSource, QObject* parent) : QObject(parent)
{
  m_data = dataSource;
  m_data->setParent(this);

  addDataSource(dataSource);

  PipelineSettings settings;
  auto executor = settings.executionMode();
  setExecutionMode(executor);
}

Pipeline::~Pipeline() = default;

void Pipeline::execute()
{
  execute(m_data);
}

void Pipeline::startedEditingOp(Operator* op)
{
  ++m_editingOperators;
  op->setEditing();
}

void Pipeline::finishedEditingOp(Operator* op)
{
  if (op->isModified()) {
    op->resetState();
  } else {
    op->setComplete();
  }

  if (m_editingOperators > 0) {
    --m_editingOperators;
    if (m_editingOperators == 0 && !isRunning()) {
      execute(op->dataSource());
    }
  }
}

void Pipeline::execute(DataSource* ds, Operator* start)
{
  if (paused()) {
    return;
  }

  if (ds == nullptr) {
    ds = m_data;
  }

  if (beingEdited(ds)) {
    return;
  }

  Operator* firstModifiedOperator;
  if (!isModified(ds, &firstModifiedOperator)) {
    return;
  }

  m_operatorsDeleted = false;

  emit started();

  auto operators = ds->operators();
  if (operators.isEmpty()) {
    emit finished();
    return;
  }
  int startIndex = 0;
  // We currently only support running the last operator or the entire pipeline.
  if (start == nullptr) {
    start = firstModifiedOperator;
  }
  if (start == ds->operators().last() && start->isNew()) {
    // See if we have any canceled operators in the pipeline, if so we have to
    // re-run the anyway pipeline.
    bool haveCanceled = false;
    for (auto itr = operators.begin(); *itr != start; ++itr) {
      auto currentOp = *itr;
      if (currentOp->isCanceled()) {
        currentOp->resetState();
        haveCanceled = true;
        break;
      }
    }

    if (!haveCanceled) {
      startIndex = operators.indexOf(start);
      // Use transformed data source
      ds = transformedDataSource(ds);
    }
  }

  m_executor->execute(ds->dataObject(), operators, startIndex);
}

bool Pipeline::beingEdited(DataSource* ds) const
{
  // If any operators in the pipeline are in editing state,
  // don't execute the pipeline
  if (ds == nullptr) {
    return false;
  }
  auto operators = ds->operators();
  for (auto itr = operators.begin(); itr != operators.end(); ++itr) {
    auto currentOp = *itr;
    if (currentOp->isEditing()) {
      return true;
    }
    // Also check if the operators in a branch are being edited.
    if (beingEdited(currentOp->childDataSource())) {
      return true;
    }
  }
  return false;
}

bool Pipeline::isModified(DataSource* datasource, Operator** start) const
{
  // If the m_operatorsDeleted flag is tripped
  // (i.e. if one or more operator were deleted since the last execution)
  // we should execute the pipeline even if no operators are in a modified state
  if (m_operatorsDeleted) {
    return true;
  }
  // If no operators are in a modified state,
  // there is no need to execute the pipeline
  if (datasource == nullptr) {
    return false;
  }
  auto operators = datasource->operators();
  for (auto itr = operators.begin(); itr != operators.end(); ++itr) {
    auto currentOp = *itr;
    if (currentOp->isModified()) {
      *start = currentOp;
      return true;
    }
    // Also check if the operators in a branch are being edited.
    if (isModified(currentOp->childDataSource(), start)) {
      return true;
    }
  }
  return false;
}

void Pipeline::branchFinished(DataSource* start, vtkDataObject* newData)
{
  // We only add the transformed child data source if the last operator
  // doesn't already have an explicit child data source i.e.
  // hasChildDataSource is true.
  auto lastOp = start->operators().last();
  if (!lastOp->hasChildDataSource()) {
    DataSource* newChildDataSource = nullptr;
    if (lastOp->childDataSource() == nullptr) {
      newChildDataSource = new DataSource("Output");
      newChildDataSource->setPersistenceState(
        tomviz::DataSource::PersistenceState::Transient);
      newChildDataSource->setForkable(false);
      newChildDataSource->setParent(this);
      lastOp->setChildDataSource(newChildDataSource);
      auto rootDataSource = dataSource();
      // connect signal to flow units and spacing to child data source.
      connect(dataSource(), &DataSource::dataPropertiesChanged,
              [rootDataSource, newChildDataSource]() {
                // Only flow the properties if no user modifications have been
                // made.
                if (!newChildDataSource->unitsModified()) {
                  newChildDataSource->setUnits(rootDataSource->getUnits(),
                                               false);
                  double spacing[3];
                  rootDataSource->getSpacing(spacing);
                  newChildDataSource->setSpacing(spacing, false);
                }
              });
    }

    lastOp->childDataSource()->setData(newData);
    lastOp->childDataSource()->dataModified();

    if (newChildDataSource != nullptr) {
      emit lastOp->newChildDataSource(newChildDataSource);
      // Move modules from root data source.
      bool oldMoveObjectsEnabled =
        ActiveObjects::instance().moveObjectsEnabled();
      ActiveObjects::instance().setMoveObjectsMode(false);
      auto view = ActiveObjects::instance().activeView();
      foreach (Module* module, ModuleManager::instance().findModules<Module*>(
                                 dataSource(), nullptr)) {
        // TODO: We should really copy the module properties as well.
        auto newModule = ModuleManager::instance().createAndAddModule(
          module->label(), newChildDataSource, view);
        // Copy over properties using the serialization code.
        newModule->deserialize(module->serialize());
        ModuleManager::instance().removeModule(module);
      }
      ActiveObjects::instance().setMoveObjectsMode(oldMoveObjectsEnabled);
    }
  }
}

void Pipeline::pause()
{
  m_paused = true;
}

bool Pipeline::paused() const
{
  return m_paused;
}

void Pipeline::resume(bool run)
{
  m_paused = false;
  if (run) {
    execute();
  }
}

void Pipeline::resume(DataSource* at)
{
  m_paused = false;
  execute(at);
}

void Pipeline::cancel(std::function<void()> canceled)
{
  m_executor->cancel(canceled);
}

bool Pipeline::isRunning()
{
  return m_executor->isRunning();
}

DataSource* Pipeline::findTransformedDataSource(DataSource* dataSource)
{
  auto op = findTransformedDataSourceOperator(dataSource);
  if (op != nullptr) {
    return op->childDataSource();
  }

  return nullptr;
}

Operator* Pipeline::findTransformedDataSourceOperator(DataSource* dataSource)
{
  if (dataSource == nullptr) {
    return nullptr;
  }

  auto operators = dataSource->operators();
  for (auto itr = operators.rbegin(); itr != operators.rend(); ++itr) {
    auto op = *itr;
    if (op->childDataSource() != nullptr) {
      auto child = op->childDataSource();
      // If the child has operators we need to go deeper
      if (!child->operators().isEmpty()) {
        return findTransformedDataSourceOperator(child);
      }

      return op;
    }
  }

  return nullptr;
}

void Pipeline::addDataSource(DataSource* dataSource)
{
  connect(dataSource, &DataSource::operatorAdded,
          [this](Operator* op) { execute(op->dataSource(), op); });
  // Wire up transformModified to execute pipeline
  connect(dataSource, &DataSource::operatorAdded, [this](Operator* op) {
    // Extract out source and execute all.
    connect(op, &Operator::transformModified, this, [this]() { execute(); });

    // Ensure that new child data source signals are correctly wired up.
    connect(op,
            static_cast<void (Operator::*)(DataSource*)>(
              &Operator::newChildDataSource),
            [this](DataSource* ds) { addDataSource(ds); });

    // We need to ensure we move add datasource to the end of the branch
    auto operators = op->dataSource()->operators();
    if (operators.size() > 1) {
      auto transformedDataSourceOp =
        findTransformedDataSourceOperator(op->dataSource());
      if (transformedDataSourceOp != nullptr) {
        auto transformedDataSource = transformedDataSourceOp->childDataSource();
        transformedDataSourceOp->setChildDataSource(nullptr);
        op->setChildDataSource(transformedDataSource);
        emit operatorAdded(op, transformedDataSource);
      } else {
        emit operatorAdded(op);
      }
    } else {
      emit operatorAdded(op);
    }
  });
  // Wire up operatorRemoved. TODO We need to check the branch of the
  // pipeline we are currently executing.
  connect(dataSource, &DataSource::operatorRemoved, [this](Operator* op) {
    // If an operator has been removed, there's a chance that none of the
    // remaining operators are in a modified state.
    // But the pipeline should still be executed to reflect changes
    if (!op->isNew()) {
      m_operatorsDeleted = true;
    }
    // Do we need to move the transformed data source, !hasChildDataSource as we
    // don't want to move "explicit" child data sources.
    if (!op->hasChildDataSource() && op->childDataSource() != nullptr) {
      auto transformedDataSource = op->childDataSource();
      auto operators = op->dataSource()->operators();
      // We have an operator to move it to.
      if (!operators.isEmpty()) {
        auto newOp = operators.last();
        op->setChildDataSource(nullptr);
        newOp->setChildDataSource(transformedDataSource);
        emit newOp->dataSourceMoved(transformedDataSource);
      }
      // Clean it up
      else {
        transformedDataSource->removeAllOperators();
        transformedDataSource->deleteLater();
      }
    }

    // If pipeline is running see if we can safely remove the operator
    if (isRunning()) {
      // If we can't safely cancel the execution then trigger the rerun of the
      // pipeline.
      if (!m_executor->cancel(op)) {
        execute(op->dataSource());
      }
    } else {
      // Trigger the pipeline to run
      execute(op->dataSource());
    }
  });
}

void Pipeline::addDefaultModules(DataSource* dataSource)
{
  // Note: In the future we can pull this out into a setting.
  QStringList defaultModules = { "Outline", "Slice" };
  bool oldMoveObjectsEnabled = ActiveObjects::instance().moveObjectsEnabled();
  ActiveObjects::instance().setMoveObjectsMode(false);
  auto view = ActiveObjects::instance().activeView();

  if (view == nullptr || !view->IsA("vtkSMRenderViewProxy")) {
    return;
  }

  Module* module = nullptr;
  foreach (QString name, defaultModules) {
    module =
      ModuleManager::instance().createAndAddModule(name, dataSource, view);
  }
  ActiveObjects::instance().setActiveModule(module);
  ActiveObjects::instance().setMoveObjectsMode(oldMoveObjectsEnabled);

  auto pqview = tomviz::convert<pqView*>(view);
  pqview->resetDisplay();
  pqview->render();
}

Pipeline::ImageFuture::ImageFuture(Operator* op, vtkImageData* imageData,
                                   PipelineWorker::Future* future,
                                   QObject* parent)
  : QObject(parent), m_operator(op), m_imageData(imageData), m_future(future)
{

  if (m_future != nullptr) {
    connect(m_future, &PipelineWorker::Future::finished, this,
            &Pipeline::ImageFuture::finished);
    connect(m_future, &PipelineWorker::Future::canceled, this,
            &Pipeline::ImageFuture::canceled);
  }
}

Pipeline::ImageFuture::~ImageFuture()
{
  if (m_future != nullptr) {
    m_future->deleteLater();
  }
}

Pipeline::ImageFuture* Pipeline::getCopyOfImagePriorTo(Operator* op)
{
  return m_executor->getCopyOfImagePriorTo(op);
}

DataSource* Pipeline::transformedDataSource(DataSource* ds)
{
  if (ds == nullptr) {
    ds = dataSource();
  }

  auto transformed = findTransformedDataSource(ds);
  if (transformed != nullptr) {
    return transformed;
  }

  // Default to dataSource at being of pipeline
  return ds;
}

void Pipeline::setExecutionMode(ExecutionMode executor)
{
  m_executionMode = executor;
  if (executor == ExecutionMode::Docker) {
    m_executor.reset(new DockerPipelineExecutor(this));
  } else {
    m_executor.reset(new ThreadPipelineExecutor(this));
  }
}

} // namespace tomviz
<|endoftext|>


<commit_before>/*
 * Store a URI along with a list of socket addresses.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_ADDRESS_LIST_HXX
#define BENG_PROXY_ADDRESS_LIST_HXX

#include "net/SocketAddress.hxx"
#include "util/StaticArray.hxx"
#include "util/ShallowCopy.hxx"
#include "StickyMode.hxx"

#include <inline/compiler.h>

#include <stddef.h>
#include <assert.h>

struct dpool;
class AllocatorPtr;
class SocketAddress;
class AddressInfo;

struct AddressList {
    static constexpr size_t MAX_ADDRESSES = 16;

    StickyMode sticky_mode = StickyMode::NONE;

    typedef StaticArray<SocketAddress, MAX_ADDRESSES> Array;
    typedef Array::const_iterator const_iterator;

    Array addresses;

    AddressList() = default;

    constexpr AddressList(ShallowCopy, const AddressList &src)
        :sticky_mode(src.sticky_mode),
         addresses(src.addresses)
    {
    }

    AddressList(ShallowCopy, const AddressInfo &src);

    AddressList(AllocatorPtr alloc, const AddressList &src);

    AddressList(struct dpool &pool, const AddressList &src);
    void Free(struct dpool &pool);

    void SetStickyMode(StickyMode _sticky_mode) {
        sticky_mode = _sticky_mode;
    }

    constexpr
    bool IsEmpty() const {
        return addresses.empty();
    }

    Array::size_type GetSize() const {
        return addresses.size();
    }

    /**
     * Is there no more than one address?
     */
    constexpr
    bool IsSingle() const {
        return addresses.size() == 1;
    }

    constexpr const_iterator begin() const {
        return addresses.begin();
    }

    constexpr const_iterator end() const {
        return addresses.end();
    }

    /**
     * @return false if the list is full
     */
    bool Add(AllocatorPtr alloc, SocketAddress address);

    bool Add(struct dpool &pool, SocketAddress address);

    const SocketAddress &operator[](unsigned n) const {
        assert(addresses[n].IsDefined());

        return addresses[n];
    }

    /**
     * Generates a unique string which identifies this object in a hash
     * table.  This string stored in a statically allocated buffer.
     */
    gcc_pure
    const char *GetKey() const;
};

#endif
<commit_msg>address_list: add method AddPointer()<commit_after>/*
 * Store a URI along with a list of socket addresses.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_ADDRESS_LIST_HXX
#define BENG_PROXY_ADDRESS_LIST_HXX

#include "net/SocketAddress.hxx"
#include "util/StaticArray.hxx"
#include "util/ShallowCopy.hxx"
#include "StickyMode.hxx"

#include <inline/compiler.h>

#include <stddef.h>
#include <assert.h>

struct dpool;
class AllocatorPtr;
class SocketAddress;
class AddressInfo;

struct AddressList {
    static constexpr size_t MAX_ADDRESSES = 16;

    StickyMode sticky_mode = StickyMode::NONE;

    typedef StaticArray<SocketAddress, MAX_ADDRESSES> Array;
    typedef Array::const_iterator const_iterator;

    Array addresses;

    AddressList() = default;

    constexpr AddressList(ShallowCopy, const AddressList &src)
        :sticky_mode(src.sticky_mode),
         addresses(src.addresses)
    {
    }

    AddressList(ShallowCopy, const AddressInfo &src);

    AddressList(AllocatorPtr alloc, const AddressList &src);

    AddressList(struct dpool &pool, const AddressList &src);
    void Free(struct dpool &pool);

    void SetStickyMode(StickyMode _sticky_mode) {
        sticky_mode = _sticky_mode;
    }

    constexpr
    bool IsEmpty() const {
        return addresses.empty();
    }

    Array::size_type GetSize() const {
        return addresses.size();
    }

    /**
     * Is there no more than one address?
     */
    constexpr
    bool IsSingle() const {
        return addresses.size() == 1;
    }

    constexpr const_iterator begin() const {
        return addresses.begin();
    }

    constexpr const_iterator end() const {
        return addresses.end();
    }

    /**
     * @return false if the list is full
     */
    bool AddPointer(SocketAddress address) {
        return addresses.checked_append(address);
    }

    bool Add(AllocatorPtr alloc, SocketAddress address);

    bool Add(struct dpool &pool, SocketAddress address);

    const SocketAddress &operator[](unsigned n) const {
        assert(addresses[n].IsDefined());

        return addresses[n];
    }

    /**
     * Generates a unique string which identifies this object in a hash
     * table.  This string stored in a statically allocated buffer.
     */
    gcc_pure
    const char *GetKey() const;
};

#endif
<|endoftext|>


<commit_before>#include <cassert>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>

extern "C" {
#include "http-server/http-server.h"
}

struct http_error_category
    : boost::system::error_category
{
    const char * name() const
    {
        return "http_server";
    }
    std::string message(int rc) const
    {
        char * str = http_server_errstr(static_cast<http_server_errno>(rc));
        assert(str);
        return str;
    }
};

inline boost::system::error_category & get_http_error_category()
{
    static http_error_category category;
    return category;
}

class http_server_service
    : public boost::asio::io_service::service
{
public:
    static boost::asio::io_service::id id;
    http_server_service(boost::asio::io_service & io_service)
        : boost::asio::io_service::service(io_service)
        , srv_()
        , handler_()
    {
        http_server_init(&srv_);
        // srv_.sock_listen_data = NULL; // should be null by default
        int result;
        // Set callbacks
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_OPEN_SOCKET_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_OPEN_SOCKET_FUNCTION, &opensocket_function);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }

        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_SOCKET_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_SOCKET_FUNCTION, &socket_function);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        // Prepare handler object
        handler_.on_url = &on_url;
        handler_.on_message_complete = &on_message_complete;

        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_HANDLER, &handler_);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_HANDLER_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
    }
    void shutdown_service()
    {
    }
    void start()
    {
        int result = http_server_start(&srv_);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_start");
        }
    }
private:
    static http_server_socket_t opensocket_function(void * clientp)
    {
        http_server_service * svc = static_cast<http_server_service *>(clientp);
        boost::asio::ip::tcp::acceptor * acceptor = new boost::asio::ip::tcp::acceptor(svc->get_io_service());
        boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 5000);
        acceptor->open(endpoint.protocol());
        acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor->bind(endpoint);
        acceptor->listen();

        fprintf(stderr, "new acceptor: %d\n", acceptor->native_handle());
        svc->acceptors_.insert(std::make_pair(static_cast<http_server_socket_t>(acceptor->native_handle()), acceptor));
        return acceptor->native_handle();
    }
    static int socket_function(void * clientp, http_server_socket_t sock, int flags, void * socketp)
    {
        http_server_service * svc = static_cast<http_server_service *>(clientp);
        http_server_service::acceptors_t::iterator it = svc->acceptors_.find(sock);
        if (it != svc->acceptors_.end())
        {
            // Call acceptor
            fprintf(stderr, "async_accept on acceptor %d\n", it->second->native_handle());
            // Prepare new socket
            boost::asio::ip::tcp::socket * new_socket = new boost::asio::ip::tcp::socket(svc->get_io_service());
            it->second->async_accept(*new_socket,
                boost::bind(&http_server_service::handle_accept, svc,
                    boost::asio::placeholders::error,
                    new_socket));
            return 0;
        }
        fprintf(stderr, "clientp=%p sock=%d flags=%d socketp=%p", clientp, sock, flags, socketp);
        http_server_service::sockets_t::iterator it2 = svc->sockets_.find(sock);
        if (it2 == svc->sockets_.end())
        {
            fprintf(stderr, "socket %d not found!\n", sock);
            abort();
            return 0;
        }
        if (flags & HTTP_SERVER_POLL_IN)
        {
            it2->second->async_read_some(boost::asio::null_buffers(),
                boost::bind(&http_server_service::handle_read, svc,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred,
                    it2->second));
        }
        if (flags & HTTP_SERVER_POLL_IN)
        {
            it2->second->async_write_some(boost::asio::null_buffers(),
                boost::bind(&http_server_service::handle_write, svc,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred,
                    it2->second));
        }
        return 0;
    }
    void handle_accept(const boost::system::error_code & error,
        boost::asio::ip::tcp::socket * socket)
    {
        if (error)
        {
            fprintf(stderr, "unable to accept new connection: %s\n", error.message().c_str());
            // TODO: Remove socket?
            return;
        }
        fprintf(stderr, "handle new conn %d\n", socket->native_handle());

        sockets_.insert(std::make_pair(
            static_cast<http_server_socket_t>(socket->native_handle()),
            socket));

        int result = http_server_socket_action(&srv_, socket->native_handle(), 0);
        if (result != HTTP_SERVER_OK)
        {
            sockets_.erase(socket->native_handle());
            throw boost::system::system_error(result, get_http_error_category(), "http_server_socket_action");
        }
    }
    void handle_read(const boost::system::error_code & error,
        std::size_t bytes_transferred,
        boost::asio::ip::tcp::socket * socket)
    {
        if (error)
        {
            fprintf(stderr, "Unable to read data from socket: %s", error.message().c_str());
            return;
        }
        fprintf(stderr, "handle read %d\n", socket->native_handle());
        int result = http_server_socket_action(&srv_, socket->native_handle(), HTTP_SERVER_POLL_IN);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_socket_action");
        }
    }
    void handle_write(const boost::system::error_code & error,
        std::size_t bytes_transferred,
        boost::asio::ip::tcp::socket * socket)
    {
        if (error)
        {
            fprintf(stderr, "Unable to write data to socket: %s", error.message().c_str());
            return;
        }
        fprintf(stderr, "handle write %d\n", socket->native_handle());
        int result = http_server_socket_action(&srv_, socket->native_handle(), HTTP_SERVER_POLL_OUT);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_socket_action");
        }
    }
    static int on_url(http_server_client * client, void * data, const char * buf, size_t size)
    {
        fprintf(stderr, "URL chunk: %.*s\n", (int)size, buf);
        return 0;
    }
    static int on_message_complete(http_server_client * client, void * data)
    {
        // Write response
        http_server_response * res = http_server_response_new();

        int result = http_server_response_begin(client, res);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_begin");
        }

        // Start response by writing header
        result = http_server_response_write_head(res, 200);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_write_head");
        }
        // Send message
        char chunk[1024];
        int length = sprintf(chunk, "Hello world!\n");
        result = http_server_response_write(res, chunk, length);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_write");
        }
        // Finish response
        result = http_server_response_end(res);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_end");
        }
        return 0;
    }
    http_server srv_;
    http_server_handler handler_;
    // Map of open sockets
    typedef std::map<http_server_socket_t, boost::asio::ip::tcp::acceptor *> acceptors_t;
    acceptors_t acceptors_;
    typedef std::map<http_server_socket_t, boost::asio::ip::tcp::socket *> sockets_t;
    sockets_t sockets_;
};

boost::asio::io_service::id http_server_service::id;

int
main(int argc, char * argv[])
{
    int port;
    boost::asio::io_service io_service;
    boost::asio::use_service<http_server_service>(io_service)
        .start();
    io_service.run();
}<commit_msg>Updated `boost.asio` example with new API.<commit_after>#include <cassert>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>

extern "C" {
#include "http-server/http-server.h"
}

struct http_error_category
    : boost::system::error_category
{
    const char * name() const
    {
        return "http_server";
    }
    std::string message(int rc) const
    {
        char * str = http_server_errstr(static_cast<http_server_errno>(rc));
        assert(str);
        return str;
    }
};

inline boost::system::error_category & get_http_error_category()
{
    static http_error_category category;
    return category;
}

class http_server_service
    : public boost::asio::io_service::service
{
public:
    static boost::asio::io_service::id id;
    http_server_service(boost::asio::io_service & io_service)
        : boost::asio::io_service::service(io_service)
        , srv_()
        , handler_()
    {
        http_server_init(&srv_);
        // srv_.sock_listen_data = NULL; // should be null by default
        int result;
        // Set callbacks
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_OPEN_SOCKET_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_OPEN_SOCKET_FUNCTION, &opensocket_function);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_CLOSE_SOCKET_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_CLOSE_SOCKET_FUNCTION, &closesocket_function);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }

        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_SOCKET_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_SOCKET_FUNCTION, &socket_function);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        // Prepare handler object
        handler_.on_url = &on_url;
        handler_.on_message_complete = &on_message_complete;

        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_HANDLER, &handler_);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
        result = http_server_setopt(&srv_, HTTP_SERVER_OPT_HANDLER_DATA, this);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_setopt");
        }
    }
    void shutdown_service()
    {
    }
    void start()
    {
        int result = http_server_start(&srv_);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_start");
        }
    }
private:
    static http_server_socket_t opensocket_function(void * clientp)
    {
        http_server_service * svc = static_cast<http_server_service *>(clientp);
        boost::asio::ip::tcp::acceptor * acceptor = new boost::asio::ip::tcp::acceptor(svc->get_io_service());
        boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 5000);
        acceptor->open(endpoint.protocol());
        acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor->bind(endpoint);
        acceptor->listen();

        fprintf(stderr, "new acceptor: %d\n", acceptor->native_handle());
        svc->acceptors_.insert(std::make_pair(static_cast<http_server_socket_t>(acceptor->native_handle()), acceptor));
        return acceptor->native_handle();
    }
    static int closesocket_function(http_server_socket_t socket, void * clientp)
    {
        http_server_service * svc = static_cast<http_server_service *>(clientp);
        http_server_service::acceptors_t::iterator it = svc->acceptors_.find(socket);
        if (it != svc->acceptors_.end())
        {
            fprintf(stderr, "erase asio acceptor socket %d\n", it->first);
            it->second->cancel();
            delete it->second;
            svc->acceptors_.erase(it);
            return HTTP_SERVER_OK;
        }
        http_server_service::sockets_t::iterator it2 = svc->sockets_.find(socket);
        if (it2 != svc->sockets_.end())
        {
            fprintf(stderr, "erase asio client socket %d\n", it2->first);
            it2->second->cancel();
            delete it2->second;
            svc->sockets_.erase(it2);
            return HTTP_SERVER_OK;
        }
        fprintf(stderr, "close socket invalid socket: %d\n", socket);
        return HTTP_SERVER_INVALID_SOCKET;
    }
    static int socket_function(void * clientp, http_server_socket_t sock, int flags, void * socketp)
    {
        http_server_service * svc = static_cast<http_server_service *>(clientp);
        http_server_service::acceptors_t::iterator it = svc->acceptors_.find(sock);
        if (it != svc->acceptors_.end())
        {
            // Call acceptor
            fprintf(stderr, "async_accept on acceptor %d\n", it->second->native_handle());
            // Prepare new socket
            boost::asio::ip::tcp::socket * new_socket = new boost::asio::ip::tcp::socket(svc->get_io_service());
            it->second->async_accept(*new_socket,
                boost::bind(&http_server_service::handle_accept, svc,
                    boost::asio::placeholders::error,
                    new_socket));
            return 0;
        }
        fprintf(stderr, "clientp=%p sock=%d flags=%d socketp=%p\n", clientp, sock, flags, socketp);
        http_server_service::sockets_t::iterator it2 = svc->sockets_.find(sock);
        if (it2 == svc->sockets_.end())
        {
            fprintf(stderr, "socket %d not found!\n", sock);
            //abort();
            return 0;
        }
        if (flags & HTTP_SERVER_POLL_REMOVE)
        {
            fprintf(stderr, "cancel asio socket %d\n", sock);
            it2->second->cancel();
        }
        if (flags & HTTP_SERVER_POLL_IN)
        {
            it2->second->async_read_some(boost::asio::null_buffers(),
                boost::bind(&http_server_service::handle_read, svc,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred,
                    it2->second));
        }
        if (flags & HTTP_SERVER_POLL_OUT)
        {
            it2->second->async_write_some(boost::asio::null_buffers(),
                boost::bind(&http_server_service::handle_write, svc,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred,
                    it2->second));
        }
        return 0;
    }
    void handle_accept(const boost::system::error_code & error,
        boost::asio::ip::tcp::socket * socket)
    {
        if (error)
        {
            fprintf(stderr, "unable to accept new connection: %s\n", error.message().c_str());
            // TODO: Remove socket?
            return;
        }
        fprintf(stderr, "handle new conn %d\n", socket->native_handle());

        sockets_.insert(std::make_pair(
            static_cast<http_server_socket_t>(socket->native_handle()),
            socket));

        int result = http_server_socket_action(&srv_, socket->native_handle(), 0);
        if (result != HTTP_SERVER_OK)
        {
            sockets_.erase(socket->native_handle());
            throw boost::system::system_error(result, get_http_error_category(), "http_server_socket_action");
        }
    }
    void handle_read(const boost::system::error_code & error,
        std::size_t bytes_transferred,
        boost::asio::ip::tcp::socket * socket)
    {
        if (error)
        {
            fprintf(stderr, "Unable to read data from socket: %s", error.message().c_str());
            return;
        }
        fprintf(stderr, "handle read %d\n", socket->native_handle());
        int result = http_server_socket_action(&srv_, socket->native_handle(), HTTP_SERVER_POLL_IN);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_socket_action");
        }
    }
    void handle_write(const boost::system::error_code & error,
        std::size_t bytes_transferred,
        boost::asio::ip::tcp::socket * socket)
    {
        if (error)
        {
            fprintf(stderr, "Unable to write data to socket: %s", error.message().c_str());
            return;
        }
        fprintf(stderr, "handle write %d\n", socket->native_handle());
        int result = http_server_socket_action(&srv_, socket->native_handle(), HTTP_SERVER_POLL_OUT);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_socket_action");
        }
    }
    static int on_url(http_server_client * client, void * data, const char * buf, size_t size)
    {
        fprintf(stderr, "URL chunk: %.*s\n", (int)size, buf);
        return 0;
    }
    static int on_message_complete(http_server_client * client, void * data)
    {
        // Write response
        http_server_response * res = http_server_response_new();

        int result = http_server_response_begin(client, res);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_begin");
        }

        // Start response by writing header
        result = http_server_response_write_head(res, 200);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_write_head");
        }
        // Send message
        char chunk[1024];
        int length = sprintf(chunk, "Hello world!\n");
        result = http_server_response_write(res, chunk, length);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_write");
        }
        // Finish response
        result = http_server_response_end(res);
        if (result != HTTP_SERVER_OK)
        {
            throw boost::system::system_error(result, get_http_error_category(), "http_server_response_end");
        }
        return 0;
    }
    http_server srv_;
    http_server_handler handler_;
    // Map of open sockets
    typedef std::map<http_server_socket_t, boost::asio::ip::tcp::acceptor *> acceptors_t;
    acceptors_t acceptors_;
    typedef std::map<http_server_socket_t, boost::asio::ip::tcp::socket *> sockets_t;
    sockets_t sockets_;
};

boost::asio::io_service::id http_server_service::id;

int
main(int argc, char * argv[])
{
    int port;
    boost::asio::io_service io_service;
    boost::asio::use_service<http_server_service>(io_service)
        .start();
    io_service.run();
}<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Andrew Kallmeyer <fsmv@sapium.net>
// Provided under the MIT License: https://mit-license.org

// TODO: Do we actually need a separate lexer?
#include "lexer.cpp"
#include "nfa.h"

inline nfa_arc_list *NFACreateArcList(nfa *NFA, nfa_label Label) {
    nfa_arc_list *ArcList = NFAGetArcList(NFA, NFA->ArcListCount++);
    ArcList->Label = Label;
    ArcList->TransitionCount = 0;
    return ArcList;
}

void NFAAddArc(nfa *NFA, nfa_label Label, nfa_transition Transition) {
    nfa_arc_list *ArcListToUse = (nfa_arc_list *) 0;
    for (size_t ArcListIdx = 0; ArcListIdx < NFA->ArcListCount; ++ArcListIdx) {
        nfa_arc_list *TestArcList = NFAGetArcList(NFA, ArcListIdx);
        if (TestArcList->Label == Label) {
            ArcListToUse = TestArcList;
        }
    }

    if (!ArcListToUse) {
        ArcListToUse = NFACreateArcList(NFA, Label);
    }

    nfa_transition *TransitionLocation =
        &ArcListToUse->Transitions[ArcListToUse->TransitionCount++];
    *TransitionLocation = Transition;
}

#define NULLSTATE ((uint32_t) -1)

void ReParse(char *regex, nfa *NFA) {
    NFA->NumStates = 1;

    uint32_t LoopBackState = NULLSTATE;
    uint32_t ParenLoopBackStates[16];
    size_t NumOpenParens = 0;

    // NOTE(fsmv): Epsilon is garunteed to be the first arc list for the code-gen step
    nfa_label EpsilonLabel = {};
    EpsilonLabel.Type = EPSILON;
    NFACreateArcList(NFA, EpsilonLabel);

    // NOTE(fsmv): Dot is garunteed to be the second arc list for the code-gen step
    nfa_label DotLabel = {};
    DotLabel.Type = DOT;
    NFACreateArcList(NFA, DotLabel);

    lexer_state Lexer = ReLexer(regex);
    while(ReLexerHasNext(&Lexer)) {
        token Token = ReLexerNext(&Lexer);

        switch(*Token.Str) {
            case '.': {
                LoopBackState = NFA->NumStates - 1;
                uint32_t MyState = NFA->NumStates++;

                nfa_label Label = {};
                Label.Type = DOT;

                nfa_transition Transition = {};
                Transition.From = LoopBackState;
                Transition.To = MyState;

                NFAAddArc(NFA, Label, Transition);
            } break;
            case '*': {
                // TODO: Report error
                Assert(LoopBackState != NULLSTATE);

                nfa_label Label = {};
                Label.Type = EPSILON;

                nfa_transition Transition = {};
                Transition.From = NFA->NumStates - 1;
                Transition.To = LoopBackState;

                NFAAddArc(NFA, Label, Transition);

                uint32_t MyState = NFA->NumStates++;
                Transition.To = MyState; // last accept => new accept

                NFAAddArc(NFA, Label, Transition);

                Transition.From = LoopBackState; // loop back => new accept

                NFAAddArc(NFA, Label, Transition);

                LoopBackState = NULLSTATE;
            } break;
            case '+': {
                // TODO: Report error
                Assert(LoopBackState != NULLSTATE);

                nfa_label Label = {};
                Label.Type = EPSILON;

                nfa_transition Transition = {};
                Transition.From = NFA->NumStates - 1;
                Transition.To = LoopBackState;

                NFAAddArc(NFA, Label, Transition);

                LoopBackState = NULLSTATE;
            } break;
            case '?': {
                // TODO: Report error
                Assert(LoopBackState != NULLSTATE);

                uint32_t LastAccept = NFA->NumStates - 1;
                uint32_t NewAccept = NFA->NumStates++;

                nfa_label Label = {};
                Label.Type = EPSILON;

                nfa_transition Transition = {};
                Transition.From = LastAccept;
                Transition.To = NewAccept;

                NFAAddArc(NFA, Label, Transition);

                Transition.From = LoopBackState; // loop back => new accept

                NFAAddArc(NFA, Label, Transition);

                LoopBackState = NULLSTATE;
            } break;
            case '(': {
                Assert(NumOpenParens < ArrayLength(ParenLoopBackStates));

                ParenLoopBackStates[NumOpenParens++] = NFA->NumStates - 1;
            } break;
            case ')': {
                // TODO: Report error
                Assert(NumOpenParens > 0);

                uint32_t OpenParenState = ParenLoopBackStates[--NumOpenParens];
                LoopBackState = OpenParenState;
            } break;
            case '|': {
            } break;
            case '\\':
            default: {
                nfa_label Label = {};
                Label.Type = MATCH;

                nfa_transition Transition = {};
                for (char *c = Token.Str; (c - Token.Str) < Token.Length; ++c) {
                    // Move the the escaped char
                    if (*c == '\\' && (c - Token.Str) + 1 < Token.Length) {
                        c += 1;
                    }
                    Label.A = *c;

                    Transition.From = NFA->NumStates - 1;
                    Transition.To = NFA->NumStates++;

                    NFAAddArc(NFA, Label, Transition);

                    LoopBackState = Transition.From;
                }
            } break;
        }
    }
}
<commit_msg>Fixed a bug in the NFA gadget + adds<commit_after>// Copyright (c) 2016-2017 Andrew Kallmeyer <fsmv@sapium.net>
// Provided under the MIT License: https://mit-license.org

// TODO: Do we actually need a separate lexer?
#include "lexer.cpp"
#include "nfa.h"

inline nfa_arc_list *NFACreateArcList(nfa *NFA, nfa_label Label) {
    nfa_arc_list *ArcList = NFAGetArcList(NFA, NFA->ArcListCount++);
    ArcList->Label = Label;
    ArcList->TransitionCount = 0;
    return ArcList;
}

void NFAAddArc(nfa *NFA, nfa_label Label, nfa_transition Transition) {
    nfa_arc_list *ArcListToUse = (nfa_arc_list *) 0;
    for (size_t ArcListIdx = 0; ArcListIdx < NFA->ArcListCount; ++ArcListIdx) {
        nfa_arc_list *TestArcList = NFAGetArcList(NFA, ArcListIdx);
        if (TestArcList->Label == Label) {
            ArcListToUse = TestArcList;
        }
    }

    if (!ArcListToUse) {
        ArcListToUse = NFACreateArcList(NFA, Label);
    }

    nfa_transition *TransitionLocation =
        &ArcListToUse->Transitions[ArcListToUse->TransitionCount++];
    *TransitionLocation = Transition;
}

#define NULLSTATE ((uint32_t) -1)

void ReParse(char *regex, nfa *NFA) {
    NFA->NumStates = 1;

    uint32_t LoopBackState = NULLSTATE;
    uint32_t ParenLoopBackStates[16];
    size_t NumOpenParens = 0;

    // NOTE(fsmv): Epsilon is garunteed to be the first arc list for the code-gen step
    nfa_label EpsilonLabel = {};
    EpsilonLabel.Type = EPSILON;
    NFACreateArcList(NFA, EpsilonLabel);

    // NOTE(fsmv): Dot is garunteed to be the second arc list for the code-gen step
    nfa_label DotLabel = {};
    DotLabel.Type = DOT;
    NFACreateArcList(NFA, DotLabel);

    lexer_state Lexer = ReLexer(regex);
    while(ReLexerHasNext(&Lexer)) {
        token Token = ReLexerNext(&Lexer);

        switch(*Token.Str) {
            case '.': {
                LoopBackState = NFA->NumStates - 1;
                uint32_t MyState = NFA->NumStates++;

                nfa_label Label = {};
                Label.Type = DOT;

                nfa_transition Transition = {};
                Transition.From = LoopBackState;
                Transition.To = MyState;

                NFAAddArc(NFA, Label, Transition);
            } break;
            case '*': {
                // TODO: Report error
                Assert(LoopBackState != NULLSTATE);

                nfa_label Label = {};
                Label.Type = EPSILON;

                nfa_transition Transition = {};
                Transition.From = NFA->NumStates - 1;
                Transition.To = LoopBackState;

                NFAAddArc(NFA, Label, Transition);

                uint32_t MyState = NFA->NumStates++;
                Transition.To = MyState; // last accept => new accept

                NFAAddArc(NFA, Label, Transition);

                Transition.From = LoopBackState; // loop back => new accept

                NFAAddArc(NFA, Label, Transition);

                LoopBackState = NULLSTATE;
            } break;
            case '+': {
                // TODO: Report error
                Assert(LoopBackState != NULLSTATE);

                nfa_label Label = {};
                Label.Type = EPSILON;
                nfa_transition Transition = {};

                Transition.From = NFA->NumStates - 1;
                Transition.To = LoopBackState;
                NFAAddArc(NFA, Label, Transition);
                // Must not end on a state with out transitions
                Transition.To = NFA->NumStates++;
                NFAAddArc(NFA, Label, Transition);

                LoopBackState = NULLSTATE;
            } break;
            case '?': {
                // TODO: Report error
                Assert(LoopBackState != NULLSTATE);

                uint32_t LastAccept = NFA->NumStates - 1;
                uint32_t NewAccept = NFA->NumStates++;

                nfa_label Label = {};
                Label.Type = EPSILON;

                nfa_transition Transition = {};
                Transition.From = LastAccept;
                Transition.To = NewAccept;

                NFAAddArc(NFA, Label, Transition);

                Transition.From = LoopBackState; // loop back => new accept

                NFAAddArc(NFA, Label, Transition);

                LoopBackState = NULLSTATE;
            } break;
            case '(': {
                Assert(NumOpenParens < ArrayLength(ParenLoopBackStates));

                ParenLoopBackStates[NumOpenParens++] = NFA->NumStates - 1;
            } break;
            case ')': {
                // TODO: Report error
                Assert(NumOpenParens > 0);

                uint32_t OpenParenState = ParenLoopBackStates[--NumOpenParens];
                LoopBackState = OpenParenState;
            } break;
            case '|': {
            } break;
            case '\\':
            default: {
                nfa_label Label = {};
                Label.Type = MATCH;

                nfa_transition Transition = {};
                for (char *c = Token.Str; (c - Token.Str) < Token.Length; ++c) {
                    // Move the the escaped char
                    if (*c == '\\' && (c - Token.Str) + 1 < Token.Length) {
                        c += 1;
                    }
                    Label.A = *c;

                    Transition.From = NFA->NumStates - 1;
                    Transition.To = NFA->NumStates++;

                    NFAAddArc(NFA, Label, Transition);

                    LoopBackState = Transition.From;
                }
            } break;
        }
    }
}
<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) FFLAS-FFPACK
 * Written by David Lucas
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

//--------------------------------------------------------------------------
//                        Test for minpoly
//
//--------------------------------------------------------------------------
// David Lucas
//-------------------------------------------------------------------------

#include <iomanip>
#include <iostream>

#include "fflas-ffpack/fflas-ffpack-config.h"
#include "fflas-ffpack/fflas/fflas.h"
#include "fflas-ffpack/ffpack/ffpack.h"
#include "fflas-ffpack/utils/args-parser.h"
#include "fflas-ffpack/utils/fflas_randommatrix.h"
#include "test-utils.h"
#include <givaro/modular.h>
#include <givaro/modular-balanced.h>
#include <givaro/modular-integer.h>
#include <givaro/givpoly1factor.h>
#include <givaro/givpoly1.h>

using namespace std;
using namespace FFPACK;
using Givaro::Modular;
using Givaro::ModularBalanced;

typedef Givaro::ModularBalanced<double> Field;
typedef vector<Field::Element> Polynomial;

/* Computes P(A)*V and stores it in E using Horner's scheme for
 * polynomial evaluation. */
template<typename Field, typename Element>
void horner_matrix_vector(const Field &F, size_t n, Element *A, size_t lda, Element *V,
						  Element *E, Polynomial P)
{

	//TODO: Quite a few copies. Could be improved.
	size_t deg = P.size() - 1;
	Element *E_tmp;
	E_tmp = FFLAS::fflas_new(F, 1, n);

	FFLAS::fassign(F, n, V, 1, E, 1);
	FFLAS::fscalin(F, n, P[deg], E, 1); // E <- P[deg+1] * V

    for(long i = deg; i > 0; --i)
    {
		FFLAS::fassign(F, n, E, 1, E_tmp, 1); //E_tmp <- E
		FFLAS::fgemv(F, FFLAS::FflasNoTrans, n, n, F.one, A, lda, E_tmp, 1, F.zero, E, 1);//E <- A * E_tmp
		FFLAS::faxpy(F, 1, n, P[i-1], V, 1, E, 1); //E <- minP[i-1] * V + E
    }
	FFLAS::fflas_delete(E_tmp);
}

template<typename Field, class RandIter>
bool check_minpoly(const Field &F, size_t n, RandIter& G)
{
	cout<<"Entering check_minpoly"<<endl;
	typedef typename Field::Element Element;
	size_t lda, ldv;
	Element *A, *V, *Vcst;

	//Default
	lda = n;
	ldv = n;

	/*Create variables used for testing (matrices, vectors and polynomials) */

    A = FFLAS::fflas_new(F, n, n);
    V = FFLAS::fflas_new(F, n+1, n);
	Vcst = FFLAS::fflas_new(F, 1, n);
    Polynomial minP;

    FFPACK::RandomMatrix (F, n, n, A, lda, G);

	FFPACK::NonZeroRandomMatrix(F, 1, n, V, n, G);
	FFLAS::fassign(F, n, V, 1, Vcst, 1); //MatVecMinPoly modifies V, we store it in Vcst beforehand

	FFPACK::MatVecMinPoly(F, minP, n, A, lda, V, ldv);
	FFLAS::fflas_delete(V);

	/*Check that minP is monic*/

	size_t deg = minP.size() - 1;
	if(!(minP[deg]==F.one))
		return false;

	/*Check that minP(A).V is zero*/

	Element *E;
    E = FFLAS::fflas_new(F, 1, n);

	horner_matrix_vector(F, n, A, lda, Vcst, E, minP);

    if (!FFLAS::fiszero(F, n, E, 1))
	{
		cout<<"NONZEROERROR"<<endl;
		FFLAS::fflas_delete(E);
		return false;
	}

	FFLAS::fflas_delete(E);

	/* Check minimality of minP */

	// Krylov matrix computation
	Element *K, *tmp;
	size_t ldk = n;
	K = FFLAS::fflas_new(F, deg+1, ldk);
	tmp = FFLAS::fflas_new(F, 1, n);
	FFLAS::fassign(F, n, K, 1, Vcst, 1);
	Element *Kptr = K;

	for(size_t i = 0; i < deg; ++i, Kptr += ldk)
	{
		FFLAS::fgemv(F, FFLAS::FflasNoTrans, n, n, F.one, A, lda, Kptr, 1, F.zero, tmp, 1);
		FFLAS::fassign(F, n, tmp, 1, Kptr+ldk, 1);
	}
	FFLAS::fflas_delete(tmp);

	//minP factorization
	//typedef typename Givaro::Poly1FactorDom<Field, Givaro::Dense>::Element FieldPoly;
	//vector<FieldPoly> factors;
	//vector<size_t> powers;

	//Givaro::CZfactor(factors, powers, minP);

	//factorized minP checks
	//divide minP by each factor, and evaluate it. None shall pass eval==0.
	//call horner_matrix_vector to evaluate.

	FFLAS::fflas_delete(A);
	FFLAS::fflas_delete(Vcst);
	FFLAS::fflas_delete(K);
	return true;
}

template <class Field>
bool run_with_field (Givaro::Integer q, size_t b, size_t n, size_t iters, uint64_t seed)
{
	bool ok = true;
	int nbiter = iters;

	while (ok && nbiter)
	{
		Field* F = chooseField<Field>(q, b); // F, characteristic q of b bits
		typename Field::RandIter G(*F, 0, seed); //random generator over F

		if(F == nullptr)
			return true; //if F is null, nothing to test, just pass

		cout<<"Checking with "; F->write(cout)<<endl;

		ok = ok && check_minpoly(*F, n, G);

		if(!ok)
			cout<<"FAILED"<<endl;
		else
			cout<<"PASS"<<endl;

		delete F;
		nbiter--;
	}

	return ok;
}

int main(int argc, char** argv)
{
    /* Test parameters */
	Givaro::Integer q = -1;
	size_t b = 0;
    size_t n = 128;
	size_t iters = 1;
	bool loop = false;
    uint64_t seed = time(NULL);

	Argument as[] = {
		{ 'q', "-q Q", "Set the field characteristic (-1 for random).",	TYPE_INTEGER, &q },
		{ 'b', "-b B", "Set the bitsize of the field characteristic.", TYPE_INT, &b },
		{ 'n', "-n N", "Set the order of the matrix.", TYPE_INT, &b },
		{ 'i', "-i, R", "set the number of repetitions.", TYPE_INT, &iters },
		{ 'l', "-loop Y/N", "run the test in an infinite loop.", TYPE_BOOL , &loop },
		{ 's', "-s seed", "set seed for the random generator.", TYPE_INT, &seed },
			END_OF_ARGUMENTS
		};

	FFLAS::parseArguments(argc, argv, as);

	bool ok = true;

	do
	{
		ok &= run_with_field<Modular<double>>(q,b,n,iters,seed);
		//more tests?
	} while(ok && loop);

	return !ok ;
}
<commit_msg>Working minP factorization<commit_after>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) FFLAS-FFPACK
 * Written by David Lucas
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

//--------------------------------------------------------------------------
//                        Test for minpoly
//
//--------------------------------------------------------------------------
// David Lucas
//-------------------------------------------------------------------------

#include <iomanip>
#include <iostream>

#include "fflas-ffpack/fflas-ffpack-config.h"
#include "fflas-ffpack/fflas/fflas.h"
#include "fflas-ffpack/ffpack/ffpack.h"
#include "fflas-ffpack/utils/args-parser.h"
#include "fflas-ffpack/utils/fflas_randommatrix.h"
#include "test-utils.h"
#include <givaro/modular.h>
#include <givaro/modular-balanced.h>
#include <givaro/modular-integer.h>
#include <givaro/givpoly1factor.h>
#include <givaro/givpoly1.h>

using namespace std;
using namespace FFPACK;
using Givaro::Modular;
using Givaro::ModularBalanced;

typedef Givaro::ModularBalanced<double> Field;
typedef vector<Field::Element> Polynomial;

/* Computes P(A)*V and stores it in E using Horner's scheme for
 * polynomial evaluation. */
template<typename Field, typename Element>
void horner_matrix_vector(const Field &F, size_t n, Element *A, size_t lda, Element *V,
						  Element *E, Polynomial P)
{

	//TODO: Quite a few copies. Could be improved.
	size_t deg = P.size() - 1;
	Element *E_tmp;
	E_tmp = FFLAS::fflas_new(F, 1, n);

	FFLAS::fassign(F, n, V, 1, E, 1);
	FFLAS::fscalin(F, n, P[deg], E, 1); // E <- P[deg+1] * V

    for(long i = deg; i > 0; --i)
    {
		FFLAS::fassign(F, n, E, 1, E_tmp, 1); //E_tmp <- E
		FFLAS::fgemv(F, FFLAS::FflasNoTrans, n, n, F.one, A, lda, E_tmp, 1, F.zero, E, 1);//E <- A * E_tmp
		FFLAS::faxpy(F, 1, n, P[i-1], V, 1, E, 1); //E <- minP[i-1] * V + E
    }
	FFLAS::fflas_delete(E_tmp);
}

template<typename Field, class RandIter>
bool check_minpoly(const Field &F, size_t n, RandIter& G)
{
	cout<<"Entering check_minpoly"<<endl;
	typedef typename Field::Element Element;
	size_t lda, ldv;
	Element *A, *V, *Vcst;

	//Default
	lda = n;
	ldv = n;

	/*Create variables used for testing (matrices, vectors and polynomials) */

    A = FFLAS::fflas_new(F, n, n);
    V = FFLAS::fflas_new(F, n+1, n);
	Vcst = FFLAS::fflas_new(F, 1, n);
    Polynomial minP;

    FFPACK::RandomMatrix (F, n, n, A, lda, G);

	FFPACK::NonZeroRandomMatrix(F, 1, n, V, n, G);
	FFLAS::fassign(F, n, V, 1, Vcst, 1); //MatVecMinPoly modifies V, we store it in Vcst beforehand

	FFPACK::MatVecMinPoly(F, minP, n, A, lda, V, ldv);
	FFLAS::fflas_delete(V);

	/*Check that minP is monic*/

	size_t deg = minP.size() - 1;
	if(!(minP[deg]==F.one))
		return false;

	/*Check that minP(A).V is zero*/

	Element *E;
    E = FFLAS::fflas_new(F, 1, n);

	horner_matrix_vector(F, n, A, lda, Vcst, E, minP);

    if (!FFLAS::fiszero(F, n, E, 1))
	{
		cout<<"NONZEROERROR"<<endl;
		FFLAS::fflas_delete(E);
		return false;
	}

	FFLAS::fflas_delete(E);

	/* Check minimality of minP */

	// Krylov matrix computation
	Element *K, *tmp;
	size_t ldk = n;
	K = FFLAS::fflas_new(F, deg+1, ldk);
	tmp = FFLAS::fflas_new(F, 1, n);
	FFLAS::fassign(F, n, K, 1, Vcst, 1);
	Element *Kptr = K;

	for(size_t i = 0; i < deg; ++i, Kptr += ldk)
	{
		FFLAS::fgemv(F, FFLAS::FflasNoTrans, n, n, F.one, A, lda, Kptr, 1, F.zero, tmp, 1);
		FFLAS::fassign(F, n, tmp, 1, Kptr+ldk, 1);
	}
	FFLAS::fflas_delete(tmp);

	// minP factorization
	typedef Givaro::Poly1FactorDom<Field, Givaro::Dense> PolyDom; //defines a polynomial domain for Givaro
	typedef typename PolyDom::Element FieldPoly; //defines an element over this polynomial domain (casting purposes)
	vector<FieldPoly> factors;
	vector<size_t> powers;

	PolyDom PD(F);
	FieldPoly FP = FieldPoly(minP.begin(), minP.end());
	PD.factor(factors, powers, FP);

	// Factorized minP checks
	//divide minP by each factor, and evaluate it. None shall pass eval==0.
	//call horner_matrix_vector to evaluate.

	FFLAS::fflas_delete(A);
	FFLAS::fflas_delete(Vcst);
	FFLAS::fflas_delete(K);
	return true;
}

template <class Field>
bool run_with_field (Givaro::Integer q, size_t b, size_t n, size_t iters, uint64_t seed)
{
	bool ok = true;
	int nbiter = iters;

	while (ok && nbiter)
	{
		Field* F = chooseField<Field>(q, b); // F, characteristic q of b bits
		typename Field::RandIter G(*F, 0, seed); //random generator over F

		if(F == nullptr)
			return true; //if F is null, nothing to test, just pass

		cout<<"Checking with "; F->write(cout)<<endl;

		ok = ok && check_minpoly(*F, n, G);

		if(!ok)
			cout<<"FAILED"<<endl;
		else
			cout<<"PASS"<<endl;

		delete F;
		nbiter--;
	}

	return ok;
}

int main(int argc, char** argv)
{
    /* Test parameters */
	Givaro::Integer q = -1;
	size_t b = 0;
    size_t n = 128;
	size_t iters = 1;
	bool loop = false;
    uint64_t seed = time(NULL);

	Argument as[] = {
		{ 'q', "-q Q", "Set the field characteristic (-1 for random).",	TYPE_INTEGER, &q },
		{ 'b', "-b B", "Set the bitsize of the field characteristic.", TYPE_INT, &b },
		{ 'n', "-n N", "Set the order of the matrix.", TYPE_INT, &b },
		{ 'i', "-i, R", "set the number of repetitions.", TYPE_INT, &iters },
		{ 'l', "-loop Y/N", "run the test in an infinite loop.", TYPE_BOOL , &loop },
		{ 's', "-s seed", "set seed for the random generator.", TYPE_INT, &seed },
			END_OF_ARGUMENTS
		};

	FFLAS::parseArguments(argc, argv, as);

	bool ok = true;

	do
	{
		ok &= run_with_field<Modular<double>>(q,b,n,iters,seed);
		//more tests?
	} while(ok && loop);

	return !ok ;
}
<|endoftext|>


<commit_before>/*
    This file is part of KAddressBook.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <kabc/phonenumber.h>
#include <kabc/address.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kstringhandler.h>
#include <ktextbrowser.h>

#include "look_html.h"

KABHtmlView::KABHtmlView( QWidget *parent, const char *name )
  : KABBasicLook( parent, name )
{
  mTextBrowser = new KTextBrowser( this );
  mTextBrowser->setWrapPolicy( QTextEdit::AtWordBoundary );
  mTextBrowser->setVScrollBarMode( QScrollView::AlwaysOff );
  mTextBrowser->setHScrollBarMode( QScrollView::AlwaysOff );
}

KABHtmlView::~KABHtmlView()
{
}

void KABHtmlView::setAddressee( const KABC::Addressee &addr )
{
  mTextBrowser->setText( QString::null );

  if ( addr.isEmpty() )
    return;

  QString name = ( addr.formattedName().isEmpty() ? addr.assembledName() :
                   addr.formattedName() );

  QString dynamicPart;

  KABC::PhoneNumber::List phones = addr.phoneNumbers();
  KABC::PhoneNumber::List::ConstIterator phoneIt;
  for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt ) {
    dynamicPart += QString(
      "
%1	"
      "%2
" )
      .arg( KABC::PhoneNumber::typeLabel( (*phoneIt).type() ) )
      .arg( (*phoneIt).number() );
  }

  QStringList emails = addr.emails();
  QStringList::ConstIterator emailIt;
  QString type = i18n( "Privat" );
  for ( emailIt = emails.begin(); emailIt != emails.end(); ++emailIt ) {
    dynamicPart += QString(
      "
%1	"
      "%3
" )
      .arg( type )
      .arg( *emailIt )
      .arg( *emailIt );
    type = i18n( "Other" );
  }

  if ( !addr.url().url().isEmpty() ) {
    dynamicPart += QString(
      "
%1	"
      "%2
" )
      .arg( i18n( "Homepage" ) )
      .arg( KStringHandler::tagURLs( addr.url().url() ) );
  }

  KABC::Address::List addresses = addr.addresses();
  KABC::Address::List::ConstIterator addrIt;
  for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt ) {
    QString formattedAddress = (*addrIt).formattedAddress().stripWhiteSpace();
    formattedAddress = formattedAddress.replace( '\n', "
" );

    dynamicPart += QString(
      "
%1	"
      "%2
" )
      .arg( KABC::Address::typeLabel( (*addrIt).type() ) )
      .arg( formattedAddress );
  }

  QString notes;
  if ( !addr.note().isEmpty() ) {
    notes = QString(
      "

"
      "
"
      "%1:	" // note label
      "%2	"          // note
      "
" ).arg( i18n( "Notes" ) ).arg( addr.note() );
  }

  QString strAddr = QString::fromLatin1(
  ""
  ""
  "
"
  "
"
  ""
  ""
  "	"
  "%1	"   // name
  "
"
  "
"
  "%2	"          // role
  "
"
  "
"
  "%3	"          // organization
  "
"
  "

"
  "%4"                                  // dynamic part
  "%5"
  "
"
  ""
  "").arg( name ).arg( addr.role() ).arg( addr.organization() )
  .arg( dynamicPart ).arg( notes );

  KABC::Picture picture = addr.photo();
  if ( picture.isIntern() && !picture.data().isNull() )
    QMimeSourceFactory::defaultFactory()->setImage( "myimage", picture.data() );
  else
    QMimeSourceFactory::defaultFactory()->setPixmap( "myimage",
      KGlobal::iconLoader()->loadIcon( "penguin", KIcon::Desktop, 128 ) );

  mTextBrowser->setText( strAddr );
}

#include "look_html.moc"
<commit_msg><commit_after>/*
    This file is part of KAddressBook.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <kabc/phonenumber.h>
#include <kabc/address.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kstringhandler.h>
#include <ktextbrowser.h>

#include "look_html.h"

KABHtmlView::KABHtmlView( QWidget *parent, const char *name )
  : KABBasicLook( parent, name )
{
  mTextBrowser = new KTextBrowser( this );
  mTextBrowser->setWrapPolicy( QTextEdit::AtWordBoundary );
  mTextBrowser->setLinkUnderline( false );
  mTextBrowser->setVScrollBarMode( QScrollView::AlwaysOff );
  mTextBrowser->setHScrollBarMode( QScrollView::AlwaysOff );

  QStyleSheet *sheet = mTextBrowser->styleSheet();
  QStyleSheetItem *link = sheet->item( "a" );
  link->setColor( KGlobalSettings::linkColor() );
}

KABHtmlView::~KABHtmlView()
{
}

void KABHtmlView::setAddressee( const KABC::Addressee &addr )
{
  mTextBrowser->setText( QString::null );

  if ( addr.isEmpty() )
    return;

  QString name = ( addr.formattedName().isEmpty() ? addr.assembledName() :
                   addr.formattedName() );

  QString dynamicPart;

  KABC::PhoneNumber::List phones = addr.phoneNumbers();
  KABC::PhoneNumber::List::ConstIterator phoneIt;
  for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt ) {
    dynamicPart += QString(
      "
%1	"
      "%2
" )
      .arg( KABC::PhoneNumber::typeLabel( (*phoneIt).type() ) )
      .arg( (*phoneIt).number() );
  }

  QStringList emails = addr.emails();
  QStringList::ConstIterator emailIt;
  QString type = i18n( "Privat" );
  for ( emailIt = emails.begin(); emailIt != emails.end(); ++emailIt ) {
    dynamicPart += QString(
      "
%1	"
      "%3
" )
      .arg( type )
      .arg( *emailIt )
      .arg( *emailIt );
    type = i18n( "Other" );
  }

  if ( !addr.url().url().isEmpty() ) {
    dynamicPart += QString(
      "
%1	"
      "%2
" )
      .arg( i18n( "Homepage" ) )
      .arg( KStringHandler::tagURLs( addr.url().url() ) );
  }

  KABC::Address::List addresses = addr.addresses();
  KABC::Address::List::ConstIterator addrIt;
  for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt ) {
    QString formattedAddress = (*addrIt).formattedAddress().stripWhiteSpace();
    formattedAddress = formattedAddress.replace( '\n', "
" );

    dynamicPart += QString(
      "
%1	"
      "%2
" )
      .arg( KABC::Address::typeLabel( (*addrIt).type() ) )
      .arg( formattedAddress );
  }

  QString notes;
  if ( !addr.note().isEmpty() ) {
    notes = QString(
      "

"
      "
"
      "%1:	" // note label
      "%2	"          // note
      "
" ).arg( i18n( "Notes" ) ).arg( addr.note() );
  }

  QString strAddr = QString::fromLatin1(
  ""
  ""
  "
"
  "
"
  ""
  ""
  "	"
  "%1	"   // name
  "
"
  "
"
  "%2	"          // role
  "
"
  "
"
  "%3	"          // organization
  "
"
  "

"
  "%4"                                  // dynamic part
  "%5"
  "
"
  ""
  "").arg( name ).arg( addr.role() ).arg( addr.organization() )
  .arg( dynamicPart ).arg( notes );

  KABC::Picture picture = addr.photo();
  if ( picture.isIntern() && !picture.data().isNull() )
    QMimeSourceFactory::defaultFactory()->setImage( "myimage", picture.data() );
  else
    QMimeSourceFactory::defaultFactory()->setPixmap( "myimage",
      KGlobal::iconLoader()->loadIcon( "penguin", KIcon::Desktop, 128 ) );

  mTextBrowser->setText( strAddr );
}

#include "look_html.moc"
<|endoftext|>