<commit_before>/* -*- Mode: c++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim:set softtabstop=2 shiftwidth=2 tabstop=2 expandtab: */
/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Dirk Holz, University of Bonn.
 *  All rights reserved.
 *  The code is based on early pcl example code.
 *
 *  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.
 *
 *  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.
 */

#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <boost/thread/mutex.hpp>
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
#include <pcl_conversions/pcl_conversions.h>
typedef pcl::PCLPointCloud2 PointCloud2;
#else
typedef sensor_msgs::PointCloud2 PointCloud2;
#endif

typedef pcl::PointXYZ Point;
typedef pcl::visualization::PointCloudColorHandler<PointCloud2> ColorHandler;
typedef ColorHandler::Ptr ColorHandlerPtr;
typedef ColorHandler::ConstPtr ColorHandlerConstPtr;

typedef PointCloud2::Ptr PointCloudPtr;
typedef PointCloud2::ConstPtr PointCloudConstPtr;
PointCloudConstPtr cloud_, cloud_old_;
boost::mutex m;

bool paused = false;
bool record_continuously = false;
bool record_single = false;
std::string topic_name = "";

bool record_fixed_number = false;
int rec_max_frames = 100;
int rec_nr_frames = 0;

void cloud_cb (const PointCloudConstPtr& cloud)
{
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
  float stamp = static_cast<float>(cloud->header.stamp); // TODO: check!
#else
  float stamp = cloud->header.stamp.toSec ();
#endif
  ROS_INFO ("PointCloud with %d data points (%s), stamp %f, and frame %s.",
            cloud->width * cloud->height,
            pcl::getFieldsList (*cloud).c_str (),
            stamp,
            cloud->header.frame_id.c_str ());
  m.lock ();

  cloud_ = cloud;

  if(record_continuously || record_single)
  {
    boost::posix_time::time_facet *facet = new boost::posix_time::time_facet("%Y_%m_%d_%H_%M_%s");
    std::basic_stringstream<char> ss;
    ss.imbue(std::locale(std::cout.getloc(), facet));
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
    ss << boost::posix_time::from_time_t(cloud->header.stamp); // TODO: check
#else
    ss << cloud->header.stamp.toBoost();
#endif
    std::string formatted_stamp = ss.str();
    replace(formatted_stamp.begin(), formatted_stamp.end(), '.', '_');

    std::string filename = str(boost::format("%s_%s.pcd")
                               % topic_name
                               % formatted_stamp);
    replace(filename.begin(), filename.end(), '/', '_');

    try
    {
      pcl::io::savePCDFile(filename.c_str(),
                           *cloud,
                           Eigen::Vector4f::Zero(),
                           Eigen::Quaternionf::Identity(),
                           true);
      if (record_single)
        pcl::console::print_info("Stored file %s.\n", filename.c_str());
      record_single = false;
    }
    catch (pcl::IOException& e)
    {
      std::cerr << e.what() << std::endl;
      return;
    }

    if (record_fixed_number)
      if (++rec_nr_frames >= rec_max_frames)
        record_continuously = false;
  }

  m.unlock ();
}

void keyboardEventOccurred (const pcl::visualization::KeyboardEvent &event,
                            void* viewer_void)
{
  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer = *static_cast<boost::shared_ptr<pcl::visualization::PCLVisualizer> *> (viewer_void);
  if (event.keyDown())
  {
    switch (event.getKeyCode())
    {
      case ' ':    // space: grab a single frame
        record_single = true;
        break;

      case 'p':   // paused
        paused = !paused;
        break;

      case 'R':
        record_fixed_number = false;
        record_continuously = !record_continuously;
        if (record_continuously)
          std::cerr << "STARTED recording." << std::endl;
        else
          std::cerr << "STOPPED recording." << std::endl;
        break;

      case 'L':
        record_fixed_number = true;
        record_continuously = !record_continuously;
        if (record_continuously)
        {
          std::cerr << "STARTED recording." << std::endl;
          rec_nr_frames = 0;
        }
        else
          std::cerr << "STOPPED recording." << std::endl;
        break;
    }
  }
}

int main (int argc, char** argv)
{
  ros::init (argc, argv, "pcl_online_viewer");
  ros::NodeHandle nh;

  int queue_size = 1;
  pcl::console::parse_argument (argc, argv, "-qsize", queue_size);

  ros::Subscriber sub = nh.subscribe ("input", queue_size, cloud_cb);
  topic_name = ros::names::remap("input").c_str();
  pcl::console::print_highlight("Subscribing to %s using a queue size of %d\n", topic_name.c_str(), queue_size);

  pcl::visualization::PCLVisualizer p (argc, argv, "Online PointCloud2 Viewer");
  pcl::PointCloud<Point>::Ptr cloud_xyz(new pcl::PointCloud<Point>);
  ColorHandlerPtr color_handler;

  p.registerKeyboardCallback(keyboardEventOccurred, (void*)&p);

  int color_handler_idx = 0;
  double psize = 0;
  while (nh.ok ())
  {
    ros::spinOnce ();
    ros::Duration (0.001).sleep ();
    p.spinOnce (10);

    if (!cloud_)
      continue;

    if (cloud_ == cloud_old_)
      continue;

    color_handler_idx = p.getColorHandlerIndex ("cloud");
    p.getPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, psize, "cloud");
    p.removePointCloud ("cloud");
    m.lock ();
    {
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
      pcl::fromPCLPointCloud2 (*cloud_, *cloud_xyz);
#else
      pcl::fromROSMsg (*cloud_, *cloud_xyz);
#endif
      color_handler.reset (new pcl::visualization::PointCloudColorHandlerCustom<PointCloud2> (cloud_, 255.0, 1.0, 1.0));
      p.addPointCloud<Point>(cloud_xyz, color_handler, "cloud");
      for (size_t i = 0; i < cloud_->fields.size (); ++i)
      {
        if (cloud_->fields[i].name == "rgb" || cloud_->fields[i].name == "rgba")
          color_handler.reset (new pcl::visualization::PointCloudColorHandlerRGBField<PointCloud2> (cloud_));
        else
          color_handler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<PointCloud2> (cloud_, cloud_->fields[i].name));
        p.addPointCloud<Point>(cloud_xyz, color_handler, "cloud");
      }
      p.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, psize, "cloud");
      if (color_handler_idx != -1)
        p.updateColorHandlerIndex ("cloud", color_handler_idx);
      cloud_old_ = cloud_;
    }
    m.unlock ();
  }

  return (0);
}
<commit_msg>changed keyboard shortcut for continuous recording (-> 'K'), temp: showing min and max measurement distance<commit_after>/* -*- Mode: c++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim:set softtabstop=2 shiftwidth=2 tabstop=2 expandtab: */
/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Dirk Holz, University of Bonn.
 *  All rights reserved.
 *  The code is based on early pcl example code.
 *
 *  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.
 *
 *  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.
 */

#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <boost/thread/mutex.hpp>
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
#include <pcl_conversions/pcl_conversions.h>
typedef pcl::PCLPointCloud2 PointCloud2;
#else
typedef sensor_msgs::PointCloud2 PointCloud2;
#endif

typedef pcl::PointXYZ Point;
typedef pcl::visualization::PointCloudColorHandler<PointCloud2> ColorHandler;
typedef ColorHandler::Ptr ColorHandlerPtr;
typedef ColorHandler::ConstPtr ColorHandlerConstPtr;

typedef PointCloud2::Ptr PointCloudPtr;
typedef PointCloud2::ConstPtr PointCloudConstPtr;
PointCloudConstPtr cloud_, cloud_old_;
boost::mutex m;

bool paused = false;
bool record_continuously = false;
bool record_single = false;
std::string topic_name = "";

bool record_fixed_number = false;
int rec_max_frames = 100;
int rec_nr_frames = 0;

void cloud_cb (const PointCloudConstPtr& cloud)
{
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
  float stamp = static_cast<float>(cloud->header.stamp); // TODO: check!
#else
  float stamp = cloud->header.stamp.toSec ();
#endif
  ROS_INFO ("PointCloud with %d data points (%s), stamp %f, and frame %s.",
            cloud->width * cloud->height,
            pcl::getFieldsList (*cloud).c_str (),
            stamp,
            cloud->header.frame_id.c_str ());
  m.lock ();

  cloud_ = cloud;

  if(record_continuously || record_single)
  {
    boost::posix_time::time_facet *facet = new boost::posix_time::time_facet("%Y_%m_%d_%H_%M_%s");
    std::basic_stringstream<char> ss;
    ss.imbue(std::locale(std::cout.getloc(), facet));
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
    ss << boost::posix_time::from_time_t(cloud->header.stamp); // TODO: check
#else
    ss << cloud->header.stamp.toBoost();
#endif
    std::string formatted_stamp = ss.str();
    replace(formatted_stamp.begin(), formatted_stamp.end(), '.', '_');

    std::string filename = str(boost::format("%s_%s.pcd")
                               % topic_name
                               % formatted_stamp);
    replace(filename.begin(), filename.end(), '/', '_');

    try
    {
      pcl::io::savePCDFile(filename.c_str(),
                           *cloud,
                           Eigen::Vector4f::Zero(),
                           Eigen::Quaternionf::Identity(),
                           true);
      if (record_single)
        pcl::console::print_info("Stored file %s.\n", filename.c_str());
      record_single = false;
    }
    catch (pcl::IOException& e)
    {
      std::cerr << e.what() << std::endl;
      return;
    }

    if (record_fixed_number)
      if (++rec_nr_frames >= rec_max_frames)
        record_continuously = false;
  }

  m.unlock ();
}

void keyboardEventOccurred (const pcl::visualization::KeyboardEvent &event,
                            void* viewer_void)
{
  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer = *static_cast<boost::shared_ptr<pcl::visualization::PCLVisualizer> *> (viewer_void);
  if (event.keyDown())
  {
    switch (event.getKeyCode())
    {
      case ' ':    // space: grab a single frame
        record_single = true;
        break;

      case 'p':   // paused
        paused = !paused;
        break;

      case 'K':
        record_fixed_number = false;
        record_continuously = !record_continuously;
        if (record_continuously)
          std::cerr << "STARTED recording." << std::endl;
        else
          std::cerr << "STOPPED recording." << std::endl;
        break;

      case 'L':
        record_fixed_number = true;
        record_continuously = !record_continuously;
        if (record_continuously)
        {
          std::cerr << "STARTED recording." << std::endl;
          rec_nr_frames = 0;
        }
        else
          std::cerr << "STOPPED recording." << std::endl;
        break;
    }
  }
}

