<commit_before>/*
 * medViewerToolBoxViewProperties.cpp
 *
 *  Created on: 15 févr. 2011
 *      Author: aabadie
 */

#include <medViewerToolBoxViewProperties.h>

#include <medCore/medAbstractView.h>
#include <medGui/medToolBoxTab.h>

class medViewerToolBoxViewPropertiesPrivate
{
    public:
        medAbstractView *view;
        QWidget* propertiesToolBoxWidget;
        QComboBox * dataComboBox;
        QComboBox * lutComboBox;
        QCheckBox * visible;
        QDoubleSpinBox * opacity;
        QSlider * opacitySlider;
};

medViewerToolBoxViewProperties::medViewerToolBoxViewProperties(QWidget *parent) :
    medToolBox(parent), d(new medViewerToolBoxViewPropertiesPrivate)
{
    d->view = 0;
    d->dataComboBox = new QComboBox(this);
    d->dataComboBox->setFocusPolicy(Qt::NoFocus);

    d->lutComboBox = new QComboBox(this);
    d->lutComboBox->setFocusPolicy(Qt::NoFocus);
    d->lutComboBox->addItem("Default");
    d->lutComboBox->addItem("Black & White");
    d->lutComboBox->addItem("Black & White Inversed");
    d->lutComboBox->addItem("Spectrum");
    d->lutComboBox->addItem("Hot Metal");
    d->lutComboBox->addItem("Hot Green");
    d->lutComboBox->addItem("Hot Iron");
    d->lutComboBox->addItem("GE");
    d->lutComboBox->addItem("Flow");
    d->lutComboBox->addItem("Loni");
    d->lutComboBox->addItem("Loni 2");
    d->lutComboBox->addItem("Asymmetry");
    d->lutComboBox->addItem("P-Value");
    d->lutComboBox->addItem("Red Black Alpha");
    d->lutComboBox->addItem("Green Black Alpha");
    d->lutComboBox->addItem("Blue Black Alpha");
    d->lutComboBox->addItem("Muscles & Bones");
    d->lutComboBox->addItem("Bones");
    d->lutComboBox->addItem("Red Vessels");
    d->lutComboBox->addItem("Cardiac");
    d->lutComboBox->addItem("Gray Rainbow");
    d->lutComboBox->addItem("Stern");
    d->lutComboBox->addItem("Black Body");

    d->visible = new QCheckBox(this);

    d->opacitySlider = new QSlider(this);
    d->opacitySlider->setRange(0, 100);
    d->opacitySlider->setValue(100);
    d->opacitySlider->setOrientation(Qt::Horizontal);

    d->opacity = new QDoubleSpinBox(this);
    d->opacity->setRange(0.0, 1.0);
    d->opacity->setSingleStep(0.01);
    d->opacity->setValue(1.0);

    d->propertiesToolBoxWidget = new QWidget;
    d->propertiesToolBoxWidget->setEnabled(false);

    QHBoxLayout * opacityLayout = new QHBoxLayout;
    opacityLayout->addWidget(d->opacitySlider);
    opacityLayout->addWidget(d->opacity);

    QFormLayout * viewPropertiesLayout = new QFormLayout(d->propertiesToolBoxWidget);
    viewPropertiesLayout->addRow("Select data :", d->dataComboBox);
    viewPropertiesLayout->addRow("Visible :", d->visible);
    //    viewPropertiesLayout->addRow("Opacity :", d->opacity);
    viewPropertiesLayout->addRow("Opacity :", opacityLayout);
    viewPropertiesLayout->addRow("LUT :", d->lutComboBox);
    viewPropertiesLayout->setFormAlignment(Qt::AlignHCenter);

    this->setTitle("View properties");
    this->addWidget(d->propertiesToolBoxWidget);

    QObject::connect(d->dataComboBox,   SIGNAL(currentIndexChanged(int)),       this, SLOT(onDataSelected(int)));
    QObject::connect(d->visible,        SIGNAL(stateChanged(int)),              this, SLOT(onVisibilitySet(int)));
    QObject::connect(d->opacity,        SIGNAL(valueChanged(double)),           this, SLOT(onOpacitySet(double)));
    QObject::connect(d->opacitySlider,  SIGNAL(valueChanged(int)),              this, SLOT(onOpacitySliderSet(int)));
    QObject::connect(d->lutComboBox,    SIGNAL(currentIndexChanged(int)),       this, SLOT(onLUTChanged(int)));
}

medViewerToolBoxViewProperties::~medViewerToolBoxViewProperties(void)
{
    delete d;
    d = NULL;
}

void
medViewerToolBoxViewProperties::update(dtkAbstractView *view)
{
    d->view = dynamic_cast<medAbstractView *> (view);

    if (!d->view)
        return;

    QObject::connect(d->view, SIGNAL(dataAdded(int)), this, SLOT(onDataAdded(int)), Qt::UniqueConnection);
    QObject::connect(d->view, SIGNAL(closing()), this, SLOT(onViewClosed()), Qt::UniqueConnection);
}

void
medViewerToolBoxViewProperties::onDataAdded(int layer)
{
    if (!d->view)
        return;

    d->propertiesToolBoxWidget->setEnabled(true);
    //d->view->setVisibility(1, layer);
    //d->view->setOpacity(1.0, layer); // why forcing visibility and opacity?
    d->visible->setChecked(true);
    d->dataComboBox->insertItem(layer, QString::number(layer));
    d->dataComboBox->blockSignals(true); // if not blocked, combobox slot is called. Is it what is expected?
    d->dataComboBox->setCurrentIndex(layer);
    d->dataComboBox->blockSignals(false);
    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(layer));
    d->opacity->blockSignals(false);
    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue(d->view->opacity(layer) * 100);
    d->opacitySlider->blockSignals(false);

    d->view->setCurrentLayer(layer);
    d->lutComboBox->blockSignals(true);
    d->lutComboBox->setCurrentIndex(0);
    d->lutComboBox->blockSignals(false);
    d->view->setProperty("LookupTable", "Default");
    d->view->update();
}

void
medViewerToolBoxViewProperties::onViewClosed(void)
{
    d->dataComboBox->clear();
    d->opacity->setValue(1.0);
    d->opacitySlider->setValue(100);
    d->visible->setChecked(true);
    d->propertiesToolBoxWidget->setEnabled(false);
}

void
medViewerToolBoxViewProperties::onDataSelected(int index)
{
    if (!d->view || (index == -1))
        return;

    // this method should update toolbox's GUI w.r.t selected data settings
    // to me, it should not set data settings (only current layer)
    d->view->setCurrentLayer(index);

    // d->view->setVisibility(d->view->visibility(index), index);

    d->visible->blockSignals(true);
    d->visible->setChecked((d->view->visibility(index) == 1));
    d->visible->blockSignals(false);
    // d->view->setOpacity(d->view->opacity(index), index);

    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(index));
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacity->blockSignals(false);
}

