<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgraphicsanchorlayout_p.h"

QGraphicsAnchorLayout::QGraphicsAnchorLayout(QGraphicsLayoutItem *parent)
    : QGraphicsLayout(*new QGraphicsAnchorLayoutPrivate(), parent)
{
    Q_D(QGraphicsAnchorLayout);
    d->createLayoutEdges();
}

QGraphicsAnchorLayout::~QGraphicsAnchorLayout()
{
    Q_D(QGraphicsAnchorLayout);

    for (int i = count() - 1; i >= 0; --i) {
        QGraphicsLayoutItem *item = d->items.at(i);
        removeAt(i);
        if (item) {
            if (item->ownedByLayout())
                delete item;
        }
    }

    d->deleteLayoutEdges();
}

void QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem,
                                   Edge firstEdge,
                                   QGraphicsLayoutItem *secondItem,
                                   Edge secondEdge, qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    if ((firstItem == 0) || (secondItem == 0)) {
        qWarning("QGraphicsAnchorLayout::anchor: "
                 "Cannot anchor NULL items");
        return;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::anchor: "
                 "Cannot anchor the item to itself");
        return;
    }

    if (d->edgeOrientation(secondEdge) != d->edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::anchor: "
                 "Cannot anchor edges of different orientations");
        return;
    }

    // In QGraphicsAnchorLayout, items are represented in its internal
    // graph as four anchors that connect:
    //  - Left -> HCenter
    //  - HCenter-> Right
    //  - Top -> VCenter
    //  - VCenter -> Bottom

    // Ensure that the internal anchors have been created for both items.
    if (firstItem != this && !d->items.contains(firstItem)) {
        d->createItemEdges(firstItem);
        d->addChildItem(firstItem);
    }
    if (secondItem != this && !d->items.contains(secondItem)) {
        d->createItemEdges(secondItem);
        d->addChildItem(secondItem);
    }

    // Use heuristics to find out what the user meant with this anchor.
    d->correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);

    // Create actual anchor between firstItem and secondItem.
    AnchorData *data;
    if (spacing >= 0) {
        data = new AnchorData(spacing);
        d->addAnchor(firstItem, firstEdge, secondItem, secondEdge, data);
    } else {
        data = new AnchorData(-spacing);
        d->addAnchor(secondItem, secondEdge, firstItem, firstEdge, data);
    }

    invalidate();
}

void QGraphicsAnchorLayout::removeAnchor(QGraphicsLayoutItem *firstItem, Edge firstEdge,
                                         QGraphicsLayoutItem *secondItem, Edge secondEdge)
{
    Q_D(QGraphicsAnchorLayout);
    if ((firstItem == 0) || (secondItem == 0)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor between NULL items");
        return;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from the item to itself");
        return;
    }

    if (d->edgeOrientation(secondEdge) != d->edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from edges of different orientations");
        return;
    }

    d->removeAnchor(firstItem, firstEdge, secondItem, secondEdge);

    invalidate();
}

void QGraphicsAnchorLayout::setGeometry(const QRectF &geom)
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayout::setGeometry(geom);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Vertical);
    d->setItemsGeometries();
}

void QGraphicsAnchorLayout::removeAt(int index)
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayoutItem *item = d->items.value(index);

    if (item) {
        d->items.remove(index);
        d->removeAnchors(item);
        item->setParentLayoutItem(0);
    }
}

int QGraphicsAnchorLayout::count() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.size();
}

QGraphicsLayoutItem *QGraphicsAnchorLayout::itemAt(int index) const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.value(index);
}

void QGraphicsAnchorLayout::invalidate()
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayout::invalidate();
    d->calculateGraphCacheDirty = 1;
}

QSizeF QGraphicsAnchorLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    Q_UNUSED(which);
    Q_UNUSED(constraint);
    Q_D(const QGraphicsAnchorLayout);

    // Some setup calculations are delayed until the information is
    // actually needed, avoiding unnecessary recalculations when
    // adding multiple anchors.

    // sizeHint() / effectiveSizeHint() already have a cache
    // mechanism, using invalidate() to force recalculation. However
    // sizeHint() is called three times after invalidation (for max,
    // min and pref), but we just need do our setup once.

    const_cast<QGraphicsAnchorLayoutPrivate *>(d)->calculateGraphs();

    // ### apply constraint!
    QSizeF engineSizeHint(
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Horizontal][which],
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Vertical][which]);

    qreal left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);

    return engineSizeHint + QSizeF(left + right, top + bottom);
}

//////// DEBUG /////////
#include <QFile>
void QGraphicsAnchorLayout::dumpGraph()
{
    Q_D(QGraphicsAnchorLayout);

    QFile file(QString::fromAscii("anchorlayout.dot"));
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
        qWarning("Could not write to %s", file.fileName().toLocal8Bit().constData());

    QString dotContents = d->graph[0].serializeToDot();
    file.write(dotContents.toLocal8Bit());
    dotContents = d->graph[1].serializeToDot();
    file.write(dotContents.toLocal8Bit());

    file.close();
}
<commit_msg>QGraphicsAnchorLayout: Temporary destructor to avoid memory leaks<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgraphicsanchorlayout_p.h"

QGraphicsAnchorLayout::QGraphicsAnchorLayout(QGraphicsLayoutItem *parent)
    : QGraphicsLayout(*new QGraphicsAnchorLayoutPrivate(), parent)
{
    Q_D(QGraphicsAnchorLayout);
    d->createLayoutEdges();
}

QGraphicsAnchorLayout::~QGraphicsAnchorLayout()
{
    Q_D(QGraphicsAnchorLayout);

    for (int i = count() - 1; i >= 0; --i) {
        QGraphicsLayoutItem *item = d->items.at(i);
        removeAt(i);
        if (item) {
            if (item->ownedByLayout())
                delete item;
        }
    }

    d->deleteLayoutEdges();

    // ### make something better here
    qDeleteAll(d->itemCenterConstraints[0]);
    d->itemCenterConstraints[0].clear();
    qDeleteAll(d->itemCenterConstraints[1]);
    d->itemCenterConstraints[1].clear();

    Q_ASSERT(d->items.isEmpty());
    Q_ASSERT(d->m_vertexList.isEmpty());

    // ### Remove when integrated into Qt
    delete d_ptr;
}

void QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem,
                                   Edge firstEdge,
                                   QGraphicsLayoutItem *secondItem,
                                   Edge secondEdge, qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    if ((firstItem == 0) || (secondItem == 0)) {
        qWarning("QGraphicsAnchorLayout::anchor: "
                 "Cannot anchor NULL items");
        return;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::anchor: "
                 "Cannot anchor the item to itself");
        return;
    }

    if (d->edgeOrientation(secondEdge) != d->edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::anchor: "
                 "Cannot anchor edges of different orientations");
        return;
    }

    // In QGraphicsAnchorLayout, items are represented in its internal
    // graph as four anchors that connect:
    //  - Left -> HCenter
    //  - HCenter-> Right
    //  - Top -> VCenter
    //  - VCenter -> Bottom

    // Ensure that the internal anchors have been created for both items.
    if (firstItem != this && !d->items.contains(firstItem)) {
        d->createItemEdges(firstItem);
        d->addChildItem(firstItem);
    }
    if (secondItem != this && !d->items.contains(secondItem)) {
        d->createItemEdges(secondItem);
        d->addChildItem(secondItem);
    }

    // Use heuristics to find out what the user meant with this anchor.
    d->correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);

    // Create actual anchor between firstItem and secondItem.
    AnchorData *data;
    if (spacing >= 0) {
        data = new AnchorData(spacing);
        d->addAnchor(firstItem, firstEdge, secondItem, secondEdge, data);
    } else {
        data = new AnchorData(-spacing);
        d->addAnchor(secondItem, secondEdge, firstItem, firstEdge, data);
    }

    invalidate();
}

