<commit_before>/*
 *            Copyright 2009-2012 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/ctp/fragment.h>

using namespace std;
namespace votca { namespace ctp {

Fragment::Fragment(Fragment *stencil)
         : _id(stencil->getId()), _name(stencil->getName()+"_ghost"),
           _top(NULL), _mol(NULL), _rotateQM2MD(stencil->getRotQM2MD()),
           _CoQM(stencil->getCoQM()), _CoMD(stencil->getCoMD()),
           _trihedron(stencil->getTrihedron()) {

    vector< Atom* > ::iterator ait;
    for (ait = stencil->Atoms().begin();
         ait < stencil->Atoms().end();
         ait++) {

        Atom *newAtom = new Atom(*ait);
        this->AddAtom(newAtom);
    }
}

Fragment::~Fragment() {
    vector < Atom* > ::iterator atmit;
    for (atmit = this->Atoms().begin();
          atmit < this->Atoms().end();
          ++atmit) {
          delete *atmit;
    }
    _weights.clear();
    _atoms.clear();

    vector < PolarSite* > ::iterator pit;
    for (pit = this->PolarSites().begin();
            pit < this->PolarSites().end();
            ++pit) {
        delete *pit;
    }
    _polarSites.clear();
}

void Fragment::AddAtom(Atom* atom) {
    _atoms.push_back( atom );
    atom->setFragment(this);
    _weights.push_back( atom->getWeight() );
}

void Fragment::AddPolarSite(PolarSite *pole) {
    _polarSites.push_back(pole);
    pole->setFragment(this);
}

void Fragment::Rotate(matrix spin, vec refPos) {
    vector <Atom*> ::iterator ait;
    for (ait = _atoms.begin(); ait < _atoms.end(); ait++) {
        vec dir = (*ait)->getQMPos() - refPos;
        dir = spin * dir;
        vec pos = refPos + dir;
        (*ait)->setQMPos(pos);
    }
}

void Fragment::TranslateBy(const vec &shift) {

    _CoMD = _CoMD + shift;

    vector <Atom*> ::iterator ait;
    for (ait = _atoms.begin(); ait < _atoms.end(); ait++) {
        (*ait)->TranslateBy(shift);
    }
}

void Fragment::RotTransQM2MD() {
    vector <Atom*> ::iterator ait;
    for (ait= _atoms.begin(); ait < _atoms.end(); ait++) {
        vec newQMPos = _rotateQM2MD*( (*ait)->getQMPos() - this->_CoQM )
                      + this->_CoMD;
        (*ait)->setQMPos(newQMPos);
    }
}

void Fragment::calcPos(string tag) {
    vec pos = vec(0,0,0);
    double totWeight = 0.0;

    for (int i = 0; i< _atoms.size(); i++) {
        if (tag == "MD") {
            pos += _atoms[i]->getPos() * _atoms[i]->getWeight();
        }
        else if (tag == "QM") {
            pos += _atoms[i]->getQMPos() * _atoms[i]->getWeight();
        }
        totWeight += _atoms[i]->getWeight();
    }

    if (tag == "MD") {
        _CoMD = pos / totWeight;
    }
    else if (tag == "QM") {
        _CoQM = pos / totWeight;
    }

}

void Fragment::Rigidify(bool Auto) {

    // +++++++++++++++++++++++++++++++++++++++++ //
    // Establish reference atoms for local frame //
    // +++++++++++++++++++++++++++++++++++++++++ //

    vector<Atom*> trihedron;

    if (Auto) {

        // Automated search for suitable atoms
        bool enough = false;
        vector< Atom* > ::iterator ait = this->Atoms().begin();

        while (!enough) {

            if (ait == this->Atoms().end()) { break; }
            Atom *atm = *ait;
            ait++;

            // When specifying mapping weights for rigid fragments,
            // mobile atoms (whose position can vary significantly with
            // respect to the rigid plane, for instance) should have a weight 0.
            // We do not want to pick those to establish the local frame.
            if (atm->getWeight() == 0.0) { continue; }
            else {
                trihedron.push_back(atm);
                if (trihedron.size() == 3) { enough = true; }
            }
        }
    }
    else {

        // Take atoms specified in mapping file <= DEFAULT
        vector<Atom*> ::iterator ait;
        for (ait = _atoms.begin(); ait < _atoms.end(); ait++) {
            if ( ! (*ait)->HasQMPart() ) { continue; }

            if ( (*ait)->getQMId() == _trihedron[0] ||
                 (*ait)->getQMId() == _trihedron[1] ||
                 (*ait)->getQMId() == _trihedron[2] ) {
                Atom *atm = *ait;
                trihedron.push_back(atm);
            }
        }
    }

    int _symmetry = trihedron.size();

    // +++++++++++++++++++++++ //
    // Construct trihedra axes //
    // +++++++++++++++++++++++ //

    vec xMD, yMD, zMD;
    vec xQM, yQM, zQM;

    if (_symmetry == 3) {

        vec r1MD = trihedron[0]->getPos();
        vec r2MD = trihedron[1]->getPos();
        vec r3MD = trihedron[2]->getPos();
        vec r1QM = trihedron[0]->getQMPos();
        vec r2QM = trihedron[1]->getQMPos();
        vec r3QM = trihedron[2]->getQMPos();

        xMD = r2MD - r1MD;
        yMD = r3MD - r1MD;
        xQM = r2QM - r1QM;
        yQM = r3QM - r1QM;

        zMD = xMD ^ yMD;
        zQM = xQM ^ yQM;

        yMD = zMD ^ xMD;
        yQM = zQM ^ xQM;

        xMD = xMD.normalize();
        yMD = yMD.normalize();
        zMD = zMD.normalize();
        xQM = xQM.normalize();
        yQM = yQM.normalize();
        zQM = zQM.normalize();

    }

    else if (_symmetry = 2) {

        vec r1MD = trihedron[0]->getPos();
        vec r2MD = trihedron[1]->getPos();
        vec r1QM = trihedron[0]->getQMPos();
        vec r2QM = trihedron[1]->getQMPos();

        xMD = r2MD - r1MD;
        xQM = r2QM - r1QM;

        // Normalising not necessary, but recommendable, when doing...
        xMD = xMD.normalize();
        xQM = xQM.normalize();

        vec yMDtmp = vec(0,0,0);
        vec yQMtmp = vec(0,0,0);

        // ... this: Check whether one of the components is equal or close to
        // zero. If so, this easily gives a second leg for the trihedron.
        if      ( xMD.getX()*xMD.getX() < 1e-6 ) { yMDtmp = vec(1,0,0); }
        else if ( xMD.getY()*xMD.getY() < 1e-6 ) { yMDtmp = vec(0,1,0); }
        else if ( xMD.getZ()*xMD.getZ() < 1e-6 ) { yMDtmp = vec(0,0,1); }
        if      ( xQM.getX()*xQM.getX() < 1e-6 ) { yQMtmp = vec(1,0,0); }
        else if ( xQM.getY()*xQM.getY() < 1e-6 ) { yQMtmp = vec(0,1,0); }
        else if ( xQM.getZ()*xQM.getZ() < 1e-6 ) { yQMtmp = vec(0,0,1); }

        if ( abs(yMDtmp) < 0.5 ) {
           // All components of xMD are unequal to zero => division is safe.
           // Choose vector from plane with xMD * inPlaneVec = 0:
           double tmp_x = 1.;
           double tmp_y = 1.;
           double tmp_z = 1/xMD.getZ() * (-xMD.getX()*tmp_x - xMD.getY()*tmp_y);
           yMDtmp = vec(tmp_x, tmp_y, tmp_z);
           yMDtmp.normalize();
        }
        if ( abs(yQMtmp) < 0.5 ) {
           double tmp_x = 1.;
           double tmp_y = 1.;
           double tmp_z = 1/xQM.getZ() * (-xQM.getX()*tmp_x - xQM.getY()*tmp_y);
           yQMtmp = vec(tmp_x, tmp_y, tmp_z);
           yQMtmp.normalize();
        }

        // Now proceed as for symmetry 3
        zMD = xMD ^ yMDtmp;
        yMD = zMD ^ xMD;
        zQM = xQM ^ yQMtmp;
        yQM = zQM ^ xQM;

        xMD.normalize();
        yMD.normalize();
        zMD.normalize();
        xQM.normalize();
        yQM.normalize();
        zQM.normalize();

    }

    else if (_symmetry = 1) {

        xMD = vec(1,0,0);
        yMD = vec(0,1,0);
        zMD = vec(0,0,1);
        xQM = vec(1,0,0);
        yQM = vec(0,1,0);
        zQM = vec(0,0,1);

    }

    else {
        cout << endl
             << "ERROR: Invalid definition of local frame in fragment "
             << this->getName()
             << endl;
        throw std::runtime_error( "Error in system mapping definition. ");
    }

    // +++++++++++++++++ //
    // Rotation matrices //
    // +++++++++++++++++ //

    matrix rotMD = matrix(xMD, yMD, zMD);
    matrix rotQM = matrix(xQM, yQM, zQM);

    matrix rotateQM2MD = rotMD * rotQM.Transpose();
    _rotateQM2MD = rotateQM2MD;

    // ++++++++++++++++++ //
    // Transform fragment //
    // ++++++++++++++++++ //

    this->calcPos("QM");
    this->RotTransQM2MD();
    _translateQM2MD = _CoMD - _CoQM;

}

}}<commit_msg>Local-frame definition: Warning if ill-defined.<commit_after>/*
 *            Copyright 2009-2012 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/ctp/fragment.h>

using namespace std;
namespace votca { namespace ctp {

Fragment::Fragment(Fragment *stencil)
         : _id(stencil->getId()), _name(stencil->getName()+"_ghost"),
           _top(NULL), _mol(NULL), _rotateQM2MD(stencil->getRotQM2MD()),
           _CoQM(stencil->getCoQM()), _CoMD(stencil->getCoMD()),
           _trihedron(stencil->getTrihedron()) {

    vector< Atom* > ::iterator ait;
    for (ait = stencil->Atoms().begin();
         ait < stencil->Atoms().end();
         ait++) {

        Atom *newAtom = new Atom(*ait);
        this->AddAtom(newAtom);
    }
}

Fragment::~Fragment() {
    vector < Atom* > ::iterator atmit;
    for (atmit = this->Atoms().begin();
          atmit < this->Atoms().end();
          ++atmit) {
          delete *atmit;
    }
    _weights.clear();
    _atoms.clear();

    vector < PolarSite* > ::iterator pit;
    for (pit = this->PolarSites().begin();
            pit < this->PolarSites().end();
            ++pit) {
        delete *pit;
    }
    _polarSites.clear();
}

void Fragment::AddAtom(Atom* atom) {
    _atoms.push_back( atom );
    atom->setFragment(this);
    _weights.push_back( atom->getWeight() );
}

void Fragment::AddPolarSite(PolarSite *pole) {
    _polarSites.push_back(pole);
    pole->setFragment(this);
}

void Fragment::Rotate(matrix spin, vec refPos) {
    vector <Atom*> ::iterator ait;
    for (ait = _atoms.begin(); ait < _atoms.end(); ait++) {
        vec dir = (*ait)->getQMPos() - refPos;
        dir = spin * dir;
        vec pos = refPos + dir;
        (*ait)->setQMPos(pos);
    }
}

void Fragment::TranslateBy(const vec &shift) {

    _CoMD = _CoMD + shift;

    vector <Atom*> ::iterator ait;
    for (ait = _atoms.begin(); ait < _atoms.end(); ait++) {
        (*ait)->TranslateBy(shift);
    }
}

void Fragment::RotTransQM2MD() {
    vector <Atom*> ::iterator ait;
    for (ait= _atoms.begin(); ait < _atoms.end(); ait++) {
        vec newQMPos = _rotateQM2MD*( (*ait)->getQMPos() - this->_CoQM )
                      + this->_CoMD;
        (*ait)->setQMPos(newQMPos);
    }
}

void Fragment::calcPos(string tag) {
    vec pos = vec(0,0,0);
    double totWeight = 0.0;

    for (int i = 0; i< _atoms.size(); i++) {
        if (tag == "MD") {
            pos += _atoms[i]->getPos() * _atoms[i]->getWeight();
        }
        else if (tag == "QM") {
            pos += _atoms[i]->getQMPos() * _atoms[i]->getWeight();
        }
        totWeight += _atoms[i]->getWeight();
    }

    if (tag == "MD") {
        _CoMD = pos / totWeight;
    }
    else if (tag == "QM") {
        _CoQM = pos / totWeight;
    }

}

void Fragment::Rigidify(bool Auto) {

    // +++++++++++++++++++++++++++++++++++++++++ //
    // Establish reference atoms for local frame //
    // +++++++++++++++++++++++++++++++++++++++++ //

    vector<Atom*> trihedron;

    if (Auto) {

        // Automated search for suitable atoms
        bool enough = false;
        vector< Atom* > ::iterator ait = this->Atoms().begin();

        while (!enough) {

            if (ait == this->Atoms().end()) { break; }
            Atom *atm = *ait;
            ait++;

            // When specifying mapping weights for rigid fragments,
            // mobile atoms (whose position can vary significantly with
            // respect to the rigid plane, for instance) should have a weight 0.
            // We do not want to pick those to establish the local frame.
            if (atm->getWeight() == 0.0) { continue; }
            else {
                trihedron.push_back(atm);
                if (trihedron.size() == 3) { enough = true; }
            }
        }
    }
    else {

        // Take atoms specified in mapping file <= DEFAULT
        vector<Atom*> ::iterator ait;
        for (ait = _atoms.begin(); ait < _atoms.end(); ait++) {
            if ( ! (*ait)->HasQMPart() ) { continue; }

            if ( (*ait)->getQMId() == _trihedron[0] ||
                 (*ait)->getQMId() == _trihedron[1] ||
                 (*ait)->getQMId() == _trihedron[2] ) {
                Atom *atm = *ait;
                trihedron.push_back(atm);
            }
        }
    }

    int _symmetry = trihedron.size();

    // +++++++++++++++++++++++ //
    // Construct trihedra axes //
    // +++++++++++++++++++++++ //

    vec xMD, yMD, zMD;
    vec xQM, yQM, zQM;

    if (_symmetry == 3) {

        vec r1MD = trihedron[0]->getPos();
        vec r2MD = trihedron[1]->getPos();
        vec r3MD = trihedron[2]->getPos();
        vec r1QM = trihedron[0]->getQMPos();
        vec r2QM = trihedron[1]->getQMPos();
        vec r3QM = trihedron[2]->getQMPos();

        xMD = r2MD - r1MD;
        yMD = r3MD - r1MD;
        xQM = r2QM - r1QM;
        yQM = r3QM - r1QM;

        zMD = xMD ^ yMD;
        zQM = xQM ^ yQM;

        yMD = zMD ^ xMD;
        yQM = zQM ^ xQM;

        xMD = xMD.normalize();
        yMD = yMD.normalize();
        zMD = zMD.normalize();
        xQM = xQM.normalize();
        yQM = yQM.normalize();
        zQM = zQM.normalize();

    }

    else if (_symmetry = 2) {

        vec r1MD = trihedron[0]->getPos();
        vec r2MD = trihedron[1]->getPos();
        vec r1QM = trihedron[0]->getQMPos();
        vec r2QM = trihedron[1]->getQMPos();

        xMD = r2MD - r1MD;
        xQM = r2QM - r1QM;

        // Normalising not necessary, but recommendable, when doing...
        xMD = xMD.normalize();
        xQM = xQM.normalize();

        vec yMDtmp = vec(0,0,0);
        vec yQMtmp = vec(0,0,0);

        // ... this: Check whether one of the components is equal or close to
        // zero. If so, this easily gives a second leg for the trihedron.
        if      ( xMD.getX()*xMD.getX() < 1e-6 ) { yMDtmp = vec(1,0,0); }
        else if ( xMD.getY()*xMD.getY() < 1e-6 ) { yMDtmp = vec(0,1,0); }
        else if ( xMD.getZ()*xMD.getZ() < 1e-6 ) { yMDtmp = vec(0,0,1); }
        if      ( xQM.getX()*xQM.getX() < 1e-6 ) { yQMtmp = vec(1,0,0); }
        else if ( xQM.getY()*xQM.getY() < 1e-6 ) { yQMtmp = vec(0,1,0); }
        else if ( xQM.getZ()*xQM.getZ() < 1e-6 ) { yQMtmp = vec(0,0,1); }

        if ( abs(yMDtmp) < 0.5 ) {
           // All components of xMD are unequal to zero => division is safe.
           // Choose vector from plane with xMD * inPlaneVec = 0:
           double tmp_x = 1.;
           double tmp_y = 1.;
           double tmp_z = 1/xMD.getZ() * (-xMD.getX()*tmp_x - xMD.getY()*tmp_y);
           yMDtmp = vec(tmp_x, tmp_y, tmp_z);
           yMDtmp.normalize();
        }
        if ( abs(yQMtmp) < 0.5 ) {
           double tmp_x = 1.;
           double tmp_y = 1.;
           double tmp_z = 1/xQM.getZ() * (-xQM.getX()*tmp_x - xQM.getY()*tmp_y);
           yQMtmp = vec(tmp_x, tmp_y, tmp_z);
           yQMtmp.normalize();
        }

        // Now proceed as for symmetry 3
        zMD = xMD ^ yMDtmp;
        yMD = zMD ^ xMD;
        zQM = xQM ^ yQMtmp;
        yQM = zQM ^ xQM;

        xMD.normalize();
        yMD.normalize();
        zMD.normalize();
        xQM.normalize();
        yQM.normalize();
        zQM.normalize();

    }

    else if (_symmetry = 1) {

        xMD = vec(1,0,0);
        yMD = vec(0,1,0);
        zMD = vec(0,0,1);
        xQM = vec(1,0,0);
        yQM = vec(0,1,0);
        zQM = vec(0,0,1);

    }

    else {
        cout << endl
             << "NOTE: Invalid definition of local frame in fragment "
             << this->getName();
        cout << ". Assuming point particle for mapping. "
             << endl;

        xMD = vec(1,0,0);
        yMD = vec(0,1,0);
        zMD = vec(0,0,1);
        xQM = vec(1,0,0);
        yQM = vec(0,1,0);
        zQM = vec(0,0,1);

    }

    // +++++++++++++++++ //
    // Rotation matrices //
    // +++++++++++++++++ //

    matrix rotMD = matrix(xMD, yMD, zMD);
    matrix rotQM = matrix(xQM, yQM, zQM);

    matrix rotateQM2MD = rotMD * rotQM.Transpose();
    _rotateQM2MD = rotateQM2MD;

    // ++++++++++++++++++ //
    // Transform fragment //
    // ++++++++++++++++++ //

    this->calcPos("QM");
    this->RotTransQM2MD();
    _translateQM2MD = _CoMD - _CoQM;

}

}}<|endoftext|>


<commit_before>#include "catch.hpp"

// mapnik
#include <mapnik/vertex.hpp>
#include <mapnik/offset_converter.hpp>

// stl
#include <iostream>
#include <vector>
#include <tuple>

namespace offset_test {

struct fake_path
{
    using coord_type = std::tuple<double, double, unsigned>;
    using cont_type = std::vector<coord_type>;
    cont_type vertices_;
    cont_type::iterator itr_;

    fake_path(std::initializer_list<double> l)
        : fake_path(l.begin(), l.size()) {
    }

    fake_path(std::vector<double> const &v, bool make_invalid = false)
        : fake_path(v.begin(), v.size(), make_invalid) {
    }

    template <typename Itr>
    fake_path(Itr itr, size_t sz, bool make_invalid = false) {
        size_t num_coords = sz >> 1;
        if (make_invalid)
        {
            num_coords++;
        }
        vertices_.reserve(num_coords);
        if (make_invalid)
        {
            vertices_.push_back(std::make_tuple(0,0,mapnik::SEG_END));
        }

        for (size_t i = 0; i < num_coords; ++i) {
            double x = *itr++;
            double y = *itr++;
            unsigned cmd = (i == 0) ? mapnik::SEG_MOVETO : mapnik::SEG_LINETO;
            vertices_.push_back(std::make_tuple(x, y, cmd));
        }
        itr_ = vertices_.begin();
    }

    unsigned vertex(double *x, double *y) {
        if (itr_ == vertices_.end()) {
            return mapnik::SEG_END;
        }
        *x = std::get<0>(*itr_);
        *y = std::get<1>(*itr_);
        unsigned cmd = std::get<2>(*itr_);
        ++itr_;
        return cmd;
    }

    void rewind(unsigned) {
        itr_ = vertices_.begin();
    }
};

static double DELTA_BUFF = 0.5;

double dist(double x0, double y0, double x1, double y1)
{
    double dx = x0 - x1;
    double dy = y0 - y1;
    return std::sqrt(dx*dx + dy*dy);
}

void test_null_segment(double const &offset)
{
    fake_path path = {};
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);
    double x0 = 0;
    double y0 = 0;
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
}

void test_invalid_segment(double const &offset)
{
    std::vector<double> v_path = {1, 1, 1, 2};
    fake_path path(v_path, true);
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);
    double x0 = 0;
    double y0 = 0;
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
}

void test_simple_segment(double const &offset)
{
    fake_path path = {0, 0, 1, 0}, off_path = {0, offset, 1, offset};
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        if (cmd1 == mapnik::SEG_END) break;
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

void test_straight_line(double const &offset) {
    fake_path path = {0, 0, 1, 0, 9, 0, 10, 0},
        off_path = {0, offset, 1, offset, 9, offset, 10, offset};
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

void test_offset_curve(double const &offset) {
    const double r = (1.0 + offset);

    std::vector<double> pos, off_pos;
    const size_t max_i = 1000;
    for (size_t i = 0; i <= max_i; ++i) {
        double x = M_PI * double(i) / max_i;
        pos.push_back(-std::cos(x)); pos.push_back(std::sin(x));
        off_pos.push_back(-r * std::cos(x)); off_pos.push_back(r * std::sin(x));
    }

    fake_path path(pos), off_path(off_pos);
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

void test_s_shaped_curve(double const &offset) {
    const double r = (1.0 + offset);
    const double r2 = (1.0 - offset);

    std::vector<double> pos, off_pos;
    const size_t max_i = 1000;
    for (size_t i = 0; i <= max_i; ++i) {
        double x = M_PI * double(i) / max_i;
        pos.push_back(-std::cos(x) - 1); pos.push_back(std::sin(x));
        off_pos.push_back(-r * std::cos(x) - 1); off_pos.push_back(r * std::sin(x));
    }
    for (size_t i = 0; i <= max_i; ++i) {
        double x = M_PI * double(i) / max_i;
        pos.push_back(-std::cos(x) + 1); pos.push_back(-std::sin(x));
        off_pos.push_back(-r2 * std::cos(x) + 1); off_pos.push_back(-r2 * std::sin(x));
    }

    fake_path path(pos), off_path(off_pos);
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

} // END NS

TEST_CASE("offset converter") {

SECTION("null segment") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test simple straight line segment - should be easy to
            // find the correspondance here.
            offset_test::test_null_segment(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("invalid segment") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test simple straight line segment - should be easy to
            // find the correspondance here.
            offset_test::test_invalid_segment(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("simple segment") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test simple straight line segment - should be easy to
            // find the correspondance here.
            offset_test::test_simple_segment(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("straight line") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test straight line consisting of more than one segment.
            offset_test::test_straight_line(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("curve") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            offset_test::test_offset_curve(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("s curve") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            offset_test::test_s_shaped_curve(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

}
<commit_msg>unit test: fix offsetting test<commit_after>#include "catch.hpp"

// mapnik
#include <mapnik/vertex.hpp>
#include <mapnik/offset_converter.hpp>

// stl
#include <iostream>
#include <vector>
#include <tuple>

namespace offset_test {

struct fake_path
{
    using coord_type = std::tuple<double, double, unsigned>;
    using cont_type = std::vector<coord_type>;
    cont_type vertices_;
    cont_type::iterator itr_;

    fake_path(std::initializer_list<double> l)
        : fake_path(l.begin(), l.size()) {
    }

    fake_path(std::vector<double> const &v, bool make_invalid = false)
        : fake_path(v.begin(), v.size(), make_invalid) {
    }

    template <typename Itr>
    fake_path(Itr itr, size_t sz, bool make_invalid = false) {
        size_t num_coords = sz >> 1;
        vertices_.reserve(num_coords + (make_invalid ? 1 : 0));
        if (make_invalid)
        {
            vertices_.push_back(std::make_tuple(0,0,mapnik::SEG_END));
        }

        for (size_t i = 0; i < num_coords; ++i) {
            double x = *itr++;
            double y = *itr++;
            unsigned cmd = (i == 0) ? mapnik::SEG_MOVETO : mapnik::SEG_LINETO;
            vertices_.push_back(std::make_tuple(x, y, cmd));
        }
        itr_ = vertices_.begin();
    }

    unsigned vertex(double *x, double *y) {
        if (itr_ == vertices_.end()) {
            return mapnik::SEG_END;
        }
        *x = std::get<0>(*itr_);
        *y = std::get<1>(*itr_);
        unsigned cmd = std::get<2>(*itr_);
        ++itr_;
        return cmd;
    }

    void rewind(unsigned) {
        itr_ = vertices_.begin();
    }
};

static double DELTA_BUFF = 0.5;

double dist(double x0, double y0, double x1, double y1)
{
    double dx = x0 - x1;
    double dy = y0 - y1;
    return std::sqrt(dx*dx + dy*dy);
}

void test_null_segment(double const &offset)
{
    fake_path path = {};
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);
    double x0 = 0;
    double y0 = 0;
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
}

void test_invalid_segment(double const &offset)
{
    std::vector<double> v_path = {1, 1, 1, 2};
    fake_path path(v_path, true);
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);
    double x0 = 0;
    double y0 = 0;
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
    REQUIRE(off_path_new.vertex(&x0, &y0) == mapnik::SEG_END);
}

void test_simple_segment(double const &offset)
{
    fake_path path = {0, 0, 1, 0}, off_path = {0, offset, 1, offset};
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        if (cmd1 == mapnik::SEG_END) break;
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

void test_straight_line(double const &offset) {
    fake_path path = {0, 0, 1, 0, 9, 0, 10, 0},
        off_path = {0, offset, 1, offset, 9, offset, 10, offset};
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

void test_offset_curve(double const &offset) {
    const double r = (1.0 + offset);

    std::vector<double> pos, off_pos;
    const size_t max_i = 1000;
    for (size_t i = 0; i <= max_i; ++i) {
        double x = M_PI * double(i) / max_i;
        pos.push_back(-std::cos(x)); pos.push_back(std::sin(x));
        off_pos.push_back(-r * std::cos(x)); off_pos.push_back(r * std::sin(x));
    }

    fake_path path(pos), off_path(off_pos);
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

void test_s_shaped_curve(double const &offset) {
    const double r = (1.0 + offset);
    const double r2 = (1.0 - offset);

    std::vector<double> pos, off_pos;
    const size_t max_i = 1000;
    for (size_t i = 0; i <= max_i; ++i) {
        double x = M_PI * double(i) / max_i;
        pos.push_back(-std::cos(x) - 1); pos.push_back(std::sin(x));
        off_pos.push_back(-r * std::cos(x) - 1); off_pos.push_back(r * std::sin(x));
    }
    for (size_t i = 0; i <= max_i; ++i) {
        double x = M_PI * double(i) / max_i;
        pos.push_back(-std::cos(x) + 1); pos.push_back(-std::sin(x));
        off_pos.push_back(-r2 * std::cos(x) + 1); off_pos.push_back(-r2 * std::sin(x));
    }

    fake_path path(pos), off_path(off_pos);
    mapnik::offset_converter<fake_path> off_path_new(path);
    off_path_new.set_offset(offset);

    double x0, y0, x1, y1;
    unsigned cmd0 = off_path_new.vertex(&x0, &y0);
    unsigned cmd1 = off_path.vertex(&x1,&y1);
    double d = dist(x0, y0, x1, y1);
    while (true) {
        if (d > (std::abs(offset) + DELTA_BUFF))
        {
            cmd0 = off_path_new.vertex(&x0,&y0);
            REQUIRE(cmd0 != mapnik::SEG_END);
            d = dist(x0, y0, x1, y1);
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));
        }
        else
        {
            REQUIRE(d <= (std::abs(offset) + DELTA_BUFF));

        }

        cmd1 = off_path.vertex(&x1,&y1);
        d = dist(x0, y0, x1, y1);
        bool done = false;
        while (d <= (std::abs(offset) + DELTA_BUFF))
        {
            CHECK(true);
            cmd0 = off_path_new.vertex(&x0,&y0);
            if (cmd0 == mapnik::SEG_END)
            {
                done = true;
                break;
            }
        }
        if (done) break;
    }
}

} // END NS

TEST_CASE("offset converter") {

SECTION("null segment") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test simple straight line segment - should be easy to
            // find the correspondance here.
            offset_test::test_null_segment(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("invalid segment") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test simple straight line segment - should be easy to
            // find the correspondance here.
            offset_test::test_invalid_segment(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("simple segment") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test simple straight line segment - should be easy to
            // find the correspondance here.
            offset_test::test_simple_segment(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("straight line") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            // test straight line consisting of more than one segment.
            offset_test::test_straight_line(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("curve") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            offset_test::test_offset_curve(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

SECTION("s curve") {
    try {

        std::vector<double> offsets = { 1, -1 };
        for (double offset : offsets) {
            offset_test::test_s_shaped_curve(offset);
        }
    }
    catch (std::exception const& ex)
    {
        std::cerr << ex.what() << "\n";
        REQUIRE(false);
    }
}

}
<|endoftext|>


<commit_before>#include <silicium/asio/accepting_source.hpp>
#include <silicium/asio/connecting_observable.hpp>
#include <silicium/asio/connecting_source.hpp>
#include <silicium/asio/reading_observable.hpp>
#include <silicium/asio/socket_sink.hpp>
#include <silicium/asio/socket_source.hpp>
#include <silicium/asio/tcp_acceptor.hpp>
#include <silicium/asio/tcp_trigger.hpp>
#include <silicium/asio/timer.hpp>
#include <silicium/asio/writing_observable.hpp>
#include <silicium/boost_threading.hpp>
#include <silicium/buffer.hpp>
#include <silicium/build_result.hpp>
#include <silicium/config.hpp>
#include <silicium/detail/basic_dynamic_library.hpp>
#include <silicium/detail/element_from_optional_like.hpp>
#include <silicium/detail/integer_sequence.hpp>
#include <silicium/detail/line_source.hpp>
#include <silicium/detail/proper_value_function.hpp>
#include <silicium/directory_allocator.hpp>
#include <silicium/directory_builder.hpp>
#include <silicium/directory_watcher.hpp>
#include <silicium/dynamic_library.hpp>
#include <silicium/error_code.hpp>
#include <silicium/error_or.hpp>
#include <silicium/exchange.hpp>
#include <silicium/fast_variant.hpp>
#include <silicium/file_handle.hpp>
#include <silicium/file_notification.hpp>
#include <silicium/flush.hpp>
#include <silicium/git/oxid.hpp>
#include <silicium/git/repository.hpp>
#include <silicium/html.hpp>
#include <silicium/http/generate_header.hpp>
#include <silicium/http/generate_request.hpp>
#include <silicium/http/generate_response.hpp>
#include <silicium/http/http.hpp>
#include <silicium/http/parse_request.hpp>
#include <silicium/http/parse_response.hpp>
#include <silicium/http/uri.hpp>
#include <silicium/iterator_range.hpp>
#include <silicium/memory_range.hpp>
#include <silicium/noexcept_string.hpp>
#include <silicium/observable/bridge.hpp>
#include <silicium/observable/cache.hpp>
#include <silicium/observable/constant.hpp>
#include <silicium/observable/consume.hpp>
#include <silicium/observable/coroutine.hpp>
#include <silicium/observable/coroutine_generator.hpp>
#include <silicium/observable/deref_optional.hpp>
#include <silicium/observable/empty.hpp>
#include <silicium/observable/end.hpp>
#include <silicium/observable/enumerate.hpp>
#include <silicium/observable/filter.hpp>
#include <silicium/observable/finite_state_machine.hpp>
#include <silicium/observable/flatten.hpp>
#include <silicium/observable/for_each.hpp>
#include <silicium/observable/function.hpp>
#include <silicium/observable/generator.hpp>
#include <silicium/observable/observable.hpp>
#include <silicium/observable/observer.hpp>
#include <silicium/observable/ptr.hpp>
#include <silicium/observable/ready_future.hpp>
#include <silicium/observable/ref.hpp>
#include <silicium/observable/source.hpp>
#include <silicium/observable/thread.hpp>
#include <silicium/observable/total_consumer.hpp>
#include <silicium/observable/transform.hpp>
#include <silicium/observable/transform_if_initialized.hpp>
#include <silicium/observable/tuple.hpp>
#include <silicium/observable/variant.hpp>
#include <silicium/observable/virtualized.hpp>
#include <silicium/observable/while.hpp>
#include <silicium/observable/yield_context.hpp>
#include <silicium/open.hpp>
#include <silicium/optional.hpp>
#include <silicium/process.hpp>
#include <silicium/process_parameters.hpp>
#include <silicium/read_file.hpp>
#include <silicium/sink/buffering_sink.hpp>
#include <silicium/sink/container_buffer.hpp>
#include <silicium/sink/file_sink.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <silicium/sink/ptr_sink.hpp>
#include <silicium/sink/sink.hpp>
#include <silicium/sink/throwing_sink.hpp>
#include <silicium/source/buffering_source.hpp>
#include <silicium/source/enumerating_source.hpp>
#include <silicium/source/error_extracting_source.hpp>
#include <silicium/source/file_source.hpp>
#include <silicium/source/filter_source.hpp>
#include <silicium/source/generator_source.hpp>
#include <silicium/source/memory_source.hpp>
#include <silicium/source/observable_source.hpp>
#include <silicium/source/received_from_socket_source.hpp>
#include <silicium/source/ref.hpp>
#include <silicium/source/single_source.hpp>
#include <silicium/source/source.hpp>
#include <silicium/source/transforming_source.hpp>
#include <silicium/source/virtualized_source.hpp>
#include <silicium/std_threading.hpp>
#include <silicium/then.hpp>
#include <silicium/to_shared.hpp>
#include <silicium/to_unique.hpp>
#include <silicium/version.hpp>
#include <silicium/win32/directory_changes.hpp>
#include <silicium/win32/directory_watcher.hpp>
#include <silicium/win32/dynamic_library_impl.hpp>
#include <silicium/win32/native_file_descriptor.hpp>
#include <silicium/win32/open.hpp>
#include <silicium/win32/process.hpp>
#include <silicium/win32/win32.hpp>
#include <silicium/write_file.hpp>
#include <silicium/zlib/deflating_sink.hpp>
#include <silicium/zlib/inflating_sink.hpp>
#include <silicium/zlib/zlib.hpp>
<commit_msg>generate _all_headers.cpp for Windows<commit_after>#include <silicium/asio/accepting_source.hpp>
#include <silicium/asio/connecting_observable.hpp>
#include <silicium/asio/connecting_source.hpp>
#include <silicium/asio/reading_observable.hpp>
#include <silicium/asio/socket_sink.hpp>
#include <silicium/asio/socket_source.hpp>
#include <silicium/asio/tcp_acceptor.hpp>
#include <silicium/asio/tcp_trigger.hpp>
#include <silicium/asio/timer.hpp>
#include <silicium/asio/writing_observable.hpp>
#include <silicium/boost_threading.hpp>
#include <silicium/buffer.hpp>
#include <silicium/build_result.hpp>
#include <silicium/config.hpp>
#include <silicium/detail/basic_dynamic_library.hpp>
#include <silicium/detail/element_from_optional_like.hpp>
#include <silicium/detail/integer_sequence.hpp>
#include <silicium/detail/line_source.hpp>
#include <silicium/detail/proper_value_function.hpp>
#include <silicium/directory_allocator.hpp>
#include <silicium/directory_builder.hpp>
#include <silicium/directory_watcher.hpp>
#include <silicium/dynamic_library.hpp>
#include <silicium/error_code.hpp>
#include <silicium/error_or.hpp>
#include <silicium/exchange.hpp>
#include <silicium/fast_variant.hpp>
#include <silicium/file_handle.hpp>
#include <silicium/file_notification.hpp>
#include <silicium/flush.hpp>
#include <silicium/git/oxid.hpp>
#include <silicium/git/repository.hpp>
#include <silicium/html.hpp>
#include <silicium/http/generate_header.hpp>
#include <silicium/http/generate_request.hpp>
#include <silicium/http/generate_response.hpp>
#include <silicium/http/http.hpp>
#include <silicium/http/parse_request.hpp>
#include <silicium/http/parse_response.hpp>
#include <silicium/http/request_parser_sink.hpp>
#include <silicium/http/uri.hpp>
#include <silicium/iterator_range.hpp>
#include <silicium/memory_range.hpp>
#include <silicium/noexcept_string.hpp>
#include <silicium/observable/bridge.hpp>
#include <silicium/observable/cache.hpp>
#include <silicium/observable/constant.hpp>
#include <silicium/observable/consume.hpp>
#include <silicium/observable/coroutine.hpp>
#include <silicium/observable/coroutine_generator.hpp>
#include <silicium/observable/deref_optional.hpp>
#include <silicium/observable/empty.hpp>
#include <silicium/observable/end.hpp>
#include <silicium/observable/enumerate.hpp>
#include <silicium/observable/filter.hpp>
#include <silicium/observable/finite_state_machine.hpp>
#include <silicium/observable/flatten.hpp>
#include <silicium/observable/for_each.hpp>
#include <silicium/observable/function.hpp>
#include <silicium/observable/generator.hpp>
#include <silicium/observable/observable.hpp>
#include <silicium/observable/observer.hpp>
#include <silicium/observable/on_first.hpp>
#include <silicium/observable/ptr.hpp>
#include <silicium/observable/ready_future.hpp>
#include <silicium/observable/ref.hpp>
#include <silicium/observable/source.hpp>
#include <silicium/observable/thread.hpp>
#include <silicium/observable/total_consumer.hpp>
#include <silicium/observable/transform.hpp>
#include <silicium/observable/transform_if_initialized.hpp>
#include <silicium/observable/tuple.hpp>
#include <silicium/observable/variant.hpp>
#include <silicium/observable/virtualized.hpp>
#include <silicium/observable/while.hpp>
#include <silicium/observable/yield_context.hpp>
#include <silicium/open.hpp>
#include <silicium/optional.hpp>
#include <silicium/process.hpp>
#include <silicium/process_parameters.hpp>
#include <silicium/read_file.hpp>
#include <silicium/sink/buffering_sink.hpp>
#include <silicium/sink/container_buffer.hpp>
#include <silicium/sink/file_sink.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <silicium/sink/ostream_sink.hpp>
#include <silicium/sink/ptr_sink.hpp>
#include <silicium/sink/sink.hpp>
#include <silicium/sink/throwing_sink.hpp>
#include <silicium/sink/virtualized_sink.hpp>
#include <silicium/source/buffering_source.hpp>
#include <silicium/source/empty.hpp>
#include <silicium/source/enumerating_source.hpp>
#include <silicium/source/error_extracting_source.hpp>
#include <silicium/source/file_source.hpp>
#include <silicium/source/filter_source.hpp>
#include <silicium/source/generator_source.hpp>
#include <silicium/source/memory_source.hpp>
#include <silicium/source/observable_source.hpp>
#include <silicium/source/received_from_socket_source.hpp>
#include <silicium/source/ref.hpp>
#include <silicium/source/single_source.hpp>
#include <silicium/source/source.hpp>
#include <silicium/source/transforming_source.hpp>
#include <silicium/source/virtualized_source.hpp>
#include <silicium/std_threading.hpp>
#include <silicium/then.hpp>
#include <silicium/to_shared.hpp>
#include <silicium/to_unique.hpp>
#include <silicium/utility.hpp>
#include <silicium/version.hpp>
#include <silicium/win32/directory_changes.hpp>
#include <silicium/win32/directory_watcher.hpp>
#include <silicium/win32/dynamic_library_impl.hpp>
#include <silicium/win32/native_file_descriptor.hpp>
#include <silicium/win32/open.hpp>
#include <silicium/win32/process.hpp>
#include <silicium/win32/win32.hpp>
#include <silicium/write_file.hpp>
#include <silicium/zlib/deflating_sink.hpp>
#include <silicium/zlib/inflating_sink.hpp>
#include <silicium/zlib/zlib.hpp>
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-2017 Los Alamos National Security, LLC
 *                         All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * LA-CC 10-123
 */