int main (int argc, char** argv)
{
  ros::init (argc, argv, "pcl_online_viewer");
  ros::NodeHandle nh;

  int queue_size = 1;
  pcl::console::parse_argument (argc, argv, "-qsize", queue_size);

  ros::Subscriber sub = nh.subscribe ("input", queue_size, cloud_cb);
  topic_name = ros::names::remap("input").c_str();
  pcl::console::print_highlight("Subscribing to %s using a queue size of %d\n", topic_name.c_str(), queue_size);

  pcl::visualization::PCLVisualizer p (argc, argv, "Online PointCloud2 Viewer");
  pcl::PointCloud<Point>::Ptr cloud_xyz(new pcl::PointCloud<Point>);
  ColorHandlerPtr color_handler;

  p.registerKeyboardCallback(keyboardEventOccurred, (void*)&p);

  int color_handler_idx = 0;
  double psize = 0;
  while (nh.ok ())
  {
    ros::spinOnce ();
    ros::Duration (0.001).sleep ();
    p.spinOnce (10);

    if (!cloud_)
      continue;

    if (cloud_ == cloud_old_)
      continue;

    color_handler_idx = p.getColorHandlerIndex ("cloud");
    p.getPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, psize, "cloud");
    p.removePointCloud ("cloud");
    m.lock ();
    {
#if (defined PCL_MINOR_VERSION && (PCL_MINOR_VERSION >= 7))
      pcl::fromPCLPointCloud2 (*cloud_, *cloud_xyz);
#else
      pcl::fromROSMsg (*cloud_, *cloud_xyz);
#endif
      color_handler.reset (new pcl::visualization::PointCloudColorHandlerCustom<PointCloud2> (cloud_, 255.0, 1.0, 1.0));
      p.addPointCloud<Point>(cloud_xyz, color_handler, "cloud");
      for (size_t i = 0; i < cloud_->fields.size (); ++i)
      {
        if (cloud_->fields[i].name == "rgb" || cloud_->fields[i].name == "rgba")
          color_handler.reset (new pcl::visualization::PointCloudColorHandlerRGBField<PointCloud2> (cloud_));
        else
          color_handler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<PointCloud2> (cloud_, cloud_->fields[i].name));
        p.addPointCloud<Point>(cloud_xyz, color_handler, "cloud");
      }
      p.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, psize, "cloud");
      if (color_handler_idx != -1)
        p.updateColorHandlerIndex ("cloud", color_handler_idx);
      cloud_old_ = cloud_;

      float min_z = std::numeric_limits<float>::max();
      float max_z = std::numeric_limits<float>::min();
      for(pcl::PointCloud<Point>::iterator iter = cloud_xyz->begin(); iter != cloud_xyz->end(); ++iter)
      {
        min_z = std::min(min_z, iter->z);
        max_z = std::max(max_z, iter->z);
      }
      printf("Measurement range: %0.2fcm - %0.2fcm\n", min_z*100.0f, max_z*100.0f);
    }
    m.unlock ();
  }

  return (0);
}
<|endoftext|>


<commit_before>/*****************************************************************************\
 * Copyright 2005, 2006 Niels Lohmann, Christian Gierds, Dennis Reinert      *
 *                                                                           *
 * This file is part of BPEL2oWFN.                                           *
 *                                                                           *
 * BPEL2oWFN is free software; you can redistribute it and/or modify it      *
 * under the terms of the GNU General Public License as published by the     *
 * Free Software Foundation; either version 2 of the License, or(at your    *
 * option) any later version.                                                *
 *                                                                           *
 * BPEL2oWFN 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 BPEL2oWFN; if not, write to the Free Software Foundation, Inc., 51   *
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.                      *
\*****************************************************************************/

/*!
 * \file petrinet-reduction.cc
 *
 * \brief Reduction rules for Petri nets (implementation)
 *
 * This file implements the classes and functions defined in petrinet.h.
 *
 *  - PetriNet::removeInterface()
 *  - PetriNet::simplify()
 *  - PetriNet::removeIsolatedNodes()
 *  - PetriNet::removeVariables()
 *
 * \author
 *          - responsible: Niels Lohmann <nlohmann@informatik.hu-berlin.de>
 *          - last changes of: \$Author: gierds $
 *
 * \date
 *          - created: 2006-03-16
 *          - last changed: \$Date: 2006/04/12 16:21:33 $
 *
 * \note    This file is part of the tool BPEL2oWFN and was created during the
 *          project "Tools4BPEL" at the Humboldt-Universitt zu Berlin. See
 *          http://www.informatik.hu-berlin.de/top/tools4bpel for details.
 *
 * \version \$Revision: 1.11 $
 */

#include <list>
#include "petrinet.h"
#include "debug.h"		// debugging help
#include "symbol-table.h"
#include "helpers.h"

/******************************************************************************
 * Functions to remove several aspects of the Petri net model
 *****************************************************************************/

/*!
 * Collect all input and output places and remove (i.e. detach) them. Formally
 * the inner of the generated open workflow is builded.
 */
void PetriNet::removeInterface()
{
  trace(TRACE_DEBUG, "[PN]\tRemoving interface places.\n");

  list<Place *> killList;

  for (set<Place *>::iterator p = P_in.begin(); p != P_in.end(); p++)
    killList.push_back(*p);

  for (set<Place *>::iterator p = P_out.begin(); p != P_out.end(); p++)
    killList.push_back(*p);

  for (list<Place *>::iterator it = killList.begin(); it != killList.end(); it++)
    removePlace(*it);

  hasNoInterface = true;
}

/*!
 * Remove the places modelling variables.
 */
void PetriNet::removeVariables()
{
  extern SymbolTable symTab;

  for (list<string>::iterator variable = symTab.variables.begin();
      variable != symTab.variables.end(); variable++)
  {
    removePlace( findPlace("variable." + *variable) );
  }

  removePlace( findPlace("1.internal.clock") );
}

/******************************************************************************
 * Functions to structurally simplify the Petri net model
 *****************************************************************************/

/*!
 * Remove structural dead nodes.
 */
void PetriNet::removeDeadNodes()
{
  bool done = false;
  while (!done)
  {
    done = true;

    list<Place*> deadPlaces;
    list<Transition*> deadTransitions;
    list<Place*> tempPlaces;

    // find unmarked places with empty preset
    for (set<Place*>::iterator p = P.begin(); p != P.end(); p++)
    {
      if (preset(*p).empty() && !(*p)->marked)
      {
	deadPlaces.push_back(*p);
	tempPlaces.push_back(*p);
	trace(TRACE_VERY_DEBUG, "[PN]\tPlace p" + intToString((*p)->id) + " is structurally dead.\n");
	done = false;
      }
    }

    while (!tempPlaces.empty())
    {
      // p is a dead place
      Place* p = tempPlaces.back();
      tempPlaces.pop_back();
      set<Node*> ps = postset(p);

      // transitions in the postset of a dead place are dead
      for (set<Node*>::iterator t = ps.begin(); t != ps.end(); t++)
      {
      	deadTransitions.push_back( (Transition*)(*t) );
	trace(TRACE_VERY_DEBUG, "[PN]\tTransition t" + intToString((*t)->id) + " is structurally dead\n");
	done = false;
      }
    }

    // remove dead places and transitions
    for (list<Place*>::iterator p = deadPlaces.begin(); p != deadPlaces.end(); p++)
      if (P.find(*p) != P.end())
	removePlace(*p);
    for (list<Transition*>::iterator t = deadTransitions.begin(); t != deadTransitions.end(); t++)
      if (T. find(*t) != T.end())
	removeTransition(*t);
  }
}

/*!
 * Merges twin transitions.
 */
void PetriNet::mergeTwinTransitions()
{
  // a pair to store transitions to be merged
  vector<pair<string, string> > transitionPairs;

  trace(TRACE_VERY_DEBUG, "[PN]\tSearching for transitions with same preset and postset...\n");
  // find transitions with same preset and postset
  for (set<Transition *>::iterator t1 = T.begin(); t1 != T.end(); t1++)
  {
    set<Node*> postSet = postset(*t1);
    set<Node*> preSet  = preset(*t1);

    for (set<Node *>:: iterator prePlace = preSet.begin(); prePlace != preSet.end(); prePlace++)
    {
      set<Node *> pPostSet = postset(*prePlace);
      for (set<Node *>::iterator t2 = pPostSet.begin(); t2 != pPostSet.end(); t2++)
	if (*t1 != *t2)
	  if ((preSet == preset(*t2)) && (postSet == postset(*t2)))
	    transitionPairs.push_back(pair<string, string>(*((*t1)->history.begin()), *((*t2)->history.begin())));
    }

  }

  trace(TRACE_VERY_DEBUG, "[PN]\tFound " + intToString(transitionPairs.size()) + " transitions with same preset and postset...\n");

  // merge the found transitions
  for (unsigned int i = 0; i < transitionPairs.size(); i++)
  {
    Transition *t1 = findTransition(transitionPairs[i].first);
    Transition *t2 = findTransition(transitionPairs[i].second);

    if ((t1 != NULL) && (t2 != NULL) && (t1 != t2))
      mergeTransitions(t1, t2);
  }
}

/*!
 * Returns true if there is a communicating transition in the postset of the
 * given place p.
 *
 * \param  p a place to check
 * \return true, if a communicating transition was found
 */
bool PetriNet::communicationInPostSet(Place *p)
{
  set<Node*> pp = postset(p);
  for (set<Node*>::iterator t = pp.begin();
      t != pp.end();
      t++)
  {
    if (((Transition*)(*t))->communicating)
      return true;
  }

  return false;
}

/*!
 * Collapse simple sequences.
 *
 * A simple sequence is a transition with
 *  - singleton preset
 *  - singleton postset
 *  - no communicating transition following
 *  - preset != postset
 */
void PetriNet::collapseSequences()
{
  trace(TRACE_VERY_DEBUG, "[PN]\tCollapsing simple sequences\n");

  // a pair to store places to be merged
  vector<string> sequenceTransitions;
  vector<pair<string, string> >placeMerge;

  // find transitions with singelton preset and postset
  for (set<Transition *>::iterator t = T.begin(); t != T.end(); t++)
  {
    if (
	(preset(*t).size() == 1) &&
	(postset(*t).size() == 1) &&
	!communicationInPostSet((Place*)*(postset(*t).begin())) &&
	(*(postset(*t).begin()) != (*preset(*t).begin()))
       )
    {
      string id1 = *((*(preset(*t).begin()))->history.begin());
      string id2 = *((*(postset(*t).begin()))->history.begin());
      placeMerge.push_back(pair < string, string >(id1, id2));
      sequenceTransitions.push_back(*((*t)->history.begin()));
    }
  }

  // merge preset and postset
  for (unsigned int i = 0; i < placeMerge.size(); i++)
    mergePlaces(placeMerge[i].first, placeMerge[i].second);

  // remove "sequence"-transtions
  for (unsigned int i = 0; i < sequenceTransitions.size(); i++)
  {
    Transition *sequenceTransition = findTransition(sequenceTransitions[i]);
    if (sequenceTransition != NULL)
      removeTransition(sequenceTransition);
  }
}

/*!
 * Implements some simple structural reduction rules for Petri nets:
 *
 * - Structural dead nodes are removed.
 * - If two transitions t1 and t2 have the same preset and postset, one of them
 *   can safely be removed.
 * - If a transition has a singleton preset and postset, the transition can be
 *   removed(sequence) and the preset and postset can be merged.
 *
 * \todo
 *       -(nlohmann) improve performance
 *       -(nlohmann) implement more reduction rules
 *
 */
