<commit_before>/*
 * Copyright © 2012, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
 * under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
*/

/**
 * @file tgStructureInfo.cpp
 * @brief Implementation of class tgStructureInfo
 * @author Ryan Adams
 * @date January 2014
 * $Id$
 */

// This module
#include "tgStructureInfo.h"
// This library
#include "tgConnectorInfo.h"
#include "tgRigidAutoCompound.h"
#include "tgStructure.h"
#include "core/tgWorld.h"
#include "core/tgModel.h"
// The C++ Standard Library
#include <stdexcept>

tgStructureInfo::tgStructureInfo(tgStructure& structure, tgBuildSpec& buildSpec) :
    tgTaggable(),
    m_structure(structure),
    m_buildSpec(buildSpec)
{
    createTree(*this, structure);
}

tgStructureInfo::tgStructureInfo(tgStructure& structure, tgBuildSpec& buildSpec,
                 const tgTags& tags) :
    tgTaggable(tags),
    m_structure(structure),
    m_buildSpec(buildSpec)
{
    createTree(*this, structure);
}

tgStructureInfo::~tgStructureInfo()
{
    // Have to do this first, if all the rigids are deleted it segfaults
    for (std::size_t i = 0; i < m_compounded.size(); i++)
    {
        const tgRigidInfo * const pRigidInfo = m_compounded[i];
    assert(pRigidInfo != NULL);
    // If this is true, rigid is in a group with itself, and
    // will be deleted with m_rigids
    if (pRigidInfo->getRigidInfoGroup() != pRigidInfo)
    {
        delete pRigidInfo;
    }
    }

    for (std::size_t i = 0; i < m_rigids.size(); i++)
    {
    delete m_rigids[i];
    }

    for (std::size_t i = 0; i < m_connectors.size(); i++)
    {
    delete m_connectors[i];
    }

    for (std::size_t i = 0; i < m_children.size(); i++)
    {
    delete m_children[i];
    }
}

void tgStructureInfo::createTree(tgStructureInfo& structureInfo,
                 const tgStructure& structure)
{
    const std::vector<tgStructure*> children = structure.getChildren();
    for (std::size_t i = 0; i < children.size(); i++)
    {
        tgStructure * const pStructure = children[i];
    assert(pStructure != NULL);
        tgStructureInfo* const pStructureInfo =
        new tgStructureInfo(*pStructure, m_buildSpec, pStructure->getTags());
        structureInfo.addChild(pStructureInfo);
        createTree(*pStructureInfo, *pStructure);
    }
}

std::vector<tgRigidInfo*> tgStructureInfo::getAllRigids() const
{
    std::vector<tgRigidInfo*> result;
    result.insert(result.end(), m_rigids.begin(), m_rigids.end());

    // Collect child rigids
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        std::vector<tgRigidInfo*> childRigids = pStructureInfo->getAllRigids();
        result.insert(result.end(), childRigids.begin(), childRigids.end());
    }

    return result;
}

////////////////////////////
// Build methods
////////////////////////////

void tgStructureInfo::addRigidsAndConnectors() {
    const std::vector<tgBuildSpec::RigidAgent*> rigidAgents = m_buildSpec.getRigidAgents();
    const std::vector<tgBuildSpec::ConnectorAgent*> connectorAgents = m_buildSpec.getConnectorAgents();

    const tgNodes& nodes = m_structure.getNodes();
    const tgPairs& pairs = m_structure.getPairs();

    // for each node, create a rigidInfo object using a matching rigidAgent
    for (int i = 0; i < nodes.size(); i++) {
        tgRigidInfo* nodeRigid = initRigidInfo<tgNode>(nodes[i], rigidAgents);
        if (nodeRigid) {
            m_rigids.push_back(nodeRigid);
        }
    }
    // for each pair, create a rigidInfo or connectorInfo object using a matching rigidAgent or connectorAgent
    for (int i = 0; i < pairs.size(); i++) {
        tgRigidInfo* pairRigid = initRigidInfo<tgPair>(pairs[i], rigidAgents);
        if (pairRigid) {
            m_rigids.push_back(pairRigid);
        }
        else {
            tgConnectorInfo* pairConnector = initConnectorInfo<tgPair>(pairs[i], connectorAgents);
            if (pairConnector) {
                m_connectors.push_back(pairConnector);
            }
        }
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++) {
        tgStructureInfo* const pStructureInfo = m_children[i];

        assert(pStructureInfo != NULL);
        pStructureInfo->addRigidsAndConnectors();
    }
}

template <class T>
tgRigidInfo* tgStructureInfo::initRigidInfo(const T& rigidCandidate, const std::vector<tgBuildSpec::RigidAgent*>& rigidAgents) const {
    for (int i = rigidAgents.size() - 1; i >= 0; i--) {
        const tgBuildSpec::RigidAgent* pRigidAgent = rigidAgents[i];
        assert(pRigidAgent != NULL);

        tgTagSearch tagSearch = tgTagSearch(pRigidAgent->tagSearch);

        // Remove our tags so that subcomponents 'inherit' them (because of the
        // way tags work, removing a tag from the search is the same as adding
        // the tag to children to be searched)
        tagSearch.remove(getTags());

        tgRigidInfo* pRigidInfo = pRigidAgent->infoFactory;
        assert(pRigidInfo != NULL);

        tgRigidInfo* rigid = pRigidInfo->createRigidInfo(rigidCandidate, tagSearch);
        if (rigid) // check if a tgRigidInfo was found
            return rigid;
    }
    return 0;
}

template <class T>
tgConnectorInfo* tgStructureInfo::initConnectorInfo(const T& connectorCandidate, const std::vector<tgBuildSpec::ConnectorAgent*>& connectorAgents) const {
    for (int i = connectorAgents.size() - 1; i >= 0; i--) {
        const tgBuildSpec::ConnectorAgent*  pConnectorAgent = connectorAgents[i];
        assert(pConnectorAgent != NULL);

        tgTagSearch tagSearch = tgTagSearch(pConnectorAgent->tagSearch);

        // Remove our tags so that subcomponents 'inherit' them (because of the
        // way tags work, removing a tag from the search is the same as adding
        // the tag to children to be searched)
        tagSearch.remove(getTags());

        tgConnectorInfo* pConnectorInfo = pConnectorAgent->infoFactory;
        assert(pConnectorInfo != NULL);

        tgConnectorInfo* connector = pConnectorInfo->createConnectorInfo(connectorCandidate, tagSearch);
        if (connector) // check if a tgConnectorInfo was found
            return connector;
    }
    return 0;
}

void tgStructureInfo::autoCompoundRigids()
{
    tgRigidAutoCompound c(getAllRigids());
    m_compounded = c.execute();
}

void tgStructureInfo::chooseConnectorRigids()
{
    chooseConnectorRigids(getAllRigids());
}

void tgStructureInfo::chooseConnectorRigids(std::vector<tgRigidInfo*> allRigids)
{
    for (std::size_t i = 0; i < m_connectors.size(); i++)
    {
        tgConnectorInfo * const pConnectorInfo = m_connectors[i];
    assert(pConnectorInfo != NULL);
        pConnectorInfo->chooseRigids(allRigids);
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        pStructureInfo->chooseConnectorRigids(allRigids);
    }
}

void tgStructureInfo::initRigidBodies(tgWorld& world)
{
    // Rigids
    for (std::size_t i = 0; i < m_rigids.size(); i++)
    {
        tgRigidInfo * const pRigidInfo = m_rigids[i];
    assert(pRigidInfo != NULL);
        pRigidInfo->initRigidBody(world);
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        pStructureInfo->initRigidBodies(world);
    }
}

void tgStructureInfo::initConnectors(tgWorld& world)
{
    // Connectors
    for (std::size_t i = 0; i < m_connectors.size(); i++)
    {
        tgConnectorInfo * const pConnectorInfo = m_connectors[i];
    assert(pConnectorInfo != NULL);
        pConnectorInfo->initConnector(world);
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        pStructureInfo->initConnectors(world);
    }
}

void tgStructureInfo::buildInto(tgModel& model, tgWorld& world)
{
    // These take care of things on a global level
    addRigidsAndConnectors();
    autoCompoundRigids();
    chooseConnectorRigids();
    initRigidBodies(world);
    // Note: Muscle2Ps won't show up yet --
    // they need to be part of a model to have rendering...
    initConnectors(world);
    // Now build into the model
    buildIntoHelper(model, world, *this);
}

void tgStructureInfo::buildIntoHelper(tgModel& model, tgWorld& world,
                      tgStructureInfo& structureInfo)
{

    const std::vector<tgRigidInfo*> rigids = structureInfo.getRigids();
    for (std::size_t i = 0; i < rigids.size(); i++)
    {
        tgRigidInfo * const pRigidInfo = rigids[i];
    assert(pRigidInfo != NULL);
        tgModel* const pModel = pRigidInfo->createModel(world);
        if (pModel != NULL)
    {
        pModel->setTags(pRigidInfo->getTags());
            model.addChild(pModel);
        }
    }

    const std::vector<tgConnectorInfo*> connectors = structureInfo.getConnectors();
    for (std::size_t i = 0; i < connectors.size(); i++)
    {
        tgConnectorInfo * const pConnectorInfo = connectors[i];
    assert(pConnectorInfo != NULL);
        tgModel* const pModel = pConnectorInfo->createModel(world);
        if (pModel != NULL)
    {
            pModel->setTags(pConnectorInfo->getTags());
            model.addChild(pModel);
        }
    }

    const std::vector<tgStructureInfo*> children = structureInfo.getChildren();
    for (std::size_t i = 0; i < children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = children[i];
    assert(pStructureInfo != NULL);
        tgModel* const pModel = new tgModel();
    assert(pModel != NULL);
        buildIntoHelper(*pModel, world, *pStructureInfo);
        model.addChild(pModel);
    }

    model.setTags(structureInfo.getTags());
}

void tgStructureInfo::addChild(tgStructureInfo* pChild)
{
    if (pChild == NULL)
    {
        throw std::invalid_argument("Child is NULL");
    }
    else
    {
        m_children.push_back(pChild);
    }
}