//@HEADER
// ***************************************************
//
// HPCG: High Performance Conjugate Gradient Benchmark
//
// Contact:
// Michael A. Heroux ( maherou@sandia.gov)
// Jack Dongarra     (dongarra@eecs.utk.edu)
// Piotr Luszczek    (luszczek@eecs.utk.edu)
//
// ***************************************************
//@HEADER

/*!
 @file CG.hpp

 HPCG routine
 */

#include <fstream>
#include <cmath>
#include <unistd.h>

#include "hpcg.hpp"
#include "mytimer.hpp"

#include "LegionArrays.hpp"
#include "LegionMatrices.hpp"
#include "LegionCGData.hpp"
#include "VectorOps.hpp"

#include "ComputeSPMV.hpp"
#include "ComputeWAXPBY.hpp"
#include "ComputeDotProduct.hpp"

#if 0
#include "ComputeMG_ref.hpp"
#endif

// Use TICK and TOCK to time a code section in MATLAB-like fashion
#define TICK()  t0 = mytimer() //!< record current time in 't0'
#define TOCK(t) t += mytimer() - t0 //!< store time difference in 't' using time in 't0'

/*!
  Reference routine to compute an approximate solution to Ax = b

  @param[inout] A    The known system matrix
  @param[inout] data The data structure with all necessary CG vectors
                     preallocated
  @param[in]    b    The known right hand side vector
  @param[inout] x    On entry: the initial guess; on exit: the new approximate
                     solution
  @param[in]    max_iter  The maximum number of iterations to perform, even if
                tolerance is not met.
  @param[in]    tolerance The stopping criterion to assert convergence: if norm
                of residual is <= to tolerance.
  @param[out]   niters    The number of iterations actually performed.
  @param[out]   normr     The 2-norm of the residual vector after the last
                          iteration.
  @param[out]   normr0    The 2-norm of the residual vector before the first
                          iteration.
  @param[out]   times     The 7-element vector of the timing information
                          accumulated during all of the iterations.
  @param[in]    doPreconditioning The flag to indicate whether the
                preconditioner should be invoked at each iteration.

  @return Returns zero on success and a non-zero value otherwise.

  @see CG()
*/
inline int
CG(
    SparseMatrix &A,
    CGData &data,
    const Array<floatType> &b,
    Array<floatType> &x,
    const int max_iter,
    const double tolerance,
    int &niters,
    double &normr,
    double &normr0,
    double *times,
    bool doPreconditioning,
    LegionRuntime::HighLevel::Context ctx,
    LegionRuntime::HighLevel::Runtime *lrt
) {
    using namespace std;

    double t_begin = mytimer();  // Start timing right away
    //
    const int print_freq = 50;
    const int rank = A.geom->data()->rank;
    const local_int_t nrow = A.sclrs->data()->localNumberOfRows;
    //
    double rtz = 0.0, oldrtz = 0.0, alpha = 0.0, beta = 0.0, pAp = 0.0;
    double t0 = 0.0, t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0, t6 = 0.0;

    normr = 0.0;

    Array<floatType> &r  = *(data.r); // Residual vector.
    Array<floatType> &z  = *(data.z); // Preconditioned residual vector.
    Array<floatType> &p  = *(data.p); // Direction vector (ncol >= nrow).
    Array<floatType> &Ap = *(data.Ap);// Holds result from A * p.

    Item< DynColl<floatType> > &dcFT = *A.dcAllRedSumFT;

    if (!doPreconditioning && rank == 0) {
        std::cout << "WARNING: PERFORMING UNPRECONDITIONED ITERATIONS" << std::endl;
    }
    // p is of length ncols, copy x to p for sparse MV operation
    CopyVector(x, p, ctx, lrt);
    //
    TICK(); ComputeSPMV(A, p, Ap, ctx, lrt);  TOCK(t3); // Ap = A*p

    // r = b - Ax (x stored in p)
    TICK(); ComputeWAXPBY(nrow, 1.0, b, -1.0, Ap, r); TOCK(t2);

    TICK();
    ComputeDotProduct(nrow, r, r, normr, t4, dcFT, ctx, lrt);
    TOCK(t1);

    normr = sqrt(normr);

    if (rank == 0) std::cout << "Initial Residual = "<< normr << std::endl;

    // Record initial residual for convergence testing
    normr0 = normr;

  // Start iterations

    for (int k = 1; k <= max_iter && normr / normr0 > tolerance; k++ ) {
        TICK();
        if (doPreconditioning) {
#if 0
            ComputeMG_ref(A, r, z); // Apply preconditioner
#endif
        }
        else {
            // copy r to z (no preconditioning)
            ComputeWAXPBY(nrow, 1.0, r, 0.0, r, z);
        }
        TOCK(t5); // Preconditioner apply time

        if (k == 1) {
            TICK(); CopyVector(z, p, ctx, lrt); TOCK(t2); // Copy Mr to p
            // rtz = r'*z
            TICK();
            ComputeDotProduct(nrow, r, z, rtz, t4, dcFT, ctx, lrt);
            TOCK(t1);
        }
        else {
            oldrtz = rtz;
            //
            TICK(); // rtz = r'*z
            ComputeDotProduct(nrow, r, z, rtz, t4, dcFT, ctx, lrt);
            TOCK(t1);
            beta = rtz / oldrtz;
            //
            TICK(); // p = beta*p + z
            ComputeWAXPBY(nrow, 1.0, z, beta, p, p);
            TOCK(t2);
        }

        TICK(); // Ap = A*p
        ComputeSPMV(A, p, Ap, ctx, lrt);
        TOCK(t3);
        //
        TICK(); // alpha = p'*Ap
        ComputeDotProduct(nrow, p, Ap, pAp, t4, dcFT, ctx, lrt);
        TOCK(t1);
        //
        alpha = rtz / pAp;
        //
        TICK(); // x = x + alpha*p
        ComputeWAXPBY(nrow, 1.0, x, alpha, p, x);
        // r = r - alpha*Ap
        ComputeWAXPBY(nrow, 1.0, r, -alpha, Ap, r);
        TOCK(t2);
        //
        TICK();
        ComputeDotProduct(nrow, r, r, normr, t4, dcFT, ctx, lrt);
        TOCK(t1);
        normr = sqrt(normr);
        //
        if (rank == 0 && ( k % print_freq == 0 || k == max_iter)) {
            cout << "Iteration = "<< k << "   Scaled Residual = "
                << normr / normr0 << std::endl;
        }
        niters = k;
  }
    // Store times
    times[1] += t1; // dot product time
    times[2] += t2; // WAXPBY time
    times[3] += t3; // SPMV time
    times[4] += t4; // AllReduce time
    times[5] += t5; // preconditioner apply time
    times[6] += t6; // exchange halo time
    times[0] += mytimer() - t_begin;  // Total time. All done...

    return 0;
}
<commit_msg>CG cleanup.<commit_after>/**
 * Copyright (c) 2016-2017 Los Alamos National Security, LLC
 *                         All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * LA-CC 10-123
 */