void PetriNet::simplify()
{
  trace(TRACE_DEBUG, "[PN]\tPetri net size before simplification: " + information() + "\n");
  trace(TRACE_INFORMATION, "Simplifying Petri net...\n");

  string old = information();
  bool done = false;
  int passes = 1;
  while (!done)
  {
    removeDeadNodes();
    mergeTwinTransitions();
    // collapseSequences();

    trace(TRACE_DEBUG, "[PN]\tPetri net size after simplification pass " + intToString(passes++) + ": " + information() + "\n");

    done = (old == information());
    old = information();
  }

  trace(TRACE_INFORMATION, "Simplifying complete.\n");
  trace(TRACE_DEBUG, "[PN]\tPetri net size after simplification: " + information() + "\n");
}
<commit_msg>* real marcoplace rule<commit_after>/*****************************************************************************\
 * Copyright 2005, 2006 Niels Lohmann, Christian Gierds, Dennis Reinert      *
 *                                                                           *
 * This file is part of BPEL2oWFN.                                           *
 *                                                                           *
 * BPEL2oWFN is free software; you can redistribute it and/or modify it      *
 * under the terms of the GNU General Public License as published by the     *
 * Free Software Foundation; either version 2 of the License, or(at your    *
 * option) any later version.                                                *
 *                                                                           *
 * BPEL2oWFN 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 BPEL2oWFN; if not, write to the Free Software Foundation, Inc., 51   *
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.                      *
\*****************************************************************************/

/*!
 * \file petrinet-reduction.cc
 *
 * \brief Reduction rules for Petri nets (implementation)
 *
 * This file implements the classes and functions defined in petrinet.h.
 *
 *  - PetriNet::removeInterface()
 *  - PetriNet::simplify()
 *  - PetriNet::removeIsolatedNodes()
 *  - PetriNet::removeVariables()
 *
 * \author
 *          - responsible: Niels Lohmann <nlohmann@informatik.hu-berlin.de>
 *          - last changes of: \$Author: gierds $
 *
 * \date
 *          - created: 2006-03-16
 *          - last changed: \$Date: 2006/04/25 11:56:55 $
 *
 * \note    This file is part of the tool BPEL2oWFN and was created during the
 *          project "Tools4BPEL" at the Humboldt-Universitt zu Berlin. See
 *          http://www.informatik.hu-berlin.de/top/tools4bpel for details.
 *
 * \version \$Revision: 1.12 $
 */

#include <list>
#include "petrinet.h"
#include "debug.h"		// debugging help
#include "symbol-table.h"
#include "helpers.h"

/******************************************************************************
 * Functions to remove several aspects of the Petri net model
 *****************************************************************************/

/*!
 * Collect all input and output places and remove (i.e. detach) them. Formally
 * the inner of the generated open workflow is builded.
 */
void PetriNet::removeInterface()
{
  trace(TRACE_DEBUG, "[PN]\tRemoving interface places.\n");

  list<Place *> killList;

  for (set<Place *>::iterator p = P_in.begin(); p != P_in.end(); p++)
    killList.push_back(*p);

  for (set<Place *>::iterator p = P_out.begin(); p != P_out.end(); p++)
    killList.push_back(*p);

  for (list<Place *>::iterator it = killList.begin(); it != killList.end(); it++)
    removePlace(*it);

  hasNoInterface = true;
}

/*!
 * Remove the places modelling variables.
 */
void PetriNet::removeVariables()
{
  extern SymbolTable symTab;

  for (list<string>::iterator variable = symTab.variables.begin();
      variable != symTab.variables.end(); variable++)
  {
    removePlace( findPlace("variable." + *variable) );
  }

  removePlace( findPlace("1.internal.clock") );
}

/******************************************************************************
 * Functions to structurally simplify the Petri net model
 *****************************************************************************/

/*!
 * Remove structural dead nodes.
 */
void PetriNet::removeDeadNodes()
{
  bool done = false;
  while (!done)
  {
    done = true;

    list<Place*> deadPlaces;
    list<Transition*> deadTransitions;
    list<Place*> tempPlaces;

    // find unmarked places with empty preset
    for (set<Place*>::iterator p = P.begin(); p != P.end(); p++)
    {
      if (preset(*p).empty() && !(*p)->marked)
      {
	deadPlaces.push_back(*p);
	tempPlaces.push_back(*p);
	trace(TRACE_VERY_DEBUG, "[PN]\tPlace p" + intToString((*p)->id) + " is structurally dead.\n");
	done = false;
      }
    }

    while (!tempPlaces.empty())
    {
      // p is a dead place
      Place* p = tempPlaces.back();
      tempPlaces.pop_back();
      set<Node*> ps = postset(p);

      // transitions in the postset of a dead place are dead
      for (set<Node*>::iterator t = ps.begin(); t != ps.end(); t++)
      {
      	deadTransitions.push_back( (Transition*)(*t) );
	trace(TRACE_VERY_DEBUG, "[PN]\tTransition t" + intToString((*t)->id) + " is structurally dead\n");
	done = false;
      }
    }

    // remove dead places and transitions
    for (list<Place*>::iterator p = deadPlaces.begin(); p != deadPlaces.end(); p++)
      if (P.find(*p) != P.end())
	removePlace(*p);
    for (list<Transition*>::iterator t = deadTransitions.begin(); t != deadTransitions.end(); t++)
      if (T. find(*t) != T.end())
	removeTransition(*t);
  }
}

/*!
 * Merges twin transitions.
 */
void PetriNet::mergeTwinTransitions()
{
  // a pair to store transitions to be merged
  vector<pair<string, string> > transitionPairs;

  trace(TRACE_VERY_DEBUG, "[PN]\tSearching for transitions with same preset and postset...\n");
  // find transitions with same preset and postset
  for (set<Transition *>::iterator t1 = T.begin(); t1 != T.end(); t1++)
  {
    set<Node*> postSet = postset(*t1);
    set<Node*> preSet  = preset(*t1);

    for (set<Node *>:: iterator prePlace = preSet.begin(); prePlace != preSet.end(); prePlace++)
    {
      set<Node *> pPostSet = postset(*prePlace);
      for (set<Node *>::iterator t2 = pPostSet.begin(); t2 != pPostSet.end(); t2++)
	if (*t1 != *t2)
	  if ((preSet == preset(*t2)) && (postSet == postset(*t2)))
	    transitionPairs.push_back(pair<string, string>(*((*t1)->history.begin()), *((*t2)->history.begin())));
    }

  }

  trace(TRACE_VERY_DEBUG, "[PN]\tFound " + intToString(transitionPairs.size()) + " transitions with same preset and postset...\n");

  // merge the found transitions
  for (unsigned int i = 0; i < transitionPairs.size(); i++)
  {
    Transition *t1 = findTransition(transitionPairs[i].first);
    Transition *t2 = findTransition(transitionPairs[i].second);

    if ((t1 != NULL) && (t2 != NULL) && (t1 != t2))
      mergeTransitions(t1, t2);
  }
}

/*!
 * Returns true if there is a communicating transition in the postset of the
 * given place p.
 *
 * \param  p a place to check
 * \return true, if a communicating transition was found
 */
bool PetriNet::communicationInPostSet(Place *p)
{
  set<Node*> pp = postset(p);
  for (set<Node*>::iterator t = pp.begin();
      t != pp.end();
      t++)
  {
    if (((Transition*)(*t))->communicating)
      return true;
  }

  return false;
}

/*!
 * Collapse simple sequences.
 *
 * A simple sequence is a transition with
 *  - singleton preset
 *  - singleton postset
 *  - no communicating transition following
 *  - preset != postset
 */
void PetriNet::collapseSequences()
{
  trace(TRACE_VERY_DEBUG, "[PN]\tCollapsing simple sequences\n");

  // a pair to store places to be merged
  list<string> sequenceTransitions;
  list<pair<string, string> >placeMerge;

  // find transitions with singelton preset and postset
  for (set<Transition *>::iterator t = T.begin(); t != T.end(); t++)
  {
    set<Node *> postSet = postset(*t);
    set<Node *> preSet  = preset (*t);
    Place * prePlace = (Place*) *(preSet.begin());
    Place * postPlace = (Place*) *(postSet.begin());
    if (
	(preSet.size() == 1) &&
	(postSet.size() == 1) &&
//	!communicationInPostSet((Place*)*(postSet.begin())) &&
	(prePlace != postPlace) &&
	(postset(prePlace).size() == 1)
       )
    {
      string id1 = *((*(preSet.begin()))->history.begin());
      string id2 = *((*(postSet.begin()))->history.begin());
      placeMerge.push_back(pair < string, string >(id1, id2));
      sequenceTransitions.push_back(*((*t)->history.begin()));
    }
  }

  // remove "sequence"-transtions
  for (list< string >::iterator i = sequenceTransitions.begin(); i != sequenceTransitions.end(); i++)
  {
    Transition *sequenceTransition = findTransition(*i);
    if (sequenceTransition != NULL)
      removeTransition(sequenceTransition);
  }

  // merge preset and postset
  for (list< pair<string, string> >::iterator i = placeMerge.begin(); i != placeMerge.end(); i++)
    mergePlaces(i->first, i->second);

}

/*!
 * Implements some simple structural reduction rules for Petri nets:
 *
 * - Structural dead nodes are removed.
 * - If two transitions t1 and t2 have the same preset and postset, one of them
 *   can safely be removed.
 * - If a transition has a singleton preset and postset, the transition can be
 *   removed(sequence) and the preset and postset can be merged.
 *
 * \todo
 *       -(nlohmann) improve performance
 *       -(nlohmann) implement more reduction rules
 *
 */
void PetriNet::simplify()
{
  trace(TRACE_DEBUG, "[PN]\tPetri net size before simplification: " + information() + "\n");
  trace(TRACE_INFORMATION, "Simplifying Petri net...\n");

  string old = information();
  bool done = false;
  int passes = 1;
  while (!done)
  {
    removeDeadNodes();
    mergeTwinTransitions();
    collapseSequences();

    trace(TRACE_DEBUG, "[PN]\tPetri net size after simplification pass " + intToString(passes++) + ": " + information() + "\n");

    done = (old == information());
    old = information();
  }

  trace(TRACE_INFORMATION, "Simplifying complete.\n");
  trace(TRACE_DEBUG, "[PN]\tPetri net size after simplification: " + information() + "\n");
}
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <assert.h>
#include "ast.h"

void test()
{
    extern void lex_test();
    extern void ast_test();
    lex_test();
    ast_test();
}

class expr {
public:
    virtual ~expr() {}
    virtual std::unique_ptr<expr> clone() const = 0;

    friend std::ostream& operator<<(std::ostream& os, const expr& e) {
        e.print(os);
        return os;
    }

protected:
    expr() {}

private:
    virtual void print(std::ostream& os) const = 0;
};

typedef std::unique_ptr<expr> expr_ptr;

class const_expr : public expr {
public:
    explicit const_expr(double value) : value_(value) {}
    virtual std::unique_ptr<expr> clone() const override { return std::unique_ptr<expr>{new const_expr{value_}}; }
    double value() const { return value_; }
private:
    double value_;
    virtual void print(std::ostream& os) const override {
        os << value_;
    }
};