std::string tgStructureInfo::toString(const std::string& prefix) const
{
        std::string p = "  ";
        std::ostringstream os;
        os << prefix << "tgStructureInfo(" << std::endl;

        os << prefix << p << "Rigids:" << std::endl;
        for (std::size_t i = 0; i < m_rigids.size(); i++) {
            os << prefix << p << p << *(m_rigids[i]) << std::endl;
        }

        os << prefix << p << "Connectors:" << std::endl;
        for (std::size_t i = 0; i < m_connectors.size(); i++) {
            os << prefix << p << p << *(m_connectors[i]) << std::endl;
        }

        os << prefix << p << "Children:" << std::endl;
        for (std::size_t i = 0; i < m_children.size(); i++) {
            os << m_children[i]->toString(prefix + p + p) << std::endl;
        }

        os << prefix << p << "Tags: [" << getTags() << "]" << std::endl;

        os << prefix << ")" << std::endl;
        return os.str();
}

std::ostream&
operator<<(std::ostream& os, const tgStructureInfo& obj)
{
    os << obj.toString() << std::endl;
    return os;
}

<commit_msg>fix bug where structures with children nested more than one lvl are built twice<commit_after>/*
 * Copyright © 2012, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
 * under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
*/

/**
 * @file tgStructureInfo.cpp
 * @brief Implementation of class tgStructureInfo
 * @author Ryan Adams
 * @date January 2014
 * $Id$
 */

// This module
#include "tgStructureInfo.h"
// This library
#include "tgConnectorInfo.h"
#include "tgRigidAutoCompound.h"
#include "tgStructure.h"
#include "core/tgWorld.h"
#include "core/tgModel.h"
// The C++ Standard Library
#include <stdexcept>

tgStructureInfo::tgStructureInfo(tgStructure& structure, tgBuildSpec& buildSpec) :
    tgTaggable(),
    m_structure(structure),
    m_buildSpec(buildSpec)
{
    createTree(*this, structure);
}

tgStructureInfo::tgStructureInfo(tgStructure& structure, tgBuildSpec& buildSpec,
                 const tgTags& tags) :
    tgTaggable(tags),
    m_structure(structure),
    m_buildSpec(buildSpec)
{
    createTree(*this, structure);
}

tgStructureInfo::~tgStructureInfo()
{
    // Have to do this first, if all the rigids are deleted it segfaults
    for (std::size_t i = 0; i < m_compounded.size(); i++)
    {
        const tgRigidInfo * const pRigidInfo = m_compounded[i];
    assert(pRigidInfo != NULL);
    // If this is true, rigid is in a group with itself, and
    // will be deleted with m_rigids
    if (pRigidInfo->getRigidInfoGroup() != pRigidInfo)
    {
        delete pRigidInfo;
    }
    }

    for (std::size_t i = 0; i < m_rigids.size(); i++)
    {
    delete m_rigids[i];
    }

    for (std::size_t i = 0; i < m_connectors.size(); i++)
    {
    delete m_connectors[i];
    }

    for (std::size_t i = 0; i < m_children.size(); i++)
    {
    delete m_children[i];
    }
}

void tgStructureInfo::createTree(tgStructureInfo& structureInfo,
                 const tgStructure& structure)
{
    const std::vector<tgStructure*> children = structure.getChildren();
    for (std::size_t i = 0; i < children.size(); i++)
    {
        tgStructure * const pStructure = children[i];
    assert(pStructure != NULL);
        tgStructureInfo* const pStructureInfo =
        new tgStructureInfo(*pStructure, m_buildSpec, pStructure->getTags());
        structureInfo.addChild(pStructureInfo);
    }
}

std::vector<tgRigidInfo*> tgStructureInfo::getAllRigids() const
{
    std::vector<tgRigidInfo*> result;
    result.insert(result.end(), m_rigids.begin(), m_rigids.end());

    // Collect child rigids
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        std::vector<tgRigidInfo*> childRigids = pStructureInfo->getAllRigids();
        result.insert(result.end(), childRigids.begin(), childRigids.end());
    }

    return result;
}

////////////////////////////
// Build methods
////////////////////////////

void tgStructureInfo::addRigidsAndConnectors() {
    const std::vector<tgBuildSpec::RigidAgent*> rigidAgents = m_buildSpec.getRigidAgents();
    const std::vector<tgBuildSpec::ConnectorAgent*> connectorAgents = m_buildSpec.getConnectorAgents();

    const tgNodes& nodes = m_structure.getNodes();
    const tgPairs& pairs = m_structure.getPairs();

    // for each node, create a rigidInfo object using a matching rigidAgent
    for (int i = 0; i < nodes.size(); i++) {
        tgRigidInfo* nodeRigid = initRigidInfo<tgNode>(nodes[i], rigidAgents);
        if (nodeRigid) {
            m_rigids.push_back(nodeRigid);
        }
    }
    // for each pair, create a rigidInfo or connectorInfo object using a matching rigidAgent or connectorAgent
    for (int i = 0; i < pairs.size(); i++) {
        tgRigidInfo* pairRigid = initRigidInfo<tgPair>(pairs[i], rigidAgents);
        if (pairRigid) {
            m_rigids.push_back(pairRigid);
        }
        else {
            tgConnectorInfo* pairConnector = initConnectorInfo<tgPair>(pairs[i], connectorAgents);
            if (pairConnector) {
                m_connectors.push_back(pairConnector);
            }
        }
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++) {
        tgStructureInfo* const pStructureInfo = m_children[i];

        assert(pStructureInfo != NULL);
        pStructureInfo->addRigidsAndConnectors();
    }
}

template <class T>
tgRigidInfo* tgStructureInfo::initRigidInfo(const T& rigidCandidate, const std::vector<tgBuildSpec::RigidAgent*>& rigidAgents) const {
    for (int i = rigidAgents.size() - 1; i >= 0; i--) {
        const tgBuildSpec::RigidAgent* pRigidAgent = rigidAgents[i];
        assert(pRigidAgent != NULL);

        tgTagSearch tagSearch = tgTagSearch(pRigidAgent->tagSearch);

        // Remove our tags so that subcomponents 'inherit' them (because of the
        // way tags work, removing a tag from the search is the same as adding
        // the tag to children to be searched)
        tagSearch.remove(getTags());

        tgRigidInfo* pRigidInfo = pRigidAgent->infoFactory;
        assert(pRigidInfo != NULL);

        tgRigidInfo* rigid = pRigidInfo->createRigidInfo(rigidCandidate, tagSearch);
        if (rigid) // check if a tgRigidInfo was found
            return rigid;
    }
    return 0;
}

template <class T>
tgConnectorInfo* tgStructureInfo::initConnectorInfo(const T& connectorCandidate, const std::vector<tgBuildSpec::ConnectorAgent*>& connectorAgents) const {
    for (int i = connectorAgents.size() - 1; i >= 0; i--) {
        const tgBuildSpec::ConnectorAgent*  pConnectorAgent = connectorAgents[i];
        assert(pConnectorAgent != NULL);

        tgTagSearch tagSearch = tgTagSearch(pConnectorAgent->tagSearch);

        // Remove our tags so that subcomponents 'inherit' them (because of the
        // way tags work, removing a tag from the search is the same as adding
        // the tag to children to be searched)
        tagSearch.remove(getTags());

        tgConnectorInfo* pConnectorInfo = pConnectorAgent->infoFactory;
        assert(pConnectorInfo != NULL);

        tgConnectorInfo* connector = pConnectorInfo->createConnectorInfo(connectorCandidate, tagSearch);
        if (connector) // check if a tgConnectorInfo was found
            return connector;
    }
    return 0;
}

void tgStructureInfo::autoCompoundRigids()
{
    tgRigidAutoCompound c(getAllRigids());
    m_compounded = c.execute();
}

void tgStructureInfo::chooseConnectorRigids()
{
    chooseConnectorRigids(getAllRigids());
}

void tgStructureInfo::chooseConnectorRigids(std::vector<tgRigidInfo*> allRigids)
{
    for (std::size_t i = 0; i < m_connectors.size(); i++)
    {
        tgConnectorInfo * const pConnectorInfo = m_connectors[i];
    assert(pConnectorInfo != NULL);
        pConnectorInfo->chooseRigids(allRigids);
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        pStructureInfo->chooseConnectorRigids(allRigids);
    }
}

void tgStructureInfo::initRigidBodies(tgWorld& world)
{
    // Rigids
    for (std::size_t i = 0; i < m_rigids.size(); i++)
    {
        tgRigidInfo * const pRigidInfo = m_rigids[i];
    assert(pRigidInfo != NULL);
        pRigidInfo->initRigidBody(world);
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        pStructureInfo->initRigidBodies(world);
    }
}

void tgStructureInfo::initConnectors(tgWorld& world)
{
    // Connectors
    for (std::size_t i = 0; i < m_connectors.size(); i++)
    {
        tgConnectorInfo * const pConnectorInfo = m_connectors[i];
    assert(pConnectorInfo != NULL);
        pConnectorInfo->initConnector(world);
    }

    // Children
    for (std::size_t i = 0; i < m_children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = m_children[i];
    assert(pStructureInfo != NULL);
        pStructureInfo->initConnectors(world);
    }
}

void tgStructureInfo::buildInto(tgModel& model, tgWorld& world)
{
    // These take care of things on a global level
    addRigidsAndConnectors();
    autoCompoundRigids();
    chooseConnectorRigids();
    initRigidBodies(world);
    // Note: Muscle2Ps won't show up yet --
    // they need to be part of a model to have rendering...
    initConnectors(world);
    // Now build into the model
    buildIntoHelper(model, world, *this);
}

void tgStructureInfo::buildIntoHelper(tgModel& model, tgWorld& world,
                      tgStructureInfo& structureInfo)
{

    const std::vector<tgRigidInfo*> rigids = structureInfo.getRigids();
    for (std::size_t i = 0; i < rigids.size(); i++)
    {
        tgRigidInfo * const pRigidInfo = rigids[i];
    assert(pRigidInfo != NULL);
        tgModel* const pModel = pRigidInfo->createModel(world);
        if (pModel != NULL)
    {
        pModel->setTags(pRigidInfo->getTags());
            model.addChild(pModel);
        }
    }

    const std::vector<tgConnectorInfo*> connectors = structureInfo.getConnectors();
    for (std::size_t i = 0; i < connectors.size(); i++)
    {
        tgConnectorInfo * const pConnectorInfo = connectors[i];
    assert(pConnectorInfo != NULL);
        tgModel* const pModel = pConnectorInfo->createModel(world);
        if (pModel != NULL)
    {
            pModel->setTags(pConnectorInfo->getTags());
            model.addChild(pModel);
        }
    }

    const std::vector<tgStructureInfo*> children = structureInfo.getChildren();
    for (std::size_t i = 0; i < children.size(); i++)
    {
        tgStructureInfo * const pStructureInfo = children[i];
    assert(pStructureInfo != NULL);
        tgModel* const pModel = new tgModel();
    assert(pModel != NULL);
        buildIntoHelper(*pModel, world, *pStructureInfo);
        model.addChild(pModel);
    }

    model.setTags(structureInfo.getTags());
}

