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

#include <pcl/outofcore/outofcore_base_data.h>

#include <pcl/pcl_macros.h>
#include <pcl/exceptions.h>
#include <pcl/console/print.h>

#include <fstream>

#define __PCL_OUTOFCORE_VERSION__ 3

namespace pcl
{
  namespace outofcore
  {
    OutofcoreOctreeBaseMetadata::OutofcoreOctreeBaseMetadata ()
      : metadata_filename_ ()
      , outofcore_version_ ()
      , coordinate_system_ ()
      , tree_name_ ()
      , point_type_ ("urp")
      , levels_of_depth_ ()
      , LOD_num_points_ ()
    {
    }

    ////////////////////////////////////////////////////////////////////////////////

    OutofcoreOctreeBaseMetadata::OutofcoreOctreeBaseMetadata (const boost::filesystem::path& metadata_filename)
      : metadata_filename_ (metadata_filename)
      , outofcore_version_ ()
      , coordinate_system_ ()
      , tree_name_ ()
      , point_type_ ("urp")
      , levels_of_depth_ ()
      , LOD_num_points_ ()
    {
      //read metadata from file and store in fields
      loadMetadataFromDisk ();
    }

    ////////////////////////////////////////////////////////////////////////////////

    OutofcoreOctreeBaseMetadata::~OutofcoreOctreeBaseMetadata ()
    {
      this->serializeMetadataToDisk ();
    }

    ////////////////////////////////////////////////////////////////////////////////

    OutofcoreOctreeBaseMetadata::OutofcoreOctreeBaseMetadata (const OutofcoreOctreeBaseMetadata& orig)
      : OutofcoreAbstractMetadata ()
      , metadata_filename_ (orig.metadata_filename_)
      , outofcore_version_ (orig.outofcore_version_)
      , coordinate_system_ (orig.coordinate_system_)
      , tree_name_ (orig.tree_name_)
      , point_type_ (orig.point_type_)
      , levels_of_depth_ (orig.levels_of_depth_)
      , LOD_num_points_ (orig.LOD_num_points_)
    {

    }

    ////////////////////////////////////////////////////////////////////////////////