void QGraphicsAnchorLayout::removeAnchor(QGraphicsLayoutItem *firstItem, Edge firstEdge,
                                         QGraphicsLayoutItem *secondItem, Edge secondEdge)
{
    Q_D(QGraphicsAnchorLayout);
    if ((firstItem == 0) || (secondItem == 0)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor between NULL items");
        return;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from the item to itself");
        return;
    }

    if (d->edgeOrientation(secondEdge) != d->edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from edges of different orientations");
        return;
    }

    d->removeAnchor(firstItem, firstEdge, secondItem, secondEdge);

    invalidate();
}

void QGraphicsAnchorLayout::setGeometry(const QRectF &geom)
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayout::setGeometry(geom);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Vertical);
    d->setItemsGeometries();
}

void QGraphicsAnchorLayout::removeAt(int index)
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayoutItem *item = d->items.value(index);

    if (item) {
        d->items.remove(index);
        d->removeAnchors(item);
        item->setParentLayoutItem(0);
    }
}

int QGraphicsAnchorLayout::count() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.size();
}

QGraphicsLayoutItem *QGraphicsAnchorLayout::itemAt(int index) const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.value(index);
}

void QGraphicsAnchorLayout::invalidate()
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayout::invalidate();
    d->calculateGraphCacheDirty = 1;
}

QSizeF QGraphicsAnchorLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    Q_UNUSED(which);
    Q_UNUSED(constraint);
    Q_D(const QGraphicsAnchorLayout);

    // Some setup calculations are delayed until the information is
    // actually needed, avoiding unnecessary recalculations when
    // adding multiple anchors.

    // sizeHint() / effectiveSizeHint() already have a cache
    // mechanism, using invalidate() to force recalculation. However
    // sizeHint() is called three times after invalidation (for max,
    // min and pref), but we just need do our setup once.

    const_cast<QGraphicsAnchorLayoutPrivate *>(d)->calculateGraphs();

    // ### apply constraint!
    QSizeF engineSizeHint(
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Horizontal][which],
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Vertical][which]);

    qreal left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);

    return engineSizeHint + QSizeF(left + right, top + bottom);
}

//////// DEBUG /////////
#include <QFile>
void QGraphicsAnchorLayout::dumpGraph()
{
    Q_D(QGraphicsAnchorLayout);

    QFile file(QString::fromAscii("anchorlayout.dot"));
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
        qWarning("Could not write to %s", file.fileName().toLocal8Bit().constData());

    QString dotContents = d->graph[0].serializeToDot();
    file.write(dotContents.toLocal8Bit());
    dotContents = d->graph[1].serializeToDot();
    file.write(dotContents.toLocal8Bit());

    file.close();
}
<|endoftext|>


<commit_before>#include "sipdialogclient.h"

#include "initiation/siptransactionuser.h"
#include "initiation/transaction/sipdialogstate.h"

#include "common.h"

#include <QDebug>

SIPDialogClient::SIPDialogClient():
  sessionID_(0),
  transactionUser_(nullptr)
{}

void SIPDialogClient::init(SIPTransactionUser* tu, uint32_t sessionID)
{
  Q_ASSERT(sessionID != 0);
  sessionID_ = sessionID;

  transactionUser_ = tu;
}

void SIPDialogClient::getRequestMessageInfo(RequestType type,
                                            std::shared_ptr<SIPMessageInfo> &outMessage)
{
  SIPClient::getRequestMessageInfo(type, outMessage);

  if (type == SIP_INVITE || type == SIP_ACK)
  {
    if (!outMessage->vias.empty())
    {
      outMessage->vias.back().rport = true;
    }
  }
}

//processes incoming response
bool SIPDialogClient::processResponse(SIPResponse& response,
                                      SIPDialogState &state)
{
  printNormal(this, "Client starts processing response");
  Q_ASSERT(sessionID_ != 0);

  if(!sessionID_)
  {
    printProgramError(this, "SIP Client Transaction not initialized.");
    return true;
  }

  if (!checkTransactionType(response.message->transactionRequest))
  {
    printPeerError(this, "Their response transaction type is not the same as our request!");
    return false;
  }

  // check if this is failure that requires shutdown of session
  if (!SIPClient::processResponse(response, state))
  {
    printWarning(this, "Got a failure response!");
    transactionUser_->failure(sessionID_, response.text);
    return false;
  }

  // process anything that is not a failure and may cause a new request to be sent.
  // this must be done after the SIPClientTransaction processResponse, because that checks our
  // current active transaction and may modify it.
  if(response.message->transactionRequest == SIP_INVITE)
  {
    if(response.type == SIP_RINGING)
    {
      if (!state.getState())
      {
        transactionUser_->callRinging(sessionID_);
      }
    }
    else if(response.type == SIP_OK)
    {
      if (!state.getState())
      {
        transactionUser_->peerAccepted(sessionID_);
      }

      if (startTransaction(SIP_ACK))
      {
        state.setState(true);
        transactionUser_->callNegotiated(sessionID_);
      }
    }
  }

  return true;
}

bool SIPDialogClient::startCall(QString callee)
{
  qDebug() << "SIP, Dialog client: Starting a call and sending an INVITE in session";
  Q_ASSERT(sessionID_ != 0);
  if(!sessionID_)
  {
    printDebug(DEBUG_WARNING, this, "SIP Client Transaction not initialized.");
    return false;
  }

  if (startTransaction(SIP_INVITE))
  {
    transactionUser_->outgoingCall(sessionID_, callee);
  }

  return true;
}

void SIPDialogClient::requestEnd()
{
  qDebug() << "Ending the call with BYE";
  startTransaction(SIP_BYE);
}

void SIPDialogClient::requestCancel()
{
  startTransaction(SIP_CANCEL);
}

void SIPDialogClient::requestRenegotiation()
{
  startTransaction(SIP_INVITE);
}

void SIPDialogClient::processTimeout()
{
  if(getOngoingRequest() == SIP_INVITE)
  {
    emit sendDialogRequest(sessionID_, SIP_BYE);
    // TODO tell user we have failed
    startTransaction(SIP_CANCEL);
    transactionUser_->failure(sessionID_, "No response. Request timed out");
  }

  SIPClient::processTimeout();

  // destroys the whole dialog
  if (getOngoingRequest() == SIP_BYE)
  {
    emit BYETimeout(sessionID_);
  }
}

bool SIPDialogClient::startTransaction(RequestType type)
{
  if (SIPClient::startTransaction(type))
  {
    emit sendDialogRequest(sessionID_, type);
    return true;
  }
  return false;
}
<commit_msg>fix(Transaction): Ending the call to their reply.<commit_after>#include "sipdialogclient.h"

#include "initiation/siptransactionuser.h"
#include "initiation/transaction/sipdialogstate.h"

#include "common.h"

#include <QDebug>

SIPDialogClient::SIPDialogClient():
  sessionID_(0),
  transactionUser_(nullptr)
{}

void SIPDialogClient::init(SIPTransactionUser* tu, uint32_t sessionID)
{
  Q_ASSERT(sessionID != 0);
  sessionID_ = sessionID;

  transactionUser_ = tu;
}

void SIPDialogClient::getRequestMessageInfo(RequestType type,
                                            std::shared_ptr<SIPMessageInfo> &outMessage)
{
  SIPClient::getRequestMessageInfo(type, outMessage);

  if (type == SIP_INVITE || type == SIP_ACK)
  {
    if (!outMessage->vias.empty())
    {
      outMessage->vias.back().rport = true;
    }
  }
}