void tgStructureInfo::addChild(tgStructureInfo* pChild)
{
    if (pChild == NULL)
    {
        throw std::invalid_argument("Child is NULL");
    }
    else
    {
        m_children.push_back(pChild);
    }
}

std::string tgStructureInfo::toString(const std::string& prefix) const
{
        std::string p = "  ";
        std::ostringstream os;
        os << prefix << "tgStructureInfo(" << std::endl;

        os << prefix << p << "Rigids:" << std::endl;
        for (std::size_t i = 0; i < m_rigids.size(); i++) {
            os << prefix << p << p << *(m_rigids[i]) << std::endl;
        }

        os << prefix << p << "Connectors:" << std::endl;
        for (std::size_t i = 0; i < m_connectors.size(); i++) {
            os << prefix << p << p << *(m_connectors[i]) << std::endl;
        }

        os << prefix << p << "Children:" << std::endl;
        for (std::size_t i = 0; i < m_children.size(); i++) {
            os << m_children[i]->toString(prefix + p + p) << std::endl;
        }

        os << prefix << p << "Tags: [" << getTags() << "]" << std::endl;

        os << prefix << ")" << std::endl;
        return os.str();
}

std::ostream&
operator<<(std::ostream& os, const tgStructureInfo& obj)
{
    os << obj.toString() << std::endl;
    return os;
}

<|endoftext|>


<commit_before>/*
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Given an input point cloud, it performs local dimensionality
  estimation (using different schmes) and stores the estimates
  along with the original point cloud.
*/

#include <aleph/containers/DimensionalityEstimators.hh>
#include <aleph/containers/PointCloud.hh>

#include <aleph/geometry/FLANN.hh>
#include <aleph/geometry/BruteForce.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/math/KahanSummation.hh>

#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <getopt.h>

using DataType   = double;
using PointCloud = aleph::containers::PointCloud<DataType>;
using Distance   = aleph::geometry::distances::Euclidean<DataType>;

#ifdef ALEPH_WITH_FLANN
  using NearestNeighbours = aleph::geometry::FLANN<PointCloud, Distance>;
#else
  using NearestNeighbours = aleph::geometry::BruteForce<PointCloud, Distance>;
#endif

std::vector<double> smoothValues( const PointCloud& pointCloud, const std::vector<double>& values, unsigned k, unsigned n = 1 )
{
  using IndexType   = typename NearestNeighbours::IndexType;
  using ElementType = typename NearestNeighbours::ElementType;

  std::vector< std::vector<IndexType> > indices;
  std::vector< std::vector<ElementType> > distances;

  NearestNeighbours nn( pointCloud );
  nn.neighbourSearch( k+1, indices, distances );

  std::vector<double> result = values;

  for( unsigned iteration = 0; iteration < n; iteration++ )
  {
    std::vector<double> values_;
    values_.resize( values.size() );

    for( std::size_t i = 0; i < pointCloud.size(); i++ )
    {
      auto&& neighbours_  = indices[i];
      auto&& distances_   = distances[i];

      aleph::math::KahanSummation<double> value        = 0.0;
      aleph::math::KahanSummation<double> sumOfWeights = 0.0;

      for( std::size_t j = 0; j < neighbours_.size(); j++ )
      {
        auto index    = neighbours_[j];
        auto weight   = distances_[j] > 0 ? 1.0 / ( distances_[j] * distances_[j] ) : 1.0;
        value        += result[ index ] * weight;
        sumOfWeights += weight;
      }

      value      /= sumOfWeights;
      values_[i]  = value;
    }

    result.swap( values_ );
  }

  return result;
}