//@HEADER
// ***************************************************
//
// HPCG: High Performance Conjugate Gradient Benchmark
//
// Contact:
// Michael A. Heroux ( maherou@sandia.gov)
// Jack Dongarra     (dongarra@eecs.utk.edu)
// Piotr Luszczek    (luszczek@eecs.utk.edu)
//
// ***************************************************
//@HEADER

/*!
 @file CG.hpp

 HPCG routine
 */

#include <fstream>
#include <cmath>
#include <unistd.h>

#include "hpcg.hpp"
#include "mytimer.hpp"

#include "LegionArrays.hpp"
#include "LegionMatrices.hpp"
#include "LegionCGData.hpp"
#include "VectorOps.hpp"

#include "ComputeSPMV.hpp"
#include "ComputeWAXPBY.hpp"
#include "ComputeDotProduct.hpp"

#if 0
#include "ComputeMG_ref.hpp"
#endif

// Use TICK and TOCK to time a code section in MATLAB-like fashion
#define TICK()  t0 = mytimer() //!< record current time in 't0'
#define TOCK(t) t += mytimer() - t0 //!< store time difference in 't' using time in 't0'

/*!
  Reference routine to compute an approximate solution to Ax = b

  @param[inout] A    The known system matrix
  @param[inout] data The data structure with all necessary CG vectors
                     preallocated
  @param[in]    b    The known right hand side vector
  @param[inout] x    On entry: the initial guess; on exit: the new approximate
                     solution
  @param[in]    max_iter  The maximum number of iterations to perform, even if
                tolerance is not met.
  @param[in]    tolerance The stopping criterion to assert convergence: if norm
                of residual is <= to tolerance.
  @param[out]   niters    The number of iterations actually performed.
  @param[out]   normr     The 2-norm of the residual vector after the last
                          iteration.
  @param[out]   normr0    The 2-norm of the residual vector before the first
                          iteration.
  @param[out]   times     The 7-element vector of the timing information
                          accumulated during all of the iterations.
  @param[in]    doPreconditioning The flag to indicate whether the
                preconditioner should be invoked at each iteration.

  @return Returns zero on success and a non-zero value otherwise.

  @see CG()
*/
inline int
CG(
    SparseMatrix &A,
    CGData &data,
    const Array<floatType> &b,
    Array<floatType> &x,
    const int max_iter,
    const double tolerance,
    int &niters,
    double &normr,
    double &normr0,
    double *times,
    bool doPreconditioning,
    LegionRuntime::HighLevel::Context ctx,
    LegionRuntime::HighLevel::Runtime *lrt
) {
    using namespace std;

    double t_begin = mytimer();  // Start timing right away
    //
    const int print_freq = 50;
    const int rank = A.geom->data()->rank;
    const local_int_t nrow = A.sclrs->data()->localNumberOfRows;
    //
    double rtz = 0.0, oldrtz = 0.0, alpha = 0.0, beta = 0.0, pAp = 0.0;
    double t0 = 0.0, t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0, t6 = 0.0;

    normr = 0.0;

    Array<floatType> &r  = *(data.r); // Residual vector.
    Array<floatType> &z  = *(data.z); // Preconditioned residual vector.
    Array<floatType> &p  = *(data.p); // Direction vector (ncol >= nrow).
    Array<floatType> &Ap = *(data.Ap);// Holds result from A * p.

    Item< DynColl<floatType> > &dcFT = *A.dcAllRedSumFT;

    if (!doPreconditioning && rank == 0) {
        std::cout << "WARNING: PERFORMING UNPRECONDITIONED ITERATIONS" << std::endl;
    }
    // p is of length ncols, copy x to p for sparse MV operation
    CopyVector(x, p, ctx, lrt);
    //
    TICK(); // Ap = A*p
    ComputeSPMV(A, p, Ap, ctx, lrt);  TOCK(t3); // Ap = A*p
    TOCK(t3);
    //
    TICK(); // r = b - Ax (x stored in p)
    ComputeWAXPBY(nrow, 1.0, b, -1.0, Ap, r);
    TOCK(t2);
    //
    TICK();
    ComputeDotProduct(nrow, r, r, normr, t4, dcFT, ctx, lrt);
    TOCK(t1);
    //
    normr = sqrt(normr);
    //
    if (rank == 0) std::cout << "Initial Residual = "<< normr << std::endl;
    // Record initial residual for convergence testing
    normr0 = normr;

    // Start iterations
    for (int k = 1; k <= max_iter && normr / normr0 > tolerance; k++ ) {
        TICK();
        if (doPreconditioning) {
#if 0
            ComputeMG_ref(A, r, z); // Apply preconditioner
#endif
        }
        else {
            // copy r to z (no preconditioning)
            ComputeWAXPBY(nrow, 1.0, r, 0.0, r, z);
        }
        TOCK(t5); // Preconditioner apply time

        if (k == 1) {
            TICK(); CopyVector(z, p, ctx, lrt); TOCK(t2); // Copy Mr to p
            // rtz = r'*z
            TICK();
            ComputeDotProduct(nrow, r, z, rtz, t4, dcFT, ctx, lrt);
            TOCK(t1);
        }
        else {
            oldrtz = rtz;
            //
            TICK(); // rtz = r'*z
            ComputeDotProduct(nrow, r, z, rtz, t4, dcFT, ctx, lrt);
            TOCK(t1);
            //
            beta = rtz / oldrtz;
            //
            TICK(); // p = beta*p + z
            ComputeWAXPBY(nrow, 1.0, z, beta, p, p);
            TOCK(t2);
        }
        TICK(); // Ap = A*p
        ComputeSPMV(A, p, Ap, ctx, lrt);
        TOCK(t3);
        //
        TICK(); // alpha = p'*Ap
        ComputeDotProduct(nrow, p, Ap, pAp, t4, dcFT, ctx, lrt);
        TOCK(t1);
        //
        alpha = rtz / pAp;
        //
        TICK(); // x = x + alpha*p
        ComputeWAXPBY(nrow, 1.0, x, alpha, p, x);
        // r = r - alpha*Ap
        ComputeWAXPBY(nrow, 1.0, r, -alpha, Ap, r);
        TOCK(t2);
        //
        TICK();
        ComputeDotProduct(nrow, r, r, normr, t4, dcFT, ctx, lrt);
        TOCK(t1);
        normr = sqrt(normr);
        //
        if (rank == 0 && ( k % print_freq == 0 || k == max_iter)) {
            cout << "Iteration = "<< k << "   Scaled Residual = "
                << normr / normr0 << std::endl;
        }
        niters = k;
  }
    // Store times
    times[1] += t1; // dot product time
    times[2] += t2; // WAXPBY time
    times[3] += t3; // SPMV time
    times[4] += t4; // AllReduce time
    times[5] += t5; // preconditioner apply time
    times[6] += t6; // exchange halo time
    times[0] += mytimer() - t_begin;  // Total time. All done...

    return 0;
}
<|endoftext|>