void
medViewerToolBoxViewProperties::onVisibilitySet(int state)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    if (state == Qt::Checked)
        d->view->setVisibility(1, d->dataComboBox->currentIndex());
    else
        d->view->setVisibility(0, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySet(double opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacitySlider->blockSignals(false);

    d->view->setOpacity(opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySliderSet(int opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacity->blockSignals(true);
    double d_opacity = static_cast<double> (opacity) / 100.0;
    d->opacity->setValue(d_opacity);
    d->opacity->blockSignals(false);

    d->view->setOpacity(d_opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onLUTChanged(int index)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->view->setProperty("LookupTable", d->lutComboBox->itemText(index));
    d->view->update();
}

<commit_msg>Towards hnadling of different views<commit_after>/*
 * medViewerToolBoxViewProperties.cpp
 *
 *  Created on: 15 févr. 2011
 *      Author: aabadie
 */

#include <medViewerToolBoxViewProperties.h>

#include <medCore/medAbstractView.h>
#include <medGui/medToolBoxTab.h>

class medViewerToolBoxViewPropertiesPrivate
{
    public:
        medAbstractView *view;
        QWidget* propertiesToolBoxWidget;
        QComboBox * dataComboBox;
        QComboBox * lutComboBox;
        QCheckBox * visible;
        QDoubleSpinBox * opacity;
        QSlider * opacitySlider;
};

medViewerToolBoxViewProperties::medViewerToolBoxViewProperties(QWidget *parent) :
    medToolBox(parent), d(new medViewerToolBoxViewPropertiesPrivate)
{
    d->view = 0;
    d->dataComboBox = new QComboBox(this);
    d->dataComboBox->setFocusPolicy(Qt::NoFocus);

    d->lutComboBox = new QComboBox(this);
    d->lutComboBox->setFocusPolicy(Qt::NoFocus);
    d->lutComboBox->addItem("Default");
    d->lutComboBox->addItem("Black & White");
    d->lutComboBox->addItem("Black & White Inversed");
    d->lutComboBox->addItem("Spectrum");
    d->lutComboBox->addItem("Hot Metal");
    d->lutComboBox->addItem("Hot Green");
    d->lutComboBox->addItem("Hot Iron");
    d->lutComboBox->addItem("GE");
    d->lutComboBox->addItem("Flow");
    d->lutComboBox->addItem("Loni");
    d->lutComboBox->addItem("Loni 2");
    d->lutComboBox->addItem("Asymmetry");
    d->lutComboBox->addItem("P-Value");
    d->lutComboBox->addItem("Red Black Alpha");
    d->lutComboBox->addItem("Green Black Alpha");
    d->lutComboBox->addItem("Blue Black Alpha");
    d->lutComboBox->addItem("Muscles & Bones");
    d->lutComboBox->addItem("Bones");
    d->lutComboBox->addItem("Red Vessels");
    d->lutComboBox->addItem("Cardiac");
    d->lutComboBox->addItem("Gray Rainbow");
    d->lutComboBox->addItem("Stern");
    d->lutComboBox->addItem("Black Body");

    d->visible = new QCheckBox(this);

    d->opacitySlider = new QSlider(this);
    d->opacitySlider->setRange(0, 100);
    d->opacitySlider->setValue(100);
    d->opacitySlider->setOrientation(Qt::Horizontal);

    d->opacity = new QDoubleSpinBox(this);
    d->opacity->setRange(0.0, 1.0);
    d->opacity->setSingleStep(0.01);
    d->opacity->setValue(1.0);

    d->propertiesToolBoxWidget = new QWidget;
    d->propertiesToolBoxWidget->setEnabled(false);

    QHBoxLayout * opacityLayout = new QHBoxLayout;
    opacityLayout->addWidget(d->opacitySlider);
    opacityLayout->addWidget(d->opacity);

    QFormLayout * viewPropertiesLayout = new QFormLayout(d->propertiesToolBoxWidget);
    viewPropertiesLayout->addRow("Select data :", d->dataComboBox);
    viewPropertiesLayout->addRow("Visible :", d->visible);
    //    viewPropertiesLayout->addRow("Opacity :", d->opacity);
    viewPropertiesLayout->addRow("Opacity :", opacityLayout);
    viewPropertiesLayout->addRow("LUT :", d->lutComboBox);
    viewPropertiesLayout->setFormAlignment(Qt::AlignHCenter);

    this->setTitle("View properties");
    this->addWidget(d->propertiesToolBoxWidget);

    QObject::connect(d->dataComboBox,   SIGNAL(currentIndexChanged(int)),       this, SLOT(onDataSelected(int)));
    QObject::connect(d->visible,        SIGNAL(stateChanged(int)),              this, SLOT(onVisibilitySet(int)));
    QObject::connect(d->opacity,        SIGNAL(valueChanged(double)),           this, SLOT(onOpacitySet(double)));
    QObject::connect(d->opacitySlider,  SIGNAL(valueChanged(int)),              this, SLOT(onOpacitySliderSet(int)));
    QObject::connect(d->lutComboBox,    SIGNAL(currentIndexChanged(int)),       this, SLOT(onLUTChanged(int)));
}

medViewerToolBoxViewProperties::~medViewerToolBoxViewProperties(void)
{
    delete d;
    d = NULL;
}

void
medViewerToolBoxViewProperties::update(dtkAbstractView *view)
{
    if (d->view)
    {
        QObject::disconnect(d->view, SIGNAL(dataAdded(int)), this, SLOT(onDataAdded(int)));
        QObject::disconnect(d->view, SIGNAL(closing()),      this, SLOT(onViewClosed()));

        this->onViewClosed();
    }

    if (medAbstractView *medView = dynamic_cast<medAbstractView *> (view))
    {
        d->view = medView;

        QObject::connect(d->view, SIGNAL(dataAdded(int)), this, SLOT(onDataAdded(int)), Qt::UniqueConnection);
        QObject::connect(d->view, SIGNAL(closing()), this, SLOT(onViewClosed()), Qt::UniqueConnection);

        d->propertiesToolBoxWidget->setEnabled(true);
    }
}

void
medViewerToolBoxViewProperties::onDataAdded(int layer)
{
    if (!d->view)
        return;

    //d->view->setVisibility(1, layer);
    //d->view->setOpacity(1.0, layer); // why forcing visibility and opacity?
    d->visible->setChecked(true);
    d->dataComboBox->insertItem(layer, QString::number(layer));
    d->dataComboBox->blockSignals(true); // if not blocked, combobox slot is called. Is it what is expected?
    d->dataComboBox->setCurrentIndex(layer);
    d->dataComboBox->blockSignals(false);
    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(layer));
    d->opacity->blockSignals(false);
    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue(d->view->opacity(layer) * 100);
    d->opacitySlider->blockSignals(false);

    d->view->setCurrentLayer(layer);
    d->lutComboBox->blockSignals(true);
    d->lutComboBox->setCurrentIndex(0);
    d->lutComboBox->blockSignals(false);
    d->view->setProperty("LookupTable", "Default");
    d->view->update();
}

void
medViewerToolBoxViewProperties::onViewClosed(void)
{
    d->dataComboBox->clear();
    d->opacity->setValue(1.0);
    d->opacitySlider->setValue(100);
    d->visible->setChecked(true);
    d->propertiesToolBoxWidget->setEnabled(false);

    d->view = 0;
}

void
medViewerToolBoxViewProperties::onDataSelected(int index)
{
    if (!d->view || (index == -1))
        return;

    // this method should update toolbox's GUI w.r.t selected data settings
    // to me, it should not set data settings (only current layer)
    d->view->setCurrentLayer(index);

    // d->view->setVisibility(d->view->visibility(index), index);

    d->visible->blockSignals(true);
    d->visible->setChecked((d->view->visibility(index) == 1));
    d->visible->blockSignals(false);
    // d->view->setOpacity(d->view->opacity(index), index);

    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(index));
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacity->blockSignals(false);
}

void
medViewerToolBoxViewProperties::onVisibilitySet(int state)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    if (state == Qt::Checked)
        d->view->setVisibility(1, d->dataComboBox->currentIndex());
    else
        d->view->setVisibility(0, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySet(double opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacitySlider->blockSignals(false);

    d->view->setOpacity(opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySliderSet(int opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacity->blockSignals(true);
    double d_opacity = static_cast<double> (opacity) / 100.0;
    d->opacity->setValue(d_opacity);
    d->opacity->blockSignals(false);

    d->view->setOpacity(d_opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onLUTChanged(int index)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->view->setProperty("LookupTable", d->lutComboBox->itemText(index));
    d->view->update();
}

<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Transient.h"

//Moose includes
#include "Kernel.h"
#include "Factory.h"
#include "SubProblem.h"
#include "ProblemFactory.h"

//libMesh includes
#include "implicit_system.h"
#include "nonlinear_implicit_system.h"
#include "transient_system.h"
#include "numeric_vector.h"

// C++ Includes
#include <iomanip>
#include <iostream>
#include <fstream>

template<>
InputParameters validParams<Transient>()
{
  InputParameters params = validParams<Executioner>();
  std::vector<Real> sync_times(1);
  sync_times[0] = -1;

  params.addParam<Real>("start_time",      0.0,    "The start time of the simulation");
  params.addParam<Real>("end_time",        1.0e30, "The end time of the simulation");
  params.addRequiredParam<Real>("dt", "The timestep size between solves");
  params.addParam<Real>("dtmin",           0.0,    "The minimum timestep size in an adaptive run");
  params.addParam<Real>("dtmax",           1.0e30, "The maximum timestep size in an adaptive run");
  params.addParam<Real>("num_steps",       std::numeric_limits<Real>::max(),     "The number of timesteps in a transient run");
  params.addParam<int> ("n_startup_steps", 0,      "The number of timesteps during startup");
  params.addParam<bool>("trans_ss_check",  false,  "Whether or not to check for steady state conditions");
  params.addParam<Real>("ss_check_tol",    1.0e-08,"Whenever the relative residual changes by less than this the solution will be considered to be at steady state.");
  params.addParam<Real>("ss_tmin",         0.0,    "Minimum number of timesteps to take before checking for steady state conditions.");
  params.addParam<std::vector<Real> >("sync_times", sync_times, "A list of times that will be solved for provided they are within the simulation time");
  params.addParam<std::vector<Real> >("time_t", "The values of t");
  params.addParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.  For use with 'time_t' and 'time_dt'.");
  params.addParam<Real>("predictor_scale",      0.0,    "The scale factor for the predictor (can range from 0 to 1)");

  params.addParam<std::vector<std::string> >("time_periods", "The names of periods");
  params.addParam<std::vector<Real> >("time_period_starts", "The start times of time periods");
  params.addParam<std::vector<Real> >("time_period_ends", "The end times of time periods");

  return params;
}

Transient::Transient(const std::string & name, InputParameters parameters) :
    Executioner(name, parameters),
    _problem(*ProblemFactory::instance()->createFEProblem(_mesh)),
    _t_step(_problem.timeStep()),
    _time(_problem.time()),
    _time_old(_time),
    _input_dt(getParam<Real>("dt")),
    _dt(_problem.dt()),
    _dt_old(_problem.dtOld()),
    _prev_dt(-1),
    _reset_dt(false),
    _end_time(getParam<Real>("end_time")),
    _dtmin(getParam<Real>("dtmin")),
    _dtmax(getParam<Real>("dtmax")),
    _num_steps(getParam<Real>("num_steps")),
    _n_startup_steps(getParam<int>("n_startup_steps")),
    _trans_ss_check(getParam<bool>("trans_ss_check")),
    _ss_check_tol(getParam<Real>("ss_check_tol")),
    _ss_tmin(getParam<Real>("ss_tmin")),
    _converged(true),
    _sync_times(getParam<std::vector<Real> >("sync_times")),
    _curr_sync_time_iter(_sync_times.begin()),
    _remaining_sync_time(true),
    _time_ipol(getParam<std::vector<Real> >("time_t"),
               getParam<std::vector<Real> >("time_dt")),
    _use_time_ipol(_time_ipol.getSampleSize() > 0),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false)
{
  _t_step = 0;
  _dt = 0;
  _time = _time_old = getParam<Real>("start_time");
  _problem.transient(true);
  if (parameters.wasSeenInInput("predictor_scale"))
  {
    Real predscale(getParam<Real>("predictor_scale"));
    if (predscale >= 0.0 and predscale <= 1.0)
      _problem.getNonlinearSystem().setPredictorScale(getParam<Real>("predictor_scale"));
    else
      mooseError("Input value for predictor_scale = "<< predscale << ", outside of permissible range (0 to 1)");
  }

  // process time periods
  const std::vector<std::string> & time_period_names = getParam<std::vector<std::string> >("time_periods");
  const std::vector<Real> & time_start = getParam<std::vector<Real> >("time_period_starts");
  const std::vector<Real> & time_end = getParam<std::vector<Real> >("time_period_ends");
  for (unsigned int i = 0; i < time_period_names.size(); ++i)
  {
    Real t_start = time_start[i];
    Real t_end = 0;
    if (time_end.size() > 0)
      t_end = time_end[i];                              // use the time end specified in the input file
    else
    {
      if (i < time_period_names.size() - 1)
        t_end = time_start[i + 1];                      // use the next start time as an end time of this period
      else
        t_end = std::numeric_limits<Real>::max();       // use the max as the end
    }
    _problem.addTimePeriod(time_period_names[i], t_start, t_end);
    _sync_times.push_back(t_start);
  }

  const std::vector<Real> & time = getParam<std::vector<Real> >("time_t");
  if (_use_time_ipol)
  {
    _sync_times.insert(_sync_times.end(), time.begin()+1, time.end());          // insert times as sync points except the very first one
    _curr_sync_time_iter = _sync_times.begin();
  }
  sort(_sync_times.begin(), _sync_times.end());
  _sync_times.erase(std::unique(_sync_times.begin(), _sync_times.end()), _sync_times.end());    // remove duplicates (needs sorted array)

  // Advance to the first sync time if one is provided in sim time range
  while (_remaining_sync_time && *_curr_sync_time_iter < _time)
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

  if (!_restart_file_base.empty())
    _problem.setRestartFile(_restart_file_base);
}

Transient::~Transient()
{
  // This problem was built by the Factory and needs to be released by this destructor
  delete &_problem;
}

void
Transient::execute()
{
  _problem.initialSetup();

  preExecute();

  // Start time loop...
  while(keepGoing())
  {
    takeStep();
    if (lastSolveConverged())
      endStep();
  }
  postExecute();
}

void
Transient::takeStep(Real input_dt)
{
  if (_converged)
    _problem.copyOldSolutions();
  else
    _problem.restoreSolutions();

  _dt_old = _dt;
  if (input_dt == -1.0)
    _dt = computeConstrainedDT();
  else
    _dt = input_dt;

  _problem.onTimestepBegin();
  if (_converged)
  {
    // Update backward material data structures
    _problem.updateMaterials();
  }

  // Increment time
  _time = _time_old + _dt;

  // Compute TimestepBegin AuxKernels
  _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN);

  // Compute TimestepBegin Postprocessors
  _problem.computePostprocessors(EXEC_TIMESTEP_BEGIN);

  std::cout<<"DT: "<<_dt<<std::endl;

  std::cout << " Solving time step ";
  {
    OStringStream out;

    OSSInt(out,2,_t_step);
    out << ", time=";
    OSSRealzeroleft(out,9,6,_time);
    out <<  "...";
    std::cout << out.str() << std::endl;
  }

  preSolve();

  _problem.timestepSetup();
  _problem.solve();

  _converged = _problem.converged();

  postSolve();

  _problem.onTimestepEnd();

  // We know whether or not the nonlinear solver thinks it converged, but we need to see if the executioner concurs
  bool last_solve_converged = lastSolveConverged();

  // If _reset_dt is true, the time step was synced to the user defined value and we dump the solution in an output file
  if (last_solve_converged)
    _problem.computePostprocessors();
}

void
Transient::endStep()
{
  // if _reset_dt is true, force the output no matter what
  _problem.output(_reset_dt);
  _problem.outputPostprocessors(_reset_dt);

#ifdef LIBMESH_ENABLE_AMR
  if (_problem.adaptivity().isOn())
  {
    _problem.adaptMesh();
    _problem.out().meshChanged();
  }
#endif

  _t_step++;
  _time_old = _time;
}

Real
Transient::computeConstrainedDT()
{
  // If this is the first step
  if (_t_step == 0)
  {
    _t_step = 1;
    _dt = _input_dt;
  }

//  // If start up steps are needed
//  if(_t_step == 1 && _n_startup_steps > 1)
//    _dt = _input_dt/(double)(_n_startup_steps);
//  else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
//    _dt = _input_dt;

  Real dt_cur = _dt;
  //After startup steps, compute new dt
  if (_t_step > _n_startup_steps)
    dt_cur = computeDT();

  // Don't let the time step size exceed maximum time step size
  if (dt_cur > _dtmax)
    dt_cur = _dtmax;

  // Don't allow time step size to be smaller than minimum time step size
  if (dt_cur < _dtmin)
    dt_cur = _dtmin;

  // Don't let time go beyond simulation end time
  if (_time + dt_cur > _end_time)
    dt_cur = _end_time - _time;

  // Adjust to a sync time if supplied and skipped over
  if (_remaining_sync_time && _time + dt_cur >= *_curr_sync_time_iter)
  {
    dt_cur = *_curr_sync_time_iter - _time;
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

    _prev_dt = _dt;

    _reset_dt = true;
  }
  else
  {
    if (_reset_dt)
    {
      if (_use_time_ipol)
        dt_cur = _time_ipol.sample(_time);
      else
        dt_cur = _prev_dt;
      _reset_dt = false;
    }
  }

  return dt_cur;

}

Real
Transient::computeDT()
{
  if (!lastSolveConverged())
  {
    _cutback_occurred = true;
    //std::cout<<"Solve failed... cutting timestep"<<std::endl;
    //return _dt / 2.0;

    // Instead of blindly cutting timestep, respect dtmin.
    if (_dt <= _dtmin)
      mooseError("Solve failed and timestep already at or below dtmin, cannot continue!");

    if (0.5 * _dt >= _dtmin)
      return 0.5 * _dt;

    else // (0.5 * _dt < _dtmin)
      return _dtmin;
  }

  Real dt = _dt;
  if (_use_time_ipol)
  {
    dt = _time_ipol.sample(_time);
    if (_cutback_occurred &&
        dt > _dt * _growth_factor)
    {
      dt = _dt * _growth_factor;
    }
  }

  _cutback_occurred = false;
  return dt;
}

bool
Transient::keepGoing()
{
  // Check for stop condition based upon steady-state check flag:
  if(_converged && _trans_ss_check == true && _time > _ss_tmin)
  {
    // Compute new time solution l2_norm
    Real new_time_solution_norm = _problem.getNonlinearSystem().currentSolution()->l2_norm();

    // Compute l2_norm relative error
    Real ss_relerr_norm = fabs(new_time_solution_norm - _old_time_solution_norm)/new_time_solution_norm;

    // Check current solution relative error norm against steady-state tolerance
    if(ss_relerr_norm < _ss_check_tol)
    {
      std::cout<<"Steady-State Solution Achieved at time: "<<_time<<std::endl;
      return false;
    }
    else // Keep going
    {
      // Update solution norm for next time step
      _old_time_solution_norm = new_time_solution_norm;
      // Print steady-state relative error norm
      std::cout<<"Steady-State Relative Differential Norm: "<<ss_relerr_norm<<std::endl;
    }
  }

  // Check for stop condition based upon number of simulation steps and/or solution end time:
  if(_t_step>_num_steps)
    return false;

  if((_time>_end_time) || (fabs(_time-_end_time)<1.e-14))
    return false;

  return true;
}

bool
Transient::lastSolveConverged()
{
  return _converged;
}

void
Transient::preExecute()
{
  Executioner::preExecute();
}
<commit_msg>Fixing issue with sync_times and BFD2 time scheme (#1015)<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Transient.h"

//Moose includes
#include "Kernel.h"
#include "Factory.h"
#include "SubProblem.h"
#include "ProblemFactory.h"

//libMesh includes
#include "implicit_system.h"
#include "nonlinear_implicit_system.h"
#include "transient_system.h"
#include "numeric_vector.h"

// C++ Includes
#include <iomanip>
#include <iostream>
#include <fstream>

template<>
InputParameters validParams<Transient>()
{
  InputParameters params = validParams<Executioner>();
  std::vector<Real> sync_times(1);
  sync_times[0] = -1;

  params.addParam<Real>("start_time",      0.0,    "The start time of the simulation");
  params.addParam<Real>("end_time",        1.0e30, "The end time of the simulation");
  params.addRequiredParam<Real>("dt", "The timestep size between solves");
  params.addParam<Real>("dtmin",           0.0,    "The minimum timestep size in an adaptive run");
  params.addParam<Real>("dtmax",           1.0e30, "The maximum timestep size in an adaptive run");
  params.addParam<Real>("num_steps",       std::numeric_limits<Real>::max(),     "The number of timesteps in a transient run");
  params.addParam<int> ("n_startup_steps", 0,      "The number of timesteps during startup");
  params.addParam<bool>("trans_ss_check",  false,  "Whether or not to check for steady state conditions");
  params.addParam<Real>("ss_check_tol",    1.0e-08,"Whenever the relative residual changes by less than this the solution will be considered to be at steady state.");
  params.addParam<Real>("ss_tmin",         0.0,    "Minimum number of timesteps to take before checking for steady state conditions.");
  params.addParam<std::vector<Real> >("sync_times", sync_times, "A list of times that will be solved for provided they are within the simulation time");
  params.addParam<std::vector<Real> >("time_t", "The values of t");
  params.addParam<std::vector<Real> >("time_dt", "The values of dt");
  params.addParam<Real>("growth_factor", 2, "Maximum ratio of new to previous timestep sizes following a step that required the time step to be cut due to a failed solve.  For use with 'time_t' and 'time_dt'.");
  params.addParam<Real>("predictor_scale",      0.0,    "The scale factor for the predictor (can range from 0 to 1)");

  params.addParam<std::vector<std::string> >("time_periods", "The names of periods");
  params.addParam<std::vector<Real> >("time_period_starts", "The start times of time periods");
  params.addParam<std::vector<Real> >("time_period_ends", "The end times of time periods");

  return params;
}

Transient::Transient(const std::string & name, InputParameters parameters) :
    Executioner(name, parameters),
    _problem(*ProblemFactory::instance()->createFEProblem(_mesh)),
    _t_step(_problem.timeStep()),
    _time(_problem.time()),
    _time_old(_time),
    _input_dt(getParam<Real>("dt")),
    _dt(_problem.dt()),
    _dt_old(_problem.dtOld()),
    _prev_dt(-1),
    _reset_dt(false),
    _end_time(getParam<Real>("end_time")),
    _dtmin(getParam<Real>("dtmin")),
    _dtmax(getParam<Real>("dtmax")),
    _num_steps(getParam<Real>("num_steps")),
    _n_startup_steps(getParam<int>("n_startup_steps")),
    _trans_ss_check(getParam<bool>("trans_ss_check")),
    _ss_check_tol(getParam<Real>("ss_check_tol")),
    _ss_tmin(getParam<Real>("ss_tmin")),
    _converged(true),
    _sync_times(getParam<std::vector<Real> >("sync_times")),
    _remaining_sync_time(true),
    _time_ipol(getParam<std::vector<Real> >("time_t"),
               getParam<std::vector<Real> >("time_dt")),
    _use_time_ipol(_time_ipol.getSampleSize() > 0),
    _growth_factor(getParam<Real>("growth_factor")),
    _cutback_occurred(false)
{
  _t_step = 0;
  _dt = 0;
  _time = _time_old = getParam<Real>("start_time");
  _problem.transient(true);
  if (parameters.wasSeenInInput("predictor_scale"))
  {
    Real predscale(getParam<Real>("predictor_scale"));
    if (predscale >= 0.0 and predscale <= 1.0)
      _problem.getNonlinearSystem().setPredictorScale(getParam<Real>("predictor_scale"));
    else
      mooseError("Input value for predictor_scale = "<< predscale << ", outside of permissible range (0 to 1)");
  }

  // process time periods
  const std::vector<std::string> & time_period_names = getParam<std::vector<std::string> >("time_periods");
  const std::vector<Real> & time_start = getParam<std::vector<Real> >("time_period_starts");
  const std::vector<Real> & time_end = getParam<std::vector<Real> >("time_period_ends");
  for (unsigned int i = 0; i < time_period_names.size(); ++i)
  {
    Real t_start = time_start[i];
    Real t_end = 0;
    if (time_end.size() > 0)
      t_end = time_end[i];                              // use the time end specified in the input file
    else
    {
      if (i < time_period_names.size() - 1)
        t_end = time_start[i + 1];                      // use the next start time as an end time of this period
      else
        t_end = std::numeric_limits<Real>::max();       // use the max as the end
    }
    _problem.addTimePeriod(time_period_names[i], t_start, t_end);
    _sync_times.push_back(t_start);
  }

  const std::vector<Real> & time = getParam<std::vector<Real> >("time_t");
  if (_use_time_ipol)
    _sync_times.insert(_sync_times.end(), time.begin()+1, time.end());          // insert times as sync points except the very first one
  sort(_sync_times.begin(), _sync_times.end());
  _sync_times.erase(std::unique(_sync_times.begin(), _sync_times.end()), _sync_times.end());    // remove duplicates (needs sorted array)

  // Advance to the first sync time if one is provided in sim time range
  _curr_sync_time_iter = _sync_times.begin();
  while (_remaining_sync_time && *_curr_sync_time_iter <= _time)
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

  if (!_restart_file_base.empty())
    _problem.setRestartFile(_restart_file_base);
}

Transient::~Transient()
{
  // This problem was built by the Factory and needs to be released by this destructor
  delete &_problem;
}

void
Transient::execute()
{
  _problem.initialSetup();

  preExecute();

  // Start time loop...
  while(keepGoing())
  {
    takeStep();
    if (lastSolveConverged())
      endStep();
  }
  postExecute();
}

void
Transient::takeStep(Real input_dt)
{
  if (_converged)
    _problem.copyOldSolutions();
  else
    _problem.restoreSolutions();

  _dt_old = _dt;
  if (input_dt == -1.0)
    _dt = computeConstrainedDT();
  else
    _dt = input_dt;

  _problem.onTimestepBegin();
  if (_converged)
  {
    // Update backward material data structures
    _problem.updateMaterials();
  }

  // Increment time
  _time = _time_old + _dt;

  // Compute TimestepBegin AuxKernels
  _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN);

  // Compute TimestepBegin Postprocessors
  _problem.computePostprocessors(EXEC_TIMESTEP_BEGIN);

  std::cout<<"DT: "<<_dt<<std::endl;

  std::cout << " Solving time step ";
  {
    OStringStream out;

    OSSInt(out,2,_t_step);
    out << ", time=";
    OSSRealzeroleft(out,9,6,_time);
    out <<  "...";
    std::cout << out.str() << std::endl;
  }

  preSolve();

  _problem.timestepSetup();
  _problem.solve();

  _converged = _problem.converged();

  postSolve();

  _problem.onTimestepEnd();

  // We know whether or not the nonlinear solver thinks it converged, but we need to see if the executioner concurs
  bool last_solve_converged = lastSolveConverged();

  // If _reset_dt is true, the time step was synced to the user defined value and we dump the solution in an output file
  if (last_solve_converged)
    _problem.computePostprocessors();
}

void
Transient::endStep()
{
  // if _reset_dt is true, force the output no matter what
  _problem.output(_reset_dt);
  _problem.outputPostprocessors(_reset_dt);

#ifdef LIBMESH_ENABLE_AMR
  if (_problem.adaptivity().isOn())
  {
    _problem.adaptMesh();
    _problem.out().meshChanged();
  }
#endif

  _t_step++;
  _time_old = _time;
}

Real
Transient::computeConstrainedDT()
{
  // If this is the first step
  if (_t_step == 0)
  {
    _t_step = 1;
    _dt = _input_dt;
  }

//  // If start up steps are needed
//  if(_t_step == 1 && _n_startup_steps > 1)
//    _dt = _input_dt/(double)(_n_startup_steps);
//  else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
//    _dt = _input_dt;

  Real dt_cur = _dt;
  //After startup steps, compute new dt
  if (_t_step > _n_startup_steps)
    dt_cur = computeDT();

  // Don't let the time step size exceed maximum time step size
  if (dt_cur > _dtmax)
    dt_cur = _dtmax;

  // Don't allow time step size to be smaller than minimum time step size
  if (dt_cur < _dtmin)
    dt_cur = _dtmin;

  // Don't let time go beyond simulation end time
  if (_time + dt_cur > _end_time)
    dt_cur = _end_time - _time;

  // Adjust to a sync time if supplied and skipped over
  if (_remaining_sync_time && _time + dt_cur >= *_curr_sync_time_iter)
  {
    dt_cur = *_curr_sync_time_iter - _time;
    if (++_curr_sync_time_iter == _sync_times.end())
      _remaining_sync_time = false;

    _prev_dt = _dt;

    _reset_dt = true;
  }
  else
  {
    if (_reset_dt)
    {
      if (_use_time_ipol)
        dt_cur = _time_ipol.sample(_time);
      else
        dt_cur = _prev_dt;
      _reset_dt = false;
    }
  }

  return dt_cur;

}

Real
Transient::computeDT()
{
  if (!lastSolveConverged())
  {
    _cutback_occurred = true;
    //std::cout<<"Solve failed... cutting timestep"<<std::endl;
    //return _dt / 2.0;

    // Instead of blindly cutting timestep, respect dtmin.
    if (_dt <= _dtmin)
      mooseError("Solve failed and timestep already at or below dtmin, cannot continue!");

    if (0.5 * _dt >= _dtmin)
      return 0.5 * _dt;

    else // (0.5 * _dt < _dtmin)
      return _dtmin;
  }

  Real dt = _dt;
  if (_use_time_ipol)
  {
    dt = _time_ipol.sample(_time);
    if (_cutback_occurred &&
        dt > _dt * _growth_factor)
    {
      dt = _dt * _growth_factor;
    }
  }

  _cutback_occurred = false;
  return dt;
}

bool
Transient::keepGoing()
{
  // Check for stop condition based upon steady-state check flag:
  if(_converged && _trans_ss_check == true && _time > _ss_tmin)
  {
    // Compute new time solution l2_norm
    Real new_time_solution_norm = _problem.getNonlinearSystem().currentSolution()->l2_norm();

    // Compute l2_norm relative error
    Real ss_relerr_norm = fabs(new_time_solution_norm - _old_time_solution_norm)/new_time_solution_norm;

    // Check current solution relative error norm against steady-state tolerance
    if(ss_relerr_norm < _ss_check_tol)
    {
      std::cout<<"Steady-State Solution Achieved at time: "<<_time<<std::endl;
      return false;
    }
    else // Keep going
    {
      // Update solution norm for next time step
      _old_time_solution_norm = new_time_solution_norm;
      // Print steady-state relative error norm
      std::cout<<"Steady-State Relative Differential Norm: "<<ss_relerr_norm<<std::endl;
    }
  }

  // Check for stop condition based upon number of simulation steps and/or solution end time:
  if(_t_step>_num_steps)
    return false;

  if((_time>_end_time) || (fabs(_time-_end_time)<1.e-14))
    return false;

  return true;
}

bool
Transient::lastSolveConverged()
{
  return _converged;
}

void
Transient::preExecute()
{
  Executioner::preExecute();
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2013 Intel Corporation
 *
 * 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 (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "main/teximage.h"
#include "main/blend.h"
#include "main/fbobject.h"
#include "main/renderbuffer.h"
#include "main/glformats.h"

#include "util/ralloc.h"

#include "intel_fbo.h"

#include "brw_blorp.h"
#include "brw_meta_util.h"
#include "brw_context.h"
#include "brw_eu.h"
#include "brw_state.h"

#include "nir_builder.h"

#define FILE_DEBUG_FLAG DEBUG_BLORP

struct brw_blorp_const_color_prog_key
{
   bool use_simd16_replicated_data;
   bool pad[3];
};

static void
brw_blorp_params_get_clear_kernel(struct brw_context *brw,
                                  struct brw_blorp_params *params,
                                  bool use_replicated_data)
{
   struct brw_blorp_const_color_prog_key blorp_key;
   memset(&blorp_key, 0, sizeof(blorp_key));
   blorp_key.use_simd16_replicated_data = use_replicated_data;

   if (brw_search_cache(&brw->cache, BRW_CACHE_BLORP_PROG,
                        &blorp_key, sizeof(blorp_key),
                        &params->wm_prog_kernel, &params->wm_prog_data))
      return;

   void *mem_ctx = ralloc_context(NULL);

   nir_builder b;
   nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
   b.shader->info.name = ralloc_strdup(b.shader, "BLORP-clear");

   nir_variable *v_color = nir_variable_create(b.shader, nir_var_shader_in,
                                               glsl_vec4_type(), "v_color");
   v_color->data.location = VARYING_SLOT_VAR0;
   v_color->data.interpolation = INTERP_MODE_FLAT;

   nir_variable *frag_color = nir_variable_create(b.shader, nir_var_shader_out,
                                                  glsl_vec4_type(),
                                                  "gl_FragColor");
   frag_color->data.location = FRAG_RESULT_COLOR;

   nir_copy_var(&b, frag_color, v_color);

   struct brw_wm_prog_key wm_key;
   brw_blorp_init_wm_prog_key(&wm_key);

   struct brw_blorp_prog_data prog_data;
   unsigned program_size;
   const unsigned *program =
      brw_blorp_compile_nir_shader(brw, b.shader, &wm_key, use_replicated_data,
                                   &prog_data, &program_size);

   brw_upload_cache(&brw->cache, BRW_CACHE_BLORP_PROG,
                    &blorp_key, sizeof(blorp_key),
                    program, program_size,
                    &prog_data, sizeof(prog_data),
                    &params->wm_prog_kernel, &params->wm_prog_data);

   ralloc_free(mem_ctx);
}

static bool
set_write_disables(const struct intel_renderbuffer *irb,
                   const GLubyte *color_mask, bool *color_write_disable)
{
   /* Format information in the renderbuffer represents the requirements
    * given by the client. There are cases where the backing miptree uses,
    * for example, RGBA to represent RGBX. Since the client is only expecting
    * RGB we can treat alpha as not used and write whatever we like into it.
    */
   const GLenum base_format = irb->Base.Base._BaseFormat;
   const int components = _mesa_base_format_component_count(base_format);
   bool disables = false;

   assert(components > 0);

   for (int i = 0; i < components; i++) {
      color_write_disable[i] = !color_mask[i];
      disables = disables || !color_mask[i];
   }

   return disables;
}

static bool
do_single_blorp_clear(struct brw_context *brw, struct gl_framebuffer *fb,
                      struct gl_renderbuffer *rb, unsigned buf,
                      bool partial_clear, bool encode_srgb, unsigned layer)
{
   struct gl_context *ctx = &brw->ctx;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
   mesa_format format = irb->mt->format;

   struct brw_blorp_params params;
   brw_blorp_params_init(&params);

   /* Override the surface format according to the context's sRGB rules. */
   if (!encode_srgb && _mesa_get_format_color_encoding(format) == GL_SRGB)
      format = _mesa_get_srgb_format_linear(format);

   params.x0 = fb->_Xmin;
   params.x1 = fb->_Xmax;
   if (rb->Name != 0) {
      params.y0 = fb->_Ymin;
      params.y1 = fb->_Ymax;
   } else {
      params.y0 = rb->Height - fb->_Ymax;
      params.y1 = rb->Height - fb->_Ymin;
   }

   memcpy(&params.wm_inputs, ctx->Color.ClearColor.f, sizeof(float) * 4);

   bool use_simd16_replicated_data = true;

   /* From the SNB PRM (Vol4_Part1):
    *
    *     "Replicated data (Message Type = 111) is only supported when
    *      accessing tiled memory.  Using this Message Type to access linear
    *      (untiled) memory is UNDEFINED."
    */
   if (irb->mt->tiling == I915_TILING_NONE)
      use_simd16_replicated_data = false;

   /* Constant color writes ignore everyting in blend and color calculator
    * state.  This is not documented.
    */
   if (set_write_disables(irb, ctx->Color.ColorMask[buf],
                          params.color_write_disable))
      use_simd16_replicated_data = false;

   bool is_fast_clear = false;
   if (irb->mt->fast_clear_state != INTEL_FAST_CLEAR_STATE_NO_MCS &&
       !partial_clear && use_simd16_replicated_data &&
       brw_is_color_fast_clear_compatible(brw, irb->mt,
                                          &ctx->Color.ClearColor)) {
      /* Record the clear color in the miptree so that it will be
       * programmed in SURFACE_STATE by later rendering and resolve
       * operations.
       */
      const bool color_updated = brw_meta_set_fast_clear_color(
                                    brw, irb->mt, &ctx->Color.ClearColor);

      /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the clear
       * is redundant and can be skipped.
       */
      if (!color_updated &&
          irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR)
         return true;

      /* If the MCS buffer hasn't been allocated yet, we need to allocate
       * it now.
       */
      if (!irb->mt->mcs_mt) {
         if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) {
            /* MCS allocation failed--probably this will only happen in
             * out-of-memory conditions.  But in any case, try to recover
             * by falling back to a non-blorp clear technique.
             */
            return false;
         }
      }

      is_fast_clear = true;
   }

   intel_miptree_check_level_layer(irb->mt, irb->mt_level, layer);
   intel_miptree_used_for_rendering(irb->mt);

   struct isl_surf isl_tmp[2];
   struct brw_blorp_surf surf;
   unsigned level = irb->mt_level;
   brw_blorp_surf_for_miptree(brw, &surf, irb->mt, true, &level, isl_tmp);
   brw_blorp_surface_info_init(brw, &params.dst, &surf, level, layer,
                               brw_blorp_to_isl_format(brw, format, true),
                               true);

   if (is_fast_clear) {
      memset(&params.wm_inputs, 0xff, 4*sizeof(float));
      params.fast_clear_op = GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE;

      brw_get_fast_clear_rect(brw, &params.dst.aux_surf, &params.x0, &params.y0,
                              &params.x1, &params.y1);
   }

   brw_blorp_params_get_clear_kernel(brw, &params, use_simd16_replicated_data);

   const char *clear_type;
   if (is_fast_clear)
      clear_type = "fast";
   else if (use_simd16_replicated_data)
      clear_type = "replicated";
   else
      clear_type = "slow";

   DBG("%s (%s) to mt %p level %d layer %d\n", __FUNCTION__, clear_type,
       irb->mt, irb->mt_level, irb->mt_layer);

   brw_blorp_exec(brw, &params);

   if (is_fast_clear) {
      /* Now that the fast clear has occurred, put the buffer in
       * INTEL_FAST_CLEAR_STATE_CLEAR so that we won't waste time doing
       * redundant clears.
       */
      irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR;
   } else if (intel_miptree_is_lossless_compressed(brw, irb->mt)) {
      /* Compressed buffers can be cleared also using normal rep-clear. In
       * such case they bahave such as if they were drawn using normal 3D
       * render pipeline, and we simply mark the mcs as dirty.
       */
      assert(partial_clear);
      irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_UNRESOLVED;
   }

   return true;
}

extern "C" {
bool
brw_blorp_clear_color(struct brw_context *brw, struct gl_framebuffer *fb,
                      GLbitfield mask, bool partial_clear, bool encode_srgb)
{
   for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) {
      struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf];
      struct intel_renderbuffer *irb = intel_renderbuffer(rb);

      /* Only clear the buffers present in the provided mask */
      if (((1 << fb->_ColorDrawBufferIndexes[buf]) & mask) == 0)
         continue;

      /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
       * the framebuffer can be complete with some attachments missing.  In
       * this case the _ColorDrawBuffers pointer will be NULL.
       */
      if (rb == NULL)
         continue;

      if (fb->MaxNumLayers > 0) {
         unsigned layer_multiplier =
            (irb->mt->msaa_layout == INTEL_MSAA_LAYOUT_UMS ||
             irb->mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS) ?
            irb->mt->num_samples : 1;
         unsigned num_layers = irb->layer_count;
         for (unsigned layer = 0; layer < num_layers; layer++) {
            if (!do_single_blorp_clear(
                    brw, fb, rb, buf, partial_clear, encode_srgb,
                    irb->mt_layer + layer * layer_multiplier)) {
               return false;
            }
         }
      } else {
         unsigned layer = irb->mt_layer;
         if (!do_single_blorp_clear(brw, fb, rb, buf, partial_clear,
                                    encode_srgb, layer))
            return false;
      }

      irb->need_downsample = true;
   }

   return true;
}

static void
brw_blorp_ccs_resolve(struct brw_context *brw, struct brw_blorp_surf *surf,
                      enum isl_format format)
{
   struct brw_blorp_params params;
   brw_blorp_params_init(&params);

   brw_blorp_surface_info_init(brw, &params.dst, surf,
                               0 /* level */, 0 /* layer */, format, true);

   brw_get_ccs_resolve_rect(&brw->isl_dev, &params.dst.aux_surf,
                            &params.x0, &params.y0,
                            &params.x1, &params.y1);

   if (params.dst.aux_usage == ISL_AUX_USAGE_CCS_E)
      params.resolve_type = GEN9_PS_RENDER_TARGET_RESOLVE_FULL;
   else
      params.resolve_type = GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE;

   /* Note: there is no need to initialize push constants because it doesn't
    * matter what data gets dispatched to the render target.  However, we must
    * ensure that the fragment shader delivers the data using the "replicated
    * color" message.
    */

   brw_blorp_params_get_clear_kernel(brw, &params, true);

   brw_blorp_exec(brw, &params);
}

void
brw_blorp_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt)
{
   DBG("%s to mt %p\n", __FUNCTION__, mt);

   const mesa_format format = _mesa_get_srgb_format_linear(mt->format);

   intel_miptree_check_level_layer(mt, 0 /* level */, 0 /* layer */);
   intel_miptree_used_for_rendering(mt);

   struct isl_surf isl_tmp[2];
   struct brw_blorp_surf surf;
   unsigned level = 0;
   brw_blorp_surf_for_miptree(brw, &surf, mt, true, &level, isl_tmp);

   brw_blorp_ccs_resolve(brw, &surf, brw_blorp_to_isl_format(brw, format, true));

   mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED;
}

} /* extern "C" */
<commit_msg>i965/blorp: Break the guts of do_single_blorp_clear into two helpers<commit_after>/*
 * Copyright © 2013 Intel Corporation
 *
 * 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 (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "main/teximage.h"
#include "main/blend.h"
#include "main/fbobject.h"
#include "main/renderbuffer.h"
#include "main/glformats.h"

#include "util/ralloc.h"

#include "intel_fbo.h"

#include "brw_blorp.h"
#include "brw_meta_util.h"
#include "brw_context.h"
#include "brw_eu.h"
#include "brw_state.h"

#include "nir_builder.h"

#define FILE_DEBUG_FLAG DEBUG_BLORP

struct brw_blorp_const_color_prog_key
{
   bool use_simd16_replicated_data;
   bool pad[3];
};

static void
brw_blorp_params_get_clear_kernel(struct brw_context *brw,
                                  struct brw_blorp_params *params,
                                  bool use_replicated_data)
{
   struct brw_blorp_const_color_prog_key blorp_key;
   memset(&blorp_key, 0, sizeof(blorp_key));
   blorp_key.use_simd16_replicated_data = use_replicated_data;

   if (brw_search_cache(&brw->cache, BRW_CACHE_BLORP_PROG,
                        &blorp_key, sizeof(blorp_key),
                        &params->wm_prog_kernel, &params->wm_prog_data))
      return;

   void *mem_ctx = ralloc_context(NULL);

   nir_builder b;
   nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
   b.shader->info.name = ralloc_strdup(b.shader, "BLORP-clear");

   nir_variable *v_color = nir_variable_create(b.shader, nir_var_shader_in,
                                               glsl_vec4_type(), "v_color");
   v_color->data.location = VARYING_SLOT_VAR0;
   v_color->data.interpolation = INTERP_MODE_FLAT;

   nir_variable *frag_color = nir_variable_create(b.shader, nir_var_shader_out,
                                                  glsl_vec4_type(),
                                                  "gl_FragColor");
   frag_color->data.location = FRAG_RESULT_COLOR;

   nir_copy_var(&b, frag_color, v_color);

   struct brw_wm_prog_key wm_key;
   brw_blorp_init_wm_prog_key(&wm_key);

   struct brw_blorp_prog_data prog_data;
   unsigned program_size;
   const unsigned *program =
      brw_blorp_compile_nir_shader(brw, b.shader, &wm_key, use_replicated_data,
                                   &prog_data, &program_size);

   brw_upload_cache(&brw->cache, BRW_CACHE_BLORP_PROG,
                    &blorp_key, sizeof(blorp_key),
                    program, program_size,
                    &prog_data, sizeof(prog_data),
                    &params->wm_prog_kernel, &params->wm_prog_data);

   ralloc_free(mem_ctx);
}

static bool
set_write_disables(const struct intel_renderbuffer *irb,
                   const GLubyte *color_mask, bool *color_write_disable)
{
   /* Format information in the renderbuffer represents the requirements
    * given by the client. There are cases where the backing miptree uses,
    * for example, RGBA to represent RGBX. Since the client is only expecting
    * RGB we can treat alpha as not used and write whatever we like into it.
    */
   const GLenum base_format = irb->Base.Base._BaseFormat;
   const int components = _mesa_base_format_component_count(base_format);
   bool disables = false;

   assert(components > 0);

   for (int i = 0; i < components; i++) {
      color_write_disable[i] = !color_mask[i];
      disables = disables || !color_mask[i];
   }

   return disables;
}

static void
blorp_fast_clear(struct brw_context *brw, const struct brw_blorp_surf *surf,
                 uint32_t level, uint32_t layer,
                 uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1)
{
   struct brw_blorp_params params;
   brw_blorp_params_init(&params);

   params.x0 = x0;
   params.y0 = y0;
   params.x1 = x1;
   params.y1 = y1;

   memset(&params.wm_inputs, 0xff, 4*sizeof(float));
   params.fast_clear_op = GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE;

   brw_get_fast_clear_rect(brw, surf->aux_surf, &params.x0, &params.y0,
                           &params.x1, &params.y1);

   brw_blorp_params_get_clear_kernel(brw, &params, true);

   brw_blorp_surface_info_init(brw, &params.dst, surf, level, layer,
                               surf->surf->format, true);

   brw_blorp_exec(brw, &params);
}

static void
blorp_clear(struct brw_context *brw, const struct brw_blorp_surf *surf,
            uint32_t level, uint32_t layer,
            uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1,
            enum isl_format format, union isl_color_value clear_color,
            bool color_write_disable[4])
{
   struct brw_blorp_params params;
   brw_blorp_params_init(&params);

   params.x0 = x0;
   params.y0 = y0;
   params.x1 = x1;
   params.y1 = y1;

   memcpy(&params.wm_inputs, clear_color.f32, sizeof(float) * 4);

   bool use_simd16_replicated_data = true;

   /* From the SNB PRM (Vol4_Part1):
    *
    *     "Replicated data (Message Type = 111) is only supported when
    *      accessing tiled memory.  Using this Message Type to access linear
    *      (untiled) memory is UNDEFINED."
    */
   if (surf->surf->tiling == ISL_TILING_LINEAR)
      use_simd16_replicated_data = false;

   /* Constant color writes ignore everyting in blend and color calculator
    * state.  This is not documented.
    */
   for (unsigned i = 0; i < 4; i++) {
      params.color_write_disable[i] = color_write_disable[i];
      if (color_write_disable[i])
         use_simd16_replicated_data = false;
   }

   brw_blorp_params_get_clear_kernel(brw, &params, use_simd16_replicated_data);

   brw_blorp_surface_info_init(brw, &params.dst, surf, level, layer,
                               format, true);

   brw_blorp_exec(brw, &params);
}

static bool
do_single_blorp_clear(struct brw_context *brw, struct gl_framebuffer *fb,
                      struct gl_renderbuffer *rb, unsigned buf,
                      bool partial_clear, bool encode_srgb, unsigned layer)
{
   struct gl_context *ctx = &brw->ctx;
   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
   mesa_format format = irb->mt->format;
   uint32_t x0, x1, y0, y1;

   if (!encode_srgb && _mesa_get_format_color_encoding(format) == GL_SRGB)
      format = _mesa_get_srgb_format_linear(format);

   x0 = fb->_Xmin;
   x1 = fb->_Xmax;
   if (rb->Name != 0) {
      y0 = fb->_Ymin;
      y1 = fb->_Ymax;
   } else {
      y0 = rb->Height - fb->_Ymax;
      y1 = rb->Height - fb->_Ymin;
   }

   bool can_fast_clear = !partial_clear;

   bool color_write_disable[4] = { false, false, false, false };
   if (set_write_disables(irb, ctx->Color.ColorMask[buf], color_write_disable))
      can_fast_clear = false;

   if (irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_NO_MCS ||
       !brw_is_color_fast_clear_compatible(brw, irb->mt, &ctx->Color.ClearColor))
      can_fast_clear = false;

   if (can_fast_clear) {
      /* Record the clear color in the miptree so that it will be
       * programmed in SURFACE_STATE by later rendering and resolve
       * operations.
       */
      const bool color_updated = brw_meta_set_fast_clear_color(
                                    brw, irb->mt, &ctx->Color.ClearColor);

      /* If the buffer is already in INTEL_FAST_CLEAR_STATE_CLEAR, the clear
       * is redundant and can be skipped.
       */
      if (!color_updated &&
          irb->mt->fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR)
         return true;

      /* If the MCS buffer hasn't been allocated yet, we need to allocate
       * it now.
       */
      if (!irb->mt->mcs_mt) {
         if (!intel_miptree_alloc_non_msrt_mcs(brw, irb->mt)) {
            /* MCS allocation failed--probably this will only happen in
             * out-of-memory conditions.  But in any case, try to recover
             * by falling back to a non-blorp clear technique.
             */
            return false;
         }
      }
   }

   intel_miptree_check_level_layer(irb->mt, irb->mt_level, layer);
   intel_miptree_used_for_rendering(irb->mt);

   /* We can't setup the blorp_surf until we've allocated the MCS above */
   struct isl_surf isl_tmp[2];
   struct brw_blorp_surf surf;
   unsigned level = irb->mt_level;
   brw_blorp_surf_for_miptree(brw, &surf, irb->mt, true, &level, isl_tmp);

   if (can_fast_clear) {
      DBG("%s (fast) to mt %p level %d layer %d\n", __FUNCTION__,
          irb->mt, irb->mt_level, irb->mt_layer);

      blorp_fast_clear(brw, &surf, level, layer, x0, y0, x1, y1);

      /* Now that the fast clear has occurred, put the buffer in
       * INTEL_FAST_CLEAR_STATE_CLEAR so that we won't waste time doing
       * redundant clears.
       */
      irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR;
   } else {
      DBG("%s (slow) to mt %p level %d layer %d\n", __FUNCTION__,
          irb->mt, irb->mt_level, irb->mt_layer);

      union isl_color_value clear_color;
      memcpy(clear_color.f32, ctx->Color.ClearColor.f, sizeof(float) * 4);

      blorp_clear(brw, &surf, level, layer, x0, y0, x1, y1,
                  (enum isl_format)brw->render_target_format[format],
                  clear_color, color_write_disable);

      if (intel_miptree_is_lossless_compressed(brw, irb->mt)) {
         /* Compressed buffers can be cleared also using normal rep-clear. In
          * such case they bahave such as if they were drawn using normal 3D
          * render pipeline, and we simply mark the mcs as dirty.
          */
         assert(partial_clear);
         irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_UNRESOLVED;
      }
   }

   return true;
}

extern "C" {
bool
brw_blorp_clear_color(struct brw_context *brw, struct gl_framebuffer *fb,
                      GLbitfield mask, bool partial_clear, bool encode_srgb)
{
   for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) {
      struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf];
      struct intel_renderbuffer *irb = intel_renderbuffer(rb);

      /* Only clear the buffers present in the provided mask */
      if (((1 << fb->_ColorDrawBufferIndexes[buf]) & mask) == 0)
         continue;

      /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
       * the framebuffer can be complete with some attachments missing.  In
       * this case the _ColorDrawBuffers pointer will be NULL.
       */
      if (rb == NULL)
         continue;

      if (fb->MaxNumLayers > 0) {
         unsigned layer_multiplier =
            (irb->mt->msaa_layout == INTEL_MSAA_LAYOUT_UMS ||
             irb->mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS) ?
            irb->mt->num_samples : 1;
         unsigned num_layers = irb->layer_count;
         for (unsigned layer = 0; layer < num_layers; layer++) {
            if (!do_single_blorp_clear(
                    brw, fb, rb, buf, partial_clear, encode_srgb,
                    irb->mt_layer + layer * layer_multiplier)) {
               return false;
            }
         }
      } else {
         unsigned layer = irb->mt_layer;
         if (!do_single_blorp_clear(brw, fb, rb, buf, partial_clear,
                                    encode_srgb, layer))
            return false;
      }

      irb->need_downsample = true;
   }

   return true;
}