//processes incoming response
bool SIPDialogClient::processResponse(SIPResponse& response,
                                      SIPDialogState &state)
{
  printNormal(this, "Client starts processing response");
  Q_ASSERT(sessionID_ != 0);

  if(!sessionID_)
  {
    printProgramError(this, "SIP Client Transaction not initialized.");
    return true;
  }

  if (!checkTransactionType(response.message->transactionRequest))
  {
    printPeerError(this, "Their response transaction type is not the same as our request!");
    return false;
  }

  // check if this is failure that requires shutdown of session
  if (!SIPClient::processResponse(response, state))
  {
    printWarning(this, "Got a failure response!");
    transactionUser_->failure(sessionID_, response.text);
    return false;
  }

  // process anything that is not a failure and may cause a new request to be sent.
  // this must be done after the SIPClientTransaction processResponse, because that checks our
  // current active transaction and may modify it.
  if(response.message->transactionRequest == SIP_INVITE)
  {
    if(response.type == SIP_RINGING)
    {
      if (!state.getState())
      {
        transactionUser_->callRinging(sessionID_);
      }
    }
    else if(response.type == SIP_OK)
    {
      if (!state.getState())
      {
        transactionUser_->peerAccepted(sessionID_);
      }

      if (startTransaction(SIP_ACK))
      {
        state.setState(true);
        transactionUser_->callNegotiated(sessionID_);
      }
    }
  }
  else if(response.message->transactionRequest == SIP_BYE)
  {
    transactionUser_->endCall(sessionID_);
  }

  return true;
}

bool SIPDialogClient::startCall(QString callee)
{
  qDebug() << "SIP, Dialog client: Starting a call and sending an INVITE in session";
  Q_ASSERT(sessionID_ != 0);
  if(!sessionID_)
  {
    printDebug(DEBUG_WARNING, this, "SIP Client Transaction not initialized.");
    return false;
  }

  if (startTransaction(SIP_INVITE))
  {
    transactionUser_->outgoingCall(sessionID_, callee);
  }

  return true;
}

void SIPDialogClient::requestEnd()
{
  qDebug() << "Ending the call with BYE";
  startTransaction(SIP_BYE);
}

void SIPDialogClient::requestCancel()
{
  startTransaction(SIP_CANCEL);
}

void SIPDialogClient::requestRenegotiation()
{
  startTransaction(SIP_INVITE);
}

void SIPDialogClient::processTimeout()
{
  if(getOngoingRequest() == SIP_INVITE)
  {
    emit sendDialogRequest(sessionID_, SIP_BYE);
    // TODO tell user we have failed
    startTransaction(SIP_CANCEL);
    transactionUser_->failure(sessionID_, "No response. Request timed out");
  }

  SIPClient::processTimeout();

  // destroys the whole dialog
  if (getOngoingRequest() == SIP_BYE)
  {
    emit BYETimeout(sessionID_);
  }
}

bool SIPDialogClient::startTransaction(RequestType type)
{
  if (SIPClient::startTransaction(type))
  {
    emit sendDialogRequest(sessionID_, type);
    return true;
  }
  return false;
}
<|endoftext|>


<commit_before>
/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Julius Kammerl (julius@kammerl.de)
 */

#include <pcl/impl/instantiate.hpp>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>

#include <pcl/octree/octree.h>
#include <pcl/octree/octree_impl.h>

// Instantiations of specific point types

template class PCL_EXPORTS pcl::octree::OctreeBase<int>;
template class PCL_EXPORTS pcl::octree::Octree2BufBase<int>;

PCL_INSTANTIATE(OctreePointCloudSingleBufferWithLeafDataTVector, PCL_XYZ_POINT_TYPES)
PCL_INSTANTIATE(OctreePointCloudDoubleBufferWithLeafDataTVector, PCL_XYZ_POINT_TYPES)

PCL_INSTANTIATE(OctreePointCloudSearch, PCL_XYZ_POINT_TYPES)

// PCL_INSTANTIATE(OctreePointCloudSingleBufferWithLeafDataT, PCL_XYZ_POINT_TYPES);

// PCL_INSTANTIATE(OctreePointCloudSingleBufferWithEmptyLeaf, PCL_XYZ_POINT_TYPES);

// PCL_INSTANTIATE(OctreePointCloudDensity, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudSingleBufferWithDensityLeaf, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudDoubleBufferWithDensityLeaf, PCL_XYZ_POINT_TYPES);

// PCL_INSTANTIATE(OctreePointCloudOccupancy, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudSinglePoint, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudPointVector, PCL_XYZ_POINT_TYPES);
PCL_INSTANTIATE(OctreePointCloudChangeDetector, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudVoxelCentroid, PCL_XYZ_POINT_TYPES);

<commit_msg>Fixed missing symbols in octree search<commit_after>
/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Julius Kammerl (julius@kammerl.de)
 */

#include <pcl/impl/instantiate.hpp>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>

#include <pcl/octree/octree.h>
#include <pcl/octree/octree_impl.h>

// Instantiations of specific point types

template class PCL_EXPORTS pcl::octree::OctreeBase<int>;
template class PCL_EXPORTS pcl::octree::Octree2BufBase<int>;

template class PCL_EXPORTS pcl::octree::OctreeBase<int,
    pcl::octree::OctreeContainerDataTVector<int>,
    pcl::octree::OctreeContainerEmpty<int> >;

template class PCL_EXPORTS pcl::octree::Octree2BufBase<int,
    pcl::octree::OctreeContainerDataTVector<int>,
    pcl::octree::OctreeContainerEmpty<int> >;

PCL_INSTANTIATE(OctreePointCloudSingleBufferWithLeafDataTVector,
    PCL_XYZ_POINT_TYPES)
PCL_INSTANTIATE(OctreePointCloudDoubleBufferWithLeafDataTVector,
    PCL_XYZ_POINT_TYPES)

PCL_INSTANTIATE(OctreePointCloudSearch, PCL_XYZ_POINT_TYPES)

// PCL_INSTANTIATE(OctreePointCloudSingleBufferWithLeafDataT, PCL_XYZ_POINT_TYPES);

// PCL_INSTANTIATE(OctreePointCloudSingleBufferWithEmptyLeaf, PCL_XYZ_POINT_TYPES);

// PCL_INSTANTIATE(OctreePointCloudDensity, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudSingleBufferWithDensityLeaf, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudDoubleBufferWithDensityLeaf, PCL_XYZ_POINT_TYPES);

// PCL_INSTANTIATE(OctreePointCloudOccupancy, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudSinglePoint, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudPointVector, PCL_XYZ_POINT_TYPES);
PCL_INSTANTIATE(OctreePointCloudChangeDetector, PCL_XYZ_POINT_TYPES);
// PCL_INSTANTIATE(OctreePointCloudVoxelCentroid, PCL_XYZ_POINT_TYPES);

<|endoftext|>


<commit_before>/*
 * ANNTriggerUpdateOnNewImageLayer.cpp
 *
 *  Created on: Jul 26, 2013
 *      Author: gkenyon
 */

//#include "ANNLayer.hpp"
#include "ANNTriggerUpdateOnNewImageLayer.hpp"