<commit_before>/*
This file is part of Groho, a simulator for inter-planetary travel and warfare.
Copyright (c) 2017-2018 by Kaushik Ghose. Some rights reserved, see LICENSE

Convenient container for managing data to display for a given object
*/

#pragma once

#include <vector>

#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/Shaders/Flat.h>

#include "globals.hpp"
#include "vector.hpp"

namespace sim {

using namespace Magnum;
using namespace Corrade;

// const float scale = 10 * 149597870.700; // 10 AU

class Path {

public:
    void set_color(Color3 color) { _color = color; }
    void set_data(const std::vector<BodyState> state)
    {
        size_t size = state.size();

        // If we try to map zero points we get a runtime error ...
        if (size == 0) {
            return;
        }

        _buffer.setData(
            { nullptr, size * sizeof(Vector3) }, GL::BufferUsage::StaticDraw);
        Containers::ArrayView<Vector3> data
            = Containers::arrayCast<Vector3>(_buffer.map(
                0,
                size * sizeof(Vector3),
                GL::Buffer::MapFlag::Write
                    | GL::Buffer::MapFlag::InvalidateBuffer));

        CORRADE_INTERNAL_ASSERT(data);

        for (size_t i = 0; i < size; i++) {
            data[i] = { static_cast<float>(state[i].pos.x / globals::scale),
                        static_cast<float>(state[i].pos.y / globals::scale),
                        static_cast<float>(state[i].pos.z / globals::scale) };
        }

        CORRADE_INTERNAL_ASSERT_OUTPUT(_buffer.unmap());

        _mesh.setPrimitive(GL::MeshPrimitive::LineStrip)
            .setCount(size)
            .addVertexBuffer(_buffer, 0, Shaders::Flat3D::Position{});
    }