static void
brw_blorp_ccs_resolve(struct brw_context *brw, struct brw_blorp_surf *surf,
                      enum isl_format format)
{
   struct brw_blorp_params params;
   brw_blorp_params_init(&params);

   brw_blorp_surface_info_init(brw, &params.dst, surf,
                               0 /* level */, 0 /* layer */, format, true);

   brw_get_ccs_resolve_rect(&brw->isl_dev, &params.dst.aux_surf,
                            &params.x0, &params.y0,
                            &params.x1, &params.y1);

   if (params.dst.aux_usage == ISL_AUX_USAGE_CCS_E)
      params.resolve_type = GEN9_PS_RENDER_TARGET_RESOLVE_FULL;
   else
      params.resolve_type = GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE;

   /* Note: there is no need to initialize push constants because it doesn't
    * matter what data gets dispatched to the render target.  However, we must
    * ensure that the fragment shader delivers the data using the "replicated
    * color" message.
    */

   brw_blorp_params_get_clear_kernel(brw, &params, true);

   brw_blorp_exec(brw, &params);
}

void
brw_blorp_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt)
{
   DBG("%s to mt %p\n", __FUNCTION__, mt);

   const mesa_format format = _mesa_get_srgb_format_linear(mt->format);

   intel_miptree_check_level_layer(mt, 0 /* level */, 0 /* layer */);
   intel_miptree_used_for_rendering(mt);

   struct isl_surf isl_tmp[2];
   struct brw_blorp_surf surf;
   unsigned level = 0;
   brw_blorp_surf_for_miptree(brw, &surf, mt, true, &level, isl_tmp);

   brw_blorp_ccs_resolve(brw, &surf, brw_blorp_to_isl_format(brw, format, true));

   mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED;
}

} /* extern "C" */
<|endoftext|>