class var_expr : public expr {
public:
    explicit var_expr(const std::string& name) : name_(name) {}
    std::string name() const { return name_; }
    virtual std::unique_ptr<expr> clone() const override { return std::unique_ptr<expr>{new var_expr{name_}}; }
private:
    std::string name_;
    virtual void print(std::ostream& os) const override {
        os << name_;
    }
};

class bin_op_expr : public expr {
public:
    bin_op_expr(expr_ptr lhs, expr_ptr rhs, char op) : lhs_(std::move(lhs)), rhs_(std::move(rhs)), op_(op) {}
    const expr& lhs() const { return *lhs_; }
    const expr& rhs() const { return *rhs_; }
    char op() const { return op_; }
    virtual std::unique_ptr<expr> clone() const override {
        return std::unique_ptr<expr>{new bin_op_expr{lhs().clone(), rhs().clone(), op_}};
    }
private:
    expr_ptr lhs_;
    expr_ptr rhs_;
    char op_;
    virtual void print(std::ostream& os) const override {
        os << "{" << op_ << " " << lhs() << " " << rhs() << "}";
    }
};

expr_ptr constant(double d) { return expr_ptr{new const_expr{d}}; }
expr_ptr var(const std::string& n) { return expr_ptr{new var_expr{n}}; }

expr_ptr operator+(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '+'}};
}

expr_ptr operator-(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '-'}};
}

expr_ptr operator*(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '*'}};
}

expr_ptr operator/(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '/'}};
}

std::ostream& operator<<(std::ostream& os, const expr_ptr& e) {
    os << *e;
    return os;
}

template<typename T>
const T* expr_cast(const expr_ptr& e) {
    return dynamic_cast<const T*>(e.get());
}

bool match_const(const expr_ptr& e, const double& v) {
    auto cp = expr_cast<const_expr>(e);
    return cp && cp->value() == v;
}

bool match_var(const expr_ptr& e, const std::string& v) {
    auto vp = expr_cast<var_expr>(e);
    return vp && vp->name() == v;
}

// Solve the equation "e" for variable "v"
expr_ptr solve(const expr_ptr& lhs, const expr_ptr& rhs, const std::string& v) {
    if (match_var(lhs, v)) {
        return rhs->clone();
    }
    if (match_var(rhs, v)) {
        return lhs->clone();
    }

    std::ostringstream oss;
    oss << "Unable to solve '" << lhs << "'='" << rhs << "' for '" << v << "'";
    throw std::runtime_error(oss.str());
}

void test_solve(const expr_ptr& lhs, const expr_ptr& rhs, const std::string& v, double value) {
    auto s = solve(lhs, rhs, v);
    if (match_const(s, value)) {
        return;
    }

    std::cout << "Wrong answer for '" << lhs << "'='" << rhs << "' for '" << v << "'\n";
    std::cout << "Expected: " << value << std::endl;
    std::cout << "Got: '" << s << "'" << std::endl;
}

int main()
{
    test();

    test_solve(var("x"), constant(8), "x", 8);
    test_solve(constant(42), var("x"), "x", 42);
//    std::cout << solve(constant(2) * var("x"), constant(8), "x") << std::endl;
}
<commit_msg>Basic solver<commit_after>#include <iostream>
#include <sstream>
#include <queue>
#include <assert.h>
#include "ast.h"

void test()
{
    extern void lex_test();
    extern void ast_test();
    lex_test();
    ast_test();
}

class expr {
public:
    virtual ~expr() {}
    virtual std::unique_ptr<expr> clone() const = 0;

    operator std::unique_ptr<expr>() const {
        return clone();
    }

    friend std::ostream& operator<<(std::ostream& os, const expr& e) {
        e.print(os);
        return os;
    }

protected:
    expr() {}

private:
    virtual void print(std::ostream& os) const = 0;
};

typedef std::unique_ptr<expr> expr_ptr;

class const_expr : public expr {
public:
    explicit const_expr(double value) : value_(value) {}
    virtual std::unique_ptr<expr> clone() const override { return std::unique_ptr<expr>{new const_expr{value_}}; }
    double value() const { return value_; }
private:
    double value_;
    virtual void print(std::ostream& os) const override {
        os << value_;
    }
};

class var_expr : public expr {
public:
    explicit var_expr(const std::string& name) : name_(name) {}
    std::string name() const { return name_; }
    virtual std::unique_ptr<expr> clone() const override { return std::unique_ptr<expr>{new var_expr{name_}}; }
private:
    std::string name_;
    virtual void print(std::ostream& os) const override {
        os << name_;
    }
};

class bin_op_expr : public expr {
public:
    bin_op_expr(expr_ptr lhs, expr_ptr rhs, char op) : lhs_(std::move(lhs)), rhs_(std::move(rhs)), op_(op) {}
    const expr& lhs() const { return *lhs_; }
    const expr& rhs() const { return *rhs_; }
    char op() const { return op_; }
    virtual std::unique_ptr<expr> clone() const override {
        return std::unique_ptr<expr>{new bin_op_expr{lhs().clone(), rhs().clone(), op_}};
    }
private:
    expr_ptr lhs_;
    expr_ptr rhs_;
    char op_;
    virtual void print(std::ostream& os) const override {
        os << "{" << op_ << " " << lhs() << " " << rhs() << "}";
    }
};

expr_ptr constant(double d) { return expr_ptr{new const_expr{d}}; }
expr_ptr var(const std::string& n) { return expr_ptr{new var_expr{n}}; }

expr_ptr operator+(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '+'}};
}

expr_ptr operator-(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '-'}};
}

expr_ptr operator*(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '*'}};
}

expr_ptr operator/(expr_ptr a, expr_ptr b) {
    return expr_ptr{new bin_op_expr{std::move(a), std::move(b), '/'}};
}

std::ostream& operator<<(std::ostream& os, const expr_ptr& e) {
    os << *e;
    return os;
}

template<typename T, typename E>
const T* expr_cast(const E& e) {
    return dynamic_cast<const T*>(&e);
}

bool match_const(const expr& e, const double& v) {
    auto cp = expr_cast<const_expr>(e);
    return cp && cp->value() == v;
}

bool extract_const(const expr& e, double& v) {
    if (auto cp = expr_cast<const_expr>(e)) {
        v = cp->value();
        return true;
    }
    v = 0;
    return false;
}

bool match_var(const expr& e, const std::string& v) {
    auto vp = expr_cast<var_expr>(e);
    return vp && vp->name() == v;
}

struct solver {
    explicit solver(const std::string& v) : v_(v) {}

    expr_ptr solve(const expr& lhs, const expr& rhs) {
        items_ = std::queue<item_type>{};
        push_job(lhs.clone(), rhs.clone());
        return do_solve_1();
    }

    // Solve the equation "e" for variable "v"
private:
    typedef std::pair<expr_ptr, expr_ptr> item_type;
    std::string v_;
    std::queue<item_type> items_;

    void push_job(expr_ptr lhs, expr_ptr rhs) {
        items_.push(make_pair(std::move(lhs), std::move(rhs)));
    }

    expr_ptr do_solve_1() {
        while (!items_.empty()) {
            auto& top = items_.front();
            if (auto e = do_solve(*top.first, *top.second)) {
                return e;
            }
            items_.pop();
        }
        assert(false);
        return nullptr;
    }

    expr_ptr do_solve(const expr& lhs, const expr& rhs) {
        double val;
        std::cout << ">>>solve lhs=" << lhs << " rhs=" << rhs << std::endl;
        if (match_var(lhs, v_) && extract_const(rhs, val)) {
            return constant(val);
        }
        if (match_var(rhs, v_) && extract_const(lhs, val)) {
            return constant(val);
        }
        if (auto bp = expr_cast<bin_op_expr>(lhs)) {
            return do_solve_bin_op(*bp, rhs);
        }
        if (auto bp = expr_cast<bin_op_expr>(rhs)) {
            return do_solve_bin_op(*bp, lhs);
        }
        assert(false);
        return nullptr;
    }

    expr_ptr do_solve_bin_op(const bin_op_expr& a, const expr& b) {
        double ac, bc;
        if (extract_const(a.lhs(), ac) && extract_const(a.rhs(), bc)) {
            switch (a.op()) {
                case '+': return constant(ac + bc);
                case '-': return constant(ac - bc);
                case '*': return constant(ac * bc);
                case '/': return constant(ac / bc);
                default:
                    std::cout << "Don't know how to handle " << a.op() << std::endl;
                    assert(false);
            }
        }

        switch (a.op()) {
            case '*':
                push_job(a.lhs(), b / a.rhs());
                push_job(a.rhs(), b / a.lhs());
                break;
            case '/':
                push_job(a.lhs(), b * a.rhs());
                push_job(a.rhs(), b * a.lhs());
                break;
            default:
                std::cout << "Don't know how to handle " << a.op() << std::endl;
                assert(false);
        }
        return nullptr;
    }
};

void test_solve(const expr_ptr& lhs, const expr_ptr& rhs, const std::string& v, double value) {
    solver solv{v};
    auto s = solv.solve(*lhs, *rhs);
    if (!s) {
        std::cout << "Unable to solve '" << lhs << "'='" << rhs << "' for '" << v << "'" << std::endl;
        assert(false);
    }
    if (match_const(*s, value)) {
        std::cout << "OK: " << lhs << "=" << rhs << " ==> " << v << "=" << *s << std::endl;
        return;
    }

    std::cout << "Wrong answer for '" << lhs << "'='" << rhs << "' for '" << v << "'\n";
    std::cout << "Expected: " << value << std::endl;
    std::cout << "Got: '" << s << "'" << std::endl;
}

int main()
{
    test();

    test_solve(var("x"), constant(8), "x", 8);
    test_solve(constant(42), var("x"), "x", 42);
    test_solve(constant(2) * var("x"), constant(8), "x", 4);
}
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/**************************************************************************
  Connections

  Commonality across all platforms -- move out as required.

**************************************************************************/

#include "ink_unused.h"   /* MAGIC_EDITING_TAG */
#include "libts.h"

#include "P_Net.h"

#define SET_TCP_NO_DELAY
#define SET_NO_LINGER
// set in the OS
// #define RECV_BUF_SIZE            (1024*64)
// #define SEND_BUF_SIZE            (1024*64)
#define FIRST_RANDOM_PORT        16000
#define LAST_RANDOM_PORT         32000

#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))

int
get_listen_backlog(void)
{
  int listen_backlog = 1024;

  IOCORE_ReadConfigInteger(listen_backlog, "proxy.config.net.listen_backlog");
  return listen_backlog;
}

//
// Functions
//
char const*
NetVCOptions::toString(addr_bind_style s) {
  return ANY_ADDR == s ? "any"
    : INTF_ADDR == s ? "interface"
    : "foreign"
    ;
}

Connection::Connection()
  : fd(NO_FD)
  , is_bound(false)
  , is_connected(false)
{
  memset(&sa, 0, sizeof(struct sockaddr_storage));
}