int main( int argc, char** argv )
{
  std::string method = "pca";
  unsigned k         = 8;
  unsigned K         = 0;
  unsigned n         = 1;
  bool smooth        = false;

  {
    static option commandLineOptions[] =
    {
      { "k"          , required_argument, nullptr, 'k' },
      { "K"          , required_argument, nullptr, 'K' },
      { "method"     , required_argument, nullptr, 'm' },
      { "n"          , required_argument, nullptr, 'n' },
      { "smooth"     , no_argument      , nullptr, 's' },
      { nullptr      , 0                , nullptr,  0  }
    };

    int option = 0;
    while( ( option = getopt_long( argc, argv, "k:K:m:n:s", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'k':
        k = static_cast<unsigned>( std::stoull( optarg ) );
        break;
      case 'K':
        K = static_cast<unsigned>( std::stoull( optarg ) );
        break;
      case 'm':
        method = optarg;
        break;
      case 'n':
        n = static_cast<unsigned>( std::stoull( optarg ) );
        break;
      case 's':
        smooth = true;
        break;
      }
    }
  }

  if( ( argc - optind ) < 1 )
    return -1;

  std::string filename = argv[ optind++ ];

  std::cerr << "* Loading point cloud from '" << filename << "'...";

  PointCloud pc = aleph::containers::load<DataType>( filename );

  std::cerr << "finished\n"
            << "* Loaded point cloud with " << pc.size() << " points of dimension " << pc.dimension() << "\n";

  std::vector<double> dimensionalities;

  if( method == "pca" )
  {
    std::cerr << "* Estimating local dimensionality using PCA (k=" << k << ")...";

    auto result
      = aleph::containers::estimateLocalDimensionalityPCA<Distance, PointCloud, NearestNeighbours>( pc, k );

    // converts data in the vector so that we don't have to do it
    // manually
    dimensionalities.assign( result.begin(), result.end() );
  }
  else if( method == "nn" )
  {
    if( K == 0 )
    {
      std::cerr << "* Estimating local dimensionality using nearest neighbours (k=" << k << ")...";

      dimensionalities
        = aleph::containers::estimateLocalDimensionalityNearestNeighbours<Distance, PointCloud, NearestNeighbours>(
          pc, k );
    }
    else if( k <= K )
    {
      std::cerr << "* Estimating local dimensionality using nearest neighbours (k=" << k << ", K=" << K << ")...";

      dimensionalities
        = aleph::containers::estimateLocalDimensionalityNearestNeighbours<Distance, PointCloud, NearestNeighbours>(
        pc, k, K );
    }
  }
  else if( method == "mle" )
  {
    std::cerr << "* Estimating local dimensionality using nearest neighbours and MLE (k=" << k << ")...";

    if( k > K )
      throw std::runtime_error( "Missing maximum parameter for nearest neighbours" );

    dimensionalities
      = aleph::containers::estimateLocalDimensionalityNearestNeighboursMLE<Distance, PointCloud, NearestNeighbours>(
      pc, k, K
    );
  }
  else if( method == "mst" )
  {
    std::cerr << "* Estimating local dimensionality using MST...";

    dimensionalities
      = aleph::containers::estimateLocalDimensionalityNearestNeighbours<Distance>( pc );
  }

  std::cerr << "finished\n";

  // Output ------------------------------------------------------------

  if( smooth )
  {
    std::cerr << "* Performing smoothing operation with k=" << k << " and n=" << n << "...";

    dimensionalities
      = smoothValues( pc,
                      dimensionalities,
                      k,
                      n );

    std::cerr << "\n";
  }

  for( auto&& d : dimensionalities )
    std::cout << d << "\n";
}
<commit_msg>Added mean--shift smoothing function to local dimensionality estimation tool<commit_after>/*
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Given an input point cloud, it performs local dimensionality
  estimation (using different schmes) and stores the estimates
  along with the original point cloud.
*/

#include <aleph/containers/DimensionalityEstimators.hh>
#include <aleph/containers/MeanShift.hh>
#include <aleph/containers/PointCloud.hh>

#include <aleph/geometry/FLANN.hh>
#include <aleph/geometry/BruteForce.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/math/KahanSummation.hh>

#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <getopt.h>

using DataType   = double;
using PointCloud = aleph::containers::PointCloud<DataType>;
using Distance   = aleph::geometry::distances::Euclidean<DataType>;

#ifdef ALEPH_WITH_FLANN
  using NearestNeighbours = aleph::geometry::FLANN<PointCloud, Distance>;
#else
  using NearestNeighbours = aleph::geometry::BruteForce<PointCloud, Distance>;
#endif

int main( int argc, char** argv )
{
  std::string method = "pca";
  unsigned k         = 8;
  unsigned K         = 0;
  unsigned n         = 1;
  bool smooth        = false;

  {
    static option commandLineOptions[] =
    {
      { "k"          , required_argument, nullptr, 'k' },
      { "K"          , required_argument, nullptr, 'K' },
      { "method"     , required_argument, nullptr, 'm' },
      { "n"          , required_argument, nullptr, 'n' },
      { "smooth"     , no_argument      , nullptr, 's' },
      { nullptr      , 0                , nullptr,  0  }
    };

    int option = 0;
    while( ( option = getopt_long( argc, argv, "k:K:m:n:s", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'k':
        k = static_cast<unsigned>( std::stoull( optarg ) );
        break;
      case 'K':
        K = static_cast<unsigned>( std::stoull( optarg ) );
        break;
      case 'm':
        method = optarg;
        break;
      case 'n':
        n = static_cast<unsigned>( std::stoull( optarg ) );
        break;
      case 's':
        smooth = true;
        break;
      }
    }
  }

  if( ( argc - optind ) < 1 )
    return -1;

  std::string filename = argv[ optind++ ];

  std::cerr << "* Loading point cloud from '" << filename << "'...";

  PointCloud pc = aleph::containers::load<DataType>( filename );

  std::cerr << "finished\n"
            << "* Loaded point cloud with " << pc.size() << " points of dimension " << pc.dimension() << "\n";

  std::vector<double> dimensionalities;

  if( method == "pca" )
  {
    std::cerr << "* Estimating local dimensionality using PCA (k=" << k << ")...";

    auto result
      = aleph::containers::estimateLocalDimensionalityPCA<Distance, PointCloud, NearestNeighbours>( pc, k );

    // converts data in the vector so that we don't have to do it
    // manually
    dimensionalities.assign( result.begin(), result.end() );
  }
  else if( method == "nn" )
  {
    if( K == 0 )
    {
      std::cerr << "* Estimating local dimensionality using nearest neighbours (k=" << k << ")...";

      dimensionalities
        = aleph::containers::estimateLocalDimensionalityNearestNeighbours<Distance, PointCloud, NearestNeighbours>(
          pc, k );
    }
    else if( k <= K )
    {
      std::cerr << "* Estimating local dimensionality using nearest neighbours (k=" << k << ", K=" << K << ")...";

      dimensionalities
        = aleph::containers::estimateLocalDimensionalityNearestNeighbours<Distance, PointCloud, NearestNeighbours>(
        pc, k, K );
    }
  }
  else if( method == "mle" )
  {
    std::cerr << "* Estimating local dimensionality using nearest neighbours and MLE (k=" << k << ")...";

    if( k > K )
      throw std::runtime_error( "Missing maximum parameter for nearest neighbours" );

    dimensionalities
      = aleph::containers::estimateLocalDimensionalityNearestNeighboursMLE<Distance, PointCloud, NearestNeighbours>(
      pc, k, K
    );
  }
  else if( method == "mst" )
  {
    std::cerr << "* Estimating local dimensionality using MST...";

    dimensionalities
      = aleph::containers::estimateLocalDimensionalityNearestNeighbours<Distance>( pc );
  }

  std::cerr << "finished\n";

  // Output ------------------------------------------------------------

  if( smooth )
  {
    std::cerr << "* Performing smoothing operation with k=" << k << " and n=" << n << "...";

    std::vector<double> tmp;

    aleph::containers::meanShiftSmoothing<NearestNeighbours>(
      pc,
      dimensionalities.begin(), dimensionalities.end(),
      std::back_inserter( tmp ),
      k,
      n );

    dimensionalities.swap( tmp );

    std::cerr << "\n";
  }

  for( auto&& d : dimensionalities )
    std::cout << d << "\n";
}
<|endoftext|>


<commit_before>// Copyright 2010 Google
// 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.
//
// Capacitated Vehicle Routing Problem with Time Windows (and optional orders).
// A description of the problem can be found here:
// http://en.wikipedia.org/wiki/Vehicle_routing_problem.
// The variant which is tackled by this model includes a capacity dimension,
// time windows and optional orders, with a penalty cost if orders are not
// performed. For the sake of simplicty, orders are randomly located and
// distances are computed using the Manhattan distance. Distances are assumed
// to be in meters and times in seconds.

#include <vector>

#include "base/callback.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "constraint_solver/routing.h"
#include "base/random.h"

using operations_research::Assignment;
using operations_research::IntVar;
using operations_research::RoutingModel;
using operations_research::Solver;
using operations_research::ACMRandom;
using operations_research::StrCat;
using operations_research::scoped_array;
using operations_research::scoped_ptr;
using operations_research::StringPrintf;
using operations_research::StringAppendF;

DEFINE_int32(vrp_orders, 100, "Nodes in the problem.");
DEFINE_int32(vrp_vehicles, 20, "Size of Traveling Salesman Problem instance.");
DEFINE_bool(vrp_use_deterministic_random_seed, false,
            "Use deterministic random seeds.");

const char* kTime = "Time";
const char* kCapacity = "Capacity";

// Random seed generator.
int32 GetSeed() {
  if (FLAGS_vrp_use_deterministic_random_seed) {
    return ACMRandom::DeterministicSeed();
  } else {
    return ACMRandom::HostnamePidTimeSeed();
  }
}

// Location container, contains positions of orders and can be used to obtain
// Manhattan distances/times between locations.
class LocationContainer {
 public:
  explicit LocationContainer(int64 speed)
      : randomizer_(GetSeed()), speed_(speed) {}
  void AddLocation(int64 x, int64 y) {
    locations_.push_back(Location(x, y));
  }
  void AddRandomLocation(int64 x_max, int64 y_max) {
    AddLocation(randomizer_.Uniform(x_max + 1), randomizer_.Uniform(y_max + 1));
  }
  int64 Manhattan(int64 from, int64 to) const {
    return locations_[from].DistanceTo(locations_[to]);
  }
  int64 ManhattanTime(int64 from, int64 to) const {
    return Manhattan(from, to) / speed_;
  }
 private:
  class Location {
   public:
    Location() : x_(0), y_(0) {}
    Location(int64 x, int64 y) : x_(x), y_(y) {}
    int64 DistanceTo(const Location& location) const {
      const int64 x_delta = x_ - location.x_;
      const int64 y_delta = y_ - location.y_;
      return std::max(x_delta, -x_delta) + std::max(y_delta, -y_delta);
    }
   private:
    int64 x_;
    int64 y_;
  };

  ACMRandom randomizer_;
  const int64 speed_;
  vector<Location> locations_;
};

// Random demand.
class RandomDemand {
 public:
  RandomDemand(int size, int64 depot) : size_(size), depot_(depot) {}
  void Initialize() {
    const int64 kDemandMax = 5;
    const int64 kDemandMin = 1;
    demand_.reset(new int64[size_]);
    ACMRandom randomizer(GetSeed());
    for (int order = 0; order < size_; ++order) {
      if (order == depot_) {
        demand_[order] = 0LL;
      } else {
        demand_[order] =
            kDemandMin + randomizer.Uniform(kDemandMax - kDemandMin + 1);
      }
    }
  }
  int64 Demand(int64 from, int64 to) const {
    return demand_[from];
  }
 private:
  scoped_array<int64> demand_;
  const int size_;
  const int64 depot_;
};

// Service time (proportional to demand) + transition time callback.
class ServiceTimePlusTransition {
 public:
  ServiceTimePlusTransition(int64 time_per_demand_unit,
                            Solver::IndexEvaluator2* demand,
                            Solver::IndexEvaluator2* transition_time)
      : time_per_demand_unit_(time_per_demand_unit),
        demand_(demand),
        transition_time_(transition_time) {}
  int64 Compute(int64 from, int64 to) const {
    return time_per_demand_unit_ * demand_->Run(from, to)
        + transition_time_->Run(from, to);
  }
 private:
  const int64 time_per_demand_unit_;
  scoped_ptr<Solver::IndexEvaluator2> demand_;
  scoped_ptr<Solver::IndexEvaluator2> transition_time_;
};

// Route plan displayer.
// TODO(user): Move the display code to the routing library.
void DisplayPlan(const RoutingModel& routing, const Assignment& plan) {
  // Display plan cost.
  string plan_output = StringPrintf("Cost %lld\n", plan.ObjectiveValue());

  // Display dropped orders.
  string dropped;
  for (int order = 1; order < routing.nodes(); ++order) {
    if (plan.Value(routing.NextVar(order)) == order) {
      StringAppendF(&dropped, " %d", order);
    }
  }
  if (!dropped.empty()) {
    plan_output += "Dropped orders:" + dropped + "\n";
  }

  // Display actual output for each vehicle.
  for (int route_number = 0;
       route_number < FLAGS_vrp_vehicles;
       ++route_number) {
    int64 order = routing.Start(route_number);
    StringAppendF(&plan_output, "Route %d: ", route_number);
    if (routing.IsEnd(plan.Value(routing.NextVar(order)))) {
      plan_output += "Empty\n";
    } else {
      while (!routing.IsEnd(order)) {
        IntVar* load_var = routing.CumulVar(order, kCapacity);
        IntVar* time_var = routing.CumulVar(order, kTime);
        StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld) -> ",
                      order,
                      plan.Value(load_var),
                      plan.Min(time_var),
                      plan.Max(time_var));
        order = plan.Value(routing.NextVar(order));
      }
      IntVar* load_var = routing.CumulVar(order, kCapacity);
      IntVar* time_var = routing.CumulVar(order, kTime);
      StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld)\n",
                    order,
                    plan.Value(load_var),
                    plan.Min(time_var),
                    plan.Max(time_var));
    }
  }
  LG << plan_output;
}

int main(int argc, char **argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  CHECK_GT(FLAGS_vrp_orders, 0) << "Specify an instance size greater than 0.";
  // VRP of size FLAGS_vrp_size.
  // Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
  // the routes are at node 0.
  const int64 kDepot = 0LL;
  RoutingModel routing(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles);
  routing.SetDepot(kDepot);
  // Setting first solution heuristic (cheapest addition).
  routing.SetCommandLineOption("routing_first_solution", "PathCheapestArc");
  // Disabling Large Neighborhood Search, comment out to activate it.
  routing.SetCommandLineOption("routing_no_lns", "true");

  // Setting up locations.
  const int64 kXMax = 100000;
  const int64 kYMax = 100000;
  const int64 kSpeed = 10;
  LocationContainer locations(kSpeed);
  for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
    locations.AddRandomLocation(kXMax, kYMax);
  }

  // Setting the cost function.
  routing.SetCost(NewPermanentCallback(&locations,
                                       &LocationContainer::Manhattan));

  // Adding capacity dimension constraints.
  const int64 kVehicleCapacity = 40;
  RandomDemand demand(routing.nodes(), kDepot);
  demand.Initialize();
  routing.AddDimension(NewPermanentCallback(&demand, &RandomDemand::Demand),
                       0, kVehicleCapacity, kCapacity);

  // Adding time dimension constraints.
  const int64 kTimePerDemandUnit = 300;
  const int64 kHorizon = 24 * 3600;
  ServiceTimePlusTransition time(
      kTimePerDemandUnit,
      NewPermanentCallback(&demand, &RandomDemand::Demand),
      NewPermanentCallback(&locations, &LocationContainer::ManhattanTime));
  routing.AddDimension(
      NewPermanentCallback(&time,
                           &ServiceTimePlusTransition::Compute),
      kHorizon, kHorizon, kTime);
  // Adding time windows.
  ACMRandom randomizer(GetSeed());
  const int64 kTWDuration = 5 * 3600;
  for (int order = 1; order < routing.nodes(); ++order) {
    const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
    routing.CumulVar(order, kTime)->SetRange(start, start + kTWDuration);
  }

  // Adding penalty costs to allow skipping orders.
  const int64 kPenalty = 100000;
  for (int order = 1; order < routing.nodes(); ++order) {
    vector<int64> orders(1, order);
    routing.AddDisjunction(orders, kPenalty);
  }

  // Solve, returns a solution if any (owned by RoutingModel).
  const Assignment* solution = routing.Solve();
  if (solution != NULL) {
    DisplayPlan(routing, *solution);
  } else {
    LG << "No solution found.";
  }
  return 0;
}
<commit_msg>improve cvrptw example<commit_after>// Copyright 2010 Google
// 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.
//
// Capacitated Vehicle Routing Problem with Time Windows (and optional orders).
// A description of the problem can be found here:
// http://en.wikipedia.org/wiki/Vehicle_routing_problem.
// The variant which is tackled by this model includes a capacity dimension,
// time windows and optional orders, with a penalty cost if orders are not
// performed. For the sake of simplicty, orders are randomly located and
// distances are computed using the Manhattan distance. Distances are assumed
// to be in meters and times in seconds.