    int
    OutofcoreOctreeBaseMetadata::getOutofcoreVersion () const
    {
      return (outofcore_version_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setOutofcoreVersion (const int version)
    {
      outofcore_version_ = version;
    }

    ////////////////////////////////////////////////////////////////////////////////

    boost::filesystem::path
    OutofcoreOctreeBaseMetadata::getMetadataFilename () const
    {
      return (metadata_filename_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setMetadataFilename (const boost::filesystem::path& path_to_metadata)
    {
      metadata_filename_ = path_to_metadata;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::serializeMetadataToDisk ()
    {
      // Create JSON object
      boost::shared_ptr<cJSON> idx (cJSON_CreateObject (), cJSON_Delete);

      cJSON* name = cJSON_CreateString (tree_name_.c_str ());
      cJSON* version = cJSON_CreateNumber ( __PCL_OUTOFCORE_VERSION__ );
      cJSON* pointtype = cJSON_CreateString (point_type_.c_str ());
      cJSON* lod = cJSON_CreateNumber (static_cast<double> (levels_of_depth_));

      // cJSON does not allow 64 bit ints.  Have to put the points in a double to
      // use this api, will allow counts up to 2^52 points to be stored correctly
      //or split into LSB MSB?
      std::vector<double> lodPoints_db;
      lodPoints_db.insert (lodPoints_db.begin (), LOD_num_points_.begin (), LOD_num_points_.end ());

      cJSON* numpts = cJSON_CreateDoubleArray ( &(lodPoints_db.front ()), static_cast<int>(lodPoints_db.size ()));

      cJSON_AddItemToObject (idx.get (), "name", name);
      cJSON_AddItemToObject (idx.get (), "version", version);
      cJSON_AddItemToObject (idx.get (), "pointtype", pointtype);
      cJSON_AddItemToObject (idx.get (), "lod", lod);
      cJSON_AddItemToObject (idx.get (), "numpts", numpts);
      cJSON_AddStringToObject(idx.get(), "coord_system", coordinate_system_.c_str());

      char* idx_txt = cJSON_Print (idx.get ());

      std::ofstream f (metadata_filename_.string ().c_str (), std::ios::out | std::ios::trunc);
      f << idx_txt;
      f.close ();

      free (idx_txt);
    }

    ////////////////////////////////////////////////////////////////////////////////

    int
    OutofcoreOctreeBaseMetadata::loadMetadataFromDisk ()
    {
      // Open JSON
      std::vector<char> idx_input;
      boost::uintmax_t len = boost::filesystem::file_size (metadata_filename_);
      idx_input.resize (len + 1);

      std::ifstream f (metadata_filename_.string ().c_str (), std::ios::in);
      f.read (&(idx_input.front ()), len);
      idx_input.back () = '\0';

      // Parse JSON
      boost::shared_ptr<cJSON> idx (cJSON_Parse (&(idx_input.front ())), cJSON_Delete);
      cJSON* name = cJSON_GetObjectItem (idx.get (), "name");
      cJSON* version = cJSON_GetObjectItem (idx.get (), "version");
      cJSON* pointtype = cJSON_GetObjectItem (idx.get (), "pointtype");
      cJSON* lod = cJSON_GetObjectItem (idx.get (), "lod");
      cJSON* numpts = cJSON_GetObjectItem (idx.get (), "numpts");
      cJSON* coord = cJSON_GetObjectItem (idx.get (), "coord_system");

      bool parse_failure = false;

      // Validate JSON
      if (!((name) && (version) && (pointtype) && (lod) && (numpts) && (coord)))
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] One of expected metadata fields does not exist in %s\n", metadata_filename_.c_str ());
        parse_failure = true;
      }
      if ((name->type != cJSON_String) || (version->type != cJSON_Number) || (pointtype->type != cJSON_String)
          || (lod->type != cJSON_Number) || (numpts->type != cJSON_Array) || (coord->type != cJSON_String))
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] One of metadata fields does not contain its expected type in %s\n",metadata_filename_.c_str ());
        parse_failure = true;
      }
      if (version->valuedouble != 2.0 && version->valuedouble != 3.0)//only support version 2.0 and 3.0
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] Outofcore version field (just read version:number = %.1lf) in %s does not match the current supported versions\n",metadata_filename_.c_str (), version->valuedouble);
        parse_failure = true;
      }
      if ((lod->valueint + 1) != cJSON_GetArraySize (numpts))
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] lod:num+1=%d+1 (i.e. height of tree) does not match size of LOD array (%d) in %s\n", lod->valueint, cJSON_GetArraySize (numpts), metadata_filename_.c_str ());
        parse_failure = true;
      }

      if (parse_failure)
      {
        PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] Parse Failure\n");
      }

      // Get Data
      LOD_num_points_.resize (lod->valueint + 1);
      for (int i = 0; i < (lod->valueint + 1); i++)
      {
        //cJSON doesn't have explicit 64bit int, have to use double, get up to 2^52
        LOD_num_points_[i] = static_cast<boost::uint64_t> (cJSON_GetArrayItem (numpts, i)->valuedouble );
      }
      levels_of_depth_ = lod->valueint;
      coordinate_system_ = coord->valuestring;

      //return success
      return (1);
    }

    ////////////////////////////////////////////////////////////////////////////////

    int
    OutofcoreOctreeBaseMetadata::loadMetadataFromDisk (const boost::filesystem::path& path_to_metadata)
    {
      this->setMetadataFilename (path_to_metadata);
      return (this->loadMetadataFromDisk ());
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::string
    OutofcoreOctreeBaseMetadata::getOctreeName ()
    {
      return (this->tree_name_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setOctreeName (const std::string& name_arg)
    {
      this->tree_name_ = name_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::string
    OutofcoreOctreeBaseMetadata::getPointType ()
    {
      return (this->point_type_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setPointType (const std::string& point_type_arg)
    {
      this->point_type_ = point_type_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::vector<boost::uint64_t>&
    OutofcoreOctreeBaseMetadata::getLODPoints ()
    {
      return (LOD_num_points_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::vector<boost::uint64_t>
    OutofcoreOctreeBaseMetadata::getLODPoints () const
    {
      return (LOD_num_points_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    boost::uint64_t
    OutofcoreOctreeBaseMetadata::getLODPoints (const boost::uint64_t& depth_index) const
    {
      return (LOD_num_points_[depth_index]);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setLODPoints (const boost::uint64_t& depth)
    {
      LOD_num_points_.clear ();
      LOD_num_points_.resize (depth);
      assert (LOD_num_points_.size () == this->levels_of_depth_+1);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setLODPoints (std::vector<boost::uint64_t>& lod_points_arg)
    {
      assert (this->LOD_num_points_.size () == lod_points_arg.size ());

      this->LOD_num_points_ = lod_points_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setLODPoints (const boost::uint64_t& lod_index_arg, const boost::uint64_t& num_points_arg, const bool increment)
    {
      assert (lod_index_arg < LOD_num_points_.size ());

      if (increment)
        LOD_num_points_[lod_index_arg] += num_points_arg;
      else
        LOD_num_points_[lod_index_arg] = num_points_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setCoordinateSystem (const std::string& coord_sys_arg)
    {
      this->coordinate_system_ = coord_sys_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::string
    OutofcoreOctreeBaseMetadata::getCoordinateSystem () const
    {
      return (this->coordinate_system_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setDepth (const boost::uint64_t& depth_arg)
    {
      this->levels_of_depth_ = depth_arg;
    }

    boost::uint64_t
    OutofcoreOctreeBaseMetadata::getDepth () const
    {
      return (levels_of_depth_);
    }

    ////////////////////////////////////////////////////////////////////////////////
    //Protected Member Functions
    ////////////////////////////////////////////////////////////////////////////////
    void
    OutofcoreOctreeBaseMetadata::writeMetadataString (std::vector<char>& buf)
    {
      (void)buf;
      PCL_THROW_EXCEPTION (PCLException, "Not implemented\n");
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::ostream&
    operator<<(std::ostream& os, const OutofcoreOctreeBaseMetadata& metadata_arg)
    {
      (void) metadata_arg;
      return (os);
    }

    ////////////////////////////////////////////////////////////////////////////////

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

#include <pcl/outofcore/outofcore_base_data.h>

#include <pcl/pcl_macros.h>
#include <pcl/exceptions.h>
#include <pcl/console/print.h>

#include <fstream>

#define __PCL_OUTOFCORE_VERSION__ 3

namespace pcl
{
  namespace outofcore
  {
    OutofcoreOctreeBaseMetadata::OutofcoreOctreeBaseMetadata ()
      : metadata_filename_ ()
      , outofcore_version_ ()
      , coordinate_system_ ()
      , tree_name_ ()
      , point_type_ ("urp")
      , levels_of_depth_ ()
      , LOD_num_points_ ()
    {
    }

    ////////////////////////////////////////////////////////////////////////////////

    OutofcoreOctreeBaseMetadata::OutofcoreOctreeBaseMetadata (const boost::filesystem::path& metadata_filename)
      : metadata_filename_ (metadata_filename)
      , outofcore_version_ ()
      , coordinate_system_ ()
      , tree_name_ ()
      , point_type_ ("urp")
      , levels_of_depth_ ()
      , LOD_num_points_ ()
    {
      //read metadata from file and store in fields
      loadMetadataFromDisk ();
    }

    ////////////////////////////////////////////////////////////////////////////////

    OutofcoreOctreeBaseMetadata::~OutofcoreOctreeBaseMetadata ()
    {
      this->serializeMetadataToDisk ();
    }

    ////////////////////////////////////////////////////////////////////////////////

    OutofcoreOctreeBaseMetadata::OutofcoreOctreeBaseMetadata (const OutofcoreOctreeBaseMetadata& orig)
      : OutofcoreAbstractMetadata ()
      , metadata_filename_ (orig.metadata_filename_)
      , outofcore_version_ (orig.outofcore_version_)
      , coordinate_system_ (orig.coordinate_system_)
      , tree_name_ (orig.tree_name_)
      , point_type_ (orig.point_type_)
      , levels_of_depth_ (orig.levels_of_depth_)
      , LOD_num_points_ (orig.LOD_num_points_)
    {

    }

    ////////////////////////////////////////////////////////////////////////////////

    int
    OutofcoreOctreeBaseMetadata::getOutofcoreVersion () const
    {
      return (outofcore_version_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setOutofcoreVersion (const int version)
    {
      outofcore_version_ = version;
    }

    ////////////////////////////////////////////////////////////////////////////////

    boost::filesystem::path
    OutofcoreOctreeBaseMetadata::getMetadataFilename () const
    {
      return (metadata_filename_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setMetadataFilename (const boost::filesystem::path& path_to_metadata)
    {
      metadata_filename_ = path_to_metadata;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::serializeMetadataToDisk ()
    {
      if (LOD_num_points_.empty ())
        return;

      // Create JSON object
      boost::shared_ptr<cJSON> idx (cJSON_CreateObject (), cJSON_Delete);

      cJSON* name = cJSON_CreateString (tree_name_.c_str ());
      cJSON* version = cJSON_CreateNumber ( __PCL_OUTOFCORE_VERSION__ );
      cJSON* pointtype = cJSON_CreateString (point_type_.c_str ());
      cJSON* lod = cJSON_CreateNumber (static_cast<double> (levels_of_depth_));

      // cJSON does not allow 64 bit ints.  Have to put the points in a double to
      // use this api, will allow counts up to 2^52 points to be stored correctly
      //or split into LSB MSB?
      std::vector<double> lodPoints_db;
      lodPoints_db.insert (lodPoints_db.begin (), LOD_num_points_.begin (), LOD_num_points_.end ());

      cJSON* numpts = cJSON_CreateDoubleArray ( &(lodPoints_db.front ()), static_cast<int>(lodPoints_db.size ()));

      cJSON_AddItemToObject (idx.get (), "name", name);
      cJSON_AddItemToObject (idx.get (), "version", version);
      cJSON_AddItemToObject (idx.get (), "pointtype", pointtype);
      cJSON_AddItemToObject (idx.get (), "lod", lod);
      cJSON_AddItemToObject (idx.get (), "numpts", numpts);
      cJSON_AddStringToObject(idx.get(), "coord_system", coordinate_system_.c_str());

      char* idx_txt = cJSON_Print (idx.get ());

      std::ofstream f (metadata_filename_.string ().c_str (), std::ios::out | std::ios::trunc);
      f << idx_txt;
      f.close ();

      free (idx_txt);
    }

    ////////////////////////////////////////////////////////////////////////////////

    int
    OutofcoreOctreeBaseMetadata::loadMetadataFromDisk ()
    {
      // Open JSON
      std::vector<char> idx_input;
      boost::uintmax_t len = boost::filesystem::file_size (metadata_filename_);
      idx_input.resize (len + 1);

      std::ifstream f (metadata_filename_.string ().c_str (), std::ios::in);
      f.read (&(idx_input.front ()), len);
      idx_input.back () = '\0';

      // Parse JSON
      boost::shared_ptr<cJSON> idx (cJSON_Parse (&(idx_input.front ())), cJSON_Delete);
      cJSON* name = cJSON_GetObjectItem (idx.get (), "name");
      cJSON* version = cJSON_GetObjectItem (idx.get (), "version");
      cJSON* pointtype = cJSON_GetObjectItem (idx.get (), "pointtype");
      cJSON* lod = cJSON_GetObjectItem (idx.get (), "lod");
      cJSON* numpts = cJSON_GetObjectItem (idx.get (), "numpts");
      cJSON* coord = cJSON_GetObjectItem (idx.get (), "coord_system");

      bool parse_failure = false;

      // Validate JSON
      if (!((name) && (version) && (pointtype) && (lod) && (numpts) && (coord)))
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] One of expected metadata fields does not exist in %s\n", metadata_filename_.c_str ());
        parse_failure = true;
      }
      if ((name->type != cJSON_String) || (version->type != cJSON_Number) || (pointtype->type != cJSON_String)
          || (lod->type != cJSON_Number) || (numpts->type != cJSON_Array) || (coord->type != cJSON_String))
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] One of metadata fields does not contain its expected type in %s\n",metadata_filename_.c_str ());
        parse_failure = true;
      }
      if (version->valuedouble != 2.0 && version->valuedouble != 3.0)//only support version 2.0 and 3.0
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] Outofcore version field (just read version:number = %.1lf) in %s does not match the current supported versions\n",metadata_filename_.c_str (), version->valuedouble);
        parse_failure = true;
      }
      if ((lod->valueint + 1) != cJSON_GetArraySize (numpts))
      {
        PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] lod:num+1=%d+1 (i.e. height of tree) does not match size of LOD array (%d) in %s\n", lod->valueint, cJSON_GetArraySize (numpts), metadata_filename_.c_str ());
        parse_failure = true;
      }

      if (parse_failure)
      {
        PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseMetadata::loadMetadataFromDisk] Parse Failure\n");
      }

      // Get Data
      LOD_num_points_.resize (lod->valueint + 1);
      for (int i = 0; i < (lod->valueint + 1); i++)
      {
        //cJSON doesn't have explicit 64bit int, have to use double, get up to 2^52
        LOD_num_points_[i] = static_cast<boost::uint64_t> (cJSON_GetArrayItem (numpts, i)->valuedouble );
      }
      levels_of_depth_ = lod->valueint;
      coordinate_system_ = coord->valuestring;

      //return success
      return (1);
    }

    ////////////////////////////////////////////////////////////////////////////////

    int
    OutofcoreOctreeBaseMetadata::loadMetadataFromDisk (const boost::filesystem::path& path_to_metadata)
    {
      this->setMetadataFilename (path_to_metadata);
      return (this->loadMetadataFromDisk ());
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::string
    OutofcoreOctreeBaseMetadata::getOctreeName ()
    {
      return (this->tree_name_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setOctreeName (const std::string& name_arg)
    {
      this->tree_name_ = name_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::string
    OutofcoreOctreeBaseMetadata::getPointType ()
    {
      return (this->point_type_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setPointType (const std::string& point_type_arg)
    {
      this->point_type_ = point_type_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::vector<boost::uint64_t>&
    OutofcoreOctreeBaseMetadata::getLODPoints ()
    {
      return (LOD_num_points_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::vector<boost::uint64_t>
    OutofcoreOctreeBaseMetadata::getLODPoints () const
    {
      return (LOD_num_points_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    boost::uint64_t
    OutofcoreOctreeBaseMetadata::getLODPoints (const boost::uint64_t& depth_index) const
    {
      return (LOD_num_points_[depth_index]);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setLODPoints (const boost::uint64_t& depth)
    {
      LOD_num_points_.clear ();
      LOD_num_points_.resize (depth);
      assert (LOD_num_points_.size () == this->levels_of_depth_+1);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setLODPoints (std::vector<boost::uint64_t>& lod_points_arg)
    {
      assert (this->LOD_num_points_.size () == lod_points_arg.size ());

      this->LOD_num_points_ = lod_points_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setLODPoints (const boost::uint64_t& lod_index_arg, const boost::uint64_t& num_points_arg, const bool increment)
    {
      assert (lod_index_arg < LOD_num_points_.size ());

      if (increment)
        LOD_num_points_[lod_index_arg] += num_points_arg;
      else
        LOD_num_points_[lod_index_arg] = num_points_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setCoordinateSystem (const std::string& coord_sys_arg)
    {
      this->coordinate_system_ = coord_sys_arg;
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::string
    OutofcoreOctreeBaseMetadata::getCoordinateSystem () const
    {
      return (this->coordinate_system_);
    }

    ////////////////////////////////////////////////////////////////////////////////

    void
    OutofcoreOctreeBaseMetadata::setDepth (const boost::uint64_t& depth_arg)
    {
      this->levels_of_depth_ = depth_arg;
    }

    boost::uint64_t
    OutofcoreOctreeBaseMetadata::getDepth () const
    {
      return (levels_of_depth_);
    }

    ////////////////////////////////////////////////////////////////////////////////
    //Protected Member Functions
    ////////////////////////////////////////////////////////////////////////////////
    void
    OutofcoreOctreeBaseMetadata::writeMetadataString (std::vector<char>& buf)
    {
      (void)buf;
      PCL_THROW_EXCEPTION (PCLException, "Not implemented\n");
    }

    ////////////////////////////////////////////////////////////////////////////////

    std::ostream&
    operator<<(std::ostream& os, const OutofcoreOctreeBaseMetadata& metadata_arg)
    {
      (void) metadata_arg;
      return (os);
    }

    ////////////////////////////////////////////////////////////////////////////////

  }//namespace outofcore
}//namespace pcl
#undef __PCL_OUTOFCORE_VERSION__
<|endoftext|>


<commit_before>/*
 *	info≈
 *	External object for Max/MSP to get information about TTAudioSignals from a Jamoma AudioGraph dsp chain.
 *	Copyright © 2008 by Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "maxAudioGraph.h"

// Data Structure for this object
struct Info {
    t_object				obj;
	TTAudioGraphObjectPtr	audioGraphObject;	// we wrap a simple 'thru' audiograph object
	TTPtr					outletSmartSignal;	// outlet for passing the input to the output, and so we can be pulled
	TTPtr					outletSampleRate;
	TTPtr					outletVectorSize;
	TTPtr					outletNumChannels;
	long					audioSourceOutlet;	// number of the outlet connected to our inlet
	long					maxNumChannels;		// the number of inlets or outlets, which is an argument at instantiation
	long					numChannels;		// the actual number of channels to use, set by the dsp method
	long					vectorSize;			// cached by the DSP method
	TTPtr					qelem;				// a queue for deferring 'bang' calls
};
typedef Info* InfoPtr;

// Prototypes for methods
InfoPtr	InfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv);
void	InfoFree(InfoPtr self);
void	InfoAssist(InfoPtr self, void* b, long msg, long arg, char* dst);
void	InfoBang(InfoPtr self);
void	InfoQfn(InfoPtr self);
TTErr	InfoConnect(InfoPtr self, TTAudioGraphObjectPtr audioSourceObject, long sourceOutletNumber);

// Globals
static ClassPtr sInfoClass;

/************************************************************************************/
// Main() Function

int TTCLASSWRAPPERMAX_EXPORT main(void)
{
	ClassPtr c;

	TTAudioGraphInit();
	common_symbols_init();

	c = class_new("jcom.info≈", (method)InfoNew, (method)InfoFree, sizeof(Info), (method)0L, A_GIMME, 0);

	class_addmethod(c, (method)InfoBang,			"bang",					0);
	class_addmethod(c, (method)MaxAudioGraphReset,	"graph.reset",		A_CANT, 0);
	class_addmethod(c, (method)InfoConnect,			"audio.connect",	A_OBJ, A_LONG, 0);
	class_addmethod(c, (method)MaxAudioGraphSetup,	"audio.setup",		A_CANT, 0);
	class_addmethod(c, (method)MaxAudioGraphDrop,	"audio.drop",		A_CANT, 0);
	class_addmethod(c, (method)MaxAudioGraphObject,	"audio.object",		A_CANT, 0);
	class_addmethod(c, (method)InfoAssist,			"assist",				A_CANT, 0);
    class_addmethod(c, (method)object_obex_dumpout,	"dumpout",				A_CANT, 0);

	class_register(_sym_box, c);
	sInfoClass = c;
	return 0;
}

/************************************************************************************/
// Object Creation Method

InfoPtr InfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv)
{
    InfoPtr	self;
	TTValue	v;
	TTErr	err;

    self = InfoPtr(object_alloc(sInfoClass));
    if (self) {
    	object_obex_store((TTPtr)self, _sym_dumpout, (ObjectPtr)outlet_new(self, NULL));
		self->outletNumChannels = outlet_new((t_pxobject*)self, 0);
		self->outletVectorSize = outlet_new((t_pxobject*)self, 0);
		self->outletSampleRate = outlet_new((t_pxobject*)self, 0);
		self->outletSmartSignal = outlet_new((t_pxobject*)self, "audio.connect");

		self->qelem = qelem_new(self, (method)InfoQfn);

		v.setSize(2);
		v.set(0, TT("thru"));
		v.set(1, TTUInt32(1));	// we set it up with 1 inlet, and later modify to 2 inlets if the connection is made
		err = TTObjectInstantiate(TT("audio.object"), (TTObjectPtr*)&self->audioGraphObject, v);
		if (!self->audioGraphObject->getUnitGenerator()) {
			object_error(SELF, "cannot load Jamoma DSP object");
			return NULL;
		}

		attr_args_process(self, argc, argv);
	}
	return self;
}

void InfoFree(InfoPtr self)
{
	TTObjectRelease((TTObjectPtr*)&self->audioGraphObject);
	qelem_free(self->qelem);
}

/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void InfoAssist(InfoPtr self, void* b, long msg, long arg, char* dst)
{
	if (msg==1)			// Inlets
		strcpy(dst, "multichannel audio connection and control messages");
	else if (msg==2) {	// Outlets
		if (arg == 0)
			strcpy(dst, "multichannel audio connection, passing the input thru to the output");
		else if (arg == 1)
			strcpy(dst, "sample rate of the input signal");
		else if (arg == 2)
			strcpy(dst, "vector size of the input signal");
		else if (arg == 3)
			strcpy(dst, "number of channels in the input signal");
		else if (arg == 4)
			strcpy(dst, "dumpout");
	}
}

void InfoBang(InfoPtr self)
{
	qelem_set(self->qelem);
}

void InfoQfn(InfoPtr self)
{
	outlet_int(self->outletNumChannels, self->audioGraphObject->getOutputNumChannels(self->audioSourceOutlet));
	outlet_int(self->outletVectorSize, self->audioGraphObject->getOutputVectorSize(self->audioSourceOutlet));
	outlet_int(self->outletSampleRate, self->audioGraphObject->getOutputSampleRate(self->audioSourceOutlet));
}

TTErr InfoConnect(InfoPtr self, TTAudioGraphObjectPtr newAudioSourceObject, long sourceOutletNumber)
{
	TTErr err = MaxAudioGraphConnect(ObjectPtr(self), newAudioSourceObject, sourceOutletNumber);

	self->audioSourceOutlet = sourceOutletNumber;
	InfoBang(self);
	return err;
}

<commit_msg>fixes #776<commit_after>/*
 *	info≈
 *	External object for Max/MSP to get information about TTAudioSignals from a Jamoma AudioGraph dsp chain.
 *	Copyright © 2008 by Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "maxAudioGraph.h"

// Data Structure for this object
struct Info {
    t_object				obj;
	TTAudioGraphObjectPtr	audioGraphObject;	// we wrap a simple 'thru' audiograph object
	TTPtr					outletSmartSignal;	// outlet for passing the input to the output, and so we can be pulled
	TTPtr					unused;				// this is an unused ptr, always set to NULL, to signal the end of the JAG outlets
	TTPtr					outletSampleRate;
	TTPtr					outletVectorSize;
	TTPtr					outletNumChannels;
	long					audioSourceOutlet;	// number of the outlet connected to our inlet
	long					maxNumChannels;		// the number of inlets or outlets, which is an argument at instantiation
	long					numChannels;		// the actual number of channels to use, set by the dsp method
	long					vectorSize;			// cached by the DSP method
	TTPtr					qelem;				// a queue for deferring 'bang' calls
};
typedef Info* InfoPtr;

// Prototypes for methods
InfoPtr	InfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv);
void	InfoFree(InfoPtr self);
void	InfoAssist(InfoPtr self, void* b, long msg, long arg, char* dst);
void	InfoBang(InfoPtr self);
void	InfoQfn(InfoPtr self);
TTErr	InfoConnect(InfoPtr self, TTAudioGraphObjectPtr audioSourceObject, long sourceOutletNumber);

// Globals
static ClassPtr sInfoClass;

/************************************************************************************/
// Main() Function

int TTCLASSWRAPPERMAX_EXPORT main(void)
{
	ClassPtr c;

	TTAudioGraphInit();
	common_symbols_init();

	c = class_new("jcom.info≈", (method)InfoNew, (method)InfoFree, sizeof(Info), (method)0L, A_GIMME, 0);

	class_addmethod(c, (method)InfoBang,			"bang",					0);
	class_addmethod(c, (method)MaxAudioGraphReset,	"graph.reset",		A_CANT, 0);
	class_addmethod(c, (method)InfoConnect,			"audio.connect",	A_OBJ, A_LONG, 0);
	class_addmethod(c, (method)MaxAudioGraphSetup,	"audio.setup",		A_CANT, 0);
	class_addmethod(c, (method)MaxAudioGraphDrop,	"audio.drop",		A_CANT, 0);
	class_addmethod(c, (method)MaxAudioGraphObject,	"audio.object",		A_CANT, 0);
	class_addmethod(c, (method)InfoAssist,			"assist",				A_CANT, 0);
    class_addmethod(c, (method)object_obex_dumpout,	"dumpout",				A_CANT, 0);

	class_register(_sym_box, c);
	sInfoClass = c;
	return 0;
}

/************************************************************************************/
// Object Creation Method

InfoPtr InfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv)
{
    InfoPtr	self;
	TTValue	v;
	TTErr	err;

    self = InfoPtr(object_alloc(sInfoClass));
    if (self) {
    	object_obex_store((TTPtr)self, _sym_dumpout, (ObjectPtr)outlet_new(self, NULL));
		self->outletNumChannels = outlet_new((t_pxobject*)self, 0);
		self->outletVectorSize = outlet_new((t_pxobject*)self, 0);
		self->outletSampleRate = outlet_new((t_pxobject*)self, 0);
		self->outletSmartSignal = outlet_new((t_pxobject*)self, "audio.connect");

		self->qelem = qelem_new(self, (method)InfoQfn);

		v.setSize(2);
		v.set(0, TT("thru"));
		v.set(1, TTUInt32(1));	// we set it up with 1 inlet, and later modify to 2 inlets if the connection is made
		err = TTObjectInstantiate(TT("audio.object"), (TTObjectPtr*)&self->audioGraphObject, v);
		if (!self->audioGraphObject->getUnitGenerator()) {
			object_error(SELF, "cannot load Jamoma DSP object");
			return NULL;
		}

		attr_args_process(self, argc, argv);
	}
	return self;
}

void InfoFree(InfoPtr self)
{
	TTObjectRelease((TTObjectPtr*)&self->audioGraphObject);
	qelem_free(self->qelem);
}

/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void InfoAssist(InfoPtr self, void* b, long msg, long arg, char* dst)
{
	if (msg==1)			// Inlets
		strcpy(dst, "multichannel audio connection and control messages");
	else if (msg==2) {	// Outlets
		if (arg == 0)
			strcpy(dst, "multichannel audio connection, passing the input thru to the output");
		else if (arg == 1)
			strcpy(dst, "sample rate of the input signal");
		else if (arg == 2)
			strcpy(dst, "vector size of the input signal");
		else if (arg == 3)
			strcpy(dst, "number of channels in the input signal");
		else if (arg == 4)
			strcpy(dst, "dumpout");
	}
}

void InfoBang(InfoPtr self)
{
	qelem_set(self->qelem);
}

void InfoQfn(InfoPtr self)
{
	outlet_int(self->outletNumChannels, self->audioGraphObject->getOutputNumChannels(self->audioSourceOutlet));
	outlet_int(self->outletVectorSize, self->audioGraphObject->getOutputVectorSize(self->audioSourceOutlet));
	outlet_int(self->outletSampleRate, self->audioGraphObject->getOutputSampleRate(self->audioSourceOutlet));
}

TTErr InfoConnect(InfoPtr self, TTAudioGraphObjectPtr newAudioSourceObject, long sourceOutletNumber)
{
	TTErr err = MaxAudioGraphConnect(ObjectPtr(self), newAudioSourceObject, sourceOutletNumber);

	self->audioSourceOutlet = sourceOutletNumber;
	InfoBang(self);
	return err;
}

<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * Generic implementation of non-relational domains.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <crab/domains/patricia_trees.hpp>
#include <crab/support/debug.hpp>

#include <boost/optional.hpp>

#include <set>
#include <vector>

namespace ikos {

template <typename Key, typename Value> class separate_domain {

private:
  using patricia_tree_t = patricia_tree<Key, Value>;
  using unary_op_t = typename patricia_tree_t::unary_op_t;
  using binary_op_t = typename patricia_tree_t::binary_op_t;
  using partial_order_t = typename patricia_tree_t::partial_order_t;

public:
  using separate_domain_t = separate_domain<Key, Value>;
  using iterator = typename patricia_tree_t::iterator;
  using key_type = Key;
  using value_type = Value;

private:
  bool _is_bottom;
  patricia_tree_t _tree;

public:
  class join_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator|(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }
  }; // class join_op

  class widening_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator||(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_op

  template <typename Thresholds>
  class widening_thresholds_op : public binary_op_t {
    const Thresholds &m_ts;

  public:
    widening_thresholds_op(const Thresholds &ts) : m_ts(ts) {}

    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.widening_thresholds(y, m_ts);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_thresholds_op

  class meet_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class meet_op

  class narrowing_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class narrowing_op

  class domain_po : public partial_order_t {
    bool leq(Value x, Value y) { return x.operator<=(y); }

    bool default_is_top() { return true; }

  }; // class domain_po

public:
  static separate_domain_t top() { return separate_domain_t(); }

  static separate_domain_t bottom() { return separate_domain_t(false); }

private:
  static patricia_tree_t apply_operation(binary_op_t &o, patricia_tree_t t1,
                                         const patricia_tree_t &t2,
                                         bool &is_bottom) {
    is_bottom = t1.merge_with(t2, o);
    return t1;
  }

  separate_domain(patricia_tree_t t) : _is_bottom(false), _tree(t) {}

  separate_domain(bool b) : _is_bottom(!b) {}

public:
  separate_domain() : _is_bottom(false) {}

  separate_domain(const separate_domain_t &e)
      : _is_bottom(e._is_bottom), _tree(e._tree) {}

  separate_domain(const separate_domain_t &&e)
      : _is_bottom(e._is_bottom), _tree(std::move(e._tree)) {}

  separate_domain_t &operator=(separate_domain_t e) {
    this->_is_bottom = e._is_bottom;
    this->_tree = e._tree;
    return *this;
  }

  iterator begin() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.begin();
    }
  }

  iterator end() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.end();
    }
  }

  bool is_bottom() const { return this->_is_bottom; }

  bool is_top() const {
    return (!this->is_bottom() && this->_tree.size() == 0);
  }

  bool operator<=(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return true;
    } else if (e.is_bottom()) {
      return false;
    } else {
      domain_po po;
      return this->_tree.leq(e._tree, po);
    }
  }

  bool operator==(const separate_domain_t &e) const {
    return (this->operator<=(e) && e.operator<=(*this));
  }

  // Join
  separate_domain_t operator|(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      join_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Meet
  separate_domain_t operator&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return this->bottom();
    } else {
      meet_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  // Widening
  separate_domain_t operator||(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Widening with thresholds
  template <typename Thresholds>
  separate_domain_t widening_thresholds(const separate_domain_t &e,
                                        const Thresholds &ts) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_thresholds_op<Thresholds> o(ts);
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Narrowing
  separate_domain_t operator&&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return separate_domain_t(false);
    } else {
      narrowing_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  void set(Key k, Value v) {
    if (!this->is_bottom()) {
      if (v.is_bottom()) {
        this->_is_bottom = true;
        this->_tree = patricia_tree_t();
      } else if (v.is_top()) {
        this->_tree.remove(k);
      } else {
        this->_tree.insert(k, v);
      }
    }
  }

  void set_to_bottom() {
    this->_is_bottom = true;
    this->_tree = patricia_tree_t();
  }

  separate_domain_t &operator-=(const Key &k) {
    if (!this->is_bottom()) {
      this->_tree.remove(k);
    }
    return *this;
  }

  Value operator[](const Key &k) const {
    if (this->is_bottom()) {
      return Value::bottom();
    } else {
      boost::optional<Value> v = this->_tree.lookup(k);
      if (v) {
        return *v;
      } else {
        return Value::top();
      }
    }
  }

  std::size_t size() const {
    if (is_bottom()) {
      return 0;
    } else if (is_top()) {
      CRAB_ERROR("separate_domains::size() is undefined if top");
    } else {
      return this->_tree.size();
    }
  }

  void write(crab::crab_os &o) const {
    if (this->is_bottom()) {
      o << "_|_";
    } else {
      o << "{";
      for (typename patricia_tree_t::iterator it = this->_tree.begin();
           it != this->_tree.end();) {
        Key k = it->first;
        k.write(o);
        o << " -> ";
        Value v = it->second;
        v.write(o);
        ++it;
        if (it != this->_tree.end()) {
          o << "; ";
        }
      }
      o << "}";
    }
  }

  // Assume that from does not have duplicates.
  void rename(const std::vector<Key> &from, const std::vector<Key> &to) {
    if (is_top() || is_bottom()) {
      // nothing to rename
      return;
    }
    if (from.size() != to.size()) {
      CRAB_ERROR(
          "separate_domain::rename with input vectors of different sizes");
    }

    if (::crab::CrabSanityCheckFlag) {
      std::set<Key> s1, s2;
      s1.insert(from.begin(), from.end());
      if (s1.size() != from.size()) {
        CRAB_ERROR("separate_domain::rename expects no duplicates");
      }
      s2.insert(to.begin(), to.end());
      if (s2.size() != to.size()) {
        CRAB_ERROR("separate_domain::rename expects no duplicates");
      }
    }

    for (unsigned i = 0, sz = from.size(); i < sz; ++i) {
      Key k = from[i];
      Key new_k = to[i];
      if (k == new_k) { // nothing to rename
        continue;
      }
      if (::crab::CrabSanityCheckFlag) {
        if (_tree.lookup(new_k)) {
          CRAB_ERROR("separate_domain::rename assumes that  ", new_k,
                     " does not exist in ", *this);
        }
      }
      if (boost::optional<Value> k_val_opt = _tree.lookup(k)) {
        if (!(*k_val_opt).is_top()) {
          _tree.insert(new_k, *k_val_opt);
        }
        _tree.remove(k);
      }
    }
  }

  friend crab::crab_os &operator<<(crab::crab_os &o,
                                   const separate_domain<Key, Value> &d) {
    d.write(o);
    return o;
  }
}; // class separate_domain

} // namespace ikos
<commit_msg>refactor(separate): minor refactoring<commit_after>/*******************************************************************************
 *
 * Generic implementation of non-relational domains.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <crab/domains/patricia_trees.hpp>
#include <crab/support/debug.hpp>

#include <boost/optional.hpp>

#include <set>
#include <vector>

namespace ikos {

template <typename Key, typename Value> class separate_domain {

private:
  using patricia_tree_t = patricia_tree<Key, Value>;
  using unary_op_t = typename patricia_tree_t::unary_op_t;
  using binary_op_t = typename patricia_tree_t::binary_op_t;
  using partial_order_t = typename patricia_tree_t::partial_order_t;

public:
  using separate_domain_t = separate_domain<Key, Value>;
  using iterator = typename patricia_tree_t::iterator;
  using key_type = Key;
  using value_type = Value;

private:
  bool _is_bottom;
  patricia_tree_t _tree;

public:
  class join_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator|(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }
  }; // class join_op

  class widening_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator||(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_op

  template <typename Thresholds>
  class widening_thresholds_op : public binary_op_t {
    const Thresholds &m_ts;

  public:
    widening_thresholds_op(const Thresholds &ts) : m_ts(ts) {}

    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.widening_thresholds(y, m_ts);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return true; }

  }; // class widening_thresholds_op

  class meet_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class meet_op

  class narrowing_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };

    bool default_is_absorbing() { return false; }

  }; // class narrowing_op

  class domain_po : public partial_order_t {
    bool leq(Value x, Value y) { return x.operator<=(y); }

    bool default_is_top() { return true; }

  }; // class domain_po

public:
  static separate_domain_t top() { return separate_domain_t(); }

  static separate_domain_t bottom() { return separate_domain_t(false); }

private:
  static patricia_tree_t apply_operation(binary_op_t &o, patricia_tree_t t1,
                                         const patricia_tree_t &t2,
                                         bool &is_bottom) {
    is_bottom = t1.merge_with(t2, o);
    return t1;
  }

  separate_domain(patricia_tree_t t) : _is_bottom(false), _tree(t) {}

  separate_domain(bool b) : _is_bottom(!b) {}

public:
  separate_domain() : _is_bottom(false) {}

  separate_domain(const separate_domain_t &e)
      : _is_bottom(e._is_bottom), _tree(e._tree) {}

  separate_domain(const separate_domain_t &&e)
      : _is_bottom(e._is_bottom), _tree(std::move(e._tree)) {}

  separate_domain_t &operator=(separate_domain_t e) {
    this->_is_bottom = e._is_bottom;
    this->_tree = e._tree;
    return *this;
  }

  iterator begin() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.begin();
    }
  }

  iterator end() const {
    if (this->is_bottom()) {
      CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
    } else {
      return this->_tree.end();
    }
  }

  bool is_bottom() const { return this->_is_bottom; }

  bool is_top() const {
    return (!this->is_bottom() && this->_tree.size() == 0);
  }

  bool operator<=(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return true;
    } else if (e.is_bottom()) {
      return false;
    } else {
      domain_po po;
      return this->_tree.leq(e._tree, po);
    }
  }

  bool operator==(const separate_domain_t &e) const {
    return (this->operator<=(e) && e.operator<=(*this));
  }

  // Join
  separate_domain_t operator|(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      join_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Meet
  separate_domain_t operator&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return this->bottom();
    } else {
      meet_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  // Widening
  separate_domain_t operator||(const separate_domain_t &e) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Widening with thresholds
  template <typename Thresholds>
  separate_domain_t widening_thresholds(const separate_domain_t &e,
                                        const Thresholds &ts) const {
    if (this->is_bottom()) {
      return e;
    } else if (e.is_bottom()) {
      return *this;
    } else {
      widening_thresholds_op<Thresholds> o(ts);
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      return separate_domain_t(std::move(res));
    }
  }

  // Narrowing
  separate_domain_t operator&&(const separate_domain_t &e) const {
    if (this->is_bottom() || e.is_bottom()) {
      return separate_domain_t(false);
    } else {
      narrowing_op o;
      bool is_bottom;
      patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
      if (is_bottom) {
        return this->bottom();
      } else {
        return separate_domain_t(std::move(res));
      }
    }
  }

  void set(Key k, Value v) {
    if (!this->is_bottom()) {
      if (v.is_bottom()) {
	set_to_bottom();
      } else if (v.is_top()) {
        this->_tree.remove(k);
      } else {
        this->_tree.insert(k, v);
      }
    }
  }

  void set_to_bottom() {
    this->_is_bottom = true;
    this->_tree = patricia_tree_t();
  }

  separate_domain_t &operator-=(const Key &k) {
    if (!this->is_bottom()) {
      this->_tree.remove(k);
    }
    return *this;
  }

  Value operator[](const Key &k) const {
    if (this->is_bottom()) {
      return Value::bottom();
    } else {
      boost::optional<Value> v = this->_tree.lookup(k);
      if (v) {
        return *v;
      } else {
        return Value::top();
      }
    }
  }

  std::size_t size() const {
    if (is_bottom()) {
      return 0;
    } else if (is_top()) {
      CRAB_ERROR("separate_domains::size() is undefined if top");
    } else {
      return this->_tree.size();
    }
  }

  void write(crab::crab_os &o) const {
    if (this->is_bottom()) {
      o << "_|_";
    } else {
      o << "{";
      for (typename patricia_tree_t::iterator it = this->_tree.begin();
           it != this->_tree.end();) {
        Key k = it->first;
        k.write(o);
        o << " -> ";
        Value v = it->second;
        v.write(o);
        ++it;
        if (it != this->_tree.end()) {
          o << "; ";
        }
      }
      o << "}";
    }
  }

  // Assume that from does not have duplicates.
  void rename(const std::vector<Key> &from, const std::vector<Key> &to) {
    if (is_top() || is_bottom()) {
      // nothing to rename
      return;
    }
    if (from.size() != to.size()) {
      CRAB_ERROR(
          "separate_domain::rename with input vectors of different sizes");
    }

    if (::crab::CrabSanityCheckFlag) {
      std::set<Key> s1, s2;
      s1.insert(from.begin(), from.end());
      if (s1.size() != from.size()) {
        CRAB_ERROR("separate_domain::rename expects no duplicates");
      }
      s2.insert(to.begin(), to.end());
      if (s2.size() != to.size()) {
        CRAB_ERROR("separate_domain::rename expects no duplicates");
      }
    }

    for (unsigned i = 0, sz = from.size(); i < sz; ++i) {
      Key k = from[i];
      Key new_k = to[i];
      if (k == new_k) { // nothing to rename
        continue;
      }
      if (::crab::CrabSanityCheckFlag) {
        if (_tree.lookup(new_k)) {
          CRAB_ERROR("separate_domain::rename assumes that  ", new_k,
                     " does not exist in ", *this);
        }
      }
      if (boost::optional<Value> k_val_opt = _tree.lookup(k)) {
        if (!(*k_val_opt).is_top()) {
          _tree.insert(new_k, *k_val_opt);
        }
        _tree.remove(k);
      }
    }
  }

  friend crab::crab_os &operator<<(crab::crab_os &o,
                                   const separate_domain<Key, Value> &d) {
    d.write(o);
    return o;
  }
}; // class separate_domain

} // namespace ikos
<|endoftext|>


<commit_before>/**
 * \file
 * \brief Scheduler class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-08-28
 */

#ifndef INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
#define INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_

#include "distortos/scheduler/ThreadControlBlockList.hpp"
#include "distortos/scheduler/SoftwareTimerControlBlockSupervisor.hpp"

#include <chrono>

namespace distortos
{

/// scheduler namespace has symbols related to scheduling
namespace scheduler
{

template<typename Function, typename... Args>
class Thread;
class MainThreadControlBlock;

/// Scheduler class is a system's scheduler
class Scheduler
{
public:

	/// generic iterator for all variants of ThreadControlBlockList
	using Iterator = containers::SortedContainerBase<std::list<ThreadControlBlockListValueType>>::iterator;

	/**
	 * \brief Scheduler's constructor
	 *
	 * \attention Priority of main thread must be higher than priority of idle thread.
	 *
	 * \param [in] mainThreadControlBlock is a reference to main thread
	 * \param [in] idleThread is a reference to idle thread
	 */

	Scheduler(MainThreadControlBlock& mainThreadControlBlock, Thread<void (&)()>& idleThread);

	/**
	 * \brief Adds new ThreadControlBlock to scheduler.
	 *
	 * ThreadControlBlock's state is changed to "runnable".
	 *
	 * \param [in] thread_control_block is a reference to added ThreadControlBlock object
	 */

	void add(ThreadControlBlock& thread_control_block);

	/**
	 * \brief Blocks current thread, transferring it to provided container.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 */

	void block(ThreadControlBlockList& container);

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * The thread must be in "runnable" state - trying to block thread in other state is an error.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state;
	 */

	int block(ThreadControlBlockList& container, Iterator iterator);

	/**
	 * \return reference to currently active ThreadControlBlock
	 */

	ThreadControlBlock& getCurrentThreadControlBlock() const { return *currentThreadControlBlock_; }

	/**
	 * \return reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor()
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return const reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	const SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor() const
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return current value of tick count
	 */

	uint64_t getTickCount() const;

	/**
	 * \brief Removes current thread from Scheduler's control.
	 *
	 * Thread's state is changed to "terminated" and it's terminationHook() is called.
	 *
	 * \note This function can be used only after thread's function returns an all cleanup is done.
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state and cannot be removed/terminated;
	 */

	int remove();

	/**
	 * \brief Resumes suspended thread.
	 *
	 * The thread must be in "suspended" state - trying to resume thread that is not suspended is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be resumed
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "suspended" state;
	 */

	int resume(Iterator iterator);

	/**
	 * \brief Makes the calling (current) thread sleep for at least given duration.
	 *
	 * Current thread's state is changed to "sleeping".
	 *
	 * \note To fulfill the "at least" requirement, one additional tick is always added to the sleep duration.
	 *
	 * \param [in] duration is the duration after which the thread will be woken
	 */

	void sleepFor(TickClock::duration duration);

	/**
	 * \brief Makes the calling (current) thread sleep until some time point is reached.
	 *
	 * Current thread's state is changed to "sleeping".
	 *
	 * \param [in] time_point is the time point at which the thread will be woken
	 */

	void sleepUntil(TickClock::time_point time_point);

	/**
	 * \brief Suspends current thread.
	 */

	void suspend();

	/**
	 * \brief Suspends thread.
	 *
	 * The thread must be in "runnable" state - trying to suspend thread in other state is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be suspended
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state;
	 */

	int suspend(Iterator iterator);

	/**
	 * \brief Called by architecture-specific code to do final context switch.
	 *
	 * Current task is suspended and the next available task is started.
	 *
	 * \param [in] stack_pointer is the current value of current thread's stack pointer
	 *
	 * \return new thread's stack pointer
	 */

	void* switchContext(void* stack_pointer);

	/**
	 * \brief Handler of "tick" interrupt.
	 *
	 * \note this must not be called by user code
	 *
	 * \return true if context switch is required, false otherwise
	 */

	bool tickInterruptHandler();

	/**
	 * \brief Unblocks provided thread, transferring it from provided container to "runnable" container.
	 *
	 * \param [in] container is a reference to source container from which the thread will be transferred
	 * \param [in] iterator is the iterator which points to unblocked thread
	 */

	void unblock(ThreadControlBlockList& container, Iterator iterator);

	/**
	 * \brief Yields time slot of the scheduler to next thread.
	 */

	void yield() const;

private:

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * Internal version - without interrupt masking and forced context switch.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state;
	 */

	int blockInternal_(ThreadControlBlockList& container, Iterator iterator);

	/**
	 * \brief Forces unconditional context switch.
	 *
	 * Temporarily disables any interrupt masking and requests unconditional context switch.
	 */

	void forceContextSwitch_() const;

	/**
	 * \brief Tests whether context switch is required or not.
	 *
	 * Context switch is required in following situations:
	 * - current thread is no longer in "runnable" state,
	 * - there is a higher-priority thread available,
	 * - current thread used its round-robin quantum and same-priority thread is available.
	 *
	 * \return true if context switch is required
	 */

	bool isContextSwitchRequired_() const;

	/**
	 * \brief Requests unconditional context switch.
	 *
	 * Wrapper for architecture::requestContextSwitch()
	 */

	void requestContextSwitch_() const;

	/**
	 * \brief Unblocks provided thread, transferring it from provided container to "runnable" container.
	 *
	 * Internal version - without interrupt masking and yield()
	 *
	 * \param [in] container is a reference to source container from which the thread will be transferred
	 * \param [in] iterator is the iterator which points to unblocked thread
	 */

	void unblockInternal_(ThreadControlBlockList& container, Iterator iterator);

	/// iterator to the currently active ThreadControlBlock
	Iterator currentThreadControlBlock_;

	/// list of ThreadControlBlock elements in "runnable" state, sorted by priority in descending order
	ThreadControlBlockList runnableList_;

	/// list of ThreadControlBlock elements in "suspended" state, sorted by priority in descending order
	ThreadControlBlockList suspendedList_;

	/// internal SoftwareTimerControlBlockSupervisor object
	SoftwareTimerControlBlockSupervisor softwareTimerControlBlockSupervisor_;

	/// tick count
	uint64_t tickCount_;
};

}	// namespace scheduler

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
<commit_msg>Scheduler: add templated versions of Scheduler::sleepFor() and Scheduler::sleepUntil()<commit_after>/**
 * \file
 * \brief Scheduler class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-08-28
 */

#ifndef INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
#define INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_

#include "distortos/scheduler/ThreadControlBlockList.hpp"
#include "distortos/scheduler/SoftwareTimerControlBlockSupervisor.hpp"

#include <chrono>

namespace distortos
{

/// scheduler namespace has symbols related to scheduling
namespace scheduler
{

template<typename Function, typename... Args>
class Thread;
class MainThreadControlBlock;

/// Scheduler class is a system's scheduler
class Scheduler
{
public:

	/// generic iterator for all variants of ThreadControlBlockList
	using Iterator = containers::SortedContainerBase<std::list<ThreadControlBlockListValueType>>::iterator;

	/**
	 * \brief Scheduler's constructor
	 *
	 * \attention Priority of main thread must be higher than priority of idle thread.
	 *
	 * \param [in] mainThreadControlBlock is a reference to main thread
	 * \param [in] idleThread is a reference to idle thread
	 */

	Scheduler(MainThreadControlBlock& mainThreadControlBlock, Thread<void (&)()>& idleThread);

	/**
	 * \brief Adds new ThreadControlBlock to scheduler.
	 *
	 * ThreadControlBlock's state is changed to "runnable".
	 *
	 * \param [in] thread_control_block is a reference to added ThreadControlBlock object
	 */

	void add(ThreadControlBlock& thread_control_block);

	/**
	 * \brief Blocks current thread, transferring it to provided container.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 */

	void block(ThreadControlBlockList& container);

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * The thread must be in "runnable" state - trying to block thread in other state is an error.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state;
	 */

	int block(ThreadControlBlockList& container, Iterator iterator);

	/**
	 * \return reference to currently active ThreadControlBlock
	 */

	ThreadControlBlock& getCurrentThreadControlBlock() const { return *currentThreadControlBlock_; }

	/**
	 * \return reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor()
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return const reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	const SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor() const
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return current value of tick count
	 */

	uint64_t getTickCount() const;

	/**
	 * \brief Removes current thread from Scheduler's control.
	 *
	 * Thread's state is changed to "terminated" and it's terminationHook() is called.
	 *
	 * \note This function can be used only after thread's function returns an all cleanup is done.
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state and cannot be removed/terminated;
	 */

	int remove();

	/**
	 * \brief Resumes suspended thread.
	 *
	 * The thread must be in "suspended" state - trying to resume thread that is not suspended is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be resumed
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "suspended" state;
	 */

	int resume(Iterator iterator);

	/**
	 * \brief Makes the calling (current) thread sleep for at least given duration.
	 *
	 * Current thread's state is changed to "sleeping".
	 *
	 * \note To fulfill the "at least" requirement, one additional tick is always added to the sleep duration.
	 *
	 * \param [in] duration is the duration after which the thread will be woken
	 */

	void sleepFor(TickClock::duration duration);

	/**
	 * \brief Makes the calling (current) thread sleep for at least given duration.
	 *
	 * Current thread's state is changed to "sleeping".
	 *
	 * \note To fulfill the "at least" requirement, one additional tick is always added to the sleep duration.
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 *
	 * \param [in] duration is the duration after which the thread will be woken
	 */

	template<typename Rep, typename Period>
	void sleepFor(const std::chrono::duration<Rep,Period> duration)
	{
		sleepFor(std::chrono::duration_cast<TickClock::duration>(duration));
	}

	/**
	 * \brief Makes the calling (current) thread sleep until some time point is reached.
	 *
	 * Current thread's state is changed to "sleeping".
	 *
	 * \param [in] time_point is the time point at which the thread will be woken
	 */

	void sleepUntil(TickClock::time_point time_point);

	/**
	 * \brief Makes the calling (current) thread sleep until some time point is reached.
	 *
	 * Current thread's state is changed to "sleeping".
	 *
	 * \param Duration is a std::chrono::duration type used to measure duration
	 *
	 * \param [in] time_point is the time point at which the thread will be woken
	 */

	template<typename Duration>
	void sleepUntil(std::chrono::time_point<TickClock, Duration> time_point)
	{
		sleepUntil(std::chrono::time_point_cast<TickClock::duration>(time_point));
	}

	/**
	 * \brief Suspends current thread.
	 */

	void suspend();

	/**
	 * \brief Suspends thread.
	 *
	 * The thread must be in "runnable" state - trying to suspend thread in other state is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be suspended
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state;
	 */

	int suspend(Iterator iterator);

	/**
	 * \brief Called by architecture-specific code to do final context switch.
	 *
	 * Current task is suspended and the next available task is started.
	 *
	 * \param [in] stack_pointer is the current value of current thread's stack pointer
	 *
	 * \return new thread's stack pointer
	 */

	void* switchContext(void* stack_pointer);

	/**
	 * \brief Handler of "tick" interrupt.
	 *
	 * \note this must not be called by user code
	 *
	 * \return true if context switch is required, false otherwise
	 */

	bool tickInterruptHandler();

	/**
	 * \brief Unblocks provided thread, transferring it from provided container to "runnable" container.
	 *
	 * \param [in] container is a reference to source container from which the thread will be transferred
	 * \param [in] iterator is the iterator which points to unblocked thread
	 */

	void unblock(ThreadControlBlockList& container, Iterator iterator);

	/**
	 * \brief Yields time slot of the scheduler to next thread.
	 */

	void yield() const;

private:

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * Internal version - without interrupt masking and forced context switch.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not in "runnable" state;
	 */

	int blockInternal_(ThreadControlBlockList& container, Iterator iterator);

	/**
	 * \brief Forces unconditional context switch.
	 *
	 * Temporarily disables any interrupt masking and requests unconditional context switch.
	 */

	void forceContextSwitch_() const;

	/**
	 * \brief Tests whether context switch is required or not.
	 *
	 * Context switch is required in following situations:
	 * - current thread is no longer in "runnable" state,
	 * - there is a higher-priority thread available,
	 * - current thread used its round-robin quantum and same-priority thread is available.
	 *
	 * \return true if context switch is required
	 */

	bool isContextSwitchRequired_() const;

	/**
	 * \brief Requests unconditional context switch.
	 *
	 * Wrapper for architecture::requestContextSwitch()
	 */

	void requestContextSwitch_() const;

	/**
	 * \brief Unblocks provided thread, transferring it from provided container to "runnable" container.
	 *
	 * Internal version - without interrupt masking and yield()
	 *
	 * \param [in] container is a reference to source container from which the thread will be transferred
	 * \param [in] iterator is the iterator which points to unblocked thread
	 */

	void unblockInternal_(ThreadControlBlockList& container, Iterator iterator);

	/// iterator to the currently active ThreadControlBlock
	Iterator currentThreadControlBlock_;

	/// list of ThreadControlBlock elements in "runnable" state, sorted by priority in descending order
	ThreadControlBlockList runnableList_;

	/// list of ThreadControlBlock elements in "suspended" state, sorted by priority in descending order
	ThreadControlBlockList suspendedList_;

	/// internal SoftwareTimerControlBlockSupervisor object
	SoftwareTimerControlBlockSupervisor softwareTimerControlBlockSupervisor_;

	/// tick count
	uint64_t tickCount_;
};

}	// namespace scheduler

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
<|endoftext|>


<commit_before><commit_msg>fixed some indexing issues<commit_after><|endoftext|>


<commit_before>#include "vec3.h"
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>

namespace py = pybind11;
using namespace pybind11::literals;

namespace jtrace {
    void pyExportVec3(py::module& m) {
        PYBIND11_NUMPY_DTYPE(Vec3, x, y, z);
        py::class_<Vec3>(m, "Vec3", R"pbdoc(
          Simple python 3-vector

          Parameters
          ----------
          x
            x-coordinate
          y
            y-coordinate
          z
            z-coordinate

          Notes
          -----
          `x`, `y`, and `z` may also all be left blank, in which case the 0-vector is returned.

          Examples
          --------
          >>> v = jtrace.Vec3(1, 2, 3.4)
          >>> print(v)
          Vec3(1, 2, 3.4)

          >>> v2 = jtrace.Vec3()
          >>> print(v2)
          Vec3(0, 0, 0)
        )pbdoc")
            .def(py::init<double,double,double>(), "init", "x"_a, "y"_a, "z"_a)
            .def(py::init<>())
            .def(py::init<std::array<double,3>>())
            .def("MagnitudeSquared", &Vec3::MagnitudeSquared, "Return square of vector magnitude.")
            .def("Magnitude", &Vec3::Magnitude, "Return vector magnitude.")
            .def("UnitVec3", &Vec3::UnitVec3, "Return unit vector pointing in same direction.")
            .def("MagnitudeSquared", &Vec3::MagnitudeSquared)
            .def("Magnitude", &Vec3::Magnitude)
            .def("UnitVec3", &Vec3::UnitVec3)
            .def("__repr__", &Vec3::repr)
            .def_readonly("x", &Vec3::x, "x-coordinate of vector")
            .def_readonly("y", &Vec3::y, "y-coordinate of vector")
            .def_readonly("z", &Vec3::z, "z-coordinate of vector")
            .def(py::self + py::self)
            .def(py::self += py::self)
            .def(py::self - py::self)
            .def(py::self -= py::self)
            .def(py::self * double())
            .def(py::self *= double())
            .def(py::self / double())
            .def(py::self /= double())
            .def(py::self == py::self)
            .def(py::self != py::self)
            .def(-py::self);

        py::class_<Rot3>(m, "Rot3", py::buffer_protocol())
            .def_buffer([](Rot3& r) -> py::buffer_info {
                return py::buffer_info(
                    r.data.data(),
                    sizeof(double),
                    py::format_descriptor<double>::format(),
                    2,
                    {3, 3},
                    {sizeof(double) * 3, sizeof(double)}
                );
            })
            .def(py::init<>())
            .def(py::init<std::array<double,9>>())
            .def("__repr__", &Rot3::repr)
            .def(py::self * double())
            .def(py::self *= double())
            .def(py::self / double())
            .def(py::self /= double())
            .def("determinant", &Rot3::determinant);

        m.def("DotProduct", &DotProduct, R"pbdoc(
          Compute the dot-product of two Vec3 objects.

          Parameters
          ----------
          v1 : Vec3
            First vector
          v2 : Vec3
            Second vector

          Returns
          -------
          float
            The dot product.

          Notes
          -----
          The dot product is defined as the sum of the component-wise products of two vectors.  It
          is useful for computing the magnitude of a vector, or the angle between two vectors as

          .. math::
            v1 \dot v2 = \cos(\theta)

          where :math:`\theta` is the angle in between the two vectors.

          Examples
          --------
          >>> v1 = jtrace.Vec3(0, 1, 0)
          >>> v2 = jtrace.Vec3(0, 0, 1)
          >>> print(jtrace.DotProduct(v1, v2))
          0.0
          >>> v1 = jtrace.Vec3(0, 1, 2)
          >>> v2 = jtrace.Vec3(1, 2, 3)
          >>> assert jtrace.DotProduct(v1, v2) == v1.x*v2.x + v1.y*v2.y + v1.z*v2.z

        )pbdoc");

        m.def("CrossProduct", &CrossProduct, R"pbdoc(
          Compute the cross-product of two Vec3 objects.

          Parameters
          ----------
          v1 : Vec3
            First vector
          v2 : Vec3
            Second vector

          Returns
          -------
          Vec3
            The vector cross-product v1 x v2.

          Notes
          -----
          The vector cross-product is useful for computing a vector that is perpendicular to both
          `v1` and `v2`.  The magnitude of the cross-product is equal to

          .. math::
            |v1 \cross v2| = |v1|  |v2| \sin(\theta)

          where :math:`\theta` is the angle in between `v1` and `v2`.  jtrace Vec3 objects obey the
          right-hand-rule, where Vec3(1, 0, 0) x Vec3(0, 1, 0) = Vec3(0, 0, 1), and cyclic
          permutations thereof.

          Examples
          --------
          >>> v1 = jtrace.Vec3(0, 1, 2)
          >>> v2 = jtrace.Vec3(1, 2, 3)
          >>> jtrace.CrossProduct(v1, v2)
          Vec3(-1, 2, -1)

        )pbdoc");
        m.def("RotVec", &RotVec);
        m.def("UnRotVec", &UnRotVec);
    }
}
<commit_msg>Remove duplicate pybind wrapper<commit_after>#include "vec3.h"
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>

namespace py = pybind11;
using namespace pybind11::literals;

namespace jtrace {
    void pyExportVec3(py::module& m) {
        PYBIND11_NUMPY_DTYPE(Vec3, x, y, z);
        py::class_<Vec3>(m, "Vec3", R"pbdoc(
          Simple python 3-vector

          Parameters
          ----------
          x
            x-coordinate
          y
            y-coordinate
          z
            z-coordinate

          Notes
          -----
          `x`, `y`, and `z` may also all be left blank, in which case the 0-vector is returned.

          Examples
          --------
          >>> v = jtrace.Vec3(1, 2, 3.4)
          >>> print(v)
          Vec3(1, 2, 3.4)

          >>> v2 = jtrace.Vec3()
          >>> print(v2)
          Vec3(0, 0, 0)
        )pbdoc")
            .def(py::init<double,double,double>(), "init", "x"_a, "y"_a, "z"_a)
            .def(py::init<>())
            .def(py::init<std::array<double,3>>())
            .def("MagnitudeSquared", &Vec3::MagnitudeSquared, "Return square of vector magnitude.")
            .def("Magnitude", &Vec3::Magnitude, "Return vector magnitude.")
            .def("UnitVec3", &Vec3::UnitVec3, "Return unit vector pointing in same direction.")
            .def("__repr__", &Vec3::repr)
            .def_readonly("x", &Vec3::x, "x-coordinate of vector")
            .def_readonly("y", &Vec3::y, "y-coordinate of vector")
            .def_readonly("z", &Vec3::z, "z-coordinate of vector")
            .def(py::self + py::self)
            .def(py::self += py::self)
            .def(py::self - py::self)
            .def(py::self -= py::self)
            .def(py::self * double())
            .def(py::self *= double())
            .def(py::self / double())
            .def(py::self /= double())
            .def(py::self == py::self)
            .def(py::self != py::self)
            .def(-py::self);

        py::class_<Rot3>(m, "Rot3", py::buffer_protocol())
            .def_buffer([](Rot3& r) -> py::buffer_info {
                return py::buffer_info(
                    r.data.data(),
                    sizeof(double),
                    py::format_descriptor<double>::format(),
                    2,
                    {3, 3},
                    {sizeof(double) * 3, sizeof(double)}
                );
            })
            .def(py::init<>())
            .def(py::init<std::array<double,9>>())
            .def("__repr__", &Rot3::repr)
            .def(py::self * double())
            .def(py::self *= double())
            .def(py::self / double())
            .def(py::self /= double())
            .def("determinant", &Rot3::determinant);

        m.def("DotProduct", &DotProduct, R"pbdoc(
          Compute the dot-product of two Vec3 objects.

          Parameters
          ----------
          v1 : Vec3
            First vector
          v2 : Vec3
            Second vector

          Returns
          -------
          float
            The dot product.

          Notes
          -----
          The dot product is defined as the sum of the component-wise products of two vectors.  It
          is useful for computing the magnitude of a vector, or the angle between two vectors as

          .. math::
            v1 \dot v2 = \cos(\theta)

          where :math:`\theta` is the angle in between the two vectors.

          Examples
          --------
          >>> v1 = jtrace.Vec3(0, 1, 0)
          >>> v2 = jtrace.Vec3(0, 0, 1)
          >>> print(jtrace.DotProduct(v1, v2))
          0.0
          >>> v1 = jtrace.Vec3(0, 1, 2)
          >>> v2 = jtrace.Vec3(1, 2, 3)
          >>> assert jtrace.DotProduct(v1, v2) == v1.x*v2.x + v1.y*v2.y + v1.z*v2.z

        )pbdoc");

        m.def("CrossProduct", &CrossProduct, R"pbdoc(
          Compute the cross-product of two Vec3 objects.

          Parameters
          ----------
          v1 : Vec3
            First vector
          v2 : Vec3
            Second vector

          Returns
          -------
          Vec3
            The vector cross-product v1 x v2.

          Notes
          -----
          The vector cross-product is useful for computing a vector that is perpendicular to both
          `v1` and `v2`.  The magnitude of the cross-product is equal to

          .. math::
            |v1 \cross v2| = |v1|  |v2| \sin(\theta)

          where :math:`\theta` is the angle in between `v1` and `v2`.  jtrace Vec3 objects obey the
          right-hand-rule, where Vec3(1, 0, 0) x Vec3(0, 1, 0) = Vec3(0, 0, 1), and cyclic
          permutations thereof.

          Examples
          --------
          >>> v1 = jtrace.Vec3(0, 1, 2)
          >>> v2 = jtrace.Vec3(1, 2, 3)
          >>> jtrace.CrossProduct(v1, v2)
          Vec3(-1, 2, -1)

        )pbdoc");
        m.def("RotVec", &RotVec);
        m.def("UnRotVec", &UnRotVec);
    }
}
<|endoftext|>


<commit_before>/**
 * @file svm_test.cpp
 *
 * Test for SVM.
 */
#include <mlpack/core.h>
#include <mlpack/methods/svm/svm.h>

#include <boost/test/unit_test.hpp>

using std::string;
using namespace mlpack;
using namespace mlpack::svm;

BOOST_AUTO_TEST_SUITE(SVMTest);

// Create test data
arma::mat matrix(20, 3);
bool first = true;

/**
 * Creates the data to train and test with and prints it to stdout.  Should only
 * have any effect once.
 */
void setup()
{
  if(!first)
    return;
  first = false;

  CLI::GetParam<bool>("svm/shrink") = true;
  CLI::GetParam<double>("svm/epsilon") = .1;
  CLI::GetParam<double>("svm/sigma") = 1;
  // Protect the test from taking forever
  CLI::GetParam<size_t>("svm/n_iter") = 10000;

  matrix <<
    7.19906628001437787e-01 << 1.83250823399634477e+00 << 0 << arma::endr <<
    1.37899419263889733e+01 << 1.78198235122579263e+00 << 1 << arma::endr <<
    6.68859485848275703e-01 << 2.14083320956715983e+00 << 0 << arma::endr <<
    1.84729928795588165e+01 << 2.25024702760868101e+00 << 1 << arma::endr <<
    9.22802773268335819e-01 << 1.61469358350834513e+00 << 0 << arma::endr <<
    2.06209849662245204e-01 << 6.34699695340683490e-01 << 1 << arma::endr <<
    4.01062068250524817e-01 << 1.65802752932441777e+00 << 0 << arma::endr <<
    5.02985607135568635e+00 << 1.39976642741810831e+00 << 1 << arma::endr <<
    3.66471199955079319e-01 << 1.62780588172739638e+00 << 0 << arma::endr <<
    1.56912570240400999e+01 << 2.16941541650770953e+00 << 1 << arma::endr <<
    9.98909584711729304e-01 << 2.00337906391517206e+00 << 0 << arma::endr <<
    1.31430438780891912e+01 << 1.34410346059319719e+00 << 1 << arma::endr <<
    3.41572957272442523e-01 << 1.16758463655951639e+00 << 0 << arma::endr <<
    9.53941410851637528e-01 << 6.30271704462483373e-01 << 1 << arma::endr <<
    7.07135529120981432e-01 << 2.17763537339756041e+00 << 0 << arma::endr <<
    9.68899714280338742e+00 << 1.26922579378319256e+00 << 1 << arma::endr <<
    9.82393905512240706e-01 << 2.36790583090293483e+00 << 0 << arma::endr <<
    1.31583349281727973e+01 << 1.45115094722767868e+00 << 1 << arma::endr <<
    3.80991188521027202e-01 << 9.05379134419085019e-01 << 0 << arma::endr <<
    1.86057436180327755e+01 << 2.26941891469499968e+00 << 1 << arma::endr;
  matrix = trans(matrix);

  std::cout << matrix << std::endl;
}

/**
 * Compares predicted values with known values to see if the prediction/training
 * works.
 *
 * @param learner_typeid Magic number for selecting between classification and
 *     regression.
 * @param data The dataset with the data to predict with.
 * @param svm The SVM class instance that has been trained for this data, et al.
 */
template<typename T>
void verify(size_t learner_typeid, arma::mat& data, SVM<T>& svm)
{
  for(size_t i = 0; i < data.n_cols; i++)
  {
    arma::vec testvec = data.col(i);

    double predictedvalue = svm.Predict(learner_typeid, testvec);
    BOOST_REQUIRE_CLOSE(predictedvalue, data(data.n_rows - 1, i), 1e-6);
  }
}

/**
 * Trains a classifier with a linear kernel and checks predictions against
 * classes.
 */
//BOOST_AUTO_TEST_CASE(svm_classification_linear_kernel_test) {
//  setup();
//
//  arma::mat trainingdata;
//  trainingdata = matrix;
//  SVM<SVMLinearKernel> svm;
//  svm.InitTrain(0,trainingdata); // 0 for classification
//  verify(0,trainingdata,svm);
//}

/**
 * Trains a classifier with a gaussian kernel and checks predictions against
 * classes.
 */
BOOST_AUTO_TEST_CASE(svm_classification_gaussian_kernel_test) {
  setup();

  arma::mat trainingdata;
  trainingdata = matrix;
  SVM<SVMRBFKernel> svm;
  svm.InitTrain(0,trainingdata); // 0 for classification
  verify(0,trainingdata,svm);
}

/**
 * Trains a classifier with a linear kernel and checks predictions against
 * classes, using regression. TODO: BROKEN
 */
//BOOST_AUTO_TEST_CASE(svm_regression_linear_kernel_test) {
//  setup();
//
//  arma::mat trainingdata;
//  trainingdata = matrix;
//  SVM<SVMLinearKernel> svm;
//  svm.InitTrain(1,trainingdata); // 0 for classification
//  //verify(1,trainingdata,svm);
//}

/**
 * Trains a classifier with a gaussian kernel and checks predictions against
 * classes, using regression. TODO: BROKEN
 */
//BOOST_AUTO_TEST_CASE(svm_regression_gaussian_kernel_test) {
//  setup();
//
//  arma::mat trainingdata;
//  trainingdata = matrix;
//  SVM<SVMRBFKernel> svm;
//  svm.InitTrain(1,trainingdata); // 0 for classification
//  //verify(1,trainingdata,svm);
//}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Fix formatting in tests/ as per #153.<commit_after>/**
 * @file svm_test.cpp
 *
 * Test for SVM.
 */
#include <mlpack/core.h>
#include <mlpack/methods/svm/svm.h>

#include <boost/test/unit_test.hpp>

using std::string;
using namespace mlpack;
using namespace mlpack::svm;

BOOST_AUTO_TEST_SUITE(SVMTest);

// Create test data
arma::mat matrix(20, 3);
bool first = true;

/**
 * Creates the data to train and test with and prints it to stdout.  Should only
 * have any effect once.
 */
void setup()
{
  if (!first)
    return;
  first = false;

  CLI::GetParam<bool>("svm/shrink") = true;
  CLI::GetParam<double>("svm/epsilon") = .1;
  CLI::GetParam<double>("svm/sigma") = 1;
  // Protect the test from taking forever
  CLI::GetParam<size_t>("svm/n_iter") = 10000;

  matrix <<
    7.19906628001437787e-01 << 1.83250823399634477e+00 << 0 << arma::endr <<
    1.37899419263889733e+01 << 1.78198235122579263e+00 << 1 << arma::endr <<
    6.68859485848275703e-01 << 2.14083320956715983e+00 << 0 << arma::endr <<
    1.84729928795588165e+01 << 2.25024702760868101e+00 << 1 << arma::endr <<
    9.22802773268335819e-01 << 1.61469358350834513e+00 << 0 << arma::endr <<
    2.06209849662245204e-01 << 6.34699695340683490e-01 << 1 << arma::endr <<
    4.01062068250524817e-01 << 1.65802752932441777e+00 << 0 << arma::endr <<
    5.02985607135568635e+00 << 1.39976642741810831e+00 << 1 << arma::endr <<
    3.66471199955079319e-01 << 1.62780588172739638e+00 << 0 << arma::endr <<
    1.56912570240400999e+01 << 2.16941541650770953e+00 << 1 << arma::endr <<
    9.98909584711729304e-01 << 2.00337906391517206e+00 << 0 << arma::endr <<
    1.31430438780891912e+01 << 1.34410346059319719e+00 << 1 << arma::endr <<
    3.41572957272442523e-01 << 1.16758463655951639e+00 << 0 << arma::endr <<
    9.53941410851637528e-01 << 6.30271704462483373e-01 << 1 << arma::endr <<
    7.07135529120981432e-01 << 2.17763537339756041e+00 << 0 << arma::endr <<
    9.68899714280338742e+00 << 1.26922579378319256e+00 << 1 << arma::endr <<
    9.82393905512240706e-01 << 2.36790583090293483e+00 << 0 << arma::endr <<
    1.31583349281727973e+01 << 1.45115094722767868e+00 << 1 << arma::endr <<
    3.80991188521027202e-01 << 9.05379134419085019e-01 << 0 << arma::endr <<
    1.86057436180327755e+01 << 2.26941891469499968e+00 << 1 << arma::endr;
  matrix = trans(matrix);

  std::cout << matrix << std::endl;
}

/**
 * Compares predicted values with known values to see if the prediction/training
 * works.
 *
 * @param learner_typeid Magic number for selecting between classification and
 *     regression.
 * @param data The dataset with the data to predict with.
 * @param svm The SVM class instance that has been trained for this data, et al.
 */
template<typename T>
void verify(size_t learner_typeid, arma::mat& data, SVM<T>& svm)
{
  for (size_t i = 0; i < data.n_cols; i++)
  {
    arma::vec testvec = data.col(i);

    double predictedvalue = svm.Predict(learner_typeid, testvec);
    BOOST_REQUIRE_CLOSE(predictedvalue, data(data.n_rows - 1, i), 1e-6);
  }
}

/**
 * Trains a classifier with a linear kernel and checks predictions against
 * classes.
 */
//BOOST_AUTO_TEST_CASE(svm_classification_linear_kernel_test) {
//  setup();
//
//  arma::mat trainingdata;
//  trainingdata = matrix;
//  SVM<SVMLinearKernel> svm;
//  svm.InitTrain(0,trainingdata); // 0 for classification
//  verify(0,trainingdata,svm);
//}

/**
 * Trains a classifier with a gaussian kernel and checks predictions against
 * classes.
 */
BOOST_AUTO_TEST_CASE(svm_classification_gaussian_kernel_test)
{
  setup();

  arma::mat trainingdata;
  trainingdata = matrix;
  SVM<SVMRBFKernel> svm;
  svm.InitTrain(0,trainingdata); // 0 for classification
  verify(0,trainingdata,svm);
}

/**
 * Trains a classifier with a linear kernel and checks predictions against
 * classes, using regression. TODO: BROKEN
 */
//BOOST_AUTO_TEST_CASE(svm_regression_linear_kernel_test) {
//  setup();
//
//  arma::mat trainingdata;
//  trainingdata = matrix;
//  SVM<SVMLinearKernel> svm;
//  svm.InitTrain(1,trainingdata); // 0 for classification
//  //verify(1,trainingdata,svm);
//}

/**
 * Trains a classifier with a gaussian kernel and checks predictions against
 * classes, using regression. TODO: BROKEN
 */
//BOOST_AUTO_TEST_CASE(svm_regression_gaussian_kernel_test) {
//  setup();
//
//  arma::mat trainingdata;
//  trainingdata = matrix;
//  SVM<SVMRBFKernel> svm;
//  svm.InitTrain(1,trainingdata); // 0 for classification
//  //verify(1,trainingdata,svm);
//}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>