    void draw(Shaders::Flat3D& shader)
    {
        // shader.setColor(_color);
        // using namespace Math::Literals;
        // shader.setColor(0xff0000_rgbf);
        _mesh.draw(shader.setColor(_color));
    }

private:
    GL::Buffer _buffer;
    GL::Mesh   _mesh;
    Color3     _color;
};
}<commit_msg>refactor: Use v2v function now<commit_after>/*
This file is part of Groho, a simulator for inter-planetary travel and warfare.
Copyright (c) 2017-2018 by Kaushik Ghose. Some rights reserved, see LICENSE

Convenient container for managing data to display for a given object
*/

#pragma once

#include <vector>

#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/Shaders/Flat.h>

#include "globals.hpp"
#include "vector.hpp"
#include "vector2vector.hpp"

namespace sim {

using namespace Magnum;
using namespace Corrade;

// const float scale = 10 * 149597870.700; // 10 AU

class Path {

public:
    void set_color(Color3 color) { _color = color; }
    void set_data(const std::vector<BodyState> state)
    {
        size_t size = state.size();

        // If we try to map zero points we get a runtime error ...
        if (size == 0) {
            return;
        }

        _buffer.setData(
            { nullptr, size * sizeof(Vector3) }, GL::BufferUsage::StaticDraw);
        Containers::ArrayView<Vector3> data
            = Containers::arrayCast<Vector3>(_buffer.map(
                0,
                size * sizeof(Vector3),
                GL::Buffer::MapFlag::Write
                    | GL::Buffer::MapFlag::InvalidateBuffer));

        CORRADE_INTERNAL_ASSERT(data);

        for (size_t i = 0; i < size; i++) {
            data[i] = v2v(state[i].pos);
        }

        CORRADE_INTERNAL_ASSERT_OUTPUT(_buffer.unmap());

        _mesh.setPrimitive(GL::MeshPrimitive::LineStrip)
            .setCount(size)
            .addVertexBuffer(_buffer, 0, Shaders::Flat3D::Position{});
    }