#include <vector>

#include "base/callback.h"
#include "constraint_solver/routing.h"
#include "base/random.h"

using operations_research::Assignment;
using operations_research::IntVar;
using operations_research::RoutingModel;
using operations_research::Solver;
using operations_research::ACMRandom;
using operations_research::StrCat;
using operations_research::StringAppendF;
using operations_research::StringPrintf;
using operations_research::scoped_array;
using operations_research::scoped_ptr;

DEFINE_int32(vrp_orders, 100, "Nodes in the problem.");
DEFINE_int32(vrp_vehicles, 20, "Size of Traveling Salesman Problem instance.");
DEFINE_bool(vrp_use_deterministic_random_seed, false,
            "Use deterministic random seeds.");

const char* kTime = "Time";
const char* kCapacity = "Capacity";

// Random seed generator.
int32 GetSeed() {
  if (FLAGS_vrp_use_deterministic_random_seed) {
    return ACMRandom::DeterministicSeed();
  } else {
    return ACMRandom::HostnamePidTimeSeed();
  }
}

// Location container, contains positions of orders and can be used to obtain
// Manhattan distances/times between locations.
class LocationContainer {
 public:
  explicit LocationContainer(int64 speed)
      : randomizer_(GetSeed()), speed_(speed) {
    CHECK_LT(0, speed_);
  }
  void AddLocation(int64 x, int64 y) {
    locations_.push_back(Location(x, y));
  }
  void AddRandomLocation(int64 x_max, int64 y_max) {
    AddLocation(randomizer_.Uniform(x_max + 1), randomizer_.Uniform(y_max + 1));
  }
  int64 ManhattanDistance(int64 from, int64 to) const {
    return locations_[from].DistanceTo(locations_[to]);
  }
  int64 ManhattanTime(int64 from, int64 to) const {
    return ManhattanDistance(from, to) / speed_;
  }
 private:
  class Location {
   public:
    Location() : x_(0), y_(0) {}
    Location(int64 x, int64 y) : x_(x), y_(y) {}
    int64 DistanceTo(const Location& location) const {
      return Abs(x_ - location.x_) + Abs(y_ - location.y_);
    }
   private:
    static int64 Abs(int64 value) { return std::max(value, -value); }

    int64 x_;
    int64 y_;
  };

  ACMRandom randomizer_;
  const int64 speed_;
  vector<Location> locations_;
};

// Random demand.
class RandomDemand {
 public:
  RandomDemand(int size, int64 depot) : size_(size), depot_(depot) {
    CHECK_LT(0, size_);
  }
  void Initialize() {
    const int64 kDemandMax = 5;
    const int64 kDemandMin = 1;
    demand_.reset(new int64[size_]);
    ACMRandom randomizer(GetSeed());
    for (int order = 0; order < size_; ++order) {
      if (order == depot_) {
        demand_[order] = 0;
      } else {
        demand_[order] =
            kDemandMin + randomizer.Uniform(kDemandMax - kDemandMin + 1);
      }
    }
  }
  int64 Demand(int64 from, int64 to) const {
    return demand_[from];
  }
 private:
  scoped_array<int64> demand_;
  const int size_;
  const int64 depot_;
};

// Service time (proportional to demand) + transition time callback.
class ServiceTimePlusTransition {
 public:
  ServiceTimePlusTransition(int64 time_per_demand_unit,
                            Solver::IndexEvaluator2* demand,
                            Solver::IndexEvaluator2* transition_time)
      : time_per_demand_unit_(time_per_demand_unit),
        demand_(demand),
        transition_time_(transition_time) {}
  int64 Compute(int64 from, int64 to) const {
    return time_per_demand_unit_ * demand_->Run(from, to)
        + transition_time_->Run(from, to);
  }
 private:
  const int64 time_per_demand_unit_;
  scoped_ptr<Solver::IndexEvaluator2> demand_;
  scoped_ptr<Solver::IndexEvaluator2> transition_time_;
};

// Route plan displayer.
// TODO(user): Move the display code to the routing library.
void DisplayPlan(const RoutingModel& routing, const Assignment& plan) {
  // Display plan cost.
  string plan_output = StringPrintf("Cost %lld\n", plan.ObjectiveValue());

  // Display dropped orders.
  string dropped;
  for (int order = 1; order < routing.nodes(); ++order) {
    if (plan.Value(routing.NextVar(order)) == order) {
      if (dropped.empty()) {
        StringAppendF(&dropped, " %d", order);
      } else {
        StringAppendF(&dropped, ", %d", order);
      }
    }
  }
  if (!dropped.empty()) {
    plan_output += "Dropped orders:" + dropped + "\n";
  }

  // Display actual output for each vehicle.
  for (int route_number = 0;
       route_number < routing.vehicles();
       ++route_number) {
    int64 order = routing.Start(route_number);
    StringAppendF(&plan_output, "Route %d: ", route_number);
    if (routing.IsEnd(plan.Value(routing.NextVar(order)))) {
      plan_output += "Empty\n";
    } else {
      while (!routing.IsEnd(order)) {
        IntVar* load_var = routing.CumulVar(order, kCapacity);
        IntVar* time_var = routing.CumulVar(order, kTime);
        StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld) -> ",
                      order,
                      plan.Value(load_var),
                      plan.Min(time_var),
                      plan.Max(time_var));
        order = plan.Value(routing.NextVar(order));
      }
      IntVar* load_var = routing.CumulVar(order, kCapacity);
      IntVar* time_var = routing.CumulVar(order, kTime);
      StringAppendF(&plan_output, "%lld Load(%lld) Time(%lld, %lld)\n",
                    order,
                    plan.Value(load_var),
                    plan.Min(time_var),
                    plan.Max(time_var));
    }
  }
  LG << plan_output;
}

int main(int argc, char **argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
  CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
  // VRP of size FLAGS_vrp_size.
  // Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
  // the routes are at node 0.
  const int64 kDepot = 0;
  RoutingModel routing(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles);
  routing.SetDepot(kDepot);
  // Setting first solution heuristic (cheapest addition).
  routing.SetCommandLineOption("routing_first_solution", "PathCheapestArc");
  // Disabling Large Neighborhood Search, comment out to activate it.
  routing.SetCommandLineOption("routing_no_lns", "true");

  // Setting up locations.
  const int64 kXMax = 100000;
  const int64 kYMax = 100000;
  const int64 kSpeed = 10;
  LocationContainer locations(kSpeed);
  for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
    locations.AddRandomLocation(kXMax, kYMax);
  }

  // Setting the cost function.
  routing.SetCost(NewPermanentCallback(&locations,
                                       &LocationContainer::ManhattanDistance));

  // Adding capacity dimension constraints.
  const int64 kVehicleCapacity = 40;
  const int64 kNullCapacitySlack = 0;
  RandomDemand demand(routing.nodes(), kDepot);
  demand.Initialize();
  routing.AddDimension(NewPermanentCallback(&demand, &RandomDemand::Demand),
                       kNullCapacitySlack, kVehicleCapacity, kCapacity);

  // Adding time dimension constraints.
  const int64 kTimePerDemandUnit = 300;
  const int64 kHorizon = 24 * 3600;
  ServiceTimePlusTransition time(
      kTimePerDemandUnit,
      NewPermanentCallback(&demand, &RandomDemand::Demand),
      NewPermanentCallback(&locations, &LocationContainer::ManhattanTime));
  routing.AddDimension(
      NewPermanentCallback(&time,
                           &ServiceTimePlusTransition::Compute),
      kHorizon, kHorizon, kTime);
  // Adding time windows.
  ACMRandom randomizer(GetSeed());
  const int64 kTWDuration = 5 * 3600;
  for (int order = 1; order < routing.nodes(); ++order) {
    const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
    routing.CumulVar(order, kTime)->SetRange(start, start + kTWDuration);
  }

  // Adding penalty costs to allow skipping orders.
  const int64 kPenalty = 100000;
  for (int order = 1; order < routing.nodes(); ++order) {
    vector<int64> orders(1, order);
    routing.AddDisjunction(orders, kPenalty);
  }

  // Solve, returns a solution if any (owned by RoutingModel).
  const Assignment* solution = routing.Solve();
  if (solution != NULL) {
    DisplayPlan(routing, *solution);
  } else {
    LG << "No solution found.";
  }
  return 0;
}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#pragma once

namespace Tundra
{

template<typename T>
SharedPtr<T> AssetAPI::FindAsset(String assetRef) const
{
    return Urho3D::DynamicCast<T>(FindAsset(assetRef));
}

template<typename T>
Vector<SharedPtr<T> > AssetAPI::AssetsOfType() const
{
    Vector<SharedPtr<T> > ret;
    for(AssetMap::const_iterator i = assets.begin(); i != assets.end(); ++i)
    {
        SharedPtr<T> asset = Urho3D::DynamicCast<T>(i->second);
        if (asset)
            ret.push_back(asset);
    }
    return ret;
}

template<typename T>
SharedPtr<T> AssetAPI::AssetProvider() const
{
    const Vector<AssetProviderPtr> providers = AssetProviders();
    for(uint i = 0; i < providers.Size(); ++i)
    {
        SharedPtr<T> provider = Urho3D::DynamicCast<T>(providers[i]);
        if (provider)
            return provider;
    }
    return SharedPtr<T>();
}

}
<commit_msg>Fix AssetAPI::AssetsOfType().<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#pragma once

namespace Tundra
{

template<typename T>
SharedPtr<T> AssetAPI::FindAsset(String assetRef) const
{
    return Urho3D::DynamicCast<T>(FindAsset(assetRef));
}

template<typename T>
Vector<SharedPtr<T> > AssetAPI::AssetsOfType() const
{
    Vector<SharedPtr<T> > ret;
    for(AssetMap::const_iterator i = assets.begin(); i != assets.end(); ++i)
    {
        SharedPtr<T> asset = Urho3D::DynamicCast<T>(i->second);
        if (asset)
            ret.Push(asset);
    }
    return ret;
}

template<typename T>
SharedPtr<T> AssetAPI::AssetProvider() const
{
    const Vector<AssetProviderPtr> providers = AssetProviders();
    for(uint i = 0; i < providers.Size(); ++i)
    {
        SharedPtr<T> provider = Urho3D::DynamicCast<T>(providers[i]);
        if (provider)
            return provider;
    }
    return SharedPtr<T>();
}

}
<|endoftext|>