<commit_before>// FRAGMENT(includes)
#include <seqan/file.h>
#include <iostream>

using namespace seqan;

// FRAGMENT(open_file)
int main (int argc, char const ** argv)
{
// FRAGMENT(open-guess-split)
    MultiSeqFile multiSeqFile;
    if (argc < 2 || !open(multiSeqFile.concat, argv[1], OPEN_RDONLY))
        return 1;

    AutoSeqFormat format;
    guessFormat(multiSeqFile.concat, format);
    split(multiSeqFile, format);

// FRAGMENT(load)
    unsigned seqCount = length(multiSeqFile);
    StringSet<String<Dna5Q> > seqs;
    StringSet<CharString> seqIDs;

    reserve(seqs, seqCount, Exact());
    reserve(seqIDs, seqCount, Exact());

    String<Dna5Q> seq;
    CharString qual;
    CharString id;

// FRAGMENT(output)
    for (unsigned i = 0; i < seqCount; ++i)
    {
        assignSeq(seq, multiSeqFile[i], format);    // read sequence
        assignQual(qual, multiSeqFile[i], format);  // read ascii quality values
        assignSeqId(id, multiSeqFile[i], format);   // read sequence id

        // Convert ascii to values from 0..62.
        // We store DNA and quality together in Dna5Q.
        for (unsigned j = 0; j < length(qual) && j < length(seq); ++j)
            assignQualityValue(seq[j], static_cast<int>(ordValue(qual[j]) - 33));

        // We use reserve and append, as assign is not supported
        // by StringSet<..., Owner<ConcatDirect<> > >
        appendValue(seqs, seq, Generous());
        appendValue(seqIDs, id, Generous());
    }
// FRAGMENT(return)
    return 0;
}
<commit_msg>[DOC] Update to `stream_multi_seq_file.cpp`.<commit_after>// FRAGMENT(includes-main)
#include <seqan/file.h>
#include <iostream>