Connection::~Connection()
{
  close();
}

int
Server::accept(Connection * c)
{
  int res = 0;
  socklen_t sz = sizeof(c->sa);

  res = socketManager.accept(fd, (struct sockaddr *)&c->sa, &sz);
  if (res < 0)
    return res;
  c->fd = res;

#ifdef SET_CLOSE_ON_EXEC
  if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0)
    goto Lerror;
#endif
  if ((res = safe_nonblocking(c->fd)) < 0)
    goto Lerror;
#ifdef SEND_BUF_SIZE
  socketManager.set_sndbuf_size(c->fd, SEND_BUF_SIZE);
#endif
#ifdef SET_SO_KEEPALIVE
  // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0)
    goto Lerror;
#endif

  return 0;
Lerror:
  c->close();
  return res;
}

int
Connection::close()
{
  is_connected = false;
  is_bound = false;
  // don't close any of the standards
  if (fd >= 2) {
    int fd_save = fd;
    fd = NO_FD;
    return socketManager.close(fd_save);
  } else {
    fd = NO_FD;
    return -EBADF;
  }
}

int
Server::setup_fd_for_listen(bool non_blocking, int recv_bufsize, int send_bufsize)
{
  int res = 0;
#ifdef SEND_BUF_SIZE
  {
    int send_buf_size = SEND_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &send_buf_size, sizeof(int)) < 0))
      goto Lerror;
  }
#endif
#ifdef RECV_BUF_SIZE
  {
    int recv_buf_size = RECV_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buf_size, sizeof(int))) < 0)
      goto Lerror;
  }
#endif

  if (recv_bufsize) {
    // coverity[negative_sink_in_call]
    if (socketManager.set_rcvbuf_size(fd, recv_bufsize)) {
      // Round down until success
      int rbufsz = ROUNDUP(recv_bufsize, 1024);
      while (rbufsz) {
        if (socketManager.set_rcvbuf_size(fd, rbufsz)) {
          rbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
  if (send_bufsize) {
    if (socketManager.set_sndbuf_size(fd, send_bufsize)) {
      // Round down until success
      int sbufsz = ROUNDUP(send_bufsize, 1024);
      while (sbufsz) {
        if (socketManager.set_sndbuf_size(fd, sbufsz)) {
          sbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
#ifdef SET_NO_LINGER
  {
    struct linger l;
    l.l_onoff = 0;
    l.l_linger = 0;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l))) < 0)
      goto Lerror;
  }
#endif
#ifdef SET_TCP_NO_DELAY
  if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0)
    goto Lerror;
#endif
#ifdef SET_SO_KEEPALIVE
  // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0)
    goto Lerror;
#endif

#if defined(linux)
  if (NetProcessor::accept_mss > 0)
    if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *) &NetProcessor::accept_mss, sizeof(int)) < 0))
      goto Lerror;
#endif

  /*
   * dg: this has been removed since the ISS patch under solaris seems
   * to not like the socket being listened on twice. This is first done
   * in the manager when the socket is created.
   */
  if (non_blocking)
    if ((res = safe_nonblocking(fd)) < 0)
      goto Lerror;
  {
    int namelen = sizeof(sa);
    if ((res = safe_getsockname(fd, (struct sockaddr *) &sa, &namelen)))
      goto Lerror;
  }
  return 0;
Lerror:
  res = -errno;
  // coverity[check_after_sink]
  if (fd != NO_FD)
    close();
  return res;
}

int
Server::listen(int port_number, int domain, bool non_blocking, int recv_bufsize, int send_bufsize)
{
  ink_assert(fd == NO_FD);
  int res = 0;
  int gai_errno = 0;

  char port[6] = {'\0'};
  struct addrinfo hints;
  struct addrinfo *ai_res = NULL;
  struct addrinfo *ai = NULL;
  socklen_t addrlen = 0;  // keep track of length of socket address info
  snprintf(port, sizeof(port), "%d", port_number);

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = domain;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST|AI_ADDRCONFIG;
  gai_errno = getaddrinfo(accept_ip_str, port, &hints, &ai_res);
  if(0 != gai_errno) {
    Error("getaddrinfo error %i: %s", gai_errno, gai_strerror(gai_errno));
    return -1;
  }

  ai = ai_res;

  res = socketManager.socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

  memset(&sa, 0, sizeof(sa));
  addrlen = ai->ai_addrlen;  // save value for later since ai will be freed asap
  memcpy(&sa, ai->ai_addr, ai->ai_addrlen);

  freeaddrinfo(ai_res);

  if (res < 0)
    return res;
  fd = res;

#ifdef SEND_BUF_SIZE
  {
    int send_buf_size = SEND_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &send_buf_size, sizeof(int)) < 0))
      goto Lerror;
  }
#endif
#ifdef RECV_BUF_SIZE
  {
    int recv_buf_size = RECV_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buf_size, sizeof(int))) < 0)
      goto Lerror;
  }
#endif

  if (recv_bufsize) {
    if (socketManager.set_rcvbuf_size(fd, recv_bufsize)) {
      // Round down until success
      int rbufsz = ROUNDUP(recv_bufsize, 1024);
      while (rbufsz) {
        if (socketManager.set_rcvbuf_size(fd, rbufsz)) {
          rbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
  if (send_bufsize) {
    if (socketManager.set_sndbuf_size(fd, send_bufsize)) {
      // Round down until success
      int sbufsz = ROUNDUP(send_bufsize, 1024);
      while (sbufsz) {
        if (socketManager.set_sndbuf_size(fd, sbufsz)) {
          sbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
#ifdef SET_CLOSE_ON_EXEC
  if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0)
    goto Lerror;
#endif

#ifdef SET_NO_LINGER
  {
    struct linger l;
    l.l_onoff = 0;
    l.l_linger = 0;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l))) < 0)
      goto Lerror;
  }
#endif

  if (domain == AF_INET6 && (res = safe_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, ON, sizeof(int))) < 0)
    goto Lerror;

  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ON, sizeof(int))) < 0)
    goto Lerror;

  if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &sa, addrlen, IPPROTO_TCP)) < 0) {
    goto Lerror;
  }
#ifdef SET_TCP_NO_DELAY
  if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0)
    goto Lerror;
#endif
#ifdef SET_SO_KEEPALIVE
  // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0)
    goto Lerror;
#endif

#if defined(linux)
  if (NetProcessor::accept_mss > 0)
    if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *) &NetProcessor::accept_mss, sizeof(int))) < 0)
      goto Lerror;
#endif

  if ((res = safe_listen(fd, get_listen_backlog())) < 0)
    goto Lerror;
  if (non_blocking)
    if ((res = safe_nonblocking(fd)) < 0)
      goto Lerror;
  if (!port_number) {
    int namelen = sizeof(sa);
    if ((res = safe_getsockname(fd, (struct sockaddr *) &sa, &namelen)))
      goto Lerror;
  }
  return 0;

Lerror:
  if (fd != NO_FD)
    close();
  Error("Could not bind or listen to port %d (error: %d)", port_number, res);
  return res;
}
<commit_msg>TS-851 run TS without a real interface<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/**************************************************************************
  Connections

  Commonality across all platforms -- move out as required.

**************************************************************************/

#include "ink_unused.h"   /* MAGIC_EDITING_TAG */
#include "libts.h"

#include "P_Net.h"

#define SET_TCP_NO_DELAY
#define SET_NO_LINGER
// set in the OS
// #define RECV_BUF_SIZE            (1024*64)
// #define SEND_BUF_SIZE            (1024*64)
#define FIRST_RANDOM_PORT        16000
#define LAST_RANDOM_PORT         32000

#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))

int
get_listen_backlog(void)
{
  int listen_backlog = 1024;

  IOCORE_ReadConfigInteger(listen_backlog, "proxy.config.net.listen_backlog");
  return listen_backlog;
}

//
// Functions
//
char const*
NetVCOptions::toString(addr_bind_style s) {
  return ANY_ADDR == s ? "any"
    : INTF_ADDR == s ? "interface"
    : "foreign"
    ;
}

Connection::Connection()
  : fd(NO_FD)
  , is_bound(false)
  , is_connected(false)
{
  memset(&sa, 0, sizeof(struct sockaddr_storage));
}

Connection::~Connection()
{
  close();
}

int
Server::accept(Connection * c)
{
  int res = 0;
  socklen_t sz = sizeof(c->sa);

  res = socketManager.accept(fd, (struct sockaddr *)&c->sa, &sz);
  if (res < 0)
    return res;
  c->fd = res;

#ifdef SET_CLOSE_ON_EXEC
  if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0)
    goto Lerror;
#endif
  if ((res = safe_nonblocking(c->fd)) < 0)
    goto Lerror;
#ifdef SEND_BUF_SIZE
  socketManager.set_sndbuf_size(c->fd, SEND_BUF_SIZE);
#endif
#ifdef SET_SO_KEEPALIVE
  // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0)
    goto Lerror;
#endif

  return 0;
Lerror:
  c->close();
  return res;
}

int
Connection::close()
{
  is_connected = false;
  is_bound = false;
  // don't close any of the standards
  if (fd >= 2) {
    int fd_save = fd;
    fd = NO_FD;
    return socketManager.close(fd_save);
  } else {
    fd = NO_FD;
    return -EBADF;
  }
}

int
Server::setup_fd_for_listen(bool non_blocking, int recv_bufsize, int send_bufsize)
{
  int res = 0;
#ifdef SEND_BUF_SIZE
  {
    int send_buf_size = SEND_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &send_buf_size, sizeof(int)) < 0))
      goto Lerror;
  }
#endif
#ifdef RECV_BUF_SIZE
  {
    int recv_buf_size = RECV_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buf_size, sizeof(int))) < 0)
      goto Lerror;
  }
#endif

  if (recv_bufsize) {
    // coverity[negative_sink_in_call]
    if (socketManager.set_rcvbuf_size(fd, recv_bufsize)) {
      // Round down until success
      int rbufsz = ROUNDUP(recv_bufsize, 1024);
      while (rbufsz) {
        if (socketManager.set_rcvbuf_size(fd, rbufsz)) {
          rbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
  if (send_bufsize) {
    if (socketManager.set_sndbuf_size(fd, send_bufsize)) {
      // Round down until success
      int sbufsz = ROUNDUP(send_bufsize, 1024);
      while (sbufsz) {
        if (socketManager.set_sndbuf_size(fd, sbufsz)) {
          sbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
#ifdef SET_NO_LINGER
  {
    struct linger l;
    l.l_onoff = 0;
    l.l_linger = 0;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l))) < 0)
      goto Lerror;
  }
#endif
#ifdef SET_TCP_NO_DELAY
  if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0)
    goto Lerror;
#endif
#ifdef SET_SO_KEEPALIVE
  // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0)
    goto Lerror;
#endif

#if defined(linux)
  if (NetProcessor::accept_mss > 0)
    if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *) &NetProcessor::accept_mss, sizeof(int)) < 0))
      goto Lerror;