    void draw(Shaders::Flat3D& shader)
    {
        // shader.setColor(_color);
        // using namespace Math::Literals;
        // shader.setColor(0xff0000_rgbf);
        _mesh.draw(shader.setColor(_color));
    }

private:
    GL::Buffer _buffer;
    GL::Mesh   _mesh;
    Color3     _color;
};
}<|endoftext|>


<commit_before>//== Store.cpp - Interface for maps from Locations to Values ----*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the types Store and StoreManager.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/PathSensitive/Store.h"
#include "clang/Analysis/PathSensitive/GRState.h"

using namespace clang;

StoreManager::StoreManager(GRStateManager &stateMgr, bool useNewCastRegion)
  : ValMgr(stateMgr.getValueManager()),
    StateMgr(stateMgr),
    UseNewCastRegion(useNewCastRegion),
    MRMgr(ValMgr.getRegionManager()) {}

StoreManager::CastResult
StoreManager::MakeElementRegion(const GRState *state, const MemRegion *region,
                                QualType pointeeTy, QualType castToTy) {

  // Record the cast type of the region.
  state = setCastType(state, region, castToTy);

  // Create a new ElementRegion at offset 0.
  SVal idx = ValMgr.makeZeroArrayIndex();
  return CastResult(state, MRMgr.getElementRegion(pointeeTy, idx, region,
                                                  ValMgr.getContext()));
}

StoreManager::CastResult
StoreManager::NewCastRegion(const GRState *state, const MemRegion* R,
                            QualType CastToTy) {

  ASTContext& Ctx = StateMgr.getContext();

  // We need to know the real type of CastToTy.
  QualType ToTy = Ctx.getCanonicalType(CastToTy);

  // Handle casts to Objective-C objects.
  if (Ctx.isObjCObjectPointerType(CastToTy)) {
    state = setCastType(state, R, CastToTy);
    return CastResult(state, R);
  }

  // Now assume we are casting from pointer to pointer. Other cases should
  // already be handled.
  QualType PointeeTy = CastToTy->getAsPointerType()->getPointeeType();

  // Process region cast according to the kind of the region being cast.
  switch (R->getKind()) {
    case MemRegion::BEG_TYPED_REGIONS:
    case MemRegion::MemSpaceRegionKind:
    case MemRegion::BEG_DECL_REGIONS:
    case MemRegion::END_DECL_REGIONS:
    case MemRegion::END_TYPED_REGIONS:
    case MemRegion::TypedViewRegionKind: {
      assert(0 && "Invalid region cast");
      break;
    }

    case MemRegion::CodeTextRegionKind: {
      // CodeTextRegion should be cast to only function pointer type.
      assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType()
             || (CastToTy->isPointerType() &&
                 CastToTy->getAsPointerType()->getPointeeType()->isVoidType()));
      break;
    }

    case MemRegion::StringRegionKind:
      // Handle casts of string literals.
      return MakeElementRegion(state, R, PointeeTy, CastToTy);

    case MemRegion::ObjCObjectRegionKind:
    case MemRegion::SymbolicRegionKind:
      // FIXME: Need to handle arbitrary downcasts.
    case MemRegion::AllocaRegionKind: {
      state = setCastType(state, R, CastToTy);
      break;
    }

    case MemRegion::CompoundLiteralRegionKind:
    case MemRegion::ElementRegionKind:
    case MemRegion::FieldRegionKind:
    case MemRegion::ObjCIvarRegionKind:
    case MemRegion::VarRegionKind: {
      // VarRegion, ElementRegion, and FieldRegion has an inherent type. Normally
      // they should not be cast. We only layer an ElementRegion when the cast-to
      // pointee type is of smaller size. In other cases, we return the original
      // VarRegion.

      // If the pointee type is incomplete, do not compute its size, and return
      // the original region.
      if (const RecordType *RT = PointeeTy->getAsRecordType()) {
        const RecordDecl *D = RT->getDecl();
        if (!D->getDefinition(Ctx))
          return CastResult(state, R);
      }

      QualType ObjTy = cast<TypedRegion>(R)->getValueType(Ctx);
      uint64_t PointeeTySize = Ctx.getTypeSize(PointeeTy);
      uint64_t ObjTySize = Ctx.getTypeSize(ObjTy);

      if ((PointeeTySize > 0 && PointeeTySize < ObjTySize) ||
          (ObjTy->isAggregateType() && PointeeTy->isScalarType()) ||
          ObjTySize == 0 /* R has 'void*' type. */)
        return MakeElementRegion(state, R, PointeeTy, ToTy);

      state = setCastType(state, R, ToTy);
      break;
    }
  }

  return CastResult(state, R);
}