<commit_before>#include <node/v8.h>
#include <node/node.h>
#include <list>
#include <stdexcept>
#include <string>

#include "./game_wrapper.h"
#include "../player/javascript_player_wrapper.h"
#include "../../player/async_player.h"
#include "../../player/async_robot_easy_player.h"

namespace Uno { namespace Node { namespace Game {

using namespace v8;
using namespace node;
using ::Uno::Node::Player::JavascriptPlayerWrapper;
using ::Uno::Node::Player::AsyncPlayer;
using ::Uno::Player::AsyncRobotEasyPlayer;

#define REQ_INT_ARG(I)                                                  \
    if (args.Length() <= (I) || !args[I]->IsInt32()) {                  \
        return ThrowException(Exception::TypeError(                     \
            String::New("Argument " #I " must be an integer")));        \
    }

#define REQ_OBJ_ARG(I)                                                  \
    if (args.Length() <= (I) || !args[I]->IsObject()) {                 \
        return ThrowException(Exception::TypeError(                     \
            String::New("Argument " #I " must be an object")));         \
    }

GameWrapper::GameWrapper(int max_player_count) :bot_count(0) {
    game = new AsyncGame(max_player_count);
}

void GameWrapper::Initialize(Handle<Object> target) {
    HandleScope scope;

    // t is a container
    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(t, "joinPlayer", JoinPlayer);
    NODE_SET_PROTOTYPE_METHOD(t, "addBot", AddBot);
    NODE_SET_PROTOTYPE_METHOD(t, "start", Start);
    NODE_SET_PROTOTYPE_METHOD(t, "dispose", Dispose);

    target->Set(String::NewSymbol("Game"), t->GetFunction());
}

Handle<Value> GameWrapper::New(const Arguments &args) {
    HandleScope scope;

    REQ_INT_ARG(0);

    GameWrapper* wrapper = new GameWrapper(args[0]->Int32Value());
    wrapper->Wrap(args.This());

    return args.This();
}

/**
 * @todo disallow non-unique session id
 */
Handle<Value> GameWrapper::JoinPlayer(const Arguments &args) {
    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());

    REQ_OBJ_ARG(0);

    /** @todo change the "nativePlayer" explicit get to a getter method */
    Handle<Object> jsplayer_wrapper = args[0]->ToObject()->Get(String::New("nativePlayer"))->ToObject();
    JavascriptPlayerWrapper* player_wrapper = ObjectWrap::Unwrap<JavascriptPlayerWrapper>(jsplayer_wrapper);
    AsyncPlayer* player = player_wrapper->getNativePlayer();

    try {
        wrapper->game->joinPlayer(player);
        player->setGame(wrapper->game);
        wrapper->players.push_back(player);
    } catch (std::overflow_error e) {
        delete player;

        return ThrowException(Exception::RangeError(
            String::New("Game is full")
        ));
    }

    return scope.Close(Boolean::New(true));
}

Handle<Value> GameWrapper::AddBot(const Arguments &args) {
    int count;
    if (args.Length() >= 1 && args[0]->IsInt32()) {
        count = args[0]->Int32Value();
    } else {
        count = 1;
    }

    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());
    for (int i = 0; i < count; i++) {
        AsyncRobotEasyPlayer *robot = new AsyncRobotEasyPlayer();

        { // hack ahead. 49: ASCII 0
            std::string name = "robot ";
            name.push_back((char)(wrapper->bot_count+49));
            robot->setName(name.c_str());
        }

        try {
            wrapper->game->joinPlayer(robot);
            robot->setGame(wrapper->game);
            wrapper->players.push_back(robot);
            wrapper->bot_count++;
        } catch (std::overflow_error e) {
            delete robot;

            return ThrowException(Exception::RangeError(
                String::New("Game is full")
            ));
        }
    }

    return scope.Close(Boolean::New(true));
}

Handle<Value> GameWrapper::Start(const Arguments &args) {
    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());

    wrapper->game->start();

    return scope.Close(Boolean::New(true));
}

Handle<Value> GameWrapper::Dispose(const Arguments &args) {
    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());

    delete wrapper->game;

    std::list<Player*>::iterator player;
    for (player = wrapper->players.begin(); player != wrapper->players.end(); player++) {
        delete (*player);
    }

    return scope.Close(Undefined());
}

#undef REQ_INT_ARG
#undef REQ_OBJ_ARG

}}}  // namespace
<commit_msg>use static_cast instead of C-style cast<commit_after>#include <node/v8.h>
#include <node/node.h>
#include <list>
#include <stdexcept>
#include <string>

#include "./game_wrapper.h"
#include "../player/javascript_player_wrapper.h"
#include "../../player/async_player.h"
#include "../../player/async_robot_easy_player.h"

namespace Uno { namespace Node { namespace Game {

using namespace v8;
using namespace node;
using ::Uno::Node::Player::JavascriptPlayerWrapper;
using ::Uno::Node::Player::AsyncPlayer;
using ::Uno::Player::AsyncRobotEasyPlayer;

#define REQ_INT_ARG(I)                                                  \
    if (args.Length() <= (I) || !args[I]->IsInt32()) {                  \
        return ThrowException(Exception::TypeError(                     \
            String::New("Argument " #I " must be an integer")));        \
    }

#define REQ_OBJ_ARG(I)                                                  \
    if (args.Length() <= (I) || !args[I]->IsObject()) {                 \
        return ThrowException(Exception::TypeError(                     \
            String::New("Argument " #I " must be an object")));         \
    }

GameWrapper::GameWrapper(int max_player_count) :bot_count(0) {
    game = new AsyncGame(max_player_count);
}

void GameWrapper::Initialize(Handle<Object> target) {
    HandleScope scope;

    // t is a container
    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD(t, "joinPlayer", JoinPlayer);
    NODE_SET_PROTOTYPE_METHOD(t, "addBot", AddBot);
    NODE_SET_PROTOTYPE_METHOD(t, "start", Start);
    NODE_SET_PROTOTYPE_METHOD(t, "dispose", Dispose);

    target->Set(String::NewSymbol("Game"), t->GetFunction());
}

Handle<Value> GameWrapper::New(const Arguments &args) {
    HandleScope scope;

    REQ_INT_ARG(0);

    GameWrapper* wrapper = new GameWrapper(args[0]->Int32Value());
    wrapper->Wrap(args.This());

    return args.This();
}

/**
 * @todo disallow non-unique session id
 */
Handle<Value> GameWrapper::JoinPlayer(const Arguments &args) {
    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());

    REQ_OBJ_ARG(0);

    /** @todo change the "nativePlayer" explicit get to a getter method */
    Handle<Object> jsplayer_wrapper = args[0]->ToObject()->Get(String::New("nativePlayer"))->ToObject();
    JavascriptPlayerWrapper* player_wrapper = ObjectWrap::Unwrap<JavascriptPlayerWrapper>(jsplayer_wrapper);
    AsyncPlayer* player = player_wrapper->getNativePlayer();

    try {
        wrapper->game->joinPlayer(player);
        player->setGame(wrapper->game);
        wrapper->players.push_back(player);
    } catch (std::overflow_error e) {
        delete player;

        return ThrowException(Exception::RangeError(
            String::New("Game is full")
        ));
    }

    return scope.Close(Boolean::New(true));
}

Handle<Value> GameWrapper::AddBot(const Arguments &args) {
    int count;
    if (args.Length() >= 1 && args[0]->IsInt32()) {
        count = args[0]->Int32Value();
    } else {
        count = 1;
    }

    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());
    for (int i = 0; i < count; i++) {
        AsyncRobotEasyPlayer *robot = new AsyncRobotEasyPlayer();

        { // hack ahead. 49: ASCII 0
            std::string name = "robot ";
            name.push_back(static_cast<char>(wrapper->bot_count+49));
            robot->setName(name.c_str());
        }

        try {
            wrapper->game->joinPlayer(robot);
            robot->setGame(wrapper->game);
            wrapper->players.push_back(robot);
            wrapper->bot_count++;
        } catch (std::overflow_error e) {
            delete robot;

            return ThrowException(Exception::RangeError(
                String::New("Game is full")
            ));
        }
    }

    return scope.Close(Boolean::New(true));
}

Handle<Value> GameWrapper::Start(const Arguments &args) {
    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());

    wrapper->game->start();

    return scope.Close(Boolean::New(true));
}

Handle<Value> GameWrapper::Dispose(const Arguments &args) {
    HandleScope scope;
    GameWrapper* wrapper = ObjectWrap::Unwrap<GameWrapper>(args.This());

    delete wrapper->game;

    std::list<Player*>::iterator player;
    for (player = wrapper->players.begin(); player != wrapper->players.end(); player++) {
        delete (*player);
    }

    return scope.Close(Undefined());
}

#undef REQ_INT_ARG
#undef REQ_OBJ_ARG

}}}  // namespace
<|endoftext|>


<commit_before>//===--- TypeJoinMeet.cpp - Swift Type "join" and "meet"  -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the "join" operation for types (and, eventually,
//  "meet").
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace swift;

Type Type::join(Type type1, Type type2) {
  assert(!type1->hasTypeVariable() && !type2->hasTypeVariable() &&
         "Cannot compute join of types involving type variables");

  assert(type1->getWithoutSpecifierType()->isEqual(type1) &&
         "Expected simple type!");
  assert(type2->getWithoutSpecifierType()->isEqual(type2) &&
         "Expected simple type!");

  // FIXME: This algorithm is woefully incomplete, and is only currently used
  // for optimizing away extra exploratory work in the constraint solver. It
  // should eventually encompass all of the subtyping rules of the language.

  // If the types are equivalent, the join is obvious.
  if (type1->isEqual(type2))
    return type1;

  // If both are class metatypes, compute the join of the instance type and
  // wrap the result in a metatype.
  if (auto *metatype1 = type1->getAs<MetatypeType>()) {
    if (auto *metatype2 = type2->getAs<MetatypeType>()) {
      auto instance1 = metatype1->getInstanceType();
      auto instance2 = metatype2->getInstanceType();
      if (instance1->mayHaveSuperclass() &&
          instance2->mayHaveSuperclass()) {
        auto result = Type::join(instance1, instance2);
        if (!result)
          return result;
        return MetatypeType::get(result);
      }
    }
  }

  // If both are existential metatypes, compute the join of the instance type
  // and wrap the result in an existential metatype.
  if (auto *metatype1 = type1->getAs<ExistentialMetatypeType>()) {
    if (auto *metatype2 = type2->getAs<ExistentialMetatypeType>()) {
      auto instance1 = metatype1->getInstanceType();
      auto instance2 = metatype2->getInstanceType();
      auto result = Type::join(instance1, instance2);
      if (!result)
        return result;
      return ExistentialMetatypeType::get(result);
    }
  }

  // If both are class types or opaque types that potentially have superclasses,
  // find the common superclass.
  if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass()) {
    /// Walk the superclasses of type1 looking for type2. Record them for our
    /// second step.
    llvm::SmallPtrSet<CanType, 8> superclassesOfType1;
    CanType canType2 = type2->getCanonicalType();
    for (Type super1 = type1; super1; super1 = super1->getSuperclass()) {
      CanType canSuper1 = super1->getCanonicalType();

      // If we have found the second type, we're done.
      if (canSuper1 == canType2) return super1;

      superclassesOfType1.insert(canSuper1);
    }

    // Look through the superclasses of type2 to determine if any were also
    // superclasses of type1.
    for (Type super2 = type2; super2; super2 = super2->getSuperclass()) {
      CanType canSuper2 = super2->getCanonicalType();

      // If we found the first type, we're done.
      if (superclassesOfType1.count(canSuper2)) return super2;
    }

    // There is no common superclass; we're done.
    return nullptr;
  }