int main (int argc, char const ** argv)
{
// FRAGMENT(open)
    seqan::MultiSeqFile multiSeqFile;
    if (argc < 2 || !open(multiSeqFile.concat, argv[1], seqan::OPEN_RDONLY))
        return 1;

// FRAGMENT(guess)
    seqan::AutoSeqFormat format;
    guessFormat(multiSeqFile.concat, format);
// FRAGMENT(split)
    split(multiSeqFile, format);

// FRAGMENT(load)
    unsigned seqCount = length(multiSeqFile);
    seqan::StringSet<seqan::String<seqan::Dna5Q> > seqs;
    seqan::StringSet<seqan::CharString> seqIDs;

    reserve(seqs, seqCount, seqan::Exact());
    reserve(seqIDs, seqCount, seqan::Exact());

// FRAGMENT(buffers)
    seqan::String<seqan::Dna5Q> seq;
    seqan::CharString qual;
    seqan::CharString id;

// FRAGMENT(output)
    for (unsigned i = 0; i < seqCount; ++i)
    {
        assignSeq(seq, multiSeqFile[i], format);    // read sequence
        assignQual(qual, multiSeqFile[i], format);  // read ascii quality values
        assignSeqId(id, multiSeqFile[i], format);   // read sequence id

        // Convert ascii to values from 0..62.
        // We store DNA and quality together in Dna5Q.
        for (unsigned j = 0; j < length(qual) && j < length(seq); ++j)
            assignQualityValue(seq[j], static_cast<int>(seqan::ordValue(qual[j]) - 33));

        // We use reserve and append, as assign is not supported by
        // StringSet<..., Owner<ConcatDirect<> > >
        appendValue(seqs, seq);
        appendValue(seqIDs, id);
    }

// FRAGMENT(return)
    return 0;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "iterators.hpp"
#include "VisitorUtils.hpp"
#include "Type.hpp"
#include "FunctionContext.hpp"
#include "logging.hpp"
#include "Variable.hpp"

#include "mtac/Loop.hpp"
#include "mtac/induction_variable_optimizations.hpp"
#include "mtac/VariableReplace.hpp"
#include "mtac/Function.hpp"
#include "mtac/ControlFlowGraph.hpp"
#include "mtac/Quadruple.hpp"
#include "mtac/Utils.hpp"
#include "mtac/variable_usage.hpp"

using namespace eddic;

namespace {

bool strength_reduce(mtac::Loop& loop, mtac::LinearEquation& basic_equation, mtac::Function& function){
    auto& dependent_induction_variables = loop.dependent_induction_variables();

    mtac::basic_block_p pre_header = nullptr;
    bool optimized = false;

    mtac::InductionVariables new_induction_variables;

    auto i = basic_equation.i;

    for(auto& dependent : dependent_induction_variables){
        auto& equation = dependent.second;
        if(equation.i == i){
            auto j = dependent.first;

            auto tj = function.context->new_temporary(INT);
            auto db = equation.e * basic_equation.d;

            mtac::VariableClones variable_clones;
            variable_clones[j] = tj;

            mtac::VariableReplace replacer(variable_clones);

            //There is only a single assignment to j, replace it with j = tj
            function.find(equation.def).op = mtac::Operator::ASSIGN;
            function.find(equation.def).arg1 = tj;
            function.find(equation.def).arg2.reset();

            for(auto& bb : loop){
                auto it = iterate(bb->statements);
                bool here = false;

                while(it.has_next()){
                    auto& quadruple = *it;

                    //To avoid replacing j by tj
                    if(quadruple.uid() == equation.def){
                        ++it;
                        continue;
                    }
                    else if(quadruple.uid() == basic_equation.def){
                        here = true;
                        ++it;
                    }

                    if(!it.has_next()){
                        break;
                    }

                    replacer.replace(*it);

                    ++it;
                }

                if(here){
                    auto sit = bb->statements.end();
                    --sit;

                    bb->statements.insert(sit, mtac::Quadruple(tj, tj, mtac::Operator::ADD, db));
                }
            }

            //Create the preheader if necessary
            if(!pre_header){
                pre_header = mtac::find_pre_header(loop, function);
            }

            pre_header->emplace_back(tj, equation.e, mtac::Operator::MUL, i);
            pre_header->emplace_back(tj, tj, mtac::Operator::ADD, equation.d);

            optimized = true;
        }
    }

    for(auto& new_var : new_induction_variables){
        dependent_induction_variables[new_var.first] = new_var.second;
    }

    return optimized;
}

void induction_variable_removal(mtac::Function& function, mtac::Loop& loop){
    auto& dependent_induction_variables = loop.dependent_induction_variables();

    mtac::Usage usage = compute_read_usage(loop);
    mtac::Usage function_usage = compute_read_usage(function);

    //Remove generated copy when useless
    for(auto& bb : loop){
        auto it = iterate(bb->statements);

        while(it.has_next()){
            auto& quadruple = *it;
            auto op = quadruple.op;

            if(op == mtac::Operator::ASSIGN && mtac::isVariable(*quadruple.arg1)){
                auto j = quadruple.result;
                auto tj = boost::get<std::shared_ptr<Variable>>(*quadruple.arg1);

                //If j = tj generated in strength reduction phase
                if(dependent_induction_variables.count(j) && dependent_induction_variables.count(tj)){
                    if(dependent_induction_variables[tj].generated && usage.read[j] == 0){
                        LOG<Trace>("Loops") << "Remove copy " << j->name() << "=" << tj->name() << " generated during strength reduction" << log::endl;

                        //There is one less read of tj
                        --usage.read[tj];

                        dependent_induction_variables.erase(j);

                        it.erase();
                        continue;
                    }
                }
            }

            //Remove statements generated during strength reduction that are not necessary
            if(op == mtac::Operator::ADD && mtac::isVariable(*quadruple.arg1)){
                auto j = quadruple.result;
                auto tj = boost::get<std::shared_ptr<Variable>>(*quadruple.arg1);

                if(j == tj && usage.read[j] == 1 && function_usage.read[j] == 1){
                    //If it is a dependent induction variable, remove it
                    if(dependent_induction_variables.count(j)){
                        dependent_induction_variables.erase(j);
                    }

                    //There is one less read of j
                    --usage.read[j];

                    it.erase();
                    continue;
                }
            }

            ++it;
        }
    }

    std::vector<std::shared_ptr<Variable>> removed_variables;

    //Remove induction variables that contribute only to themselves
    for(auto& var : dependent_induction_variables){
        if(usage.read[var.first] == 1){
            auto& def = function.find(var.second.def);

            def.op = mtac::Operator::NOP;
            def.result = nullptr;
            def.arg1.reset();
            def.arg2.reset();

            usage.read[var.first] = 0;

            removed_variables.push_back(var.first);

            LOG<Trace>("Loops") << "Remove DIV " << var.first->name() << log::endl;
        }
    }

    for(auto& variable : removed_variables){
        dependent_induction_variables.erase(variable);
    }
}

void induction_variable_replace(mtac::Function& function, mtac::Loop& loop){
    auto& basic_induction_variables = loop.basic_induction_variables();
    auto& dependent_induction_variables = loop.dependent_induction_variables();

    auto exit_block = *loop.blocks().rbegin();

    auto& if_ = exit_block->statements.back();

    std::shared_ptr<Variable> biv;
    int end = 0;

    if(if_.is_if()){
        if(if_.op != mtac::Operator::IF_UNARY && if_.op <= mtac::Operator::IF_LESS_EQUALS){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg1);
                end = boost::get<int>(*if_.arg2);
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg2);
                end = boost::get<int>(*if_.arg1);
            }
        }
    } else if(if_.is_if_false()){
        if(if_.op != mtac::Operator::IF_FALSE_UNARY && if_.op <= mtac::Operator::IF_FALSE_LESS_EQUALS){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg1);
                end = boost::get<int>(*if_.arg2);
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg2);
                end = boost::get<int>(*if_.arg1);
            }
        }
    }

    //The loop is only countable if the condition depends on biv and the biv is increasing
    if(!biv || !basic_induction_variables.count(biv) || basic_induction_variables[biv].d <= 0){
        return;
    }

    mtac::Usage usage = compute_read_usage(loop);

    //If biv is only used to compute itself (as a basic induction variable) and in the condition
    if(usage.read[biv] == 2){
        std::shared_ptr<Variable> div;

        for(auto& d : dependent_induction_variables){
            auto eq = d.second;
            auto& def = function.find(eq.def);

            if(def.op != mtac::Operator::NOP && eq.i == biv && eq.e > 0){
                div = d.first;
                break;
            }
        }

        //If there are no candidate
        if(!div){
            return;
        }

        LOG<Trace>("Loops") << "Replace BIV " << biv->name() << " by DIV " << div->name() << log::endl;

        auto div_equation = dependent_induction_variables[div];
        auto new_end = div_equation.e * (end-1) + div_equation.d;

        usage.read[biv] = 0;

        //Update the exit condition
        if(if_.is_if()){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                if_.arg1 = div;
                if_.arg2 = new_end;
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                if_.arg2 = div;
                if_.arg1 = new_end;
            }
        } else if(if_.is_if_false()){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                if_.arg1 = div;
                if_.arg2 = new_end;
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                if_.arg2 = div;
                if_.arg1 = new_end;
            }
        }

        //The unique assignment to i is not useful anymore
        auto& def = function.find(basic_induction_variables[biv].def);
        def.op = mtac::Operator::NOP;
        def.result = nullptr;
        def.arg1.reset();
        def.arg2.reset();

        //Not a basic induction variable anymore
        basic_induction_variables.erase(biv);
    }
}