namespace PV {

ANNTriggerUpdateOnNewImageLayer::ANNTriggerUpdateOnNewImageLayer()
{
   initialize_base();
}

ANNTriggerUpdateOnNewImageLayer::ANNTriggerUpdateOnNewImageLayer(const char * name, HyPerCol * hc,
		int num_channels, const char * movieLayerName)
{
   initialize_base();
   initialize(name, hc, num_channels, movieLayerName);
}

ANNTriggerUpdateOnNewImageLayer::ANNTriggerUpdateOnNewImageLayer(const char * name, HyPerCol * hc,
		const char * movieLayerName)
{
   initialize_base();
   initialize(name, hc, 2, movieLayerName);
}

ANNTriggerUpdateOnNewImageLayer::~ANNTriggerUpdateOnNewImageLayer()
{
}

int ANNTriggerUpdateOnNewImageLayer::initialize_base()
{
	movieLayerName = NULL;
	movieLayer = NULL;
	return PV_SUCCESS;
}

int ANNTriggerUpdateOnNewImageLayer::initialize(const char * name, HyPerCol * hc,
		int num_channels, const char * movieLayerName)
{
	this->movieLayerName = strdup(movieLayerName);
	if (this->movieLayerName==NULL) {
		fprintf(stderr,
				"ANNTriggerUpdateOnNewImageLayer \"%s\" error: unable to copy movieLayerName \"%s\": %s\n",
				name, this->movieLayerName, strerror(errno));
		exit(EXIT_FAILURE);
	}
	return ANNLayer::initialize(name, hc, num_channels);
}

int ANNTriggerUpdateOnNewImageLayer::communicateInitInfo() {
   int status = ANNLayer::communicateInitInfo();

   HyPerLayer * origHyPerLayer = parent->getLayerFromName(movieLayerName);
   if (origHyPerLayer==NULL) {
      fprintf(stderr, "ANNTriggerUpdateOnNewImageLayer \"%s\" error: movieLayerName \"%s\" is not a layer in the HyPerCol.\n",
    		  name, movieLayerName);
      return(EXIT_FAILURE);
   }
   movieLayer = dynamic_cast<Movie *>(origHyPerLayer);
   if (movieLayer==NULL) {
      fprintf(stderr, "SigmoidLayer \"%s\" error: movieLayerName \"%s\" is not a Movie or Movie-derived layer in the HyPerCol.\n",
    		  name, movieLayerName);
      return(EXIT_FAILURE);
   }

   return status;
}

int ANNTriggerUpdateOnNewImageLayer::recvAllSynapticInput(){
	update_timer->start();
	int status = PV_SUCCESS;
	if (movieLayer->getNewImageFlag()){
		status = ANNLayer::recvAllSynapticInput();
	}
	update_timer->stop();
	return status;
}

int ANNTriggerUpdateOnNewImageLayer::doUpdateState(double time, double dt, const PVLayerLoc * loc, pvdata_t * A,
      pvdata_t * V, int num_channels, pvdata_t * gSynHead, bool spiking,
      unsigned int * active_indices, unsigned int * num_active)
{
   update_timer->start();
   int status = PV_SUCCESS;
   if (movieLayer->getNewImageFlag()){
	   status = ANNLayer::doUpdateState(time,  dt, loc, A, V, num_channels, gSynHead, spiking, active_indices, num_active);
   }
   update_timer->stop();
   return status;
}

} /* namespace PV */

<commit_msg>ANNTriggerUpdateOnNewImageLayer::recvAllSynapticInput() should not call update_timer->start or stop.  It doesn't need to call recvsyn_timer either, since recvSynapticInput and recvSynapticInputFromPost both call recvsyn_timer.<commit_after>/*
 * ANNTriggerUpdateOnNewImageLayer.cpp
 *
 *  Created on: Jul 26, 2013
 *      Author: gkenyon
 */

//#include "ANNLayer.hpp"
#include "ANNTriggerUpdateOnNewImageLayer.hpp"

namespace PV {

ANNTriggerUpdateOnNewImageLayer::ANNTriggerUpdateOnNewImageLayer()
{
   initialize_base();
}

ANNTriggerUpdateOnNewImageLayer::ANNTriggerUpdateOnNewImageLayer(const char * name, HyPerCol * hc,
		int num_channels, const char * movieLayerName)
{
   initialize_base();
   initialize(name, hc, num_channels, movieLayerName);
}

ANNTriggerUpdateOnNewImageLayer::ANNTriggerUpdateOnNewImageLayer(const char * name, HyPerCol * hc,
		const char * movieLayerName)
{
   initialize_base();
   initialize(name, hc, 2, movieLayerName);
}

ANNTriggerUpdateOnNewImageLayer::~ANNTriggerUpdateOnNewImageLayer()
{
}

int ANNTriggerUpdateOnNewImageLayer::initialize_base()
{
	movieLayerName = NULL;
	movieLayer = NULL;
	return PV_SUCCESS;
}

int ANNTriggerUpdateOnNewImageLayer::initialize(const char * name, HyPerCol * hc,
		int num_channels, const char * movieLayerName)
{
	this->movieLayerName = strdup(movieLayerName);
	if (this->movieLayerName==NULL) {
		fprintf(stderr,
				"ANNTriggerUpdateOnNewImageLayer \"%s\" error: unable to copy movieLayerName \"%s\": %s\n",
				name, this->movieLayerName, strerror(errno));
		exit(EXIT_FAILURE);
	}
	return ANNLayer::initialize(name, hc, num_channels);
}

int ANNTriggerUpdateOnNewImageLayer::communicateInitInfo() {
   int status = ANNLayer::communicateInitInfo();

   HyPerLayer * origHyPerLayer = parent->getLayerFromName(movieLayerName);
   if (origHyPerLayer==NULL) {
      fprintf(stderr, "ANNTriggerUpdateOnNewImageLayer \"%s\" error: movieLayerName \"%s\" is not a layer in the HyPerCol.\n",
    		  name, movieLayerName);
      return(EXIT_FAILURE);
   }
   movieLayer = dynamic_cast<Movie *>(origHyPerLayer);
   if (movieLayer==NULL) {
      fprintf(stderr, "SigmoidLayer \"%s\" error: movieLayerName \"%s\" is not a Movie or Movie-derived layer in the HyPerCol.\n",
    		  name, movieLayerName);
      return(EXIT_FAILURE);
   }

   return status;
}

int ANNTriggerUpdateOnNewImageLayer::recvAllSynapticInput(){
	int status = PV_SUCCESS;
	if (movieLayer->getNewImageFlag()){
		status = ANNLayer::recvAllSynapticInput();
	}
	return status;
}

int ANNTriggerUpdateOnNewImageLayer::doUpdateState(double time, double dt, const PVLayerLoc * loc, pvdata_t * A,
      pvdata_t * V, int num_channels, pvdata_t * gSynHead, bool spiking,
      unsigned int * active_indices, unsigned int * num_active)
{
   update_timer->start();
   int status = PV_SUCCESS;
   if (movieLayer->getNewImageFlag()){
	   status = ANNLayer::doUpdateState(time,  dt, loc, A, V, num_channels, gSynHead, spiking, active_indices, num_active);
   }
   update_timer->stop();
   return status;
}

} /* namespace PV */

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void matrixRedux(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols);

  VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
  VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
  Scalar s(0), p(1), minc(internal::real(m1.coeff(0))), maxc(internal::real(m1.coeff(0)));
  for(int j = 0; j < cols; j++)
  for(int i = 0; i < rows; i++)
  {
    s += m1(i,j);
    p *= m1(i,j);
    minc = (std::min)(internal::real(minc), internal::real(m1(i,j)));
    maxc = (std::max)(internal::real(maxc), internal::real(m1(i,j)));
  }
  const Scalar mean = s/Scalar(RealScalar(rows*cols));

  VERIFY_IS_APPROX(m1.sum(), s);
  VERIFY_IS_APPROX(m1.mean(), mean);
  VERIFY_IS_APPROX(m1.prod(), p);
  VERIFY_IS_APPROX(m1.real().minCoeff(), internal::real(minc));
  VERIFY_IS_APPROX(m1.real().maxCoeff(), internal::real(maxc));

  // test slice vectorization assuming assign is ok
  Index r0 = internal::random<Index>(0,rows-1);
  Index c0 = internal::random<Index>(0,cols-1);
  Index r1 = internal::random<Index>(r0+1,rows)-r0;
  Index c1 = internal::random<Index>(c0+1,cols)-c0;
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).sum(), m1.block(r0,c0,r1,c1).eval().sum());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).mean(), m1.block(r0,c0,r1,c1).eval().mean());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).prod(), m1.block(r0,c0,r1,c1).eval().prod());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());

  // test empty objects
  VERIFY_IS_APPROX(m1.block(r0,c0,0,0).sum(),   Scalar(0));
  VERIFY_IS_APPROX(m1.block(r0,c0,0,0).prod(),  Scalar(1));
}