#endif

  /*
   * dg: this has been removed since the ISS patch under solaris seems
   * to not like the socket being listened on twice. This is first done
   * in the manager when the socket is created.
   */
  if (non_blocking)
    if ((res = safe_nonblocking(fd)) < 0)
      goto Lerror;
  {
    int namelen = sizeof(sa);
    if ((res = safe_getsockname(fd, (struct sockaddr *) &sa, &namelen)))
      goto Lerror;
  }
  return 0;
Lerror:
  res = -errno;
  // coverity[check_after_sink]
  if (fd != NO_FD)
    close();
  return res;
}

int
Server::listen(int port_number, int domain, bool non_blocking, int recv_bufsize, int send_bufsize)
{
  ink_assert(fd == NO_FD);
  int res = 0;
  int gai_errno = 0;

  char port[6] = {'\0'};
  struct addrinfo hints;
  struct addrinfo *ai_res = NULL;
  struct addrinfo *ai = NULL;
  socklen_t addrlen = 0;  // keep track of length of socket address info
  snprintf(port, sizeof(port), "%d", port_number);

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = domain;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
  gai_errno = getaddrinfo(accept_ip_str, port, &hints, &ai_res);
  if(0 != gai_errno) {
    Error("getaddrinfo %s:%s error %i: %s", accept_ip_str, port, gai_errno, gai_strerror(gai_errno));
    return -1;
  }

  ai = ai_res;

  res = socketManager.socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

  memset(&sa, 0, sizeof(sa));
  addrlen = ai->ai_addrlen;  // save value for later since ai will be freed asap
  memcpy(&sa, ai->ai_addr, ai->ai_addrlen);

  freeaddrinfo(ai_res);

  if (res < 0)
    return res;
  fd = res;

#ifdef SEND_BUF_SIZE
  {
    int send_buf_size = SEND_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &send_buf_size, sizeof(int)) < 0))
      goto Lerror;
  }
#endif
#ifdef RECV_BUF_SIZE
  {
    int recv_buf_size = RECV_BUF_SIZE;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buf_size, sizeof(int))) < 0)
      goto Lerror;
  }
#endif

  if (recv_bufsize) {
    if (socketManager.set_rcvbuf_size(fd, recv_bufsize)) {
      // Round down until success
      int rbufsz = ROUNDUP(recv_bufsize, 1024);
      while (rbufsz) {
        if (socketManager.set_rcvbuf_size(fd, rbufsz)) {
          rbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
  if (send_bufsize) {
    if (socketManager.set_sndbuf_size(fd, send_bufsize)) {
      // Round down until success
      int sbufsz = ROUNDUP(send_bufsize, 1024);
      while (sbufsz) {
        if (socketManager.set_sndbuf_size(fd, sbufsz)) {
          sbufsz -= 1024;
        } else {
          break;
        }
      }
    }
  }
#ifdef SET_CLOSE_ON_EXEC
  if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0)
    goto Lerror;
#endif

#ifdef SET_NO_LINGER
  {
    struct linger l;
    l.l_onoff = 0;
    l.l_linger = 0;
    if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l))) < 0)
      goto Lerror;
  }
#endif

  if (domain == AF_INET6 && (res = safe_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, ON, sizeof(int))) < 0)
    goto Lerror;

  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ON, sizeof(int))) < 0)
    goto Lerror;

  if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &sa, addrlen, IPPROTO_TCP)) < 0) {
    goto Lerror;
  }
#ifdef SET_TCP_NO_DELAY
  if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0)
    goto Lerror;
#endif
#ifdef SET_SO_KEEPALIVE
  // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
  if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0)
    goto Lerror;
#endif

#if defined(linux)
  if (NetProcessor::accept_mss > 0)
    if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *) &NetProcessor::accept_mss, sizeof(int))) < 0)
      goto Lerror;
#endif

  if ((res = safe_listen(fd, get_listen_backlog())) < 0)
    goto Lerror;
  if (non_blocking)
    if ((res = safe_nonblocking(fd)) < 0)
      goto Lerror;
  if (!port_number) {
    int namelen = sizeof(sa);
    if ((res = safe_getsockname(fd, (struct sockaddr *) &sa, &namelen)))
      goto Lerror;
  }
  return 0;

Lerror:
  if (fd != NO_FD)
    close();
  Error("Could not bind or listen to port %d (error: %d)", port_number, res);
  return res;
}
<|endoftext|>


<commit_before>#include "Halide.h"

using namespace Halide;

#include <iostream>
#include <limits>

#include <halide_image_io.h>
#include <benchmark.h>

enum InterpolationType {
    BOX, LINEAR, CUBIC, LANCZOS
};

Expr kernel_box(Expr x) {
    Expr xx = abs(x);
    return select(xx <= 0.5f, 1.0f, 0.0f);
}

Expr kernel_linear(Expr x) {
    Expr xx = abs(x);
    return select(xx < 1.0f, 1.0f - xx, 0.0f);
}

Expr kernel_cubic(Expr x) {
    Expr xx = abs(x);
    Expr xx2 = xx * xx;
    Expr xx3 = xx2 * xx;
    float a = -0.5f;

    return select(xx < 1.0f, (a + 2.0f) * xx3 - (a + 3.0f) * xx2 + 1,
                  select (xx < 2.0f, a * xx3 - 5 * a * xx2 + 8 * a * xx - 4.0f * a,
                          0.0f));
}

Expr sinc(Expr x) {
    return sin(float(M_PI) * x) / x;
}

Expr kernel_lanczos(Expr x) {
    Expr value = sinc(x) * sinc(x/3);
    value = select(x == 0.0f, 1.0f, value); // Take care of singularity at zero
    value = select(x > 3 || x < -3, 0.0f, value); // Clamp to zero out of bounds
    return value;
}

struct KernelInfo {
    const char *name;
    float size;
    Expr (*kernel)(Expr);
};

static KernelInfo kernelInfo[] = {
    { "box", 0.5f, kernel_box },
    { "linear", 1.0f, kernel_linear },
    { "cubic", 2.0f, kernel_cubic },
    { "lanczos", 3.0f, kernel_lanczos }
};

std::string infile, outfile;
InterpolationType interpolationType = LINEAR;
float scaleFactor = 1.0f;
bool show_usage = false;
int schedule = 0;

void parse_commandline(int argc, char **argv) {
    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];
        if (arg == "-f" && i+1 < argc) {
            scaleFactor = atof(argv[++i]);
        } else if (arg == "-s" && i+1 < argc) {
            schedule = atoi(argv[++i]);
            if (schedule < 0 || schedule > 3) {
                fprintf(stderr, "Invalid schedule\n");
                show_usage = true;
            }
        } else if (arg == "-t" && i+1 < argc) {
            arg = argv[++i];
            if (arg == "box") {
                interpolationType = BOX;
            } else if (arg == "linear") {
                interpolationType = LINEAR;
            } else if (arg == "cubic") {
                interpolationType = CUBIC;
            } else if (arg == "lanczos") {
                interpolationType = LANCZOS;
            } else {
                fprintf(stderr, "Invalid interpolation type '%s' specified.\n",
                        arg.c_str());
                show_usage = true;
            }
        } else if (infile.empty()) {
            infile = arg;
        } else if (outfile.empty()) {
            outfile = arg;
        } else {
            fprintf(stderr, "Unexpected command line option '%s'.\n", arg.c_str());
        }
    }
}

int main(int argc, char **argv) {
    parse_commandline(argc, argv);
    if (infile.empty() || outfile.empty() || show_usage) {
        fprintf(stderr,
                "Usage:\n"
                "\t./resample [-f scalefactor] [-s schedule] [-t box|linear|cubic|lanczos] in.png out.png\n"
                "\t\tSchedules: 0=default 1=vectorized 2=parallel 3=vectorized+parallel\n");
        return 1;
    }

    ImageParam input(Float(32), 3);

    Var x("x"), y("y"), c("c"), k("k");

    Func clamped = BoundaryConditions::repeat_edge(input);

    // For downscaling, widen the interpolation kernel to perform lowpass
    // filtering.
    float kernelScaling = std::min(scaleFactor, 1.0f);
    float kernelSize = kernelInfo[interpolationType].size / kernelScaling;

    // source[xy] are the (non-integer) coordinates inside the source image
    Expr sourcex = (x + 0.5f) / scaleFactor;
    Expr sourcey = (y + 0.5f) / scaleFactor;

    // Initialize interpolation kernels. Since we allow an arbitrary
    // scaling factor, the filter coefficients are different for each x
    // and y coordinate.
    Func kernelx("kernelx"), kernely("kernely");
    Expr beginx = cast<int>(sourcex - kernelSize + 0.5f);
    Expr beginy = cast<int>(sourcey - kernelSize + 0.5f);
    RDom domx(0, static_cast<int>(2.0f * kernelSize) + 1, "domx");
    RDom domy(0, static_cast<int>(2.0f * kernelSize) + 1, "domy");
    {
        const KernelInfo &info = kernelInfo[interpolationType];
        Func kx, ky;
        kx(x, k) = info.kernel((k + beginx - sourcex) * kernelScaling);
        ky(y, k) = info.kernel((k + beginy - sourcey) * kernelScaling);
        kernelx(x, k) = kx(x, k) / sum(kx(x, domx));
        kernely(y, k) = ky(y, k) / sum(ky(y, domy));
    }

    // Perform separable resizing
    Func resized_x("resized_x");
    Func resized_y("resized_y");
    resized_x(x, y, c) = sum(kernelx(x, domx) * cast<float>(clamped(domx + beginx, y, c)));
    resized_y(x, y, c) = sum(kernely(y, domy) * resized_x(x, domy + beginy, c));

    Func final("final");
    final(x, y, c) = clamp(resized_y(x, y, c), 0.0f, 1.0f);

    std::cout << "Finished function setup." << std::endl;

    // Scheduling
    bool parallelize = (schedule >= 2);
    bool vectorize = (schedule == 1 || schedule == 3);

    kernelx.compute_root();
    kernely.compute_at(final, y);

    if (vectorize) {
        resized_x.vectorize(x, 4);
        final.vectorize(x, 4);
    }

    if (parallelize) {
        Var yo, yi;
        final.split(y, yo, y, 32).parallel(yo);
        resized_x.store_at(final, yo).compute_at(final, y);
    } else {
        resized_x.store_at(final, c).compute_at(final, y);
    }

    Target target = get_jit_target_from_environment();
    final.compile_jit(target);

    printf("Loading '%s'\n", infile.c_str());
    Buffer<float> in_png = Tools::load_image(infile);
    int out_width = in_png.width() * scaleFactor;
    int out_height = in_png.height() * scaleFactor;
    Buffer<float> out(out_width, out_height, 3);
    input.set(in_png);
    printf("Resampling '%s' from %dx%d to %dx%d using %s interpolation\n",
           infile.c_str(),
           in_png.width(), in_png.height(),
           out_width, out_height,
           kernelInfo[interpolationType].name);

    double min = benchmark(10, 1, [&]() { final.realize(out); });
    std::cout << " took min=" << min * 1000 << " msec." << std::endl;

    Tools::save_image(out, outfile);
}
<commit_msg>Fix includes & benchmark in apps/resize<commit_after>#include "Halide.h"