StoreManager::CastResult
StoreManager::OldCastRegion(const GRState* state, const MemRegion* R,
                         QualType CastToTy) {

  ASTContext& Ctx = StateMgr.getContext();

  // We need to know the real type of CastToTy.
  QualType ToTy = Ctx.getCanonicalType(CastToTy);

  // Return the same region if the region types are compatible.
  if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
    QualType Ta = Ctx.getCanonicalType(TR->getLocationType(Ctx));

    if (Ta == ToTy)
      return CastResult(state, R);
  }

  if (const PointerType* PTy = dyn_cast<PointerType>(ToTy.getTypePtr())) {
    // Check if we are casting to 'void*'.
    // FIXME: Handle arbitrary upcasts.
    QualType Pointee = PTy->getPointeeType();
    if (Pointee->isVoidType()) {
      while (true) {
        if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
          // Casts to void* removes TypedViewRegion. This happens when:
          //
          // void foo(void*);
          // ...
          // void bar() {
          //   int x;
          //   foo(&x);
          // }
          //
          R = TR->removeViews();
          continue;
        }
        else if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
          // Casts to void* also removes ElementRegions. This happens when:
          //
          // void foo(void*);
          // ...
          // void bar() {
          //   int x;
          //   foo((char*)&x);
          // }
          //
          R = ER->getSuperRegion();
          continue;
        }

        break;
      }

      return CastResult(state, R);
    }
    else if (Pointee->isIntegerType()) {
      // FIXME: At some point, it stands to reason that this 'dyn_cast' should
      //  become a 'cast' and that 'R' will always be a TypedRegion.
      if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
        // Check if we are casting to a region with an integer type.  We now
        // the types aren't the same, so we construct an ElementRegion.
        SVal Idx = ValMgr.makeZeroArrayIndex();

        // If the super region is an element region, strip it away.
        // FIXME: Is this the right thing to do in all cases?
        const MemRegion *Base = isa<ElementRegion>(TR) ? TR->getSuperRegion()
                                                       : TR;
        ElementRegion* ER = MRMgr.getElementRegion(Pointee, Idx, Base,
                                                   StateMgr.getContext());
        return CastResult(state, ER);
      }
    }
  }

  // FIXME: Need to handle arbitrary downcasts.
  // FIXME: Handle the case where a TypedViewRegion (layering a SymbolicRegion
  //         or an AllocaRegion is cast to another view, thus causing the memory
  //         to be re-used for a different purpose.
  if (isa<SymbolicRegion>(R) || isa<AllocaRegion>(R)) {
    const MemRegion* ViewR = MRMgr.getTypedViewRegion(CastToTy, R);
    return CastResult(AddRegionView(state, ViewR, R), ViewR);
  }

  return CastResult(state, R);
}

const GRState *StoreManager::InvalidateRegion(const GRState *state,
                                              const MemRegion *R,
                                              const Expr *E, unsigned Count) {
  ASTContext& Ctx = StateMgr.getContext();

  if (!R->isBoundable())
    return state;

  if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) {
    // Invalidate the alloca region by setting its default value to
    // conjured symbol. The type of the symbol is irrelavant.
    SVal V = ValMgr.getConjuredSymbolVal(E, Ctx.IntTy, Count);
    state = setDefaultValue(state, R, V);
    return state;
  }

  const TypedRegion *TR = cast<TypedRegion>(R);

  QualType T = TR->getValueType(Ctx);

  if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
    SVal V = ValMgr.getConjuredSymbolVal(E, T, Count);
    return Bind(state, ValMgr.makeLoc(TR), V);
  }
  else if (const RecordType *RT = T->getAsStructureType()) {
    // FIXME: handle structs with default region value.
    const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);

    // No record definition.  There is nothing we can do.
    if (!RD)
      return state;

    // Iterate through the fields and construct new symbols.
    for (RecordDecl::field_iterator FI=RD->field_begin(),
           FE=RD->field_end(); FI!=FE; ++FI) {

      // For now just handle scalar fields.
      FieldDecl *FD = *FI;
      QualType FT = FD->getType();
      const FieldRegion* FR = MRMgr.getFieldRegion(FD, TR);

      if (Loc::IsLocType(FT) ||
          (FT->isIntegerType() && FT->isScalarType())) {
        SVal V = ValMgr.getConjuredSymbolVal(E, FT, Count);
        state = state->bindLoc(ValMgr.makeLoc(FR), V);
      }
      else if (FT->isStructureType()) {
        // set the default value of the struct field to conjured
        // symbol. Note that the type of the symbol is irrelavant.
        // We cannot use the type of the struct otherwise ValMgr won't
        // give us the conjured symbol.
        SVal V = ValMgr.getConjuredSymbolVal(E, Ctx.IntTy, Count);
        state = setDefaultValue(state, FR, V);
      }
    }
  } else if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
    // Set the default value of the array to conjured symbol.
    SVal V = ValMgr.getConjuredSymbolVal(E, AT->getElementType(),
                                         Count);
    state = setDefaultValue(state, TR, V);
  } else {
    // Just blast away other values.
    state = Bind(state, ValMgr.makeLoc(TR), UnknownVal());
  }

  return state;
}
<commit_msg>Fix 80 col violation.<commit_after>//== Store.cpp - Interface for maps from Locations to Values ----*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the types Store and StoreManager.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/PathSensitive/Store.h"
#include "clang/Analysis/PathSensitive/GRState.h"

using namespace clang;

StoreManager::StoreManager(GRStateManager &stateMgr, bool useNewCastRegion)
  : ValMgr(stateMgr.getValueManager()),
    StateMgr(stateMgr),
    UseNewCastRegion(useNewCastRegion),
    MRMgr(ValMgr.getRegionManager()) {}

StoreManager::CastResult
StoreManager::MakeElementRegion(const GRState *state, const MemRegion *region,
                                QualType pointeeTy, QualType castToTy) {

  // Record the cast type of the region.
  state = setCastType(state, region, castToTy);

  // Create a new ElementRegion at offset 0.
  SVal idx = ValMgr.makeZeroArrayIndex();
  return CastResult(state, MRMgr.getElementRegion(pointeeTy, idx, region,
                                                  ValMgr.getContext()));
}

StoreManager::CastResult
StoreManager::NewCastRegion(const GRState *state, const MemRegion* R,
                            QualType CastToTy) {

  ASTContext& Ctx = StateMgr.getContext();

  // We need to know the real type of CastToTy.
  QualType ToTy = Ctx.getCanonicalType(CastToTy);

  // Handle casts to Objective-C objects.
  if (Ctx.isObjCObjectPointerType(CastToTy)) {
    state = setCastType(state, R, CastToTy);
    return CastResult(state, R);
  }

  // Now assume we are casting from pointer to pointer. Other cases should
  // already be handled.
  QualType PointeeTy = CastToTy->getAsPointerType()->getPointeeType();

  // Process region cast according to the kind of the region being cast.
  switch (R->getKind()) {
    case MemRegion::BEG_TYPED_REGIONS:
    case MemRegion::MemSpaceRegionKind:
    case MemRegion::BEG_DECL_REGIONS:
    case MemRegion::END_DECL_REGIONS:
    case MemRegion::END_TYPED_REGIONS:
    case MemRegion::TypedViewRegionKind: {
      assert(0 && "Invalid region cast");
      break;
    }

    case MemRegion::CodeTextRegionKind: {
      // CodeTextRegion should be cast to only function pointer type.
      assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType()
             || (CastToTy->isPointerType() &&
                 CastToTy->getAsPointerType()->getPointeeType()->isVoidType()));
      break;
    }

    case MemRegion::StringRegionKind:
      // Handle casts of string literals.
      return MakeElementRegion(state, R, PointeeTy, CastToTy);

    case MemRegion::ObjCObjectRegionKind:
    case MemRegion::SymbolicRegionKind:
      // FIXME: Need to handle arbitrary downcasts.
    case MemRegion::AllocaRegionKind: {
      state = setCastType(state, R, CastToTy);
      break;
    }

    case MemRegion::CompoundLiteralRegionKind:
    case MemRegion::ElementRegionKind:
    case MemRegion::FieldRegionKind:
    case MemRegion::ObjCIvarRegionKind:
    case MemRegion::VarRegionKind: {
      // VarRegion, ElementRegion, and FieldRegion has an inherent type.
      // Normally they should not be cast. We only layer an ElementRegion when
      // the cast-to pointee type is of smaller size. In other cases, we return
      // the original VarRegion.

      // If the pointee type is incomplete, do not compute its size, and return
      // the original region.
      if (const RecordType *RT = PointeeTy->getAsRecordType()) {
        const RecordDecl *D = RT->getDecl();
        if (!D->getDefinition(Ctx))
          return CastResult(state, R);
      }

      QualType ObjTy = cast<TypedRegion>(R)->getValueType(Ctx);
      uint64_t PointeeTySize = Ctx.getTypeSize(PointeeTy);
      uint64_t ObjTySize = Ctx.getTypeSize(ObjTy);

      if ((PointeeTySize > 0 && PointeeTySize < ObjTySize) ||
          (ObjTy->isAggregateType() && PointeeTy->isScalarType()) ||
          ObjTySize == 0 /* R has 'void*' type. */)
        return MakeElementRegion(state, R, PointeeTy, ToTy);

      state = setCastType(state, R, ToTy);
      break;
    }
  }

  return CastResult(state, R);
}