template<typename VectorType> void vectorRedux(const VectorType& w)
{
  typedef typename VectorType::Index Index;
  typedef typename VectorType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  Index size = w.size();

  VectorType v = VectorType::Random(size);
  for(int i = 1; i < size; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(internal::real(v.coeff(0))), maxc(internal::real(v.coeff(0)));
    for(int j = 0; j < i; j++)
    {
      s += v[j];
      p *= v[j];
      minc = (std::min)(minc, internal::real(v[j]));
      maxc = (std::max)(maxc, internal::real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.head(i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v.head(i).prod());
    VERIFY_IS_APPROX(minc, v.real().head(i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().head(i).maxCoeff());
  }

  for(int i = 0; i < size-1; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
    for(int j = i; j < size; j++)
    {
      s += v[j];
      p *= v[j];
      minc = (std::min)(minc, internal::real(v[j]));
      maxc = (std::max)(maxc, internal::real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.tail(size-i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v.tail(size-i).prod());
    VERIFY_IS_APPROX(minc, v.real().tail(size-i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().tail(size-i).maxCoeff());
  }

  for(int i = 0; i < size/2; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
    for(int j = i; j < size-i; j++)
    {
      s += v[j];
      p *= v[j];
      minc = (std::min)(minc, internal::real(v[j]));
      maxc = (std::max)(maxc, internal::real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.segment(i, size-2*i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v.segment(i, size-2*i).prod());
    VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
  }

  // test empty objects
  VERIFY_IS_APPROX(v.head(0).sum(),   Scalar(0));
  VERIFY_IS_APPROX(v.tail(0).prod(),  Scalar(1));
  VERIFY_RAISES_ASSERT(v.head(0).mean());
  VERIFY_RAISES_ASSERT(v.head(0).minCoeff());
  VERIFY_RAISES_ASSERT(v.head(0).maxCoeff());
}

void test_redux()
{
  // the max size cannot be too large, otherwise reduxion operations obviously generate large errors.
  int maxsize = (std::min)(100,EIGEN_TEST_MAX_SIZE);
  EIGEN_UNUSED_VARIABLE(maxsize);
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( matrixRedux(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_1( matrixRedux(Array<float, 1, 1>()) );
    CALL_SUBTEST_2( matrixRedux(Matrix2f()) );
    CALL_SUBTEST_2( matrixRedux(Array2f()) );
    CALL_SUBTEST_3( matrixRedux(Matrix4d()) );
    CALL_SUBTEST_3( matrixRedux(Array4d()) );
    CALL_SUBTEST_4( matrixRedux(MatrixXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_4( matrixRedux(ArrayXXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( matrixRedux(MatrixXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( matrixRedux(ArrayXXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_6( matrixRedux(MatrixXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_6( matrixRedux(ArrayXXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_7( vectorRedux(Vector4f()) );
    CALL_SUBTEST_7( vectorRedux(Array4f()) );
    CALL_SUBTEST_5( vectorRedux(VectorXd(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( vectorRedux(ArrayXd(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_8( vectorRedux(VectorXf(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_8( vectorRedux(ArrayXf(internal::random<int>(1,maxsize))) );
  }
}
<commit_msg>Fix failures in redux test caused by underflow in .prod() test.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void matrixRedux(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols);

  // The entries of m1 are uniformly distributed in [0,1], so m1.prod() is very small. This may lead to test
  // failures if we underflow into denormals. Thus, we scale so that entires are close to 1.
  MatrixType m1_for_prod = MatrixType::Ones(rows, cols) + Scalar(0.2) * m1;

  VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
  VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
  Scalar s(0), p(1), minc(internal::real(m1.coeff(0))), maxc(internal::real(m1.coeff(0)));
  for(int j = 0; j < cols; j++)
  for(int i = 0; i < rows; i++)
  {
    s += m1(i,j);
    p *= m1_for_prod(i,j);
    minc = (std::min)(internal::real(minc), internal::real(m1(i,j)));
    maxc = (std::max)(internal::real(maxc), internal::real(m1(i,j)));
  }
  const Scalar mean = s/Scalar(RealScalar(rows*cols));

  VERIFY_IS_APPROX(m1.sum(), s);
  VERIFY_IS_APPROX(m1.mean(), mean);
  VERIFY_IS_APPROX(m1_for_prod.prod(), p);
  VERIFY_IS_APPROX(m1.real().minCoeff(), internal::real(minc));
  VERIFY_IS_APPROX(m1.real().maxCoeff(), internal::real(maxc));

  // test slice vectorization assuming assign is ok
  Index r0 = internal::random<Index>(0,rows-1);
  Index c0 = internal::random<Index>(0,cols-1);
  Index r1 = internal::random<Index>(r0+1,rows)-r0;
  Index c1 = internal::random<Index>(c0+1,cols)-c0;
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).sum(), m1.block(r0,c0,r1,c1).eval().sum());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).mean(), m1.block(r0,c0,r1,c1).eval().mean());
  VERIFY_IS_APPROX(m1_for_prod.block(r0,c0,r1,c1).prod(), m1_for_prod.block(r0,c0,r1,c1).eval().prod());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());

  // test empty objects
  VERIFY_IS_APPROX(m1.block(r0,c0,0,0).sum(),   Scalar(0));
  VERIFY_IS_APPROX(m1.block(r0,c0,0,0).prod(),  Scalar(1));
}

template<typename VectorType> void vectorRedux(const VectorType& w)
{
  typedef typename VectorType::Index Index;
  typedef typename VectorType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  Index size = w.size();

  VectorType v = VectorType::Random(size);
  VectorType v_for_prod = VectorType::Ones(size) + Scalar(0.2) * v; // see comment above declaration of m1_for_prod

  for(int i = 1; i < size; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(internal::real(v.coeff(0))), maxc(internal::real(v.coeff(0)));
    for(int j = 0; j < i; j++)
    {
      s += v[j];
      p *= v_for_prod[j];
      minc = (std::min)(minc, internal::real(v[j]));
      maxc = (std::max)(maxc, internal::real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.head(i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v_for_prod.head(i).prod());
    VERIFY_IS_APPROX(minc, v.real().head(i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().head(i).maxCoeff());
  }

  for(int i = 0; i < size-1; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
    for(int j = i; j < size; j++)
    {
      s += v[j];
      p *= v_for_prod[j];
      minc = (std::min)(minc, internal::real(v[j]));
      maxc = (std::max)(maxc, internal::real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.tail(size-i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v_for_prod.tail(size-i).prod());
    VERIFY_IS_APPROX(minc, v.real().tail(size-i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().tail(size-i).maxCoeff());
  }

  for(int i = 0; i < size/2; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
    for(int j = i; j < size-i; j++)
    {
      s += v[j];
      p *= v_for_prod[j];
      minc = (std::min)(minc, internal::real(v[j]));
      maxc = (std::max)(maxc, internal::real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.segment(i, size-2*i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v_for_prod.segment(i, size-2*i).prod());
    VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
  }

  // test empty objects
  VERIFY_IS_APPROX(v.head(0).sum(),   Scalar(0));
  VERIFY_IS_APPROX(v.tail(0).prod(),  Scalar(1));
  VERIFY_RAISES_ASSERT(v.head(0).mean());
  VERIFY_RAISES_ASSERT(v.head(0).minCoeff());
  VERIFY_RAISES_ASSERT(v.head(0).maxCoeff());
}

void test_redux()
{
  // the max size cannot be too large, otherwise reduxion operations obviously generate large errors.
  int maxsize = (std::min)(100,EIGEN_TEST_MAX_SIZE);
  EIGEN_UNUSED_VARIABLE(maxsize);
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( matrixRedux(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_1( matrixRedux(Array<float, 1, 1>()) );
    CALL_SUBTEST_2( matrixRedux(Matrix2f()) );
    CALL_SUBTEST_2( matrixRedux(Array2f()) );
    CALL_SUBTEST_3( matrixRedux(Matrix4d()) );
    CALL_SUBTEST_3( matrixRedux(Array4d()) );
    CALL_SUBTEST_4( matrixRedux(MatrixXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_4( matrixRedux(ArrayXXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( matrixRedux(MatrixXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( matrixRedux(ArrayXXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_6( matrixRedux(MatrixXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_6( matrixRedux(ArrayXXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_7( vectorRedux(Vector4f()) );
    CALL_SUBTEST_7( vectorRedux(Array4f()) );
    CALL_SUBTEST_5( vectorRedux(VectorXd(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( vectorRedux(ArrayXd(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_8( vectorRedux(VectorXf(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_8( vectorRedux(ArrayXf(internal::random<int>(1,maxsize))) );
  }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Bastien Durix

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/**
 *  \file BsplineUtils.cpp
 *  \brief Defines bspline utilitary functions
 *  \author Bastien Durix
 */

#include "Bspline.h"

double mathtools::application::BsplineBasis(double t, unsigned int degree, unsigned int indice, const Eigen::Matrix<double,1,Eigen::Dynamic> &node)
{
	if(indice + degree > node.cols())
		throw std::logic_error("BsplineBasis : Basis indice is out of node vector");
	double res = 0.0;
	/*
	 *  if degree = 0
	 *  B(t) = 1 if t_{indice-1} <= t < t_{indice}
	 *  with t_{-1}          = -infinity
	 *       t_{node.cols()} = +infinity
	 *
	 *  example:
	 *
	 *  node vector: node = {0}
	 *
	 *  B_0(t) = 1 if t <  0
	 *           0 if t >= 0
	 *
	 *  B_1(t) = 0 if t <  0
	 *           1 if t >= 0
	 *
	 */
	if(degree == 0)
	{
		if(indice == 0)
		{
			if(t < node(0,0))
				res = 1.0;
		}
		else if(indice == node.cols())
		{
			if(node(0,indice-1) <= t)
				res = 1.0;
		}
		else
		{
			if(node(0,indice-1) <= t && t < node(0,indice))
				res = 1.0;
		}
	}
	/*
	 *  if degree != 0
	 *  classical recursive definition of bspline basis
	 *
	 *  B_{d,i}(t) = B_{d-1,i}(t) * a_1(t) + B_{d-1,i+1}(t) * a_2(t)
	 *
	 *  with a_1(t) = 1                                           if i == 0
	 *	              (t - node[i-1])/(node[i+d-1] - node[i-1])   if i >  0
	 *
	 *
	 *  with a_2(t) = (node[i+d] - t)/(node[i+d] - node[i])       if i + d <  node.cols()
	 *                1                                           if i + d == node.cols()
	 */
	else
	{
		if(indice > 0)
		{
			if(node(0, indice-1) <= t && t < node(0, indice + degree - 1))
			{
				double num1 = t                            - node(0, indice - 1);
				double den1 = node(0, indice + degree - 1) - node(0, indice - 1);

				if(den1 != 0)
					res += (num1/den1) * BsplineBasis(t, degree-1, indice, node);
			}
		}
		else
		{
			if(t < node(0,indice + degree - 1))
			{
				res += BsplineBasis(t, degree-1, indice, node);
			}
		}

		if(indice + degree < node.cols())
		{
			if(node(0, indice) <= t && t < node(0, indice + degree))
			{
				double num2 = node(0, indice + degree) - t;
				double den2 = node(0, indice + degree) - node(0, indice);

				if(den2 != 0)
					res += (num2/den2) * BsplineBasis(t, degree-1, indice+1, node);
			}
		}
		else
		{
			if(node(0, indice) <= t)
			{
				res += BsplineBasis(t, degree-1, indice+1, node);
			}
		}
	}
	return res;
}

double mathtools::application::BsplineBasisDerivative(double t, unsigned int degree, unsigned int indice, const Eigen::Matrix<double,1,Eigen::Dynamic> &node, unsigned int der)
{
	if(indice + der > node.cols())
		throw std::logic_error("BsplineBasisDerivative : Basis indice is out of node vector");
	double res = 0.0;
	/*
	 *  if degree = 0 && der > 0
	 *		=> return 0
	 *
	 *  if degree = 0 && der == 0
	 *		=> return B(t)
	 */
	if(der==0)
	{
		res = BsplineBasis(t,degree,indice,node);
	}
	/*
	 *  if degree != 0
	 *  recursive definition of bspline basis derivative
	 *
	 *  B^{der}_{d,i}(t) = d( B^{der-1}_{d-1,i}(t) * a_1(t) - B^{der-1}_{d-1,i+1}(t) * a_2(t) )
	 *
	 *  with a_1(t) = 0                             if i == 0
	 *	              1/(node[i+d-1] - node[i-1])   if i >  0
	 *
	 *
	 *  with a_2(t) = 1/(node[i+d] - node[i])       if i + d <  node.cols()
	 *                0                             if i + d == node.cols()
	 */
	else if(degree != 0)
	{
		if(indice > 0)
		{
			if(node(0, indice-1) <= t && t < node(0, indice + degree - 1))
			{
				double den1 = node(0, indice + degree - 1) - node(0, indice - 1);

				if(den1 != 0)
					res += (double)degree * (1.0/den1) * BsplineBasisDerivative(t, degree-1, indice, node, der-1);
			}
		}

		if(indice + degree < node.cols())
		{
			if(node(0, indice) <= t && t < node(0, indice + degree))
			{
				double den2 = node(0, indice + degree) - node(0, indice);

				if(den2 != 0)
					res -= (double)degree * (1.0/den2) * BsplineBasisDerivative(t, degree-1, indice+1, node, der-1);
			}
		}
	}
	return res;
}

void mathtools::application::Blossom(double t, const Eigen::Matrix<double,1,Eigen::Dynamic> &node, Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> &ctrl)
{
	if(node.cols() + 1 < ctrl.cols() || ctrl.cols() == 0)
		throw std::logic_error("Blossom : wrong number of nodes or control points");

	unsigned int degree = node.cols() - ctrl.cols() + 1;

	if(degree == 0)
	{
		ctrl *= 0;
	}
	else
	{
		for(unsigned int i = 0; i < ctrl.cols()-1; i++)
		{
			double tdeb = node(0,i), tfin = node(0,i+degree);
			if(t >= tdeb && t <= tfin ) //supposed to be different
			{
				ctrl.block(0,i,ctrl.rows(),1) = ctrl.block(0,i,ctrl.rows(),1)*(tfin - t)/(tfin - tdeb) + ctrl.block(0,i+1,ctrl.rows(),1)*(t - tdeb)/(tfin - tdeb);
			}
		}
	}
}

<commit_msg>Few corrections on basis derivation<commit_after>/*
Copyright (c) 2016 Bastien Durix

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/**
 *  \file BsplineUtils.cpp
 *  \brief Defines bspline utilitary functions
 *  \author Bastien Durix
 */

#include "Bspline.h"

double mathtools::application::BsplineBasis(double t, unsigned int degree, unsigned int indice, const Eigen::Matrix<double,1,Eigen::Dynamic> &node)
{
	if(indice + degree > node.cols())
		throw std::logic_error("BsplineBasis : Basis indice is out of node vector");
	double res = 0.0;
	/*
	 *  if degree = 0
	 *  B(t) = 1 if t_{indice-1} <= t < t_{indice}
	 *  with t_{-1}          = -infinity
	 *       t_{node.cols()} = +infinity
	 *
	 *  example:
	 *
	 *  node vector: node = {0}
	 *
	 *  B_0(t) = 1 if t <  0
	 *           0 if t >= 0
	 *
	 *  B_1(t) = 0 if t <  0
	 *           1 if t >= 0
	 *
	 */
	if(degree == 0)
	{
		if(indice == 0)
		{
			if(t < node(0,0))
				res = 1.0;
		}
		else if(indice == node.cols())
		{
			if(node(0,indice-1) <= t)
				res = 1.0;
		}
		else
		{
			if(node(0,indice-1) <= t && t < node(0,indice))
				res = 1.0;
		}
	}
	/*
	 *  if degree != 0
	 *  classical recursive definition of bspline basis
	 *
	 *  B_{d,i}(t) = B_{d-1,i}(t) * a_1(t) + B_{d-1,i+1}(t) * a_2(t)
	 *
	 *  with a_1(t) = 1                                           if i == 0
	 *	              (t - node[i-1])/(node[i+d-1] - node[i-1])   if i >  0
	 *
	 *
	 *  with a_2(t) = (node[i+d] - t)/(node[i+d] - node[i])       if i + d <  node.cols()
	 *                1                                           if i + d == node.cols()
	 */
	else
	{
		if(indice > 0)
		{
			if(node(0, indice-1) <= t && t < node(0, indice + degree - 1))
			{
				double num1 = t                            - node(0, indice - 1);
				double den1 = node(0, indice + degree - 1) - node(0, indice - 1);

				if(den1 != 0)
					res += (num1/den1) * BsplineBasis(t, degree-1, indice, node);
			}
		}
		else
		{
			if(t < node(0,indice + degree - 1))
			{
				res += BsplineBasis(t, degree-1, indice, node);
			}
		}

		if(indice + degree < node.cols())
		{
			if(node(0, indice) <= t && t < node(0, indice + degree))
			{
				double num2 = node(0, indice + degree) - t;
				double den2 = node(0, indice + degree) - node(0, indice);

				if(den2 != 0)
					res += (num2/den2) * BsplineBasis(t, degree-1, indice+1, node);
			}
		}
		else
		{
			if(node(0, indice) <= t)
			{
				res += BsplineBasis(t, degree-1, indice+1, node);
			}
		}
	}
	return res;
}

double mathtools::application::BsplineBasisDerivative(double t, unsigned int degree, unsigned int indice, const Eigen::Matrix<double,1,Eigen::Dynamic> &node, unsigned int der)
{
	if(indice + der > node.cols() && degree > der)
		throw std::logic_error("BsplineBasisDerivative : Basis indice is out of node vector");
	double res = 0.0;
	/*
	 *  if degree = 0 && der > 0
	 *		=> return 0
	 *
	 *  if degree = 0 && der == 0
	 *		=> return B(t)
	 */
	if(der == 0)
	{
		res = BsplineBasis(t,degree,indice,node);
	}
	/*
	 *  if degree != 0
	 *  recursive definition of bspline basis derivative
	 *
	 *  B^{der}_{d,i}(t) = d( B^{der-1}_{d-1,i}(t) * a_1(t) - B^{der-1}_{d-1,i+1}(t) * a_2(t) )
	 *
	 *  with a_1(t) = 0                             if i == 0
	 *	              1/(node[i+d-1] - node[i-1])   if i >  0
	 *
	 *
	 *  with a_2(t) = 1/(node[i+d] - node[i])       if i + d <  node.cols()
	 *                0                             if i + d == node.cols()
	 */
	else if(degree != 0)
	{
		if(indice > 0)
		{
			double den1 = node(0, indice + degree - 1) - node(0, indice - 1);

			if(den1 != 0)
				res += (double)degree * (1.0/den1) * BsplineBasisDerivative(t, degree-1, indice, node, der-1);
		}

		if(indice + degree < node.cols())
		{
			double den2 = node(0, indice + degree) - node(0, indice);

			if(den2 != 0)
				res -= (double)degree * (1.0/den2) * BsplineBasisDerivative(t, degree-1, indice+1, node, der-1);
		}
	}
	return res;
}

void mathtools::application::Blossom(double t, const Eigen::Matrix<double,1,Eigen::Dynamic> &node, Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> &ctrl)
{
	if(node.cols() + 1 < ctrl.cols() || ctrl.cols() == 0)
		throw std::logic_error("Blossom : wrong number of nodes or control points");

	unsigned int degree = node.cols() - ctrl.cols() + 1;

	if(degree == 0)
	{
		ctrl *= 0;
	}
	else
	{
		for(unsigned int i = 0; i < ctrl.cols()-1; i++)
		{
			double tdeb = node(0,i), tfin = node(0,i+degree);
			if(t >= tdeb && t <= tfin ) //supposed to be different
			{
				ctrl.block(0,i,ctrl.rows(),1) = ctrl.block(0,i,ctrl.rows(),1)*(tfin - t)/(tfin - tdeb) + ctrl.block(0,i+1,ctrl.rows(),1)*(t - tdeb)/(tfin - tdeb);
			}
		}
	}
}

<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

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

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file state.cpp
 * @author Christoph Jentzsch <cj@ethdev.com>
 * @date 2014
 * State test functions.
 */

#include <boost/filesystem/operations.hpp>
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/State.h>
#include <libethereum/ExtVM.h>
#include <libethereum/Defaults.h>
#include <libevm/VM.h>
#include "TestHelper.h"

using namespace std;
using namespace json_spirit;
using namespace dev;
using namespace dev::eth;

namespace dev {  namespace test {

void doStateTests(json_spirit::mValue& v, bool _fillin)
{
	processCommandLineOptions();

	for (auto& i: v.get_obj())
	{
		cerr << i.first << endl;
		mObject& o = i.second.get_obj();

		BOOST_REQUIRE(o.count("env") > 0);
		BOOST_REQUIRE(o.count("pre") > 0);
		BOOST_REQUIRE(o.count("transaction") > 0);

		ImportTest importer(o, _fillin);

		State theState = importer.m_statePre;
		bytes tx = importer.m_transaction.rlp();
		bytes output;

		try
		{
			theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output);
		}
		catch (Exception const& _e)
		{
			cnote << "state execution did throw an exception: " << diagnostic_information(_e);
		}
		catch (std::exception const& _e)
		{
			cnote << "state execution did throw an exception: " << _e.what();
		}

		if (_fillin)
		{
#if ETH_FATDB
			importer.exportTest(output, theState);
#else
			BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off"));
#endif
		}
		else
		{
			BOOST_REQUIRE(o.count("post") > 0);
			BOOST_REQUIRE(o.count("out") > 0);

			// check output
			checkOutput(output, o);

			// check logs
			checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs);

			// check addresses
#if ETH_FATDB
			auto expectedAddrs = importer.m_statePost.addresses();
			auto resultAddrs = theState.addresses();
			for (auto& expectedPair : expectedAddrs)
			{
				auto& expectedAddr = expectedPair.first;
				auto resultAddrIt = resultAddrs.find(expectedAddr);
				if (resultAddrIt == resultAddrs.end())
					BOOST_ERROR("Missing expected address " << expectedAddr);
				else
				{
					BOOST_CHECK_MESSAGE(importer.m_statePost.balance(expectedAddr) ==  theState.balance(expectedAddr), expectedAddr << ": incorrect balance " << theState.balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr));
					BOOST_CHECK_MESSAGE(importer.m_statePost.transactionsFrom(expectedAddr) ==  theState.transactionsFrom(expectedAddr), expectedAddr << ": incorrect txCount " << theState.transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr));
					BOOST_CHECK_MESSAGE(importer.m_statePost.code(expectedAddr) == theState.code(expectedAddr), expectedAddr << ": incorrect code");

					checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr);
				}
			}
			checkAddresses<map<Address, u256> >(expectedAddrs, resultAddrs);
#endif
			BOOST_CHECK_MESSAGE(theState.rootHash() == h256(o["postStateRoot"].get_str()), "wrong post state root");
		}
	}
}
} }// Namespace Close

BOOST_AUTO_TEST_SUITE(StateTests)

BOOST_AUTO_TEST_CASE(stExample)
{
	dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stSystemOperationsTest)
{
	dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stPreCompiledContracts)
{
	dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stLogTests)
{
	dev::test::executeTests("stLogTests", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stRecursiveCreate)
{
	dev::test::executeTests("stRecursiveCreate", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stInitCodeTest)
{
	dev::test::executeTests("stInitCodeTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stTransactionTest)
{
	dev::test::executeTests("stTransactionTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stSpecialTest)
{
	dev::test::executeTests("stSpecialTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stRefundTest)
{
	dev::test::executeTests("stRefundTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stBlockHashTest)
{
	dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stQuadraticComplexityTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--quadratic" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stQuadraticComplexityTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stMemoryStressTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--memory" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stMemoryStressTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stSolidityTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--quadratic" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stQuadraticComplexityTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stMemoryTest)
{
	   dev::test::executeTests("stMemoryTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stMemoryStressTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--memory" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stMemoryStressTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stCreateTest)
{
	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	{
		string arg = boost::unit_test::framework::master_test_suite().argv[i];
		if (arg == "--createtest")
		{
			if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
			{
				cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
				return;
			}
			try
			{
				cnote << "Populating tests...";
				json_spirit::mValue v;
				string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
				json_spirit::read_string(s, v);
				dev::test::doStateTests(v, true);
				writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
			}
			catch (Exception const& _e)
			{
				BOOST_ERROR("Failed state test with Exception: " << diagnostic_information(_e));
			}
			catch (std::exception const& _e)
			{
				BOOST_ERROR("Failed state test with Exception: " << _e.what());
			}
		}
	}
}

BOOST_AUTO_TEST_CASE(userDefinedFileState)
{
	dev::test::userDefinedTest("--statetest", dev::test::doStateTests);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>state rebase.<commit_after>/*
	This file is part of cpp-ethereum.

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

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file state.cpp
 * @author Christoph Jentzsch <cj@ethdev.com>
 * @date 2014
 * State test functions.
 */

#include <boost/filesystem/operations.hpp>
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/State.h>
#include <libethereum/ExtVM.h>
#include <libethereum/Defaults.h>
#include <libevm/VM.h>
#include "TestHelper.h"

using namespace std;
using namespace json_spirit;
using namespace dev;
using namespace dev::eth;

namespace dev {  namespace test {

void doStateTests(json_spirit::mValue& v, bool _fillin)
{
	processCommandLineOptions();

	for (auto& i: v.get_obj())
	{
		cerr << i.first << endl;
		mObject& o = i.second.get_obj();

		BOOST_REQUIRE(o.count("env") > 0);
		BOOST_REQUIRE(o.count("pre") > 0);
		BOOST_REQUIRE(o.count("transaction") > 0);

		ImportTest importer(o, _fillin);

		State theState = importer.m_statePre;
		bytes tx = importer.m_transaction.rlp();
		bytes output;

		try
		{
			theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output);
		}
		catch (Exception const& _e)
		{
			cnote << "state execution did throw an exception: " << diagnostic_information(_e);
		}
		catch (std::exception const& _e)
		{
			cnote << "state execution did throw an exception: " << _e.what();
		}

		if (_fillin)
		{
#if ETH_FATDB
			importer.exportTest(output, theState);
#else
			BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off"));
#endif
		}
		else
		{
			BOOST_REQUIRE(o.count("post") > 0);
			BOOST_REQUIRE(o.count("out") > 0);

			// check output
			checkOutput(output, o);

			// check logs
			checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs);

			// check addresses
#if ETH_FATDB
			auto expectedAddrs = importer.m_statePost.addresses();
			auto resultAddrs = theState.addresses();
			for (auto& expectedPair : expectedAddrs)
			{
				auto& expectedAddr = expectedPair.first;
				auto resultAddrIt = resultAddrs.find(expectedAddr);
				if (resultAddrIt == resultAddrs.end())
					BOOST_ERROR("Missing expected address " << expectedAddr);
				else
				{
					BOOST_CHECK_MESSAGE(importer.m_statePost.balance(expectedAddr) ==  theState.balance(expectedAddr), expectedAddr << ": incorrect balance " << theState.balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr));
					BOOST_CHECK_MESSAGE(importer.m_statePost.transactionsFrom(expectedAddr) ==  theState.transactionsFrom(expectedAddr), expectedAddr << ": incorrect txCount " << theState.transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr));
					BOOST_CHECK_MESSAGE(importer.m_statePost.code(expectedAddr) == theState.code(expectedAddr), expectedAddr << ": incorrect code");

					checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr);
				}
			}
			checkAddresses<map<Address, u256> >(expectedAddrs, resultAddrs);
#endif
			BOOST_CHECK_MESSAGE(theState.rootHash() == h256(o["postStateRoot"].get_str()), "wrong post state root");
		}
	}
}
} }// Namespace Close

BOOST_AUTO_TEST_SUITE(StateTests)

BOOST_AUTO_TEST_CASE(stExample)
{
	dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stSystemOperationsTest)
{
	dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stPreCompiledContracts)
{
	dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stLogTests)
{
	dev::test::executeTests("stLogTests", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stRecursiveCreate)
{
	dev::test::executeTests("stRecursiveCreate", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stInitCodeTest)
{
	dev::test::executeTests("stInitCodeTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stTransactionTest)
{
	dev::test::executeTests("stTransactionTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stSpecialTest)
{
	dev::test::executeTests("stSpecialTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stRefundTest)
{
	dev::test::executeTests("stRefundTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stBlockHashTest)
{
	dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stQuadraticComplexityTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--quadratic" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stQuadraticComplexityTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stMemoryStressTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--memory" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stMemoryStressTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stSolidityTest)
{
	   for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	   {
			   string arg = boost::unit_test::framework::master_test_suite().argv[i];
			   if (arg == "--quadratic" || arg == "--all")
			   {
					   auto start = chrono::steady_clock::now();

					   dev::test::executeTests("stQuadraticComplexityTest", "/StateTests", dev::test::doStateTests);

					   auto end = chrono::steady_clock::now();
					   auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
					   cnote << "test duration: " << duration.count() << " milliseconds.\n";
			   }
	   }
}

BOOST_AUTO_TEST_CASE(stMemoryTest)
{
	   dev::test::executeTests("stMemoryTest", "/StateTests", dev::test::doStateTests);
}

BOOST_AUTO_TEST_CASE(stCreateTest)
{
	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	{
		string arg = boost::unit_test::framework::master_test_suite().argv[i];
		if (arg == "--createtest")
		{
			if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
			{
				cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
				return;
			}
			try
			{
				cnote << "Populating tests...";
				json_spirit::mValue v;
				string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
				json_spirit::read_string(s, v);
				dev::test::doStateTests(v, true);
				writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
			}
			catch (Exception const& _e)
			{
				BOOST_ERROR("Failed state test with Exception: " << diagnostic_information(_e));
			}
			catch (std::exception const& _e)
			{
				BOOST_ERROR("Failed state test with Exception: " << _e.what());
			}
		}
	}
}

BOOST_AUTO_TEST_CASE(userDefinedFileState)
{
	dev::test::userDefinedTest("--statetest", dev::test::doStateTests);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>