bool loop_induction_variables_optimization(mtac::Loop& loop, mtac::Function& function){
    bool optimized = false;

    //1. Strength reduction on each dependent induction variables
    for(auto& basic : loop.basic_induction_variables()){
        optimized |= strength_reduce(loop, basic.second, function);
    }

    for(auto& biv : loop.basic_induction_variables()){
        if(biv.second.div){
            LOG<Trace>("Loops") << "BIV: " << biv.first->name() << " = " << biv.second.i->name() << " / " << biv.second.e << " + " << biv.second.d << log::endl;
        } else {
            LOG<Trace>("Loops") << "BIV: " << biv.first->name() << " = " << biv.second.e << " * " << biv.second.i->name() << " + " << biv.second.d << log::endl;
        }
    }

    for(auto& biv : loop.dependent_induction_variables()){
        LOG<Trace>("Loops") << "DIV: " << biv.first->name() << " = " << biv.second.e << " * " << biv.second.i->name() << " + " << biv.second.d << " g:" << biv.second.generated << log::endl;
    }

    //2. Removal of dependent induction variables
    induction_variable_removal(function, loop);

    //3. Replace basic induction variable with another dependent variable
    induction_variable_replace(function, loop);

    return optimized;
}

} //end of anonymous namespace

bool mtac::loop_induction_variables_optimization::operator()(mtac::Function& function){
    if(function.loops().empty()){
        return false;
    }

    bool optimized = false;

    for(auto& loop : function.loops()){
        optimized |= ::loop_induction_variables_optimization(loop, function);
    }

    return optimized;
}
<commit_msg>Cleanup<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "iterators.hpp"
#include "VisitorUtils.hpp"
#include "Type.hpp"
#include "FunctionContext.hpp"
#include "logging.hpp"
#include "Variable.hpp"