using namespace Halide;

#include <iostream>
#include <limits>

#include "halide_image_io.h"
#include "halide_benchmark.h"

enum InterpolationType {
    BOX, LINEAR, CUBIC, LANCZOS
};

Expr kernel_box(Expr x) {
    Expr xx = abs(x);
    return select(xx <= 0.5f, 1.0f, 0.0f);
}

Expr kernel_linear(Expr x) {
    Expr xx = abs(x);
    return select(xx < 1.0f, 1.0f - xx, 0.0f);
}

Expr kernel_cubic(Expr x) {
    Expr xx = abs(x);
    Expr xx2 = xx * xx;
    Expr xx3 = xx2 * xx;
    float a = -0.5f;

    return select(xx < 1.0f, (a + 2.0f) * xx3 - (a + 3.0f) * xx2 + 1,
                  select (xx < 2.0f, a * xx3 - 5 * a * xx2 + 8 * a * xx - 4.0f * a,
                          0.0f));
}

Expr sinc(Expr x) {
    return sin(float(M_PI) * x) / x;
}

Expr kernel_lanczos(Expr x) {
    Expr value = sinc(x) * sinc(x/3);
    value = select(x == 0.0f, 1.0f, value); // Take care of singularity at zero
    value = select(x > 3 || x < -3, 0.0f, value); // Clamp to zero out of bounds
    return value;
}

struct KernelInfo {
    const char *name;
    float size;
    Expr (*kernel)(Expr);
};

static KernelInfo kernelInfo[] = {
    { "box", 0.5f, kernel_box },
    { "linear", 1.0f, kernel_linear },
    { "cubic", 2.0f, kernel_cubic },
    { "lanczos", 3.0f, kernel_lanczos }
};

std::string infile, outfile;
InterpolationType interpolationType = LINEAR;
float scaleFactor = 1.0f;
bool show_usage = false;
int schedule = 0;

void parse_commandline(int argc, char **argv) {
    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];
        if (arg == "-f" && i+1 < argc) {
            scaleFactor = atof(argv[++i]);
        } else if (arg == "-s" && i+1 < argc) {
            schedule = atoi(argv[++i]);
            if (schedule < 0 || schedule > 3) {
                fprintf(stderr, "Invalid schedule\n");
                show_usage = true;
            }
        } else if (arg == "-t" && i+1 < argc) {
            arg = argv[++i];
            if (arg == "box") {
                interpolationType = BOX;
            } else if (arg == "linear") {
                interpolationType = LINEAR;
            } else if (arg == "cubic") {
                interpolationType = CUBIC;
            } else if (arg == "lanczos") {
                interpolationType = LANCZOS;
            } else {
                fprintf(stderr, "Invalid interpolation type '%s' specified.\n",
                        arg.c_str());
                show_usage = true;
            }
        } else if (infile.empty()) {
            infile = arg;
        } else if (outfile.empty()) {
            outfile = arg;
        } else {
            fprintf(stderr, "Unexpected command line option '%s'.\n", arg.c_str());
        }
    }
}

int main(int argc, char **argv) {
    parse_commandline(argc, argv);
    if (infile.empty() || outfile.empty() || show_usage) {
        fprintf(stderr,
                "Usage:\n"
                "\t./resample [-f scalefactor] [-s schedule] [-t box|linear|cubic|lanczos] in.png out.png\n"
                "\t\tSchedules: 0=default 1=vectorized 2=parallel 3=vectorized+parallel\n");
        return 1;
    }

    ImageParam input(Float(32), 3);

    Var x("x"), y("y"), c("c"), k("k");

    Func clamped = BoundaryConditions::repeat_edge(input);

    // For downscaling, widen the interpolation kernel to perform lowpass
    // filtering.
    float kernelScaling = std::min(scaleFactor, 1.0f);
    float kernelSize = kernelInfo[interpolationType].size / kernelScaling;

    // source[xy] are the (non-integer) coordinates inside the source image
    Expr sourcex = (x + 0.5f) / scaleFactor;
    Expr sourcey = (y + 0.5f) / scaleFactor;

    // Initialize interpolation kernels. Since we allow an arbitrary
    // scaling factor, the filter coefficients are different for each x
    // and y coordinate.
    Func kernelx("kernelx"), kernely("kernely");
    Expr beginx = cast<int>(sourcex - kernelSize + 0.5f);
    Expr beginy = cast<int>(sourcey - kernelSize + 0.5f);
    RDom domx(0, static_cast<int>(2.0f * kernelSize) + 1, "domx");
    RDom domy(0, static_cast<int>(2.0f * kernelSize) + 1, "domy");
    {
        const KernelInfo &info = kernelInfo[interpolationType];
        Func kx, ky;
        kx(x, k) = info.kernel((k + beginx - sourcex) * kernelScaling);
        ky(y, k) = info.kernel((k + beginy - sourcey) * kernelScaling);
        kernelx(x, k) = kx(x, k) / sum(kx(x, domx));
        kernely(y, k) = ky(y, k) / sum(ky(y, domy));
    }

    // Perform separable resizing
    Func resized_x("resized_x");
    Func resized_y("resized_y");
    resized_x(x, y, c) = sum(kernelx(x, domx) * cast<float>(clamped(domx + beginx, y, c)));
    resized_y(x, y, c) = sum(kernely(y, domy) * resized_x(x, domy + beginy, c));

    Func final("final");
    final(x, y, c) = clamp(resized_y(x, y, c), 0.0f, 1.0f);

    std::cout << "Finished function setup." << std::endl;

    // Scheduling
    bool parallelize = (schedule >= 2);
    bool vectorize = (schedule == 1 || schedule == 3);

    kernelx.compute_root();
    kernely.compute_at(final, y);

    if (vectorize) {
        resized_x.vectorize(x, 4);
        final.vectorize(x, 4);
    }

    if (parallelize) {
        Var yo, yi;
        final.split(y, yo, y, 32).parallel(yo);
        resized_x.store_at(final, yo).compute_at(final, y);
    } else {
        resized_x.store_at(final, c).compute_at(final, y);
    }

    Target target = get_jit_target_from_environment();
    final.compile_jit(target);

    printf("Loading '%s'\n", infile.c_str());
    Buffer<float> in_png = Tools::load_image(infile);
    int out_width = in_png.width() * scaleFactor;
    int out_height = in_png.height() * scaleFactor;
    Buffer<float> out(out_width, out_height, 3);
    input.set(in_png);
    printf("Resampling '%s' from %dx%d to %dx%d using %s interpolation\n",
           infile.c_str(),
           in_png.width(), in_png.height(),
           out_width, out_height,
           kernelInfo[interpolationType].name);

    double min = Tools::benchmark(10, 1, [&]() { final.realize(out); });
    std::cout << " took min=" << min * 1000 << " msec." << std::endl;

    Tools::save_image(out, outfile);
}
<|endoftext|>


<commit_before>/*
 * Implementation of a ACME client.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "GlueHttpClient.hxx"
#include "event/Loop.hxx"
#include "curl/Request.hxx"
#include "curl/Handler.hxx"
#include "util/ConstBuffer.hxx"

#include <exception>

GlueHttpServerAddress::GlueHttpServerAddress(bool ssl,
                                             const char *_host_and_port)
    :url(ssl ? "https://" : "http://")
{
    url += _host_and_port;
}

GlueHttpClient::GlueHttpClient(EventLoop &event_loop)
    :curl_global(event_loop)
{
}

GlueHttpClient::~GlueHttpClient()
{
}

class GlueHttpResponseHandler final : public CurlResponseHandler {
    http_status_t status;
    std::multimap<std::string, std::string> headers;

    std::string body_string;

    std::exception_ptr error;

    bool done = false;

public:
    bool IsDone() const {
        return done;
    }

    void CheckThrowError() {
        if (error)
            std::rethrow_exception(error);
    }

    GlueHttpResponse MoveResponse() {
        return {status, std::move(headers), std::move(body_string)};
    }

public:
    /* virtual methods from class CurlResponseHandler */

    void OnHeaders(unsigned _status,
                   std::multimap<std::string, std::string> &&_headers) override {
        status = http_status_t(_status);
        headers = std::move(_headers);
    }

    void OnData(ConstBuffer<void> data) override {
        body_string.append((const char *)data.data, data.size);
    }

    void OnEnd() override {
        done = true;
    }

    void OnError(std::exception_ptr e) override {
        error = std::move(e);
        done = true;
    }
};

/**
 * A helper class which feeds a (foreign) memory buffer into the
 * CURLOPT_READFUNCTION.
 */
class CurlRequestBody {
    ConstBuffer<char> data;

public:
    explicit CurlRequestBody(ConstBuffer<void> _data)
        :data(ConstBuffer<char>::FromVoid(_data)) {}

    void Enable(CurlRequest &request) {
        request.SetOption(CURLOPT_READFUNCTION, Callback);
        request.SetOption(CURLOPT_READDATA, this);
    }

private:
    size_t Read(char *buffer, size_t size) {
        size_t n = std::min(size, data.size);
        std::copy_n(data.begin(), n, buffer);
        data.skip_front(n);
        return n;
    }

    static size_t Callback(char *buffer, size_t size, size_t nitems,
                           void *instream) {
        auto &rb = *(CurlRequestBody *)instream;
        return rb.Read(buffer, size * nitems);
    }
};

GlueHttpResponse
GlueHttpClient::Request(EventLoop &event_loop,
                        GlueHttpServerAddress &server,
                        http_method_t method, const char *uri,
                        ConstBuffer<void> _body)
{
    std::string url = server.url + uri;

    GlueHttpResponseHandler handler;
    CurlRequest request(curl_global, url.c_str(), handler);

    if (method == HTTP_METHOD_HEAD)
        request.SetOption(CURLOPT_NOBODY, 1l);
    else if (method == HTTP_METHOD_POST)
        request.SetOption(CURLOPT_POST, 1l);

    CurlRequestBody body(_body);
    if (!_body.IsNull())
        body.Enable(request);

    request.Start();

    while (!handler.IsDone() && event_loop.LoopOnce()) {}

    handler.CheckThrowError();
    return handler.MoveResponse();
}
<commit_msg>certdb/GlueHttpClient: use CURLOPT_POSTFIELDS instead of CURLOPT_READFUNCTION<commit_after>/*
 * Implementation of a ACME client.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "GlueHttpClient.hxx"
#include "event/Loop.hxx"
#include "curl/Request.hxx"
#include "curl/Handler.hxx"
#include "util/ConstBuffer.hxx"

#include <exception>

GlueHttpServerAddress::GlueHttpServerAddress(bool ssl,
                                             const char *_host_and_port)
    :url(ssl ? "https://" : "http://")
{
    url += _host_and_port;
}

GlueHttpClient::GlueHttpClient(EventLoop &event_loop)
    :curl_global(event_loop)
{
}

GlueHttpClient::~GlueHttpClient()
{
}

class GlueHttpResponseHandler final : public CurlResponseHandler {
    http_status_t status;
    std::multimap<std::string, std::string> headers;

    std::string body_string;

    std::exception_ptr error;

    bool done = false;

public:
    bool IsDone() const {
        return done;
    }

    void CheckThrowError() {
        if (error)
            std::rethrow_exception(error);
    }

    GlueHttpResponse MoveResponse() {
        return {status, std::move(headers), std::move(body_string)};
    }

public:
    /* virtual methods from class CurlResponseHandler */

    void OnHeaders(unsigned _status,
                   std::multimap<std::string, std::string> &&_headers) override {
        status = http_status_t(_status);
        headers = std::move(_headers);
    }

    void OnData(ConstBuffer<void> data) override {
        body_string.append((const char *)data.data, data.size);
    }

    void OnEnd() override {
        done = true;
    }

    void OnError(std::exception_ptr e) override {
        error = std::move(e);
        done = true;
    }
};