  // If one or both of the types are optional types, look at the underlying
  // object type.
  OptionalTypeKind otk1, otk2;
  Type objectType1 = type1->getAnyOptionalObjectType(otk1);
  Type objectType2 = type2->getAnyOptionalObjectType(otk2);
  if (otk1 == OTK_Optional || otk2 == OTK_Optional) {
    // Compute the join of the unwrapped type. If there is none, we're done.
    Type unwrappedJoin = join(objectType1 ? objectType1 : type1,
                              objectType2 ? objectType2 : type2);
    if (!unwrappedJoin) return nullptr;

    return OptionalType::get(unwrappedJoin);
  }

  // The join can only be an existential.
  return nullptr;
}

<commit_msg>Start implementing a more complete Type::join.<commit_after>//===--- TypeJoinMeet.cpp - Swift Type "join" and "meet"  -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the "join" operation for types (and, eventually,
//  "meet").
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeVisitor.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace swift;

struct TypeJoin : TypeVisitor<TypeJoin, Type> {
  Type First;

  static Type getSuperclassJoin(Type first, Type second);

  Type visitClassType(Type second);
  Type visitBoundGenericClassType(Type second);
  Type visitArchetypeType(Type second);
  Type visitDynamicSelfType(Type second);
  Type visitMetatypeType(Type second);
  Type visitExistentialMetatypeType(Type second);
  Type visitBoundGenericEnumType(Type second);

  Type visitOptionalType(Type second);