#include "mtac/Loop.hpp"
#include "mtac/induction_variable_optimizations.hpp"
#include "mtac/VariableReplace.hpp"
#include "mtac/Function.hpp"
#include "mtac/ControlFlowGraph.hpp"
#include "mtac/Quadruple.hpp"
#include "mtac/Utils.hpp"
#include "mtac/variable_usage.hpp"

using namespace eddic;

namespace {

bool strength_reduce(mtac::Loop& loop, mtac::LinearEquation& basic_equation, mtac::Function& function){
    auto& dependent_induction_variables = loop.dependent_induction_variables();

    mtac::basic_block_p pre_header = nullptr;
    bool optimized = false;

    mtac::InductionVariables new_induction_variables;

    auto i = basic_equation.i;

    for(auto& dependent : dependent_induction_variables){
        auto& equation = dependent.second;
        if(equation.i == i){
            auto j = dependent.first;

            auto tj = function.context->new_temporary(INT);
            auto db = equation.e * basic_equation.d;

            mtac::VariableClones variable_clones;
            variable_clones[j] = tj;

            mtac::VariableReplace replacer(variable_clones);

            //There is only a single assignment to j, replace it with j = tj
            function.find(equation.def).op = mtac::Operator::ASSIGN;
            function.find(equation.def).arg1 = tj;
            function.find(equation.def).arg2.reset();

            for(auto& bb : loop){
                auto it = iterate(bb->statements);
                bool here = false;

                while(it.has_next()){
                    auto& quadruple = *it;

                    //To avoid replacing j by tj
                    if(quadruple.uid() == equation.def){
                        ++it;
                        continue;
                    }
                    else if(quadruple.uid() == basic_equation.def){
                        here = true;
                        ++it;
                    }

                    if(!it.has_next()){
                        break;
                    }

                    replacer.replace(*it);

                    ++it;
                }

                if(here){
                    auto sit = bb->statements.end();
                    --sit;

                    bb->statements.insert(sit, mtac::Quadruple(tj, tj, mtac::Operator::ADD, db));
                }
            }

            //Create the preheader if necessary
            if(!pre_header){
                pre_header = mtac::find_pre_header(loop, function);
            }

            pre_header->emplace_back(tj, equation.e, mtac::Operator::MUL, i);
            pre_header->emplace_back(tj, tj, mtac::Operator::ADD, equation.d);

            optimized = true;
        }
    }

    for(auto& new_var : new_induction_variables){
        dependent_induction_variables[new_var.first] = new_var.second;
    }

    return optimized;
}

void induction_variable_removal(mtac::Function& function, mtac::Loop& loop){
    auto& dependent_induction_variables = loop.dependent_induction_variables();

    mtac::Usage usage = compute_read_usage(loop);
    mtac::Usage function_usage = compute_read_usage(function);

    //Remove generated copy when useless
    for(auto& bb : loop){
        auto it = iterate(bb->statements);

        while(it.has_next()){
            auto& quadruple = *it;
            auto op = quadruple.op;

            if(op == mtac::Operator::ASSIGN && mtac::isVariable(*quadruple.arg1)){
                auto j = quadruple.result;
                auto tj = boost::get<std::shared_ptr<Variable>>(*quadruple.arg1);

                //If j = tj generated in strength reduction phase
                if(dependent_induction_variables.count(j) && dependent_induction_variables.count(tj)){
                    if(dependent_induction_variables[tj].generated && usage.read[j] == 0){
                        LOG<Trace>("Loops") << "Remove copy " << j->name() << "=" << tj->name() << " generated during strength reduction" << log::endl;

                        //There is one less read of tj
                        --usage.read[tj];

                        dependent_induction_variables.erase(j);

                        it.erase();
                        continue;
                    }
                }
            }

            //Remove statements generated during strength reduction that are not necessary
            if(op == mtac::Operator::ADD && mtac::isVariable(*quadruple.arg1)){
                auto j = quadruple.result;
                auto tj = boost::get<std::shared_ptr<Variable>>(*quadruple.arg1);

                if(j == tj && usage.read[j] == 1 && function_usage.read[j] == 1){
                    //If it is a dependent induction variable, remove it
                    if(dependent_induction_variables.count(j)){
                        dependent_induction_variables.erase(j);
                    }

                    //There is one less read of j
                    --usage.read[j];

                    it.erase();
                    continue;
                }
            }

            ++it;
        }
    }

    std::vector<std::shared_ptr<Variable>> removed_variables;

    //Remove induction variables that contribute only to themselves
    for(auto& var : dependent_induction_variables){
        if(usage.read[var.first] == 1){
            auto& def = function.find(var.second.def);

            def.op = mtac::Operator::NOP;
            def.result = nullptr;
            def.arg1.reset();
            def.arg2.reset();

            usage.read[var.first] = 0;

            removed_variables.push_back(var.first);

            LOG<Trace>("Loops") << "Remove DIV " << var.first->name() << log::endl;
        }
    }

    for(auto& variable : removed_variables){
        dependent_induction_variables.erase(variable);
    }
}

void induction_variable_replace(mtac::Function& function, mtac::Loop& loop){
    auto& basic_induction_variables = loop.basic_induction_variables();
    auto& dependent_induction_variables = loop.dependent_induction_variables();

    auto exit_block = *loop.blocks().rbegin();

    auto& if_ = exit_block->statements.back();

    std::shared_ptr<Variable> biv;
    int end = 0;

    if(if_.is_if()){
        if(if_.op != mtac::Operator::IF_UNARY && if_.op <= mtac::Operator::IF_LESS_EQUALS){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg1);
                end = boost::get<int>(*if_.arg2);
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg2);
                end = boost::get<int>(*if_.arg1);
            }
        }
    } else if(if_.is_if_false()){
        if(if_.op != mtac::Operator::IF_FALSE_UNARY && if_.op <= mtac::Operator::IF_FALSE_LESS_EQUALS){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg1);
                end = boost::get<int>(*if_.arg2);
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                biv = boost::get<std::shared_ptr<Variable>>(*if_.arg2);
                end = boost::get<int>(*if_.arg1);
            }
        }
    }

    //The loop is only countable if the condition depends on biv and the biv is increasing
    if(!biv || !basic_induction_variables.count(biv) || basic_induction_variables[biv].d <= 0){
        return;
    }

    mtac::Usage usage = compute_read_usage(loop);

    //If biv is only used to compute itself (as a basic induction variable) and in the condition
    if(usage.read[biv] == 2){
        std::shared_ptr<Variable> div;

        for(auto& d : dependent_induction_variables){
            auto eq = d.second;
            auto& def = function.find(eq.def);

            if(def.op != mtac::Operator::NOP && eq.i == biv && eq.e > 0){
                div = d.first;
                break;
            }
        }

        //If there are no candidate
        if(!div){
            return;
        }

        LOG<Trace>("Loops") << "Replace BIV " << biv->name() << " by DIV " << div->name() << log::endl;

        auto div_equation = dependent_induction_variables[div];
        auto new_end = div_equation.e * (end-1) + div_equation.d;

        usage.read[biv] = 0;

        //Update the exit condition
        if(if_.is_if()){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                if_.arg1 = div;
                if_.arg2 = new_end;
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                if_.arg2 = div;
                if_.arg1 = new_end;
            }
        } else if(if_.is_if_false()){
            if(mtac::isVariable(*if_.arg1) && mtac::isInt(*if_.arg2)){
                if_.arg1 = div;
                if_.arg2 = new_end;
            } else if(mtac::isVariable(*if_.arg2) && mtac::isInt(*if_.arg1)){
                if_.arg2 = div;
                if_.arg1 = new_end;
            }
        }

        //The unique assignment to i is not useful anymore
        auto& def = function.find(basic_induction_variables[biv].def);
        def.op = mtac::Operator::NOP;
        def.result = nullptr;
        def.arg1.reset();
        def.arg2.reset();

        //Not a basic induction variable anymore
        basic_induction_variables.erase(biv);
    }
}