GlueHttpResponse
GlueHttpClient::Request(EventLoop &event_loop,
                        GlueHttpServerAddress &server,
                        http_method_t method, const char *uri,
                        ConstBuffer<void> body)
{
    std::string url = server.url + uri;

    GlueHttpResponseHandler handler;
    CurlRequest request(curl_global, url.c_str(), handler);

    if (method == HTTP_METHOD_HEAD)
        request.SetOption(CURLOPT_NOBODY, 1l);
    else if (method == HTTP_METHOD_POST)
        request.SetOption(CURLOPT_POST, 1l);

    if (!body.IsNull()) {
        request.SetOption(CURLOPT_POSTFIELDS, (const char *)body.data);
        request.SetOption(CURLOPT_POSTFIELDSIZE, long(body.size));
    }

    request.Start();

    while (!handler.IsDone() && event_loop.LoopOnce()) {}

    handler.CheckThrowError();
    return handler.MoveResponse();
}
<|endoftext|>


<commit_before>#include "sn_boundary.hpp"

#include <iostream>

using std::cout;
using std::endl;

namespace mocc {
    SnBoundary::SnBoundary( int n_group, const AngularQuadrature &ang_quad,
            const Mesh &mesh ):
        n_group_( n_group ),
        ang_quad_( ang_quad ),
        n_ang_( ang_quad.ndir() ),
        nx_( mesh.nx() ),
        ny_( mesh.ny() ),
        nz_( mesh.nz() ),
        ang_stride_( nx_*ny_ + nx_*nz_ + ny_*nz_ ),
        group_stride_( ang_stride_*n_ang_ ),
        bc_( mesh.boundary() ),
        data_( 0.0, group_stride_* n_group )
    {
        assert( n_group_ > 0 );
        n_face_[(int)Normal::X_NORM] = ny_*nz_;
        n_face_[(int)Normal::Y_NORM] = nx_*nz_;
        n_face_[(int)Normal::Z_NORM] = nx_*ny_;
        int offset = 0;
        for( const auto norm: AllNormals ) {
            face_offset_[(int)norm] = offset;
            offset += n_face_[(int)norm];
        }

        return;
    }

    void SnBoundary::update( size_t group, const SnBoundary &out ) {
        assert( group < n_group_ );
        assert( out.n_group() == 1 );

        // In the below, iang is the incoming angle index to be set, iang_refl
        // is the reflected angle from which a reflective BC should get its flux
        int iang = 0;
        for( auto &ang: ang_quad_ ) {
            Surface surf;
            Normal norm;
            int iang_refl;

            // X-normal surface
            norm = Normal::X_NORM;
            surf = (ang.ox > 0) ? Surface::WEST : Surface::EAST;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, iang_refl, norm );
                this->set_face( group, iang, norm, new_bc );
            } else {
                this->zero_face(group, iang, norm);
            }
            // Y-normal surface
            norm = Normal::Y_NORM;
            surf = (ang.oy > 0) ? Surface::SOUTH : Surface::NORTH;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, iang_refl, norm );
                this->set_face(group, iang, norm, new_bc);
            } else {
                this->zero_face(group, iang, norm);
            }
            // Z-normal surface
            norm = Normal::Z_NORM;
            surf = (ang.oz > 0) ? Surface::BOTTOM : Surface::TOP;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, iang_refl, norm );
                this->set_face(group, iang, norm, new_bc );
            } else {
                this->zero_face(group, iang, norm);
            }

            iang++;
        }
        return;
    }

    void SnBoundary::update( size_t group, size_t ang, const SnBoundary &out ) {
        Angle angle = ang_quad_[ang];
        Surface surf;
        Normal norm;
        int iang_refl = 0;

        /// \todo replace with a loop over AllNormal
        // X-normal surface
        norm = Normal::X_NORM;
        surf = (angle.ox > 0) ? Surface::WEST : Surface::EAST;
        iang_refl = ang_quad_.reflect( ang, norm );
        if( bc_[(int)surf] == Boundary::REFLECT ) {
            auto new_bc = out.get_face( 0, ang, norm );
            this->set_face( group, iang_refl, norm, new_bc );
        } else {
            this->zero_face(group, iang_refl, norm);
        }
        // Y-normal surface
        norm = Normal::Y_NORM;
        surf = (angle.oy > 0) ? Surface::SOUTH : Surface::NORTH;
        iang_refl = ang_quad_.reflect( ang, norm );
        if( bc_[(int)surf] == Boundary::REFLECT ) {
            auto new_bc = out.get_face( 0, ang, norm );
            this->set_face(group, iang_refl, norm, new_bc);
        } else {
            this->zero_face(group, iang_refl, norm);
        }
        // Z-normal surface
        norm = Normal::Z_NORM;
        surf = (angle.oz > 0) ? Surface::BOTTOM : Surface::TOP;
        iang_refl = ang_quad_.reflect( ang, norm );
        if( bc_[(int)surf] == Boundary::REFLECT ) {
            auto new_bc = out.get_face( 0, ang, norm );
            this->set_face(group, iang_refl, norm, new_bc );
        } else {
            this->zero_face(group, iang_refl, norm);
        }
    }

    std::ostream& operator<<(std::ostream& os, const SnBoundary &b ) {
        for( size_t ig=0; ig<b.n_group_; ig++ ) {
            cout << "Group " << ig << endl;
            for( size_t iang=0; iang<b.n_ang_; iang++ ) {
                cout << "Angle " << iang << endl;
                cout << "X-Normal face:" << endl;
                ArrayF f = b.get_face( ig, iang, Normal::X_NORM );
                for( auto v: f ) {
                    cout << v << " ";
                }
                cout << endl;
                cout << "Y-Normal face:" << endl;
                f = b.get_face( ig, iang, Normal::Y_NORM );
                for( auto v: f ) {
                    cout << v << " ";
                }
                cout << endl;
                cout << "Z-Normal face:" << endl;
                f = b.get_face( ig, iang, Normal::Z_NORM );
                for( auto v: f ) {
                    cout << v << " ";
                }
                cout << endl;
                cout << endl;

            }
        }
        return os;
    }
}
<commit_msg>Fix and simplify GS Sn BC update<commit_after>#include "sn_boundary.hpp"

#include <iostream>

using std::cout;
using std::endl;

namespace mocc {
    SnBoundary::SnBoundary( int n_group, const AngularQuadrature &ang_quad,
            const Mesh &mesh ):
        n_group_( n_group ),
        ang_quad_( ang_quad ),
        n_ang_( ang_quad.ndir() ),
        nx_( mesh.nx() ),
        ny_( mesh.ny() ),
        nz_( mesh.nz() ),
        ang_stride_( nx_*ny_ + nx_*nz_ + ny_*nz_ ),
        group_stride_( ang_stride_*n_ang_ ),
        bc_( mesh.boundary() ),
        data_( 0.0, group_stride_* n_group )
    {
        assert( n_group_ > 0 );
        n_face_[(int)Normal::X_NORM] = ny_*nz_;
        n_face_[(int)Normal::Y_NORM] = nx_*nz_;
        n_face_[(int)Normal::Z_NORM] = nx_*ny_;
        int offset = 0;
        for( const auto norm: AllNormals ) {
            face_offset_[(int)norm] = offset;
            offset += n_face_[(int)norm];
        }

        return;
    }

    void SnBoundary::update( size_t group, const SnBoundary &out ) {
        assert( group < n_group_ );
        assert( out.n_group() == 1 );

        // In the below, iang is the incoming angle index to be set, iang_refl
        // is the reflected angle from which a reflective BC should get its flux
        int iang = 0;
        for( auto &ang: ang_quad_ ) {
            Surface surf;
            Normal norm;
            int iang_refl;

            // X-normal surface
            norm = Normal::X_NORM;
            surf = (ang.ox > 0) ? Surface::WEST : Surface::EAST;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, iang_refl, norm );
                this->set_face( group, iang, norm, new_bc );
            } else {
                this->zero_face(group, iang, norm);
            }
            // Y-normal surface
            norm = Normal::Y_NORM;
            surf = (ang.oy > 0) ? Surface::SOUTH : Surface::NORTH;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, iang_refl, norm );
                this->set_face(group, iang, norm, new_bc);
            } else {
                this->zero_face(group, iang, norm);
            }
            // Z-normal surface
            norm = Normal::Z_NORM;
            surf = (ang.oz > 0) ? Surface::BOTTOM : Surface::TOP;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, iang_refl, norm );
                this->set_face(group, iang, norm, new_bc );
            } else {
                this->zero_face(group, iang, norm);
            }

            iang++;
        }
        return;
    }

    void SnBoundary::update( size_t group, size_t ang, const SnBoundary &out ) {
        Surface surf;
        Normal norm;

        /// \todo Refactor to use Blitz arrays, avoid excess copies
        for( auto norm: AllNormals ) {
            int iang_refl = ang_quad_.reflect( ang, norm );
            Angle angle = ang_quad_[iang_refl];
            Surface surf = angle.upwind_surface( norm );
            if( bc_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = out.get_face( 0, ang, norm );
                this->set_face( group, iang_refl, norm, new_bc );
            } else {
                this->zero_face( group, iang_refl, norm );
            }
        }
        return;
    }

    std::ostream& operator<<(std::ostream& os, const SnBoundary &b ) {
        for( size_t ig=0; ig<b.n_group_; ig++ ) {
            cout << "Group " << ig << endl;
            for( size_t iang=0; iang<b.n_ang_; iang++ ) {
                cout << "Angle " << iang << endl;
                cout << "X-Normal face:" << endl;
                ArrayF f = b.get_face( ig, iang, Normal::X_NORM );
                for( auto v: f ) {
                    cout << v << " ";
                }
                cout << endl;
                cout << "Y-Normal face:" << endl;
                f = b.get_face( ig, iang, Normal::Y_NORM );
                for( auto v: f ) {
                    cout << v << " ";
                }
                cout << endl;
                cout << "Z-Normal face:" << endl;
                f = b.get_face( ig, iang, Normal::Z_NORM );
                for( auto v: f ) {
                    cout << v << " ";
                }
                cout << endl;
                cout << endl;

            }
        }
        return os;
    }
}
<|endoftext|>