  Type visitType(Type second) {
    // FIXME: Make this unreachable by implementing all possible
    //        combinations.
    return nullptr;
  }
public:
  TypeJoin(Type First) : First(First) {}
};

Type TypeJoin::getSuperclassJoin(Type first, Type second) {
  // FIXME: Return Any
  if (!first->mayHaveSuperclass() || !second->mayHaveSuperclass())
    return nullptr;

  /// Walk the superclasses of type1 looking for second. Record them for our
  /// second step.
  llvm::SmallPtrSet<CanType, 8> superclassesOfFirst;
  CanType canSecond = second->getCanonicalType();
  for (Type super = first; super; super = super->getSuperclass()) {
    CanType canSuper = super->getCanonicalType();

    // If we have found the second type, we're done.
    if (canSuper == canSecond) return super;

    superclassesOfFirst.insert(canSuper);
  }

  // Look through the superclasses of second to determine if any were also
  // superclasses of first.
  for (Type super = second; super; super = super->getSuperclass()) {
    CanType canSuper = super->getCanonicalType();

    // If we found the first type, we're done.
    if (superclassesOfFirst.count(canSuper)) return super;
  }

  // FIXME: Return Any
  // There is no common superclass; we're done.
  return nullptr;
}

Type TypeJoin::visitClassType(Type second) {
  return getSuperclassJoin(First, second);
}

Type TypeJoin::visitBoundGenericClassType(Type second) {
  return getSuperclassJoin(First, second);
}

Type TypeJoin::visitArchetypeType(Type second) {
  return getSuperclassJoin(First, second);
}

Type TypeJoin::visitDynamicSelfType(Type second) {
  return getSuperclassJoin(First, second);
}

Type TypeJoin::visitMetatypeType(Type second) {
  assert(!First->mayHaveSuperclass() && !second->mayHaveSuperclass());

  // FIXME: Return Any
  if (First->getKind() != second->getKind())
    return nullptr;

  auto firstInstance = First->castTo<AnyMetatypeType>()->getInstanceType();
  auto secondInstance = second->castTo<AnyMetatypeType>()->getInstanceType();

  auto joinInstance = TypeJoin(firstInstance).visit(secondInstance);

  // FIXME: Return Any
  if (!joinInstance)
    return nullptr;

  return MetatypeType::get(joinInstance);
}

Type TypeJoin::visitExistentialMetatypeType(Type second) {
  assert(!First->mayHaveSuperclass() && !second->mayHaveSuperclass());

  // FIXME: Return Any
  if (First->getKind() != second->getKind())
    return nullptr;

  auto firstInstance = First->castTo<AnyMetatypeType>()->getInstanceType();
  auto secondInstance = second->castTo<AnyMetatypeType>()->getInstanceType();

  auto joinInstance = TypeJoin(firstInstance).visit(secondInstance);

  // FIXME: Return Any
  if (!joinInstance)
    return nullptr;

  return ExistentialMetatypeType::get(joinInstance);
}

Type TypeJoin::visitBoundGenericEnumType(Type second) {
  // FIXME: Return Any
  if (First->getKind() != second->getKind())
    return nullptr;

  OptionalTypeKind otk1, otk2;
  Type objectType1 = First->getAnyOptionalObjectType(otk1);
  Type objectType2 = second->getAnyOptionalObjectType(otk2);
  if (otk1 == OTK_Optional || otk2 == OTK_Optional) {
    // Compute the join of the unwrapped type. If there is none, we're done.
    Type unwrappedJoin = Type::join(objectType1 ? objectType1 : First,
                                    objectType2 ? objectType2 : second);
    // FIXME: More general joins of enums need to be handled.
    if (!unwrappedJoin) return nullptr;

    return OptionalType::get(unwrappedJoin);
  }

  // FIXME: More general joins of enums need to be handled, and
  //        then Any should be returned when there is no better
  //        choice.
  return nullptr;
}

Type TypeJoin::visitOptionalType(Type second) {
  auto canFirst = First->getCanonicalType();
  auto canSecond = second->getCanonicalType();

  return TypeJoin(canFirst).visit(canSecond);
}

Type Type::join(Type type1, Type type2) {
  assert(!type1->hasTypeVariable() && !type2->hasTypeVariable() &&
         "Cannot compute join of types involving type variables");

  assert(type1->getWithoutSpecifierType()->isEqual(type1) &&
         "Expected simple type!");
  assert(type2->getWithoutSpecifierType()->isEqual(type2) &&
         "Expected simple type!");

  // FIXME: This algorithm is woefully incomplete, and is only currently used
  // for optimizing away extra exploratory work in the constraint solver. It
  // should eventually encompass all of the subtyping rules of the language.

  // If the types are equivalent, the join is obvious.
  if (type1->isEqual(type2))
    return type1;

  // Until we handle all the combinations of joins, we need to make
  // sure we visit the optional side.
  OptionalTypeKind otk;
  if (type2->getAnyOptionalObjectType(otk))
    return TypeJoin(type1).visit(type2);

  return TypeJoin(type2).visit(type1);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/errl/errlmanager_common.C $                           */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <errl/errlmanager.H>
#include <config.h>
#include <hwas/common/hwasCallout.H>
#include <errl/errlreasoncodes.H>
#include <ipmi/ipmisel.H>
#include <ipmi/ipmisensor.H>

namespace ERRORLOG
{

extern trace_desc_t* g_trac_errl;

#ifdef CONFIG_BMC_IPMI
void ErrlManager::sendErrLogToBmc(errlHndl_t &io_err)
{
    TRACFCOMP(g_trac_errl, ENTER_MRK
                "sendErrLogToBmc errlogId 0x%.8x", io_err->eid());

    do {

        // Decide whether we want to skip the error log
        if( io_err->getSkipShowingLog() )
        {
            TRACDCOMP( g_trac_errl, INFO_MRK
                    "sendErrLogToBmc: %.8X is INFORMATIONAL/RECOVERED; skipping",
                    io_err->eid());
            break;
        }
        // look thru the errlog for any Callout UserDetail sections
        //  to determine the sensor information for the SEL
        uint8_t l_sensorNumber = TARGETING::UTIL::INVALID_IPMI_SENSOR;
        uint8_t l_sensorType = TARGETING::UTIL::INVALID_IPMI_SENSOR;
        HWAS::callOutPriority l_priority = HWAS::SRCI_PRIORITY_NONE;
        for(std::vector<ErrlUD*>::const_iterator
                it = io_err->iv_SectionVector.begin();
                it != io_err->iv_SectionVector.end();
                it++ )
        {
            HWAS::callout_ud_t *l_ud =
                    reinterpret_cast<HWAS::callout_ud_t*>((*it)->iv_pData);

            // if this is a CALLOUT that will have a target
            if ((ERRL_COMP_ID     == (*it)->iv_header.iv_compId) &&
                (1                == (*it)->iv_header.iv_ver) &&
                (ERRL_UDT_CALLOUT == (*it)->iv_header.iv_sst) &&
                (HWAS::HW_CALLOUT == l_ud->type)
               )
            {
                // if this callout is higher than any previous
                if (l_ud->priority > l_priority)
                {
                    // get the sensor number for the target
                    uint8_t * l_uData = (uint8_t *)(l_ud + 1);
                    TARGETING::Target *l_target = NULL;
                    bool l_err = HWAS::retrieveTarget(l_uData,
                            l_target, io_err);
                    if (!l_err)
                    {
                        // got a target, now get the sensor number
                        l_sensorNumber =
                                SENSOR::getFaultSensorNumber(l_target);

                        // and update the priority
                        l_priority = l_ud->priority;
                    }
                }
            }
        } // for each SectionVector

        if (l_sensorNumber != TARGETING::UTIL::INVALID_IPMI_SENSOR)
        {
            uint8_t unused = 0;
            errlHndl_t e =
                SENSOR::SensorBase::getSensorType( l_sensorNumber,
                                                   l_sensorType, unused );
            if( e )
            {
                TRACFCOMP(g_trac_errl,
                        ERR_MRK"Failed to get sensor type for sensor %d",
                        l_sensorNumber);
                // since we are in the commit path, lets just delete this
                // error and move on.
                delete e;
            }
        }

        // flatten into buffer, truncate to max eSEL size
        uint32_t l_pelSize = io_err->flattenedSize();
        if (l_pelSize > (IPMISEL::ESEL_MAX_SIZE - sizeof(IPMISEL::selRecord)))
        {
            TRACFCOMP( g_trac_errl, INFO_MRK
                    "sendErrLogToBmc: msg size %d > %d, truncating.",
                    l_pelSize, IPMISEL::ESEL_MAX_SIZE);
            l_pelSize = IPMISEL::ESEL_MAX_SIZE - sizeof(IPMISEL::selRecord);
        }

        uint8_t *l_pelData = new uint8_t[l_pelSize];
        uint32_t l_errSize = io_err->flatten (l_pelData,
                                    l_pelSize, true /* truncate */);

        if (l_errSize ==0)
        {
            // flatten didn't work
            TRACFCOMP( g_trac_errl, ERR_MRK
                    "sendErrLogToBmc: could not flatten data - not sending");
            delete [] l_pelData;
            break;
        }

        uint8_t l_eventDirType  = IPMISEL::event_transition;
        uint8_t l_eventOffset   = IPMISEL::event_data1_trans_to_non_recoverable;
        switch (io_err->sev())
        {
            case ERRORLOG::ERRL_SEV_INFORMATIONAL:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_informational;
                break;
            case ERRL_SEV_RECOVERED:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_to_ok;
                break;
            case ERRL_SEV_PREDICTIVE:
                l_eventDirType  = IPMISEL::event_predictive;
                l_eventOffset   = IPMISEL::event_data1_trans_to_noncrit_from_ok;
                break;
            case ERRL_SEV_UNRECOVERABLE:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_to_non_recoverable;
                break;
            case ERRL_SEV_CRITICAL_SYS_TERM:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_to_crit_from_non_r;
                break;
            case ERRL_SEV_UNKNOWN:
                l_eventDirType  = IPMISEL::event_state;
                l_eventOffset   = IPMISEL::event_data1_asserted;
                break;
        }

        // send it to the BMC over IPMI
        TRACFCOMP(g_trac_errl, INFO_MRK
                "sendErrLogToBmc: sensor %.2x/%.2x event %x/%x, size %d",
                l_sensorType, l_sensorNumber,
                l_eventDirType, l_eventOffset,
                l_pelSize);
        IPMISEL::sendESEL(l_pelData, l_pelSize,
                            io_err->eid(),
                            l_eventDirType, l_eventOffset,
                            l_sensorType, l_sensorNumber);

        // free the buffer
        delete [] l_pelData;

    } while(0);

    TRACFCOMP(g_trac_errl, EXIT_MRK "sendErrLogToBmc");
} // sendErrLogToBmc

#endif

} // end namespace
<commit_msg>Creating multiple SELs for errors with callouts of the same priority<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/errl/errlmanager_common.C $                           */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <errl/errlmanager.H>
#include <config.h>
#include <hwas/common/hwasCallout.H>
#include <errl/errlreasoncodes.H>
#include <ipmi/ipmisel.H>
#include <ipmi/ipmisensor.H>

namespace ERRORLOG
{

extern trace_desc_t* g_trac_errl;

#ifdef CONFIG_BMC_IPMI
void ErrlManager::sendErrLogToBmc(errlHndl_t &io_err)
{
    TRACFCOMP(g_trac_errl, ENTER_MRK
                "sendErrLogToBmc errlogId 0x%.8x", io_err->eid());

    do {

        // Decide whether we want to skip the error log
        if( io_err->getSkipShowingLog() )
        {
            TRACDCOMP( g_trac_errl, INFO_MRK
                    "sendErrLogToBmc: %.8X is INFORMATIONAL/RECOVERED; skipping",
                    io_err->eid());
            break;
        }

        // look thru the errlog for any Callout UserDetail sections
        //  to determine the sensor information for the SEL
        std::vector<uint8_t> l_sensorNumbers;
        std::vector<uint8_t> l_sensorTypes;
        HWAS::callOutPriority l_priority = HWAS::SRCI_PRIORITY_NONE;
        for(std::vector<ErrlUD*>::const_iterator
                it = io_err->iv_SectionVector.begin();
                it != io_err->iv_SectionVector.end();
                it++ )
        {
            HWAS::callout_ud_t *l_ud =
                    reinterpret_cast<HWAS::callout_ud_t*>((*it)->iv_pData);

            // if this is a CALLOUT that will have a target
            if ((ERRL_COMP_ID     == (*it)->iv_header.iv_compId) &&
                (1                == (*it)->iv_header.iv_ver) &&
                (ERRL_UDT_CALLOUT == (*it)->iv_header.iv_sst) &&
                (HWAS::HW_CALLOUT == l_ud->type)
               )
            {
                // if this callout is higher than any previous callout
                if (l_ud->priority > l_priority)
                {
                    // get the sensor number for the target
                    uint8_t * l_uData = (uint8_t *)(l_ud + 1);
                    TARGETING::Target *l_target = NULL;
                    bool l_err = HWAS::retrieveTarget(l_uData,
                            l_target, io_err);
                    if (!l_err)
                    {
                        //remove previous sensor data
                        l_sensorNumbers.clear();

                        // got a target, now get the sensor number
                        l_sensorNumbers.push_back(
                                        SENSOR::getFaultSensorNumber(l_target));

                        // and update the priority
                        l_priority = l_ud->priority;
                    }
                // if this callout is equal to any previous callout
                }else if(l_ud->priority == l_priority)
                {
                    //get the sensor number for the target
                    uint8_t * l_uData = (uint8_t *)(l_ud + 1);
                    TARGETING::Target *l_target = NULL;
                    bool l_err = HWAS::retrieveTarget(l_uData,
                            l_target, io_err);
                    if(!l_err)
                    {
                        //add sensor data to array
                        l_sensorNumbers.push_back(
                                        SENSOR::getFaultSensorNumber(l_target));
                    }
                }
            }
        } // for each SectionVector

        std::vector<uint8_t>::const_iterator l_sensorIter;
        for(l_sensorIter = l_sensorNumbers.begin();
            l_sensorIter != l_sensorNumbers.end();
            l_sensorIter++)
        {
            uint8_t unused = 0;
            uint8_t l_getSensorType;
            errlHndl_t e =
                SENSOR::SensorBase::getSensorType(
                                *l_sensorIter,
                                l_getSensorType,unused);
            l_sensorTypes.push_back(l_getSensorType);
            if( e )
            {
                TRACFCOMP(g_trac_errl,
                          ERR_MRK"Failed to get sensor type for sensor %d",
                          *l_sensorIter);
                // since we are in the commit path, lets just delete this
                // error and move on.
                delete e;
            }

        }

        // flatten into buffer, truncate to max eSEL size
        uint32_t l_pelSize = io_err->flattenedSize();
        if (l_pelSize > (IPMISEL::ESEL_MAX_SIZE - sizeof(IPMISEL::selRecord)))
        {
            TRACFCOMP( g_trac_errl, INFO_MRK
                    "sendErrLogToBmc: msg size %d > %d, truncating.",
                    l_pelSize, IPMISEL::ESEL_MAX_SIZE);
            l_pelSize = IPMISEL::ESEL_MAX_SIZE - sizeof(IPMISEL::selRecord);
        }

        uint8_t *l_pelData = new uint8_t[l_pelSize];
        uint32_t l_errSize = io_err->flatten (l_pelData,
                                    l_pelSize, true /* truncate */);

        if (l_errSize ==0)
        {
            // flatten didn't work
            TRACFCOMP( g_trac_errl, ERR_MRK
                    "sendErrLogToBmc: could not flatten data - not sending");
            delete [] l_pelData;
            break;
        }

        uint8_t l_eventDirType  = IPMISEL::event_transition;
        uint8_t l_eventOffset   = IPMISEL::event_data1_trans_to_non_recoverable;
        switch (io_err->sev())
        {
            case ERRORLOG::ERRL_SEV_INFORMATIONAL:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_informational;
                break;
            case ERRL_SEV_RECOVERED:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_to_ok;
                break;
            case ERRL_SEV_PREDICTIVE:
                l_eventDirType  = IPMISEL::event_predictive;
                l_eventOffset   = IPMISEL::event_data1_trans_to_noncrit_from_ok;
                break;
            case ERRL_SEV_UNRECOVERABLE:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_to_non_recoverable;
                break;
            case ERRL_SEV_CRITICAL_SYS_TERM:
                l_eventDirType  = IPMISEL::event_transition;
                l_eventOffset   = IPMISEL::event_data1_trans_to_crit_from_non_r;
                break;
            case ERRL_SEV_UNKNOWN:
                l_eventDirType  = IPMISEL::event_state;
                l_eventOffset   = IPMISEL::event_data1_asserted;
                break;
        }

        // send it to the BMC over IPMI
        for(uint8_t l_sendIdx=0;l_sendIdx < l_sensorNumbers.size();l_sendIdx++)
        {
            TRACFCOMP(g_trac_errl, INFO_MRK
                    "sendErrLogToBmc: creating ESEL for sensor #%d",l_sendIdx);
            TRACFCOMP(g_trac_errl, INFO_MRK
                    "sendErrLogToBmc: sensor %.2x/%.2x event %x/%x, size %d",
                    l_sensorTypes.at(l_sendIdx), l_sensorNumbers.at(l_sendIdx),
                    l_eventDirType, l_eventOffset,
                    ((l_sendIdx==0)?l_pelSize:0));

            IPMISEL::sendESEL(l_pelData, ((l_sendIdx==0) ? l_pelSize:0),
                                io_err->eid(),
                                l_eventDirType, l_eventOffset,
                                l_sensorTypes.at(l_sendIdx),
                                l_sensorNumbers.at(l_sendIdx));
        }

        // free the buffer
        delete [] l_pelData;

    } while(0);

    TRACFCOMP(g_trac_errl, EXIT_MRK "sendErrLogToBmc");
} // sendErrLogToBmc

#endif

} // end namespace
<|endoftext|>