bool loop_induction_variables_optimization(mtac::Loop& loop, mtac::Function& function){
    bool optimized = false;

    //1. Strength reduction on each dependent induction variables
    for(auto& basic : loop.basic_induction_variables()){
        optimized |= strength_reduce(loop, basic.second, function);
    }

    for(auto& biv : loop.basic_induction_variables()){
        if(biv.second.div){
            LOG<Trace>("Loops") << "BIV: " << biv.first->name() << " = " << biv.second.i->name() << " / " << biv.second.e << " + " << biv.second.d << log::endl;
        } else {
            LOG<Trace>("Loops") << "BIV: " << biv.first->name() << " = " << biv.second.e << " * " << biv.second.i->name() << " + " << biv.second.d << log::endl;
        }
    }

    for(auto& biv : loop.dependent_induction_variables()){
        LOG<Trace>("Loops") << "DIV: " << biv.first->name() << " = " << biv.second.e << " * " << biv.second.i->name() << " + " << biv.second.d << " g:" << biv.second.generated << log::endl;
    }

    //2. Removal of dependent induction variables
    induction_variable_removal(function, loop);

    //3. Replace basic induction variable with another dependent variable
    induction_variable_replace(function, loop);

    return optimized;
}

} //end of anonymous namespace

bool mtac::loop_induction_variables_optimization::operator()(mtac::Function& function){
    if(function.loops().empty()){
        return false;
    }

    bool optimized = false;

    for(auto& loop : function.loops()){
        optimized |= ::loop_induction_variables_optimization(loop, function);
    }

    return optimized;
}
<|endoftext|>


<commit_before>#include "GroupKnapsack.hpp"
#include <cassert>
#include <iostream>
using namespace std;

#define TEST_MAX 1024

struct GKTest {
    Item group[MAX][MAX];
    int group_n[MAX];
    int n;
    int total_weight;
    int result;
} test_cases[] = {
    {
        { 0, 1, 2, 3, 4, 5, 6,  7,  8,  9,  10 },
        { 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 10 },
        10, 30, 30
    },      // 0
    {
        { 0, 1, 2, 3, 4, 5,  6, 7, 8, 9, 10 },
        { 0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 },
        10, 20, 20
    },      // 1
    {
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
        { 0, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 },
        10, 25, 25
    },      // 2
    {
        { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
        { 0, 1, 2, 8, 7, 4, 3, 4, 3, 2, 1 },
        10, 20, 20
    },      // 3
    {
        { 0, 1, 1, 5,  4, 9, 7, 31, 13, 34, 21, 17 },
        { 0, 5, 6, 11, 4, 9, 2, 34, 21, 13, 17, 3 },
        11, 50, 50
    },      // 4
    {
        { 0, 12, 142, 5, 14, 15,  45, 42, 61, 41, 0, 42, 42,  25, 14, 215, 45, 42, 1,  31 },
        { 0, 42, 42,  5, 14, 215, 45, 42, 3,  31, 1, 12, 142, 5, 14, 15,  45, 42, 61, 41 },
        19, 80, 80
    },      // 5
};

int main()
{
    int count = sizeof(test_cases) / sizeof(GKTest);
    for (int i = 0; i < count; i++) {
        GKTest & t = test_cases[i];
        int r = GroupKnapsack(t.group, t.group_n, t.n, t.total_weight);
        cout << i << ": " << r << endl;
        assert(r == t.result);
    }

    return 0;
}
<commit_msg>TODO: fix bug<commit_after>#include "GroupKnapsack.hpp"
#include <cassert>
#include <iostream>
using namespace std;

#define TEST_MAX 1024

struct GKTest {
    Item group[MAX][MAX];
    int group_n[MAX];
    int n;
    int total_weight;
    int result;
} test_cases[] = {
    {
        {
            { { 1, 1 }, { 2, 5 }, { 5, 10 }, { 3, 7 }, { 4, 5 } },
            { { 1, 1 }, { 2, 5 }, { 5, 10 }, { 3, 7 } },
            { { 1, 1 }, { 2, 5 }, { 5, 10 }, { 3, 7 }, { 4, 5 }, { 7, 10 } },
            { { 1, 1 }, { 2, 5 }, { 5, 10 }, { 3, 7 }, { 4, 5 }, { 9, 1 }, { 3, 3 } },
            { { 1, 1 }, { 2, 5 }, { 5, 10 } },
        },
        { 5, 4, 6, 7, 3 },
        5, 30, 41
    },      // 0
    {
        {
            { { 1, 2 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 10 } },
            { { 10, 31 }, { 2, 5 }, { 5, 10 }, { 3, 7 } },
            { { 4, 7 }, { 2, 5 }, { 5, 10 }, { 3, 7 }, { 4, 5 }, { 7, 10 } },
            { { 9, 8 }, { 2, 5 }, { 6, 17 }, { 13, 7 } },
            { { 15, 21 }, { 32, 5 }, { 8, 10 } },
            { { 5, 1 }, { 32, 5 }, { 8, 10 } },
            { { 15, 21 }, { 2, 5 }, { 18, 13 } },
        },
        { 5, 4, 6, 4, 3, 3, 3 },
        7, 30, 41
    },      // 1
};

int main()
{
    int count = sizeof(test_cases) / sizeof(GKTest);
    for (int i = 0; i < count; i++) {
        GKTest & t = test_cases[i];
        int r = GroupKnapsack(t.group, t.group_n, t.n, t.total_weight);
        cout << i << ": " << r << endl;
        assert(r == t.result);
    }

    return 0;
}
<|endoftext|>