StoreManager::CastResult
StoreManager::OldCastRegion(const GRState* state, const MemRegion* R,
                         QualType CastToTy) {

  ASTContext& Ctx = StateMgr.getContext();

  // We need to know the real type of CastToTy.
  QualType ToTy = Ctx.getCanonicalType(CastToTy);

  // Return the same region if the region types are compatible.
  if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
    QualType Ta = Ctx.getCanonicalType(TR->getLocationType(Ctx));

    if (Ta == ToTy)
      return CastResult(state, R);
  }

  if (const PointerType* PTy = dyn_cast<PointerType>(ToTy.getTypePtr())) {
    // Check if we are casting to 'void*'.
    // FIXME: Handle arbitrary upcasts.
    QualType Pointee = PTy->getPointeeType();
    if (Pointee->isVoidType()) {
      while (true) {
        if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
          // Casts to void* removes TypedViewRegion. This happens when:
          //
          // void foo(void*);
          // ...
          // void bar() {
          //   int x;
          //   foo(&x);
          // }
          //
          R = TR->removeViews();
          continue;
        }
        else if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
          // Casts to void* also removes ElementRegions. This happens when:
          //
          // void foo(void*);
          // ...
          // void bar() {
          //   int x;
          //   foo((char*)&x);
          // }
          //
          R = ER->getSuperRegion();
          continue;
        }

        break;
      }

      return CastResult(state, R);
    }
    else if (Pointee->isIntegerType()) {
      // FIXME: At some point, it stands to reason that this 'dyn_cast' should
      //  become a 'cast' and that 'R' will always be a TypedRegion.
      if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
        // Check if we are casting to a region with an integer type.  We now
        // the types aren't the same, so we construct an ElementRegion.
        SVal Idx = ValMgr.makeZeroArrayIndex();

        // If the super region is an element region, strip it away.
        // FIXME: Is this the right thing to do in all cases?
        const MemRegion *Base = isa<ElementRegion>(TR) ? TR->getSuperRegion()
                                                       : TR;
        ElementRegion* ER = MRMgr.getElementRegion(Pointee, Idx, Base,
                                                   StateMgr.getContext());
        return CastResult(state, ER);
      }
    }
  }

  // FIXME: Need to handle arbitrary downcasts.
  // FIXME: Handle the case where a TypedViewRegion (layering a SymbolicRegion
  //         or an AllocaRegion is cast to another view, thus causing the memory
  //         to be re-used for a different purpose.
  if (isa<SymbolicRegion>(R) || isa<AllocaRegion>(R)) {
    const MemRegion* ViewR = MRMgr.getTypedViewRegion(CastToTy, R);
    return CastResult(AddRegionView(state, ViewR, R), ViewR);
  }

  return CastResult(state, R);
}

const GRState *StoreManager::InvalidateRegion(const GRState *state,
                                              const MemRegion *R,
                                              const Expr *E, unsigned Count) {
  ASTContext& Ctx = StateMgr.getContext();

  if (!R->isBoundable())
    return state;

  if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) {
    // Invalidate the alloca region by setting its default value to
    // conjured symbol. The type of the symbol is irrelavant.
    SVal V = ValMgr.getConjuredSymbolVal(E, Ctx.IntTy, Count);
    state = setDefaultValue(state, R, V);
    return state;
  }

  const TypedRegion *TR = cast<TypedRegion>(R);

  QualType T = TR->getValueType(Ctx);

  if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
    SVal V = ValMgr.getConjuredSymbolVal(E, T, Count);
    return Bind(state, ValMgr.makeLoc(TR), V);
  }
  else if (const RecordType *RT = T->getAsStructureType()) {
    // FIXME: handle structs with default region value.
    const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);

    // No record definition.  There is nothing we can do.
    if (!RD)
      return state;

    // Iterate through the fields and construct new symbols.
    for (RecordDecl::field_iterator FI=RD->field_begin(),
           FE=RD->field_end(); FI!=FE; ++FI) {

      // For now just handle scalar fields.
      FieldDecl *FD = *FI;
      QualType FT = FD->getType();
      const FieldRegion* FR = MRMgr.getFieldRegion(FD, TR);

      if (Loc::IsLocType(FT) ||
          (FT->isIntegerType() && FT->isScalarType())) {
        SVal V = ValMgr.getConjuredSymbolVal(E, FT, Count);
        state = state->bindLoc(ValMgr.makeLoc(FR), V);
      }
      else if (FT->isStructureType()) {
        // set the default value of the struct field to conjured
        // symbol. Note that the type of the symbol is irrelavant.
        // We cannot use the type of the struct otherwise ValMgr won't
        // give us the conjured symbol.
        SVal V = ValMgr.getConjuredSymbolVal(E, Ctx.IntTy, Count);
        state = setDefaultValue(state, FR, V);
      }
    }
  } else if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
    // Set the default value of the array to conjured symbol.
    SVal V = ValMgr.getConjuredSymbolVal(E, AT->getElementType(),
                                         Count);
    state = setDefaultValue(state, TR, V);
  } else {
    // Just blast away other values.
    state = Bind(state, ValMgr.makeLoc(TR), UnknownVal());
  }

  return state;
}
<|endoftext|>


<commit_before>// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "Coroutine.hpp"
#include "Reactor.hpp"

#include "benchmark/benchmark.h"

BENCHMARK_MAIN();

class Coroutines : public benchmark::Fixture
{
public:
	void SetUp(const ::benchmark::State &state) {}

	void TearDown(const ::benchmark::State &state) {}
};

BENCHMARK_DEFINE_F(Coroutines, Fibonacci)
(benchmark::State &state)
{
	using namespace rr;

	if(!Caps.CoroutinesSupported)
	{
		state.SkipWithError("Coroutines are not supported");
		return;
	}

	Coroutine<int()> function;
	{
		Yield(Int(0));
		Yield(Int(1));
		Int current = 1;
		Int next = 1;
		While(true)
		{
			Yield(next);
			auto tmp = current + next;
			current = next;
			next = tmp;
		}
	}

	auto coroutine = function();

	const auto iterations = state.range(0);

	int out = 0;
	for(auto _ : state)
	{
		for(int64_t i = 0; i < iterations; i++)
		{
			coroutine->await(out);
		}
	}
}

BENCHMARK_REGISTER_F(Coroutines, Fibonacci)->RangeMultiplier(8)->Range(1, 0x1000000)->ArgName("iterations");
<commit_msg>Add benchmarks for trigonometry and transcendental functions<commit_after>// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "Coroutine.hpp"
#include "Reactor.hpp"

#include "benchmark/benchmark.h"

using namespace rr;

BENCHMARK_MAIN();

class Coroutines : public benchmark::Fixture
{
public:
	void SetUp(const ::benchmark::State &state) {}

	void TearDown(const ::benchmark::State &state) {}
};

BENCHMARK_DEFINE_F(Coroutines, Fibonacci)
(benchmark::State &state)
{
	if(!Caps.CoroutinesSupported)
	{
		state.SkipWithError("Coroutines are not supported");
		return;
	}

	Coroutine<int()> function;
	{
		Yield(Int(0));
		Yield(Int(1));
		Int current = 1;
		Int next = 1;
		While(true)
		{
			Yield(next);
			auto tmp = current + next;
			current = next;
			next = tmp;
		}
	}

	auto coroutine = function();

	const auto iterations = state.range(0);

	int out = 0;
	for(auto _ : state)
	{
		for(int64_t i = 0; i < iterations; i++)
		{
			coroutine->await(out);
		}
	}
}

BENCHMARK_REGISTER_F(Coroutines, Fibonacci)->RangeMultiplier(8)->Range(1, 0x1000000)->ArgName("iterations");

// Macro that creates a lambda wrapper around the input overloaded function,
// creating a non-overload based on the args. This is useful for passing
// overloaded functions as template arguments.
// See https://stackoverflow.com/questions/25871381/c-overloaded-function-as-template-argument
#define LIFT(fname)                                          \
	[](auto &&...args) -> decltype(auto) {                   \
		return fname(std::forward<decltype(args)>(args)...); \
	}

template<typename Func, class... Args>
static void Transcedental1(benchmark::State &state, Func func, Args &&...args)
{
	FunctionT<float(float)> function;
	{
		Float a = function.Arg<0>();
		Float4 v{ a };
		Float4 r = func(v, args...);
		Return(Float(r.x));
	}

	auto routine = function("one");

	for(auto _ : state)
	{
		routine(1.f);
	}
}

template<typename Func, class... Args>
static void Transcedental2(benchmark::State &state, Func func, Args &&...args)
{
	FunctionT<float(float, float)> function;
	{
		Float a = function.Arg<0>();
		Float b = function.Arg<1>();
		Float4 v1{ a };
		Float4 v2{ b };
		Float4 r = func(v1, v2, args...);
		Return(Float(r.x));
	}

	auto routine = function("two");

	for(auto _ : state)
	{
		routine(0.456f, 0.789f);
	}
}

BENCHMARK_CAPTURE(Transcedental1, rr_Sin, Sin);
BENCHMARK_CAPTURE(Transcedental1, rr_Cos, Cos);
BENCHMARK_CAPTURE(Transcedental1, rr_Tan, Tan);

BENCHMARK_CAPTURE(Transcedental1, rr_Asin_fullp, Asin, Precision::Full);
BENCHMARK_CAPTURE(Transcedental1, rr_Asin_relaxedp, Asin, Precision::Relaxed);
BENCHMARK_CAPTURE(Transcedental1, rr_Acos_fullp, Acos, Precision::Full);
BENCHMARK_CAPTURE(Transcedental1, rr_Acos_relaxedp, Acos, Precision::Relaxed);

BENCHMARK_CAPTURE(Transcedental1, rr_Atan, Atan);
BENCHMARK_CAPTURE(Transcedental1, rr_Sinh, Sinh);
BENCHMARK_CAPTURE(Transcedental1, rr_Cosh, Cosh);
BENCHMARK_CAPTURE(Transcedental1, rr_Tanh, Tanh);

BENCHMARK_CAPTURE(Transcedental1, rr_Asinh, Asinh);
BENCHMARK_CAPTURE(Transcedental1, rr_Acosh, Acosh);
BENCHMARK_CAPTURE(Transcedental1, rr_Atanh, Atanh);
BENCHMARK_CAPTURE(Transcedental2, rr_Atan2, Atan2);

BENCHMARK_CAPTURE(Transcedental2, rr_Pow, Pow);
BENCHMARK_CAPTURE(Transcedental1, rr_Exp, Exp);
BENCHMARK_CAPTURE(Transcedental1, rr_Log, Log);
BENCHMARK_CAPTURE(Transcedental1, rr_Exp2, LIFT(Exp2));
BENCHMARK_CAPTURE(Transcedental1, rr_Log2, LIFT(Log2));

BENCHMARK_CAPTURE(Transcedental1, rr_Rcp_pp_exactAtPow2_true, LIFT(Rcp_pp), true);
BENCHMARK_CAPTURE(Transcedental1, rr_Rcp_pp_exactAtPow2_false, LIFT(Rcp_pp), false);
BENCHMARK_CAPTURE(Transcedental1, rr_RcpSqrt_pp, LIFT(RcpSqrt_pp));
<|endoftext|>