<commit_before>#ifndef LEPP2_FILTERED_VIDEO_SOURCE_H__
#define LEPP2_FILTERED_VIDEO_SOURCE_H__

#include "lepp2/BaseVideoSource.hpp"
#include "lepp2/VideoObserver.hpp"
#include "lepp2/filter/PointFilter.hpp"

#include <algorithm>

#include <boost/enable_shared_from_this.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/circular_buffer.hpp>

#include "lepp2/debug/timer.hpp"

/**
 * A struct that is used to describe a single point in space that can be used
 * to index sets and maps of such points.
 */
struct MapPoint {
  int x;
  int y;
  int z;
  MapPoint(int x, int y, int z) : x(x), y(y), z(z) {}
  MapPoint() {}
};

/**
 * Structs that are to be placed in associative containers must be comparable.
 */
bool operator==(MapPoint const& lhs, MapPoint const& rhs) {
  return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
}

/**
 * Provides a hash value for a `MapPoint` in order to allow for it to be
 * placed in boost's map and set.
 */
size_t hash_value(MapPoint const& pt) {
  std::size_t seed = 0;
  boost::hash_combine(seed, pt.x);
  boost::hash_combine(seed, pt.y);
  boost::hash_combine(seed, pt.z);
  return seed;
}

/**
 * ABC.
 * A VideoSource decorator.  It wraps a given VideoSource instance and emits
 * clouds that are filtered versions of the original raw cloud returned by the
 * wrapped `VideoSource`.
 *
 * The cloud it receives is first filtered by applying a number of point-wise
 * filters to each point. The filters that are applied to points (if any) are
 * set dynamically (`setFilter` method).
 *
 * Then, it delegates to a concrete implementation which needs to handle the
 * cloud-level filtering.
 *
 * Concrete implementations need to provide implementations for three protected
 * hook methods that handle the full-cloud filtering at various stages: before
 * the original cloud's points are transformed, after a particular point is
 * transformed, and finally after all points have been transformed.
 *
 * This ABC provides the plumbing required to turn the filtered source into a
 * `VideoSource` making it simple to implement a concrete filter by simply
 * providing implementations for the mentioned hooks.
 */
template<class PointT>
class FilteredVideoSource
    : public VideoSource<PointT>,
      public VideoObserver<PointT>,
      public boost::enable_shared_from_this<FilteredVideoSource<PointT> > {
public:
  using typename VideoSource<PointT>::PointCloudType;
  /**
   * Creates a new FilteredVideoSource which will perform filtering of each
   * cloud generated by the given source and emit such a filtered cloud to its
   * own observers.
   *
   * The FilteredVideoSource instance does not assume ownership of the given
   * source, but shares it.
   */
  FilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : source_(source) {}
  /**
   * Implementation of the VideoSource interface.
   */
  virtual void open();
  /**
   * Implementation of the VideoObserver interface.
   */
  virtual void notifyNewFrame(
      int idx,
      const typename pcl::PointCloud<PointT>::ConstPtr& cloud);

  /**
   * Add a filter that will be applied to individual points before the entire
   * cloud itself is filtered.
   */
  void addFilter(boost::shared_ptr<PointFilter<PointT> > filter) {
    point_filters_.push_back(filter);
  }

protected:
  /**
   * A hook method that concrete implementations of the `FilteredVideoSource`
   * should implement in order to prepare for a new frame's filtering.
   */
  virtual void newFrame() = 0;
  /**
   * A hook method that concrete implementations of the `FilteredVideoSource`
   * should implement to handle new points received in the latest frame.
   *
   * It receives a reference to the cloud that will contain the final filtered
   * representation already, if the implementation wishes to examine or modify
   * it.
   */
  virtual void newPoint(PointT& p, PointCloudType& filtered) = 0;
  /**
   * A hook method that concrete implementations of the `FilteredVideoSource`
   * should implement to return the filtered cloud assembled from the points
   * given by the `newPoint` calls since the previous `newFrame` call.
   * Implementations are free to take into account any historic data and throw
   * away or otherwise modify the points given in `newPoint` calls, though.
   *
   * The filtered cloud should be put into the cloud instance passed as the
   * parameter.
   */
  virtual void getFiltered(PointCloudType& filtered) = 0;

private:
  /**
   * The VideoSource instance that will be filtered by this instance.
   */
  boost::shared_ptr<VideoSource<PointT> > source_;
  /**
   * The filters that are applied to individual points (in the order found in
   * the vector) before passing it off to the concrete cloud filter
   * implementation.
   */
  std::vector<boost::shared_ptr<PointFilter<PointT> > > point_filters_;
};

template<class PointT>
void FilteredVideoSource<PointT>::open() {
  // Start the wrapped VideoSource and make sure that this instance is notified
  // when it emits any new clouds.
  source_->attachObserver(this->shared_from_this());
  source_->open();
}

template<class PointT>
void FilteredVideoSource<PointT>::notifyNewFrame(
    int idx,
    const typename pcl::PointCloud<PointT>::ConstPtr& cloud) {
  Timer t;
  t.start();

  // Prepare the point-wise filters for a new frame.
  {
    size_t sz = point_filters_.size();
    for (size_t i = 0; i < sz; ++i) {
      point_filters_[i]->prepareNext();
    }
  }
  // Prepare the concrete cloud filter implementation for a new frame.
  this->newFrame();

  // Process the cloud received from the wrapped instance and put the filtered
  // result in a new point cloud.
  typename PointCloudType::Ptr cloud_filtered(new PointCloudType());
  PointCloudType& filtered = *cloud_filtered;
  cloud_filtered->is_dense = true;
  cloud_filtered->sensor_origin_ = cloud->sensor_origin_;

  // Apply point-wise filters to each received point and then pass it to the
  // concrete implementation to figure out how to filter the entire cloud.
  for (typename pcl::PointCloud<PointT>::const_iterator it = cloud->begin();
        it != cloud->end();
        ++it) {
    PointT p = *it;
    // Filter out NaN points already, since we're already iterating through the
    // cloud.
    if (!pcl_isfinite(p.x) || !pcl_isfinite(p.y) || !pcl_isfinite(p.z)) {
      continue;
    }

    // Now apply point-wise filters.
    size_t const sz = point_filters_.size();
    bool valid = true;
    for (size_t i = 0; i < sz; ++i) {
      if (!point_filters_[i]->apply(p)) {
        valid = false;
        break;
      }
    }
    // And pass such a filtered/modified point to the cloud-level filter.
    if (valid) this->newPoint(p, filtered);
  }

  // Now we obtain the fully filtered cloud...
  this->getFiltered(filtered);
  // ...and we're done!
  t.stop();

  std::cerr << "Total included points " << cloud_filtered->size() << std::endl;
  std::cerr << "Filtering took " << t.duration() << std::endl;
  // Finally, the cloud that is emitted by this instance is the filtered cloud.
  this->setNextFrame(cloud_filtered);
}

/**
 * An implementation of a `FilteredVideoSource` that only applies the
 * point-wise filters, without performing any additional cloud-level filtering.
 */
template<class PointT>
class SimpleFilteredVideoSource : public FilteredVideoSource<PointT> {
public:
  using typename FilteredVideoSource<PointT>::PointCloudType;

  SimpleFilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : FilteredVideoSource<PointT>(source) {}
protected:
  void newFrame() {}
  void newPoint(PointT& p, PointCloudType& filtered) { filtered.push_back(p); }
  void getFiltered(PointCloudType& filtered) {}
};

/**
 * An implementation of a `FilteredVideoSource` where points are included only
 * if they have been seen in a certain percentage of frames of the last N
 * frames.
 */
template<class PointT>
class ProbFilteredVideoSource : public FilteredVideoSource<PointT> {
public:
  using typename FilteredVideoSource<PointT>::PointCloudType;

  ProbFilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : FilteredVideoSource<PointT>(source) {}
protected:
  void newFrame() { this_frame_.clear(); }

  void newPoint(PointT& p, PointCloudType& filtered) {
    MapPoint map_point = MapPoint(p.x * 100, p.y * 100, p.z * 100);
    boost::circular_buffer<bool>& ref = all_points_[map_point];
    // TODO Factor out the percentage and number of frames that are considered
    //      to a member constant.
    if (ref.capacity() == 0) {
      ref.set_capacity(30);
    }
    ref.push_back(true);
    this_frame_.insert(map_point);
  }

  void getFiltered(PointCloudType& filtered) {
    boost::unordered_map<MapPoint, boost::circular_buffer<bool> >::iterator it =
        all_points_.begin();
    while (it != all_points_.end()) {
      if (this_frame_.find(it->first) == this_frame_.end()) {
        it->second.push_back(false);
      }
      unsigned char const count = std::accumulate(
          it->second.begin(), it->second.end(), 0);
      if (count >= 10) {
        PointT pt;
        pt.x = it->first.x / 100.;
        pt.y = it->first.y / 100.;
        pt.z = it->first.z / 100.;
        filtered.push_back(pt);
      }
      ++it;
    }
  }
private:
  boost::unordered_set<MapPoint> this_frame_;
  boost::unordered_map<MapPoint, boost::circular_buffer<bool> > all_points_;
};

/**
 * An implementation of a `FilteredVideoSource` that applies a PT1 filter on the
 * stream of clouds.
 */
template<class PointT>
class Pt1FilteredVideoSource : public FilteredVideoSource<PointT> {
public:
  using typename FilteredVideoSource<PointT>::PointCloudType;

  Pt1FilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : FilteredVideoSource<PointT>(source) {}
protected:
  void newFrame() { this_frame_.clear(); }

  void newPoint(PointT& p, PointCloudType& filtered) {
    MapPoint map_point = MapPoint(p.x * 100, p.y * 100, p.z * 100);
    float& ref = all_points_[map_point];
    // TODO Factor out the parameter value to a member constant.
    ref = 0.9*ref + 0.1*10;
    this_frame_.insert(map_point);
  }

  void getFiltered(PointCloudType& filtered) {
    boost::unordered_map<MapPoint, float>::iterator it =
        all_points_.begin();
    while (it != all_points_.end()) {
      if (this_frame_.find(it->first) == this_frame_.end()) {
        it->second = 0.9*it->second + 0.1*0.;
      }
      if (it->second >= 4.) {
        PointT pt;
        pt.x = it->first.x / 100.;
        pt.y = it->first.y / 100.;
        pt.z = it->first.z / 100.;
        filtered.push_back(pt);
      }
      ++it;
    }
  }
private:
  boost::unordered_set<MapPoint> this_frame_;
  boost::unordered_map<MapPoint, float> all_points_;
};
#endif
<commit_msg>Optimize the probabilistic filter runtime<commit_after>#ifndef LEPP2_FILTERED_VIDEO_SOURCE_H__
#define LEPP2_FILTERED_VIDEO_SOURCE_H__

#include "lepp2/BaseVideoSource.hpp"
#include "lepp2/VideoObserver.hpp"
#include "lepp2/filter/PointFilter.hpp"

#include <algorithm>

#include <boost/enable_shared_from_this.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/circular_buffer.hpp>

#include "lepp2/debug/timer.hpp"

/**
 * A struct that is used to describe a single point in space that can be used
 * to index sets and maps of such points.
 */
struct MapPoint {
  int x;
  int y;
  int z;
  MapPoint(int x, int y, int z) : x(x), y(y), z(z) {}
  MapPoint() {}
};

/**
 * Structs that are to be placed in associative containers must be comparable.
 */
bool operator==(MapPoint const& lhs, MapPoint const& rhs) {
  return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
}

/**
 * Provides a hash value for a `MapPoint` in order to allow for it to be
 * placed in boost's map and set.
 */
size_t hash_value(MapPoint const& pt) {
  std::size_t seed = 0;
  boost::hash_combine(seed, pt.x);
  boost::hash_combine(seed, pt.y);
  boost::hash_combine(seed, pt.z);
  return seed;
}

/**
 * ABC.
 * A VideoSource decorator.  It wraps a given VideoSource instance and emits
 * clouds that are filtered versions of the original raw cloud returned by the
 * wrapped `VideoSource`.
 *
 * The cloud it receives is first filtered by applying a number of point-wise
 * filters to each point. The filters that are applied to points (if any) are
 * set dynamically (`setFilter` method).
 *
 * Then, it delegates to a concrete implementation which needs to handle the
 * cloud-level filtering.
 *
 * Concrete implementations need to provide implementations for three protected
 * hook methods that handle the full-cloud filtering at various stages: before
 * the original cloud's points are transformed, after a particular point is
 * transformed, and finally after all points have been transformed.
 *
 * This ABC provides the plumbing required to turn the filtered source into a
 * `VideoSource` making it simple to implement a concrete filter by simply
 * providing implementations for the mentioned hooks.
 */
template<class PointT>
class FilteredVideoSource
    : public VideoSource<PointT>,
      public VideoObserver<PointT>,
      public boost::enable_shared_from_this<FilteredVideoSource<PointT> > {
public:
  using typename VideoSource<PointT>::PointCloudType;
  /**
   * Creates a new FilteredVideoSource which will perform filtering of each
   * cloud generated by the given source and emit such a filtered cloud to its
   * own observers.
   *
   * The FilteredVideoSource instance does not assume ownership of the given
   * source, but shares it.
   */
  FilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : source_(source) {}
  /**
   * Implementation of the VideoSource interface.
   */
  virtual void open();
  /**
   * Implementation of the VideoObserver interface.
   */
  virtual void notifyNewFrame(
      int idx,
      const typename pcl::PointCloud<PointT>::ConstPtr& cloud);

  /**
   * Add a filter that will be applied to individual points before the entire
   * cloud itself is filtered.
   */
  void addFilter(boost::shared_ptr<PointFilter<PointT> > filter) {
    point_filters_.push_back(filter);
  }

protected:
  /**
   * A hook method that concrete implementations of the `FilteredVideoSource`
   * should implement in order to prepare for a new frame's filtering.
   */
  virtual void newFrame() = 0;
  /**
   * A hook method that concrete implementations of the `FilteredVideoSource`
   * should implement to handle new points received in the latest frame.
   *
   * It receives a reference to the cloud that will contain the final filtered
   * representation already, if the implementation wishes to examine or modify
   * it.
   */
  virtual void newPoint(PointT& p, PointCloudType& filtered) = 0;
  /**
   * A hook method that concrete implementations of the `FilteredVideoSource`
   * should implement to return the filtered cloud assembled from the points
   * given by the `newPoint` calls since the previous `newFrame` call.
   * Implementations are free to take into account any historic data and throw
   * away or otherwise modify the points given in `newPoint` calls, though.
   *
   * The filtered cloud should be put into the cloud instance passed as the
   * parameter.
   */
  virtual void getFiltered(PointCloudType& filtered) = 0;

private:
  /**
   * The VideoSource instance that will be filtered by this instance.
   */
  boost::shared_ptr<VideoSource<PointT> > source_;
  /**
   * The filters that are applied to individual points (in the order found in
   * the vector) before passing it off to the concrete cloud filter
   * implementation.
   */
  std::vector<boost::shared_ptr<PointFilter<PointT> > > point_filters_;
};

template<class PointT>
void FilteredVideoSource<PointT>::open() {
  // Start the wrapped VideoSource and make sure that this instance is notified
  // when it emits any new clouds.
  source_->attachObserver(this->shared_from_this());
  source_->open();
}

template<class PointT>
void FilteredVideoSource<PointT>::notifyNewFrame(
    int idx,
    const typename pcl::PointCloud<PointT>::ConstPtr& cloud) {
  Timer t;
  t.start();

  // Prepare the point-wise filters for a new frame.
  {
    size_t sz = point_filters_.size();
    for (size_t i = 0; i < sz; ++i) {
      point_filters_[i]->prepareNext();
    }
  }
  // Prepare the concrete cloud filter implementation for a new frame.
  this->newFrame();

  // Process the cloud received from the wrapped instance and put the filtered
  // result in a new point cloud.
  typename PointCloudType::Ptr cloud_filtered(new PointCloudType());
  PointCloudType& filtered = *cloud_filtered;
  cloud_filtered->is_dense = true;
  cloud_filtered->sensor_origin_ = cloud->sensor_origin_;

  // Apply point-wise filters to each received point and then pass it to the
  // concrete implementation to figure out how to filter the entire cloud.
  for (typename pcl::PointCloud<PointT>::const_iterator it = cloud->begin();
        it != cloud->end();
        ++it) {
    PointT p = *it;
    // Filter out NaN points already, since we're already iterating through the
    // cloud.
    if (!pcl_isfinite(p.x) || !pcl_isfinite(p.y) || !pcl_isfinite(p.z)) {
      continue;
    }

    // Now apply point-wise filters.
    size_t const sz = point_filters_.size();
    bool valid = true;
    for (size_t i = 0; i < sz; ++i) {
      if (!point_filters_[i]->apply(p)) {
        valid = false;
        break;
      }
    }
    // And pass such a filtered/modified point to the cloud-level filter.
    if (valid) this->newPoint(p, filtered);
  }

  // Now we obtain the fully filtered cloud...
  this->getFiltered(filtered);
  // ...and we're done!
  t.stop();

  std::cerr << "Total included points " << cloud_filtered->size() << std::endl;
  std::cerr << "Filtering took " << t.duration() << std::endl;
  // Finally, the cloud that is emitted by this instance is the filtered cloud.
  this->setNextFrame(cloud_filtered);
}

/**
 * An implementation of a `FilteredVideoSource` that only applies the
 * point-wise filters, without performing any additional cloud-level filtering.
 */
template<class PointT>
class SimpleFilteredVideoSource : public FilteredVideoSource<PointT> {
public:
  using typename FilteredVideoSource<PointT>::PointCloudType;

  SimpleFilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : FilteredVideoSource<PointT>(source) {}
protected:
  void newFrame() {}
  void newPoint(PointT& p, PointCloudType& filtered) { filtered.push_back(p); }
  void getFiltered(PointCloudType& filtered) {}
};

/**
 * An implementation of a `FilteredVideoSource` where points are included only
 * if they have been seen in a certain percentage of frames of the last N
 * frames.
 */
template<class PointT>
class ProbFilteredVideoSource : public FilteredVideoSource<PointT> {
public:
  using typename FilteredVideoSource<PointT>::PointCloudType;

  ProbFilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : FilteredVideoSource<PointT>(source) {}
protected:
  void newFrame() { this_frame_.clear(); }

  void newPoint(PointT& p, PointCloudType& filtered) {
    MapPoint map_point = MapPoint(p.x * 100, p.y * 100, p.z * 100);
    uint32_t& ref = all_points_[map_point];
    ref <<= 1;
    ref |= 1;
    this_frame_.insert(map_point);
  }

  void getFiltered(PointCloudType& filtered) {
    boost::unordered_map<MapPoint, uint32_t>::iterator it =
        all_points_.begin();
    while (it != all_points_.end()) {
      if (this_frame_.find(it->first) == this_frame_.end()) {
        it->second <<= 1;
      }
      int count = __builtin_popcount(it->second);
      if (count >= 10) {
        PointT pt;
        pt.x = it->first.x / 100.;
        pt.y = it->first.y / 100.;
        pt.z = it->first.z / 100.;
        filtered.push_back(pt);
      }
      ++it;
    }
  }
private:
  boost::unordered_set<MapPoint> this_frame_;
  boost::unordered_map<MapPoint, uint32_t> all_points_;
};

/**
 * An implementation of a `FilteredVideoSource` that applies a PT1 filter on the
 * stream of clouds.
 */
template<class PointT>
class Pt1FilteredVideoSource : public FilteredVideoSource<PointT> {
public:
  using typename FilteredVideoSource<PointT>::PointCloudType;

  Pt1FilteredVideoSource(boost::shared_ptr<VideoSource<PointT> > source)
      : FilteredVideoSource<PointT>(source) {}
protected:
  void newFrame() { this_frame_.clear(); }

  void newPoint(PointT& p, PointCloudType& filtered) {
    MapPoint map_point = MapPoint(p.x * 100, p.y * 100, p.z * 100);
    float& ref = all_points_[map_point];
    // TODO Factor out the parameter value to a member constant.
    ref = 0.9*ref + 0.1*10;
    this_frame_.insert(map_point);
  }

  void getFiltered(PointCloudType& filtered) {
    boost::unordered_map<MapPoint, float>::iterator it =
        all_points_.begin();
    while (it != all_points_.end()) {
      if (this_frame_.find(it->first) == this_frame_.end()) {
        it->second = 0.9*it->second + 0.1*0.;
      }
      if (it->second >= 4.) {
        PointT pt;
        pt.x = it->first.x / 100.;
        pt.y = it->first.y / 100.;
        pt.z = it->first.z / 100.;
        filtered.push_back(pt);
      }
      ++it;
    }
  }
private:
  boost::unordered_set<MapPoint> this_frame_;
  boost::unordered_map<MapPoint, float> all_points_;
};
#endif
<|endoftext|>


<commit_before>/**
 * @file logistic_regression_test.cpp
 * @author Ryan Curtin
 *
 * Test for LogisticFunction and LogisticRegression.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/logistic_regression/logistic_regression.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::regression;

BOOST_AUTO_TEST_SUITE(LogisticRegressionTest);

/**
 * Test the LogisticRegressionFunction on a simple set of points.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionEvaluate)
{
  // Very simple fake dataset.
  arma::mat data("1 1 1;" // Fake row for intercept.
                 "1 2 3;"
                 "1 2 3");
  arma::vec responses("1 1 0");

  // Create a LogisticRegressionFunction.
  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);

  // These were hand-calculated using Octave.
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("1 1 1")), 7.0562141665, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("0 0 0")), 2.0794415417, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("-1 -1 -1")), 8.0562141665, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("200 -40 -40")), 0.0, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("200 -80 0")), 0.0, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("200 -100 20")), 0.0, 1e-5);
}

/**
 * A more complicated test for the LogisticRegressionFunction.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionRandomEvaluate)
{
  const size_t points = 1000;
  const size_t dimension = 10;
  const size_t trials = 50;

  // Create a random dataset.
  arma::mat data;
  data.randu(dimension, points);
  // Create random responses.
  arma::vec responses(points);
  for (size_t i = 0; i < points; ++i)
    responses[i] = math::RandInt(0, 2);

  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);

  // Run a bunch of trials.
  for (size_t i = 0; i < trials; ++i)
  {
    // Generate a random set of parameters.
    arma::vec parameters;
    parameters.randu(dimension);

    // Hand-calculate the loss function.
    double loglikelihood = 0.0;
    for (size_t j = 0; j < points; ++j)
    {
      const double sigmoid = (1.0 / (1.0 +
          exp(-arma::dot(data.col(j), parameters))));
      if (responses[j] == 1.0)
        loglikelihood += log(std::pow(sigmoid, responses[j]));
      else
        loglikelihood += log(std::pow(1.0 - sigmoid, 1.0 - responses[j]));
    }

    BOOST_REQUIRE_CLOSE(lrf.Evaluate(parameters), -loglikelihood, 1e-5);
  }
}

/**
 * Test regularization for the LogisticRegressionFunction Evaluate() function.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionRegularizationEvaluate)
{
  const size_t points = 5000;
  const size_t dimension = 25;
  const size_t trials = 10;

  // Create a random dataset.
  arma::mat data;
  data.randu(dimension, points);
  // Create random responses.
  arma::vec responses(points);
  for (size_t i = 0; i < points; ++i)
    responses[i] = math::RandInt(0, 2);

  LogisticRegressionFunction lrfNoReg(data, responses, 0.0);
  LogisticRegressionFunction lrfSmallReg(data, responses, 0.5);
  LogisticRegressionFunction lrfBigReg(data, responses, 20.0);

  for (size_t i = 0; i < trials; ++i)
  {
    arma::vec parameters(dimension);
    parameters.randu();

    // Regularization term: 0.5 * lambda * || parameters ||_2^2 (but note that
    // the first parameters term is ignored).
    const double smallRegTerm = 0.25 * std::pow(arma::norm(parameters, 2), 2.0)
        - 0.25 * std::pow(parameters[0], 2.0);
    const double bigRegTerm = 10.0 * std::pow(arma::norm(parameters, 2), 2.0)
        - 10.0 * std::pow(parameters[0], 2.0);

    BOOST_REQUIRE_CLOSE(lrfNoReg.Evaluate(parameters) - smallRegTerm,
        lrfSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(lrfNoReg.Evaluate(parameters) - bigRegTerm,
        lrfBigReg.Evaluate(parameters), 1e-5);
  }
}

/**
 * Test gradient of the LogisticRegressionFunction.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionGradient)
{
  // Very simple fake dataset.
  arma::mat data("1 1 1;" // Fake row for intercept.
                 "1 2 3;"
                 "1 2 3");
  arma::vec responses("1 1 0");

  // Create a LogisticRegressionFunction.
  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);
  arma::vec gradient;

  // If the model is at the optimum, then the gradient should be zero.
  lrf.Gradient(arma::vec("200 -40 -40"), gradient);

  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_SMALL(gradient[0], 1e-15);
  BOOST_REQUIRE_SMALL(gradient[1], 1e-15);
  BOOST_REQUIRE_SMALL(gradient[2], 1e-15);

  // Perturb two elements in the wrong way, so they need to become smaller.
  lrf.Gradient(arma::vec("200 -20 -20"), gradient);

  // The actual values are less important; the gradient just needs to be pointed
  // the right way.
  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_GE(gradient[1], 0.0);
  BOOST_REQUIRE_GE(gradient[2], 0.0);

  // Perturb two elements in the wrong way, so they need to become larger.
  lrf.Gradient(arma::vec("200 -60 -60"), gradient);

  // The actual values are less important; the gradient just needs to be pointed
  // the right way.
  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_LE(gradient[1], 0.0);
  BOOST_REQUIRE_LE(gradient[2], 0.0);

  // Perturb the intercept element.
  lrf.Gradient(arma::vec("250 -40 -40"), gradient);

  // The actual values are less important; the gradient just needs to be pointed
  // the right way.
  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_GE(gradient[0], 0.0);
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Add test for Evaluate(parameters, i) for SGD and related optimizers.<commit_after>/**
 * @file logistic_regression_test.cpp
 * @author Ryan Curtin
 *
 * Test for LogisticFunction and LogisticRegression.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/logistic_regression/logistic_regression.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::regression;

BOOST_AUTO_TEST_SUITE(LogisticRegressionTest);

/**
 * Test the LogisticRegressionFunction on a simple set of points.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionEvaluate)
{
  // Very simple fake dataset.
  arma::mat data("1 1 1;" // Fake row for intercept.
                 "1 2 3;"
                 "1 2 3");
  arma::vec responses("1 1 0");

  // Create a LogisticRegressionFunction.
  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);

  // These were hand-calculated using Octave.
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("1 1 1")), 7.0562141665, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("0 0 0")), 2.0794415417, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("-1 -1 -1")), 8.0562141665, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("200 -40 -40")), 0.0, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("200 -80 0")), 0.0, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("200 -100 20")), 0.0, 1e-5);
}

/**
 * A more complicated test for the LogisticRegressionFunction.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionRandomEvaluate)
{
  const size_t points = 1000;
  const size_t dimension = 10;
  const size_t trials = 50;

  // Create a random dataset.
  arma::mat data;
  data.randu(dimension, points);
  // Create random responses.
  arma::vec responses(points);
  for (size_t i = 0; i < points; ++i)
    responses[i] = math::RandInt(0, 2);

  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);

  // Run a bunch of trials.
  for (size_t i = 0; i < trials; ++i)
  {
    // Generate a random set of parameters.
    arma::vec parameters;
    parameters.randu(dimension);

    // Hand-calculate the loss function.
    double loglikelihood = 0.0;
    for (size_t j = 0; j < points; ++j)
    {
      const double sigmoid = (1.0 / (1.0 +
          exp(-arma::dot(data.col(j), parameters))));
      if (responses[j] == 1.0)
        loglikelihood += log(std::pow(sigmoid, responses[j]));
      else
        loglikelihood += log(std::pow(1.0 - sigmoid, 1.0 - responses[j]));
    }

    BOOST_REQUIRE_CLOSE(lrf.Evaluate(parameters), -loglikelihood, 1e-5);
  }
}

/**
 * Test regularization for the LogisticRegressionFunction Evaluate() function.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionRegularizationEvaluate)
{
  const size_t points = 5000;
  const size_t dimension = 25;
  const size_t trials = 10;

  // Create a random dataset.
  arma::mat data;
  data.randu(dimension, points);
  // Create random responses.
  arma::vec responses(points);
  for (size_t i = 0; i < points; ++i)
    responses[i] = math::RandInt(0, 2);

  LogisticRegressionFunction lrfNoReg(data, responses, 0.0);
  LogisticRegressionFunction lrfSmallReg(data, responses, 0.5);
  LogisticRegressionFunction lrfBigReg(data, responses, 20.0);

  for (size_t i = 0; i < trials; ++i)
  {
    arma::vec parameters(dimension);
    parameters.randu();

    // Regularization term: 0.5 * lambda * || parameters ||_2^2 (but note that
    // the first parameters term is ignored).
    const double smallRegTerm = 0.25 * std::pow(arma::norm(parameters, 2), 2.0)
        - 0.25 * std::pow(parameters[0], 2.0);
    const double bigRegTerm = 10.0 * std::pow(arma::norm(parameters, 2), 2.0)
        - 10.0 * std::pow(parameters[0], 2.0);

    BOOST_REQUIRE_CLOSE(lrfNoReg.Evaluate(parameters) - smallRegTerm,
        lrfSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(lrfNoReg.Evaluate(parameters) - bigRegTerm,
        lrfBigReg.Evaluate(parameters), 1e-5);
  }
}

/**
 * Test gradient of the LogisticRegressionFunction.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionFunctionGradient)
{
  // Very simple fake dataset.
  arma::mat data("1 1 1;" // Fake row for intercept.
                 "1 2 3;"
                 "1 2 3");
  arma::vec responses("1 1 0");

  // Create a LogisticRegressionFunction.
  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);
  arma::vec gradient;

  // If the model is at the optimum, then the gradient should be zero.
  lrf.Gradient(arma::vec("200 -40 -40"), gradient);

  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_SMALL(gradient[0], 1e-15);
  BOOST_REQUIRE_SMALL(gradient[1], 1e-15);
  BOOST_REQUIRE_SMALL(gradient[2], 1e-15);

  // Perturb two elements in the wrong way, so they need to become smaller.
  lrf.Gradient(arma::vec("200 -20 -20"), gradient);

  // The actual values are less important; the gradient just needs to be pointed
  // the right way.
  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_GE(gradient[1], 0.0);
  BOOST_REQUIRE_GE(gradient[2], 0.0);

  // Perturb two elements in the wrong way, so they need to become larger.
  lrf.Gradient(arma::vec("200 -60 -60"), gradient);

  // The actual values are less important; the gradient just needs to be pointed
  // the right way.
  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_LE(gradient[1], 0.0);
  BOOST_REQUIRE_LE(gradient[2], 0.0);

  // Perturb the intercept element.
  lrf.Gradient(arma::vec("250 -40 -40"), gradient);

  // The actual values are less important; the gradient just needs to be pointed
  // the right way.
  BOOST_REQUIRE_EQUAL(gradient.n_elem, 3);
  BOOST_REQUIRE_GE(gradient[0], 0.0);
}

/**
 * Test individual Evaluate() functions for SGD.
 */
BOOST_AUTO_TEST_CASE(LogisticRegressionSeparableEvaluate)
{
  // Very simple fake dataset.
  arma::mat data("1 1 1;" // Fake row for intercept.
                 "1 2 3;"
                 "1 2 3");
  arma::vec responses("1 1 0");

  // Create a LogisticRegressionFunction.
  LogisticRegressionFunction lrf(data, responses, 0.0 /* no regularization */);

  // These were hand-calculated using Octave.
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("1 1 1"), 0), 4.85873516e-2, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("1 1 1"), 1), 6.71534849e-3, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("1 1 1"), 2), 7.00091146645, 1e-5);

  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("0 0 0"), 0), 0.6931471805, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("0 0 0"), 1), 0.6931471805, 1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("0 0 0"), 2), 0.6931471805, 1e-5);

  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("-1 -1 -1"), 0), 3.0485873516,
      1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("-1 -1 -1"), 1), 5.0067153485,
      1e-5);
  BOOST_REQUIRE_CLOSE(lrf.Evaluate(arma::vec("-1 -1 -1"), 2), 9.1146645377e-4,
      1e-5);

  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -40 -40"), 0), 1e-5);
  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -40 -40"), 1), 1e-5);
  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -40 -40"), 2), 1e-5);

  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -80 0"), 0), 1e-5);
  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -80 0"), 1), 1e-5);
  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -80 0"), 2), 1e-5);

  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -100 20"), 0), 1e-5);
  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -100 20"), 1), 1e-5);
  BOOST_REQUIRE_SMALL(lrf.Evaluate(arma::vec("200 -100 20"), 2), 1e-5);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <glog/logging.h>

#include <fstream>
#include <vector>

#include <boost/lexical_cast.hpp>

#include <process/protobuf.hpp>

#include <stout/foreach.hpp>
#include <stout/option.hpp>

#include "detector/detector.hpp"

#include "logging/logging.hpp"

#include "messages/messages.hpp"

#include "zookeeper/authentication.hpp"
#include "zookeeper/url.hpp"
#include "zookeeper/watcher.hpp"
#include "zookeeper/zookeeper.hpp"

using namespace mesos;
using namespace mesos::internal;

using boost::lexical_cast;

using process::Process;
using process::UPID;

using std::pair;
using std::string;
using std::vector;

// TODO(benh): Make this value configurable via flags and verify that
// it is always LESS THAN the slave heartbeat timeout.
const Seconds ZOOKEEPER_SESSION_TIMEOUT(10.0);

class ZooKeeperMasterDetectorProcess
  : public Process<ZooKeeperMasterDetectorProcess>
{
public:
  ZooKeeperMasterDetectorProcess(
    const zookeeper::URL& url,
    const UPID& pid,
    bool contend,
    bool quiet);

  virtual ~ZooKeeperMasterDetectorProcess();

  virtual void initialize();

  // ZooKeeper events.
  void connected(bool reconnect);
  void reconnecting();
  void expired();
  void updated(const string& path);
  void created(const string& path);
  void deleted(const string& path);

private:
  // Attempts to detect a master.
  void detectMaster();

  const zookeeper::URL url;
  const ACL_vector acl;

  const UPID pid;
  bool contend;

  Watcher* watcher;
  ZooKeeper* zk;

  // Our sequence string if contending to be a master.
  Option<string> mySeq;

  string currentMasterSeq;
  UPID currentMasterPID;
};

class ZooKeeperMasterDetector : public MasterDetector
{
public:
  /**
   * Uses ZooKeeper for both detecting masters and contending to be a
   * master.
   *
   * @param server comma separated list of server host:port pairs
   * @param znode top-level "ZooKeeper node" (directory) to use
   * @param pid libprocess pid to send messages/updates to (and to
   * use for contending to be a master)
   * @param contend true if should contend to be master and false otherwise (not
   * needed for slaves and frameworks)
   * @param quiet verbosity logging level for underlying ZooKeeper library
   */
  ZooKeeperMasterDetector(const zookeeper::URL& url,
                          const UPID& pid,
                          bool contend,
                          bool quiet);

  virtual ~ZooKeeperMasterDetector();

private:
  ZooKeeperMasterDetectorProcess* process;
};

MasterDetector::~MasterDetector() {}

Try<MasterDetector*> MasterDetector::create(const string& master,
                                            const UPID& pid,
                                            bool contend,
                                            bool quiet)
{
  if (master == "") {
    if (contend) {
      return new BasicMasterDetector(pid);
    } else {
      return Try<MasterDetector*>::error("Cannot detect master");
    }
  } else if (master.find("zk://") == 0) {
    Try<zookeeper::URL> url = zookeeper::URL::parse(master);
    if (url.isError()) {
      return Try<MasterDetector*>::error(url.error());
    }
    if (url.get().path == "/") {
      return Try<MasterDetector*>::error(
          "Expecting a (chroot) path for ZooKeeper ('/' is not supported)");
    }
    return new ZooKeeperMasterDetector(url.get(), pid, contend, quiet);
  } else if (master.find("file://") == 0) {
    const std::string& path = master.substr(7);
    std::ifstream file(path.c_str());
    if (!file.is_open()) {
      return Try<MasterDetector*>::error(
          "Failed to open file at '" + path + "'");
    }

    std::string line;
    getline(file, line);

    if (!file) {
      file.close();
      return Try<MasterDetector*>::error(
          "Failed to read from file at '" + path + "'");
    }

    file.close();

    return create(line, pid, contend, quiet);
  }

  // Okay, try and parse what we got as a PID.
  process::UPID masterPid = master.find("master@") == 0
    ? process::UPID(master)
    : process::UPID("master@" + master);

  if (!masterPid) {
    return Try<MasterDetector*>::error(
        "Cannot parse '" + std::string(masterPid) + "'");
  }

  return new BasicMasterDetector(masterPid, pid);
}

void MasterDetector::destroy(MasterDetector *detector)
{
  if (detector != NULL)
    delete detector;
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master)
  : master(_master)
{
  // Elect the master.
  NewMasterDetectedMessage message;
  message.set_pid(master);
  process::post(master, message);
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const UPID& pid,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Elect the master.
    NewMasterDetectedMessage message;
    message.set_pid(master);
    process::post(master, message);
  }

  // Tell the pid about the master.
  NewMasterDetectedMessage message;
  message.set_pid(master);
  process::post(pid, message);
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const vector<UPID>& pids,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Elect the master.
    NewMasterDetectedMessage message;
    message.set_pid(master);
    process::post(master, message);
  }

  // Tell each pid about the master.
  foreach (const UPID& pid, pids) {
    NewMasterDetectedMessage message;
    message.set_pid(master);
    process::post(pid, message);
  }
}

BasicMasterDetector::~BasicMasterDetector() {}

ZooKeeperMasterDetectorProcess::ZooKeeperMasterDetectorProcess(
    const zookeeper::URL& _url,
    const UPID& _pid,
    bool _contend,
    bool quiet)
  : url(_url),
    acl(url.authentication.isSome()
        ? zookeeper::EVERYONE_READ_CREATOR_ALL
        : ZOO_OPEN_ACL_UNSAFE),
    pid(_pid),
    contend(_contend),
    watcher(NULL),
    zk(NULL)
{
  // Set verbosity level for underlying ZooKeeper library logging.
  // TODO(benh): Put this in the C++ API.
  zoo_set_debug_level(quiet ? ZOO_LOG_LEVEL_ERROR : ZOO_LOG_LEVEL_DEBUG);
}

ZooKeeperMasterDetectorProcess::~ZooKeeperMasterDetectorProcess()
{
  delete zk;
  delete watcher;
}

void ZooKeeperMasterDetectorProcess::initialize()
{
  // Doing initialization here allows to avoid the race between
  // instantiating the ZooKeeper instance and being spawned ourself.
  watcher = new ProcessWatcher<ZooKeeperMasterDetectorProcess>(self());
  zk = new ZooKeeper(url.servers, ZOOKEEPER_SESSION_TIMEOUT, watcher);
}

void ZooKeeperMasterDetectorProcess::connected(bool reconnect)
{
  if (!reconnect) {
    LOG(INFO) << "Master detector connected to ZooKeeper ...";

    int code;
    if (url.authentication.isSome()) {
      const std::string& scheme = url.authentication.get().scheme;
      const std::string& credentials = url.authentication.get().credentials;
      LOG(INFO) << "Authenticating to ZooKeeper using scheme '" << scheme << "'";
      code = zk->authenticate(scheme, credentials);
      if (code != ZOK) {
        LOG(FATAL) << "Failed to authenticate with ZooKeeper: "
                   << zk->message(code);
      }
    }

    string result;

    static const string delimiter = "/";

    // Assume the path (chroot) being used does not end with a "/".
    CHECK(url.path.at(url.path.length() - 1) != '/');

    // Create znodes as necessary.
    size_t index = url.path.find(delimiter, 0);

    while (index < string::npos) {
      // Get out the prefix to create.
      index = url.path.find(delimiter, index + 1);
      string prefix = url.path.substr(0, index);

      LOG(INFO) << "Trying to create znode '" << prefix << "' in ZooKeeper";

      // Create the node (even if it already exists).
      code = zk->create(prefix, "", acl, 0, &result);

      if (code != ZOK && code != ZNODEEXISTS) {
        LOG(FATAL) << "Failed to create ZooKeeper znode: " << zk->message(code);
      }
    }

    // Wierdness in ZooKeeper timing, let's check that everything is created.
    code = zk->get(url.path, false, &result, NULL);

    if (code != ZOK) {
      LOG(FATAL) << "Unexpected ZooKeeper failure: " << zk->message(code);
    }

    if (contend) {
      // We contend with the pid given in constructor.
      code = zk->create(url.path + "/", pid, acl,
                        ZOO_SEQUENCE | ZOO_EPHEMERAL, &result);

      if (code != ZOK) {
        LOG(FATAL) << "Unexpected ZooKeeper failure: %s" << zk->message(code);
      }

      // Save the sequence id but only grab the basename, e.g.,
      // "/path/to/znode/000000131" => "000000131".
      size_t index;
      if ((index = result.find_last_of('/')) != string::npos) {
        mySeq = result.erase(0, index + 1);
      } else {
        mySeq = result;
      }

      LOG(INFO) << "Created ephemeral/sequence:" << mySeq.get();
    }

    // Now determine who the master is (it may be us).
    detectMaster();
  } else {
    LOG(INFO) << "Master detector reconnected ...";

    // Either we were the master and we're still the master (because
    // we haven't yet gotten a session expiration), or someone else
    // was the master and they're still the master, or someone else
    // was the master and someone else still is now the master. Either
    // way, run the leader detector.
    detectMaster();
  }
}

void ZooKeeperMasterDetectorProcess::reconnecting()
{
  LOG(INFO) << "Master detector lost connection to ZooKeeper, "
	    << "attempting to reconnect ...";
}

void ZooKeeperMasterDetectorProcess::expired()
{
  LOG(WARNING) << "Master detector ZooKeeper session expired!";

  CHECK(zk != NULL);
  delete zk;

  zk = new ZooKeeper(url.servers, ZOOKEEPER_SESSION_TIMEOUT, watcher);
}

void ZooKeeperMasterDetectorProcess::updated(const string& path)
{
  // A new master might have showed up and created a sequence
  // identifier or a master may have died, determine who the master is now!
  detectMaster();
}

void ZooKeeperMasterDetectorProcess::created(const string& path)
{
  LOG(FATAL) << "Unexpected ZooKeeper event (created) for '" << path << "'";
}

void ZooKeeperMasterDetectorProcess::deleted(const string& path)
{
  LOG(FATAL) << "Unexpected ZooKeeper event (deleted) for '" << path << "'";
}

void ZooKeeperMasterDetectorProcess::detectMaster()
{
  vector<string> results;

  int code = zk->getChildren(url.path, true, &results);

  if (code != ZOK) {
    LOG(ERROR) << "Master detector failed to get masters: "
               << zk->message(code);
  } else {
    LOG(INFO) << "Master detector found " << results.size()
              << " registered masters";
  }

  string masterSeq;
  long min = LONG_MAX;
  foreach (const string& result, results) {
    int i = lexical_cast<int>(result);
    if (i < min) {
      min = i;
      masterSeq = result;
    }
  }

  // No master present (lost or possibly hasn't come up yet).
  if (masterSeq.empty()) {
    process::post(pid, NoMasterDetectedMessage());
  } else if (masterSeq != currentMasterSeq) {
    // Okay, let's fetch the master pid from ZooKeeper.
    string result;
    code = zk->get(url.path + "/" + masterSeq, false, &result, NULL);

    if (code != ZOK) {
      // This is possible because the master might have failed since
      // the invocation of ZooKeeper::getChildren above.
      LOG(ERROR) << "Master detector failed to fetch new master pid: "
		 << zk->message(code);
      process::post(pid, NoMasterDetectedMessage());
    } else {
      // Now let's parse what we fetched from ZooKeeper.
      LOG(INFO) << "Master detector got new master pid: " << result;

      UPID masterPid = result;

      if (masterPid == UPID()) {
	// TODO(benh): Maybe we should try again then!?!? Parsing
	// might have failed because of DNS, and whoever is using the
	// detector might sit "unconnected" indefinitely!
	LOG(ERROR) << "Failed to parse new master pid!";
	process::post(pid, NoMasterDetectedMessage());
      } else {
	currentMasterSeq = masterSeq;
	currentMasterPID = masterPid;

        NewMasterDetectedMessage message;
	message.set_pid(currentMasterPID);
	process::post(pid, message);
      }
    }
  }
}

ZooKeeperMasterDetector::ZooKeeperMasterDetector(
    const zookeeper::URL& url,
    const UPID& pid,
    bool contend,
    bool quiet)
{
  process = new ZooKeeperMasterDetectorProcess(url, pid, contend, quiet);
  spawn(process);
}

ZooKeeperMasterDetector::~ZooKeeperMasterDetector()
{
  terminate(process);
  wait(process);
  delete process;
}
<commit_msg>Changed the ZooKeeper master detector to "time out" a session for instances that are being used to contend for leadership (and send a NoMasterDetectedMessage and expire the session after a reconnect does occur) (https://reviews.apache.org/r/7295).<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <glog/logging.h>

#include <fstream>
#include <ios>
#include <vector>

#include <boost/lexical_cast.hpp>

#include <process/delay.hpp>
#include <process/process.hpp>
#include <process/protobuf.hpp>
#include <process/timer.hpp>

#include <stout/foreach.hpp>
#include <stout/option.hpp>

#include "detector/detector.hpp"

#include "logging/logging.hpp"

#include "messages/messages.hpp"

#include "zookeeper/authentication.hpp"
#include "zookeeper/url.hpp"
#include "zookeeper/watcher.hpp"
#include "zookeeper/zookeeper.hpp"

using namespace mesos;
using namespace mesos::internal;

using boost::lexical_cast;

using process::Process;
using process::Timer;
using process::UPID;

using std::pair;
using std::string;
using std::vector;

// TODO(benh): Make this value configurable via flags and verify that
// it is always LESS THAN the slave heartbeat timeout.
const Seconds ZOOKEEPER_SESSION_TIMEOUT(10.0);

class ZooKeeperMasterDetectorProcess
  : public Process<ZooKeeperMasterDetectorProcess>
{
public:
  ZooKeeperMasterDetectorProcess(
    const zookeeper::URL& url,
    const UPID& pid,
    bool contend,
    bool quiet);

  virtual ~ZooKeeperMasterDetectorProcess();

  virtual void initialize();

  // ZooKeeper events.
  void connected(bool reconnect);
  void reconnecting();
  void expired();
  void updated(const string& path);
  void created(const string& path);
  void deleted(const string& path);

private:
  // Handles reconnecting "timeouts" by prematurely expiring a session
  // (only used for contending instances). TODO(benh): Remove 'const
  // &' after fixing libprocess.
  void timedout(const int64_t& sessionId);

  // Attempts to detect a master.
  void detectMaster();

  const zookeeper::URL url;
  const ACL_vector acl;

  const UPID pid;
  bool contend;

  Watcher* watcher;
  ZooKeeper* zk;

  bool expire;
  Option<Timer> timer;

  // Our sequence string if contending to be a master.
  Option<string> mySeq;

  string currentMasterSeq;
  UPID currentMasterPID;
};

class ZooKeeperMasterDetector : public MasterDetector
{
public:
  /**
   * Uses ZooKeeper for both detecting masters and contending to be a
   * master.
   *
   * @param server comma separated list of server host:port pairs
   * @param znode top-level "ZooKeeper node" (directory) to use
   * @param pid libprocess pid to send messages/updates to (and to
   * use for contending to be a master)
   * @param contend true if should contend to be master and false otherwise (not
   * needed for slaves and frameworks)
   * @param quiet verbosity logging level for underlying ZooKeeper library
   */
  ZooKeeperMasterDetector(const zookeeper::URL& url,
                          const UPID& pid,
                          bool contend,
                          bool quiet);

  virtual ~ZooKeeperMasterDetector();

private:
  ZooKeeperMasterDetectorProcess* process;
};

MasterDetector::~MasterDetector() {}

Try<MasterDetector*> MasterDetector::create(const string& master,
                                            const UPID& pid,
                                            bool contend,
                                            bool quiet)
{
  if (master == "") {
    if (contend) {
      return new BasicMasterDetector(pid);
    } else {
      return Try<MasterDetector*>::error("Cannot detect master");
    }
  } else if (master.find("zk://") == 0) {
    Try<zookeeper::URL> url = zookeeper::URL::parse(master);
    if (url.isError()) {
      return Try<MasterDetector*>::error(url.error());
    }
    if (url.get().path == "/") {
      return Try<MasterDetector*>::error(
          "Expecting a (chroot) path for ZooKeeper ('/' is not supported)");
    }
    return new ZooKeeperMasterDetector(url.get(), pid, contend, quiet);
  } else if (master.find("file://") == 0) {
    const std::string& path = master.substr(7);
    std::ifstream file(path.c_str());
    if (!file.is_open()) {
      return Try<MasterDetector*>::error(
          "Failed to open file at '" + path + "'");
    }

    std::string line;
    getline(file, line);

    if (!file) {
      file.close();
      return Try<MasterDetector*>::error(
          "Failed to read from file at '" + path + "'");
    }

    file.close();

    return create(line, pid, contend, quiet);
  }

  // Okay, try and parse what we got as a PID.
  process::UPID masterPid = master.find("master@") == 0
    ? process::UPID(master)
    : process::UPID("master@" + master);

  if (!masterPid) {
    return Try<MasterDetector*>::error(
        "Cannot parse '" + std::string(masterPid) + "'");
  }

  return new BasicMasterDetector(masterPid, pid);
}

void MasterDetector::destroy(MasterDetector *detector)
{
  if (detector != NULL)
    delete detector;
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master)
  : master(_master)
{
  // Elect the master.
  NewMasterDetectedMessage message;
  message.set_pid(master);
  process::post(master, message);
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const UPID& pid,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Elect the master.
    NewMasterDetectedMessage message;
    message.set_pid(master);
    process::post(master, message);
  }

  // Tell the pid about the master.
  NewMasterDetectedMessage message;
  message.set_pid(master);
  process::post(pid, message);
}

BasicMasterDetector::BasicMasterDetector(const UPID& _master,
					 const vector<UPID>& pids,
					 bool elect)
  : master(_master)
{
  if (elect) {
    // Elect the master.
    NewMasterDetectedMessage message;
    message.set_pid(master);
    process::post(master, message);
  }

  // Tell each pid about the master.
  foreach (const UPID& pid, pids) {
    NewMasterDetectedMessage message;
    message.set_pid(master);
    process::post(pid, message);
  }
}

BasicMasterDetector::~BasicMasterDetector() {}

ZooKeeperMasterDetectorProcess::ZooKeeperMasterDetectorProcess(
    const zookeeper::URL& _url,
    const UPID& _pid,
    bool _contend,
    bool quiet)
  : url(_url),
    acl(url.authentication.isSome()
        ? zookeeper::EVERYONE_READ_CREATOR_ALL
        : ZOO_OPEN_ACL_UNSAFE),
    pid(_pid),
    contend(_contend),
    watcher(NULL),
    zk(NULL),
    expire(false)
{
  // Set verbosity level for underlying ZooKeeper library logging.
  // TODO(benh): Put this in the C++ API.
  zoo_set_debug_level(quiet ? ZOO_LOG_LEVEL_ERROR : ZOO_LOG_LEVEL_DEBUG);
}

ZooKeeperMasterDetectorProcess::~ZooKeeperMasterDetectorProcess()
{
  delete zk;
  delete watcher;
}

void ZooKeeperMasterDetectorProcess::initialize()
{
  // Doing initialization here allows to avoid the race between
  // instantiating the ZooKeeper instance and being spawned ourself.
  watcher = new ProcessWatcher<ZooKeeperMasterDetectorProcess>(self());
  zk = new ZooKeeper(url.servers, ZOOKEEPER_SESSION_TIMEOUT, watcher);
}

void ZooKeeperMasterDetectorProcess::connected(bool reconnect)
{
  if (!reconnect) {
    LOG(INFO) << "Master detector connected to ZooKeeper ...";

    int code;
    if (url.authentication.isSome()) {
      const std::string& scheme = url.authentication.get().scheme;
      const std::string& credentials = url.authentication.get().credentials;
      LOG(INFO) << "Authenticating to ZooKeeper using scheme '" << scheme << "'";
      code = zk->authenticate(scheme, credentials);
      if (code != ZOK) {
        LOG(FATAL) << "Failed to authenticate with ZooKeeper: "
                   << zk->message(code);
      }
    }

    string result;

    static const string delimiter = "/";

    // Assume the path (chroot) being used does not end with a "/".
    CHECK(url.path.at(url.path.length() - 1) != '/');

    // Create znodes as necessary.
    size_t index = url.path.find(delimiter, 0);

    while (index < string::npos) {
      // Get out the prefix to create.
      index = url.path.find(delimiter, index + 1);
      string prefix = url.path.substr(0, index);

      LOG(INFO) << "Trying to create znode '" << prefix << "' in ZooKeeper";

      // Create the node (even if it already exists).
      code = zk->create(prefix, "", acl, 0, &result);

      if (code != ZOK && code != ZNODEEXISTS) {
        LOG(FATAL) << "Failed to create ZooKeeper znode: " << zk->message(code);
      }
    }

    // Wierdness in ZooKeeper timing, let's check that everything is created.
    code = zk->get(url.path, false, &result, NULL);

    if (code != ZOK) {
      LOG(FATAL) << "Unexpected ZooKeeper failure: " << zk->message(code);
    }

    if (contend) {
      // We contend with the pid given in constructor.
      code = zk->create(url.path + "/", pid, acl,
                        ZOO_SEQUENCE | ZOO_EPHEMERAL, &result);

      if (code != ZOK) {
        LOG(FATAL) << "Unexpected ZooKeeper failure: %s" << zk->message(code);
      }

      // Save the sequence id but only grab the basename, e.g.,
      // "/path/to/znode/000000131" => "000000131".
      size_t index;
      if ((index = result.find_last_of('/')) != string::npos) {
        mySeq = result.erase(0, index + 1);
      } else {
        mySeq = result;
      }

      LOG(INFO) << "Created ephemeral/sequence:" << mySeq.get();
    }

    // Now determine who the master is (it may be us).
    detectMaster();
  } else {
    LOG(INFO) << "Master detector reconnected ...";

    // Cancel and cleanup the reconnect timer (if necessary).
    if (timer.isSome()) {
      Timer::cancel(timer.get());
      timer = Option<Timer>::none();
    }

    // If we decided to expire the session, make sure we delete the
    // ZooKeeper instance so the session actually expires. We also
    // create a new ZooKeeper instance for clients that want to
    // continue detecting and/or contending (which is likely given
    // that this code is getting executed).
    if (expire) {
      LOG(WARNING) << "Cleaning up after expired ZooKeeper session";

      delete CHECK_NOTNULL(zk);
      delete CHECK_NOTNULL(watcher);

      watcher = new ProcessWatcher<ZooKeeperMasterDetectorProcess>(self());
      zk = new ZooKeeper(url.servers, ZOOKEEPER_SESSION_TIMEOUT, watcher);

      expire = false;
      return;
    }

    // We've reconnected and we didn't prematurely expire the session,
    // but the master might have changed, so we should run an
    // election. TODO(benh): Determine if this is really necessary or
    // if the watch set via 'ZooKeeper::getChildren' in 'detectMaster'
    // is sufficient (it should be).
    detectMaster();
  }
}

void ZooKeeperMasterDetectorProcess::reconnecting()
{
  LOG(INFO) << "Master detector lost connection to ZooKeeper, "
	    << "attempting to reconnect ...";

  // ZooKeeper won't tell us of a session expiration until we
  // reconnect, which could occur much much later than the session was
  // actually expired. This can lead to a prolonged split-brain
  // scenario when network partitions occur. Rather than wait for a
  // reconnection to occur (i.e., a network partition to be repaired)
  // we create a local timer and "expire" our session prematurely if
  // we haven't reconnected within the session expiration time
  // out. Later, when we eventually do reconnect we can force the
  // session to be expired if we decided locally to expire.
  timer = process::delay(
      ZOOKEEPER_SESSION_TIMEOUT, self(), &Self::timedout, zk->getSessionId());
}

void ZooKeeperMasterDetectorProcess::expired()
{
  LOG(WARNING) << "Master detector ZooKeeper session expired!";

  // Cancel and cleanup the reconnect timer (if necessary).
  if (timer.isSome()) {
    Timer::cancel(timer.get());
    timer = Option<Timer>::none();
  }

  delete CHECK_NOTNULL(zk);
  delete CHECK_NOTNULL(watcher);

  watcher = new ProcessWatcher<ZooKeeperMasterDetectorProcess>(self());
  zk = new ZooKeeper(url.servers, ZOOKEEPER_SESSION_TIMEOUT, watcher);

  expire = false;
}

void ZooKeeperMasterDetectorProcess::updated(const string& path)
{
  // A new master might have showed up and created a sequence
  // identifier or a master may have died, determine who the master is now!
  detectMaster();
}

void ZooKeeperMasterDetectorProcess::created(const string& path)
{
  LOG(FATAL) << "Unexpected ZooKeeper event (created) for '" << path << "'";
}

void ZooKeeperMasterDetectorProcess::deleted(const string& path)
{
  LOG(FATAL) << "Unexpected ZooKeeper event (deleted) for '" << path << "'";
}

void ZooKeeperMasterDetectorProcess::timedout(const int64_t& sessionId)
{
  CHECK_NOTNULL(zk);
  if (timer.isSome() && zk->getSessionId() == sessionId) {
    LOG(WARNING) << "Timed out waiting to reconnect to ZooKeeper "
                 << "(sessionId=" << std::hex << sessionId << ")";
    timer = Option<Timer>::none();
    expire = true;
    process::post(pid, NoMasterDetectedMessage());
  }
}

void ZooKeeperMasterDetectorProcess::detectMaster()
{
  vector<string> results;

  int code = zk->getChildren(url.path, true, &results);

  if (code != ZOK) {
    LOG(ERROR) << "Master detector failed to get masters: "
               << zk->message(code);
  } else {
    LOG(INFO) << "Master detector found " << results.size()
              << " registered masters";
  }

  string masterSeq;
  long min = LONG_MAX;
  foreach (const string& result, results) {
    int i = lexical_cast<int>(result);
    if (i < min) {
      min = i;
      masterSeq = result;
    }
  }

  // No master present (lost or possibly hasn't come up yet).
  if (masterSeq.empty()) {
    process::post(pid, NoMasterDetectedMessage());
  } else if (masterSeq != currentMasterSeq) {
    // Okay, let's fetch the master pid from ZooKeeper.
    string result;
    code = zk->get(url.path + "/" + masterSeq, false, &result, NULL);

    if (code != ZOK) {
      // This is possible because the master might have failed since
      // the invocation of ZooKeeper::getChildren above.
      LOG(ERROR) << "Master detector failed to fetch new master pid: "
		 << zk->message(code);
      process::post(pid, NoMasterDetectedMessage());
    } else {
      // Now let's parse what we fetched from ZooKeeper.
      LOG(INFO) << "Master detector got new master pid: " << result;

      UPID masterPid = result;

      if (masterPid == UPID()) {
	// TODO(benh): Maybe we should try again then!?!? Parsing
	// might have failed because of DNS, and whoever is using the
	// detector might sit "unconnected" indefinitely!
	LOG(ERROR) << "Failed to parse new master pid!";
	process::post(pid, NoMasterDetectedMessage());
      } else {
	currentMasterSeq = masterSeq;
	currentMasterPID = masterPid;

        NewMasterDetectedMessage message;
	message.set_pid(currentMasterPID);
	process::post(pid, message);
      }
    }
  }
}

ZooKeeperMasterDetector::ZooKeeperMasterDetector(
    const zookeeper::URL& url,
    const UPID& pid,
    bool contend,
    bool quiet)
{
  process = new ZooKeeperMasterDetectorProcess(url, pid, contend, quiet);
  spawn(process);
}

ZooKeeperMasterDetector::~ZooKeeperMasterDetector()
{
  terminate(process);
  wait(process);
  delete process;
}
<|endoftext|>


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

#include "qmetadatacontrolmetaobject_p.h"

#include "qmetadatacontrol.h"

QT_BEGIN_NAMESPACE

// copied from qmetaobject.cpp
// do not touch without touching the moc as well
enum PropertyFlags  {
    Invalid = 0x00000000,
    Readable = 0x00000001,
    Writable = 0x00000002,
    Resettable = 0x00000004,
    EnumOrFlag = 0x00000008,
    StdCppSet = 0x00000100,
//    Override = 0x00000200,
    Designable = 0x00001000,
    ResolveDesignable = 0x00002000,
    Scriptable = 0x00004000,
    ResolveScriptable = 0x00008000,
    Stored = 0x00010000,
    ResolveStored = 0x00020000,
    Editable = 0x00040000,
    ResolveEditable = 0x00080000,
    User = 0x00100000,
    ResolveUser = 0x00200000,
    Notify = 0x00400000,
    Dynamic = 0x00800000
};

enum MethodFlags  {
    AccessPrivate = 0x00,
    AccessProtected = 0x01,
    AccessPublic = 0x02,
    AccessMask = 0x03, //mask

    MethodMethod = 0x00,
    MethodSignal = 0x04,
    MethodSlot = 0x08,
    MethodConstructor = 0x0c,
    MethodTypeMask = 0x0c,

    MethodCompatibility = 0x10,
    MethodCloned = 0x20,
    MethodScriptable = 0x40
};

struct QMetaObjectPrivate
{
    int revision;
    int className;
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
    int constructorCount, constructorData;
    int flags;
};

static inline const QMetaObjectPrivate *priv(const uint* m_data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(m_data); }
// end of copied lines from qmetaobject.cpp

QT_END_NAMESPACE

QTM_BEGIN_NAMESPACE

namespace
{
    struct MetaDataKey
    {
        QtMedia::MetaData key;
        const char *name;
    };

    const MetaDataKey qt_metaDataKeys[] =
    {
        { QtMedia::Title, "title" },
        { QtMedia::SubTitle, "subTitle" },
        { QtMedia::Author, "author" },
        { QtMedia::Comment, "comment" },
        { QtMedia::Description, "description" },
        { QtMedia::Category, "category" },
        { QtMedia::Genre, "genre" },
        { QtMedia::Year, "year" },
        { QtMedia::Date, "date" },
        { QtMedia::UserRating, "userRating" },
        { QtMedia::Keywords, "keywords" },
        { QtMedia::Language, "language" },
        { QtMedia::Publisher, "publisher" },
        { QtMedia::Copyright, "copyright" },
        { QtMedia::ParentalRating, "parentalRating" },
        { QtMedia::RatingOrganisation, "ratingOrganisation" },

        // Media
        { QtMedia::Size, "size" },
        { QtMedia::MediaType, "mediaType" },
//        { QtMedia::Duration, "duration" },

        // Audio
        { QtMedia::AudioBitRate, "audioBitRate" },
        { QtMedia::AudioCodec, "audioCodec" },
        { QtMedia::AverageLevel, "averageLevel" },
        { QtMedia::ChannelCount, "channelCount" },
        { QtMedia::PeakValue, "peakValue" },
        { QtMedia::SampleRate, "frequency" },

        // Music
        { QtMedia::AlbumTitle, "albumTitle" },
        { QtMedia::AlbumArtist, "albumArtist" },
        { QtMedia::ContributingArtist, "contributingArtist" },
        { QtMedia::Composer, "composer" },
        { QtMedia::Conductor, "conductor" },
        { QtMedia::Lyrics, "lyrics" },
        { QtMedia::Mood, "mood" },
        { QtMedia::TrackNumber, "trackNumber" },
        { QtMedia::TrackCount, "trackCount" },

        { QtMedia::CoverArtUrlSmall, "coverArtUrlSmall" },
        { QtMedia::CoverArtUrlLarge, "coverArtUrlLarge" },

        // Image/Video
        { QtMedia::Resolution, "resolution" },
        { QtMedia::PixelAspectRatio, "pixelAspectRatio" },

        // Video
        { QtMedia::VideoFrameRate, "videoFrameRate" },
        { QtMedia::VideoBitRate, "videoBitRate" },
        { QtMedia::VideoCodec, "videoCodec" },

        { QtMedia::PosterUrl, "posterUrl" },

        // Movie
        { QtMedia::ChapterNumber, "chapterNumber" },
        { QtMedia::Director, "director" },
        { QtMedia::LeadPerformer, "leadPerformer" },
        { QtMedia::Writer, "writer" },

        // Photos
        { QtMedia::CameraManufacturer, "cameraManufacturer" },
        { QtMedia::CameraModel, "cameraModel" },
        { QtMedia::Event, "event" },
        { QtMedia::Subject, "subject" },
        { QtMedia::Orientation, "orientation" },
        { QtMedia::ExposureTime, "exposureTime" },
        { QtMedia::FNumber, "fNumber" },
        { QtMedia::ExposureProgram, "exposureProgram" },
        { QtMedia::ISOSpeedRatings, "isoSpeedRatings" },
        { QtMedia::ExposureBiasValue, "exposureBiasValue" },
        { QtMedia::DateTimeOriginal, "dateTimeOriginal" },
        { QtMedia::DateTimeDigitized, "dateTimeDigitized" },
        { QtMedia::SubjectDistance, "subjectDistance" },
        { QtMedia::MeteringMode, "meteringMode" },
        { QtMedia::LightSource, "lightSource" },
        { QtMedia::Flash, "flash" },
        { QtMedia::FocalLength, "focalLength" },
        { QtMedia::ExposureMode, "exposureMode" },
        { QtMedia::WhiteBalance, "whiteBalance" },
        { QtMedia::DigitalZoomRatio, "digitalZoomRatio" },
        { QtMedia::FocalLengthIn35mmFilm, "focalLengthIn35mmFilm" },
        { QtMedia::SceneCaptureType, "sceneCaptureType" },
        { QtMedia::GainControl, "gainControl" },
        { QtMedia::Contrast, "contrast" },
        { QtMedia::Saturation, "saturation" },
        { QtMedia::Sharpness, "sharpness" },
        { QtMedia::DeviceSettingDescription, "deviceSettingDescription" }
    };

    class QMetaDataControlObject : public QObject
    {
    public:
        inline QObjectData *data() { return d_ptr.data(); }
    };
}

QMetaDataControlMetaObject::QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object)
    : m_control(control)
    , m_object(object)
    , m_string(0)
    , m_data(0)
    , m_propertyOffset(0)
    , m_signalOffset(0)
{
    const QMetaObject *superClass = m_object->metaObject();

    const int propertyCount =  sizeof(qt_metaDataKeys) / sizeof(MetaDataKey);
    const int dataSize = sizeof(uint)
            * (13                   // QMetaObjectPrivate members.
            + 5                     // 5 members per signal.
            + 4 * propertyCount     // 3 members per property + 1 notify signal per property.
            + 1);                   // Terminating value.

    m_data = reinterpret_cast<uint *>(qMalloc(dataSize));

    QMetaObjectPrivate *pMeta = reinterpret_cast<QMetaObjectPrivate *>(m_data);

    pMeta->revision = 3;
    pMeta->className = 0;
    pMeta->classInfoCount = 0;
    pMeta->classInfoData = 0;
    pMeta->methodCount = 1;
    pMeta->methodData = 13;
    pMeta->propertyCount = propertyCount;
    pMeta->propertyData = 18;
    pMeta->enumeratorCount = 0;
    pMeta->enumeratorData = 0;
    pMeta->constructorCount = 0;
    pMeta->constructorData = 0;
    pMeta->flags = 0x01;    // Dynamic meta object flag.

    const int classNameSize = qstrlen(superClass->className()) + 1;

    int stringIndex = classNameSize + 1;

    // __metaDataChanged() signal.
    static const char *changeSignal = "__metaDataChanged()";
    const int changeSignalSize = qstrlen(changeSignal) + 1;

    m_data[13] = stringIndex;                             // Signature.
    m_data[14] = classNameSize;                           // Parameters.
    m_data[15] = classNameSize;                           // Type.
    m_data[16] = classNameSize;                           // Tag.
    m_data[17] = MethodSignal | AccessProtected;          // Flags.

    stringIndex += changeSignalSize;

    const char *qvariantName = "QVariant";
    const int qvariantSize = qstrlen(qvariantName) + 1;
    const int qvariantIndex = stringIndex;

    stringIndex += qvariantSize;

    // Properties.
    for (int i = 0; i < propertyCount; ++i) {
        m_data[18 + 3 * i] = stringIndex;                                       // Name.
        m_data[19 + 3 * i] = qvariantIndex;                                     // Type.
        m_data[20 + 3 * i]
                = Readable | Writable | Notify | Dynamic | (0xffffffff << 24);  // Flags.
        m_data[18 + propertyCount * 3 + i] = 0;                                 // Notify signal.

        stringIndex += qstrlen(qt_metaDataKeys[i].name) + 1;
    }

    // Terminating value.
    m_data[18 + propertyCount * 4] = 0;

    // Build string.
    m_string = reinterpret_cast<char *>(qMalloc(stringIndex + 1));

    // Class name.
    qMemCopy(m_string, superClass->className(), classNameSize);

    stringIndex = classNameSize;

    // Null m_string.
    m_string[stringIndex] = '\0';
    stringIndex += 1;

    // __metaDataChanged() signal.
    qMemCopy(m_string + stringIndex, changeSignal, changeSignalSize);
    stringIndex += changeSignalSize;

    qMemCopy(m_string + stringIndex, qvariantName, qvariantSize);
    stringIndex += qvariantSize;

    // Properties.
    for (int i = 0; i < propertyCount; ++i) {
        const int propertyNameSize = qstrlen(qt_metaDataKeys[i].name) + 1;

        qMemCopy(m_string + stringIndex, qt_metaDataKeys[i].name, propertyNameSize);
        stringIndex += propertyNameSize;
    }

    // Terminating character.
    m_string[stringIndex] = '\0';

    d.superdata = superClass;
    d.stringdata = m_string;
    d.data = m_data;
    d.extradata = 0;

    static_cast<QMetaDataControlObject *>(m_object)->data()->metaObject = this;

    m_propertyOffset = propertyOffset();
    m_signalOffset = methodOffset();
}

QMetaDataControlMetaObject::~QMetaDataControlMetaObject()
{
    static_cast<QMetaDataControlObject *>(m_object)->data()->metaObject = 0;

    qFree(m_data);
    qFree(m_string);
}

int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
{
    if (c == QMetaObject::ReadProperty && id >= m_propertyOffset) {
        int propId = id - m_propertyOffset;

        *reinterpret_cast<QVariant *>(a[0]) = m_control->metaData(qt_metaDataKeys[propId].key);

        return -1;
    } else if (c == QMetaObject::WriteProperty && id >= m_propertyOffset) {
        int propId = id - m_propertyOffset;

        m_control->setMetaData(qt_metaDataKeys[propId].key, *reinterpret_cast<QVariant *>(a[0]));

        return -1;
    } else {
        return m_object->qt_metacall(c, id, a);
    }
}

int QMetaDataControlMetaObject::createProperty(const char *, const char *)
{
    return -1;
}

void QMetaDataControlMetaObject::metaDataChanged()
{
    activate(m_object, m_signalOffset, 0);
}

QTM_END_NAMESPACE
<commit_msg>Correct QtMedia::SampleRate property mapping.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmetadatacontrolmetaobject_p.h"

#include "qmetadatacontrol.h"

QT_BEGIN_NAMESPACE

// copied from qmetaobject.cpp
// do not touch without touching the moc as well
enum PropertyFlags  {
    Invalid = 0x00000000,
    Readable = 0x00000001,
    Writable = 0x00000002,
    Resettable = 0x00000004,
    EnumOrFlag = 0x00000008,
    StdCppSet = 0x00000100,
//    Override = 0x00000200,
    Designable = 0x00001000,
    ResolveDesignable = 0x00002000,
    Scriptable = 0x00004000,
    ResolveScriptable = 0x00008000,
    Stored = 0x00010000,
    ResolveStored = 0x00020000,
    Editable = 0x00040000,
    ResolveEditable = 0x00080000,
    User = 0x00100000,
    ResolveUser = 0x00200000,
    Notify = 0x00400000,
    Dynamic = 0x00800000
};

enum MethodFlags  {
    AccessPrivate = 0x00,
    AccessProtected = 0x01,
    AccessPublic = 0x02,
    AccessMask = 0x03, //mask

    MethodMethod = 0x00,
    MethodSignal = 0x04,
    MethodSlot = 0x08,
    MethodConstructor = 0x0c,
    MethodTypeMask = 0x0c,

    MethodCompatibility = 0x10,
    MethodCloned = 0x20,
    MethodScriptable = 0x40
};

struct QMetaObjectPrivate
{
    int revision;
    int className;
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
    int constructorCount, constructorData;
    int flags;
};

static inline const QMetaObjectPrivate *priv(const uint* m_data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(m_data); }
// end of copied lines from qmetaobject.cpp

QT_END_NAMESPACE

QTM_BEGIN_NAMESPACE

namespace
{
    struct MetaDataKey
    {
        QtMedia::MetaData key;
        const char *name;
    };

    const MetaDataKey qt_metaDataKeys[] =
    {
        { QtMedia::Title, "title" },
        { QtMedia::SubTitle, "subTitle" },
        { QtMedia::Author, "author" },
        { QtMedia::Comment, "comment" },
        { QtMedia::Description, "description" },
        { QtMedia::Category, "category" },
        { QtMedia::Genre, "genre" },
        { QtMedia::Year, "year" },
        { QtMedia::Date, "date" },
        { QtMedia::UserRating, "userRating" },
        { QtMedia::Keywords, "keywords" },
        { QtMedia::Language, "language" },
        { QtMedia::Publisher, "publisher" },
        { QtMedia::Copyright, "copyright" },
        { QtMedia::ParentalRating, "parentalRating" },
        { QtMedia::RatingOrganisation, "ratingOrganisation" },

        // Media
        { QtMedia::Size, "size" },
        { QtMedia::MediaType, "mediaType" },
//        { QtMedia::Duration, "duration" },

        // Audio
        { QtMedia::AudioBitRate, "audioBitRate" },
        { QtMedia::AudioCodec, "audioCodec" },
        { QtMedia::AverageLevel, "averageLevel" },
        { QtMedia::ChannelCount, "channelCount" },
        { QtMedia::PeakValue, "peakValue" },
        { QtMedia::SampleRate, "sampleRate" },

        // Music
        { QtMedia::AlbumTitle, "albumTitle" },
        { QtMedia::AlbumArtist, "albumArtist" },
        { QtMedia::ContributingArtist, "contributingArtist" },
        { QtMedia::Composer, "composer" },
        { QtMedia::Conductor, "conductor" },
        { QtMedia::Lyrics, "lyrics" },
        { QtMedia::Mood, "mood" },
        { QtMedia::TrackNumber, "trackNumber" },
        { QtMedia::TrackCount, "trackCount" },

        { QtMedia::CoverArtUrlSmall, "coverArtUrlSmall" },
        { QtMedia::CoverArtUrlLarge, "coverArtUrlLarge" },

        // Image/Video
        { QtMedia::Resolution, "resolution" },
        { QtMedia::PixelAspectRatio, "pixelAspectRatio" },

        // Video
        { QtMedia::VideoFrameRate, "videoFrameRate" },
        { QtMedia::VideoBitRate, "videoBitRate" },
        { QtMedia::VideoCodec, "videoCodec" },

        { QtMedia::PosterUrl, "posterUrl" },

        // Movie
        { QtMedia::ChapterNumber, "chapterNumber" },
        { QtMedia::Director, "director" },
        { QtMedia::LeadPerformer, "leadPerformer" },
        { QtMedia::Writer, "writer" },

        // Photos
        { QtMedia::CameraManufacturer, "cameraManufacturer" },
        { QtMedia::CameraModel, "cameraModel" },
        { QtMedia::Event, "event" },
        { QtMedia::Subject, "subject" },
        { QtMedia::Orientation, "orientation" },
        { QtMedia::ExposureTime, "exposureTime" },
        { QtMedia::FNumber, "fNumber" },
        { QtMedia::ExposureProgram, "exposureProgram" },
        { QtMedia::ISOSpeedRatings, "isoSpeedRatings" },
        { QtMedia::ExposureBiasValue, "exposureBiasValue" },
        { QtMedia::DateTimeOriginal, "dateTimeOriginal" },
        { QtMedia::DateTimeDigitized, "dateTimeDigitized" },
        { QtMedia::SubjectDistance, "subjectDistance" },
        { QtMedia::MeteringMode, "meteringMode" },
        { QtMedia::LightSource, "lightSource" },
        { QtMedia::Flash, "flash" },
        { QtMedia::FocalLength, "focalLength" },
        { QtMedia::ExposureMode, "exposureMode" },
        { QtMedia::WhiteBalance, "whiteBalance" },
        { QtMedia::DigitalZoomRatio, "digitalZoomRatio" },
        { QtMedia::FocalLengthIn35mmFilm, "focalLengthIn35mmFilm" },
        { QtMedia::SceneCaptureType, "sceneCaptureType" },
        { QtMedia::GainControl, "gainControl" },
        { QtMedia::Contrast, "contrast" },
        { QtMedia::Saturation, "saturation" },
        { QtMedia::Sharpness, "sharpness" },
        { QtMedia::DeviceSettingDescription, "deviceSettingDescription" }
    };

    class QMetaDataControlObject : public QObject
    {
    public:
        inline QObjectData *data() { return d_ptr.data(); }
    };
}

QMetaDataControlMetaObject::QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object)
    : m_control(control)
    , m_object(object)
    , m_string(0)
    , m_data(0)
    , m_propertyOffset(0)
    , m_signalOffset(0)
{
    const QMetaObject *superClass = m_object->metaObject();

    const int propertyCount =  sizeof(qt_metaDataKeys) / sizeof(MetaDataKey);
    const int dataSize = sizeof(uint)
            * (13                   // QMetaObjectPrivate members.
            + 5                     // 5 members per signal.
            + 4 * propertyCount     // 3 members per property + 1 notify signal per property.
            + 1);                   // Terminating value.

    m_data = reinterpret_cast<uint *>(qMalloc(dataSize));

    QMetaObjectPrivate *pMeta = reinterpret_cast<QMetaObjectPrivate *>(m_data);

    pMeta->revision = 3;
    pMeta->className = 0;
    pMeta->classInfoCount = 0;
    pMeta->classInfoData = 0;
    pMeta->methodCount = 1;
    pMeta->methodData = 13;
    pMeta->propertyCount = propertyCount;
    pMeta->propertyData = 18;
    pMeta->enumeratorCount = 0;
    pMeta->enumeratorData = 0;
    pMeta->constructorCount = 0;
    pMeta->constructorData = 0;
    pMeta->flags = 0x01;    // Dynamic meta object flag.

    const int classNameSize = qstrlen(superClass->className()) + 1;

    int stringIndex = classNameSize + 1;

    // __metaDataChanged() signal.
    static const char *changeSignal = "__metaDataChanged()";
    const int changeSignalSize = qstrlen(changeSignal) + 1;

    m_data[13] = stringIndex;                             // Signature.
    m_data[14] = classNameSize;                           // Parameters.
    m_data[15] = classNameSize;                           // Type.
    m_data[16] = classNameSize;                           // Tag.
    m_data[17] = MethodSignal | AccessProtected;          // Flags.

    stringIndex += changeSignalSize;

    const char *qvariantName = "QVariant";
    const int qvariantSize = qstrlen(qvariantName) + 1;
    const int qvariantIndex = stringIndex;

    stringIndex += qvariantSize;

    // Properties.
    for (int i = 0; i < propertyCount; ++i) {
        m_data[18 + 3 * i] = stringIndex;                                       // Name.
        m_data[19 + 3 * i] = qvariantIndex;                                     // Type.
        m_data[20 + 3 * i]
                = Readable | Writable | Notify | Dynamic | (0xffffffff << 24);  // Flags.
        m_data[18 + propertyCount * 3 + i] = 0;                                 // Notify signal.

        stringIndex += qstrlen(qt_metaDataKeys[i].name) + 1;
    }

    // Terminating value.
    m_data[18 + propertyCount * 4] = 0;

    // Build string.
    m_string = reinterpret_cast<char *>(qMalloc(stringIndex + 1));

    // Class name.
    qMemCopy(m_string, superClass->className(), classNameSize);

    stringIndex = classNameSize;

    // Null m_string.
    m_string[stringIndex] = '\0';
    stringIndex += 1;

    // __metaDataChanged() signal.
    qMemCopy(m_string + stringIndex, changeSignal, changeSignalSize);
    stringIndex += changeSignalSize;

    qMemCopy(m_string + stringIndex, qvariantName, qvariantSize);
    stringIndex += qvariantSize;

    // Properties.
    for (int i = 0; i < propertyCount; ++i) {
        const int propertyNameSize = qstrlen(qt_metaDataKeys[i].name) + 1;

        qMemCopy(m_string + stringIndex, qt_metaDataKeys[i].name, propertyNameSize);
        stringIndex += propertyNameSize;
    }

    // Terminating character.
    m_string[stringIndex] = '\0';

    d.superdata = superClass;
    d.stringdata = m_string;
    d.data = m_data;
    d.extradata = 0;

    static_cast<QMetaDataControlObject *>(m_object)->data()->metaObject = this;

    m_propertyOffset = propertyOffset();
    m_signalOffset = methodOffset();
}

QMetaDataControlMetaObject::~QMetaDataControlMetaObject()
{
    static_cast<QMetaDataControlObject *>(m_object)->data()->metaObject = 0;

    qFree(m_data);
    qFree(m_string);
}

int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
{
    if (c == QMetaObject::ReadProperty && id >= m_propertyOffset) {
        int propId = id - m_propertyOffset;

        *reinterpret_cast<QVariant *>(a[0]) = m_control->metaData(qt_metaDataKeys[propId].key);

        return -1;
    } else if (c == QMetaObject::WriteProperty && id >= m_propertyOffset) {
        int propId = id - m_propertyOffset;

        m_control->setMetaData(qt_metaDataKeys[propId].key, *reinterpret_cast<QVariant *>(a[0]));

        return -1;
    } else {
        return m_object->qt_metacall(c, id, a);
    }
}

int QMetaDataControlMetaObject::createProperty(const char *, const char *)
{
    return -1;
}

void QMetaDataControlMetaObject::metaDataChanged()
{
    activate(m_object, m_signalOffset, 0);
}

QTM_END_NAMESPACE
<|endoftext|>


<commit_before>/* Siconos-Kernel  Copyright INRIA 2005-2012.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY siconos-team@lists.gforge.inria.fr
 */
/*! \file NewtonEulerR.hpp

*/
#ifndef PrismaticJointRELATION_H
#define PrismaticJointRELATION_H

#include "SiconosKernel.hpp"

/** \class PrismaticJointR
 *  \brief This class implements a prismatic joint between one or two Newton/Euler Dynamical system
 *
 * From a given axis, we construct two unit othorgonal vectors to the axis V1 and V2 such that
 *  (axis,V1,V2) is an orthogonal frame
 *
 *
 *
 */
class PrismaticJointR : public NewtonEulerR
{
public:
  /** Number of equalities that defines the jiont
   */
  static int _sNbEqualities;

public:
  /** Axis of the prismatic point in the inertial frame of reference
   */
  SP::SiconosVector _axis0;

  /** Pointers on the concerned dynamical systems*/
  SP::NewtonEulerDS _d1;
  SP::NewtonEulerDS _d2;

  /** _V1 is an unit vector that is orthogonal to the prismatic axis _axis0.
   * It forms with _V2 and _axis0 a base such that (_axis0,_V1,_v2) is an orthogonal
   * frame
   */
  SP::SiconosVector _V1;

  /** _V2 is an unit vector that is orthogonal to the prismatic axis _axis0.
   * It forms with _V2 and _axis0 a base such that (_axis0,_V1,_v2) is an orthogonal
   * frame
   */
  SP::SiconosVector _V2;

  /** Convenient storage of the components of _V1 and _V2
   */
  double _V1x;
  double _V1y;
  double _V1z;
  double _V2x;
  double _V2y;
  double _V2z;

  /**
   */
  double _G10G20d1x;
  double _G10G20d1y;
  double _G10G20d1z;

  double _q1cq202;
  double _q1cq203;
  double _q1cq204;

  /** constructor from two dynamical systems and an axis
   *  \param d1 first  DynamicalSystem link by the  joint
   *  \param d2 second  DynamicalSystem link by the joint
   * \param axis SiconosVector of size 3 that defines the prismatic axis
   *  in the body  frame of d1 ?
   */
  PrismaticJointR(SP::NewtonEulerDS d1, SP::NewtonEulerDS d2, SP::SiconosVector axis);

  /** constructor from one dynamical systems and an axis
   *  \param d1 the  DynamicalSystem link by the  joint
   * \param axis SiconosVector of size 3 that defines the prismatic axis
   *  in the inertial frame of reference
   */
  PrismaticJointR(SP::NewtonEulerDS d2, SP::SiconosVector axis);

  void computeFromInitialPosition();

  void displayInitialPosition();

  void computeV1V2FromAxis();

  /** destructor
   */
  virtual ~PrismaticJointR() {};

  virtual void computeJachq(const double time, Interaction& inter);

  virtual void computeh(const double time, Interaction& inter);

  virtual void computeDotJachq(const double time, Interaction& inter);

  /* The options were    : operatorarrow */
  double H1(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  /* The options were    : operatorarrow */
  double H2(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  /* The options were    : operatorarrow */
  double H3(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);
  /* The options were    : operatorarrow */
  double H5(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  /* The options were    : operatorarrow */
  double H4(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  void Jd1d2(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
             double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  void Jd2(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
           double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  void DotJd1d2(double Xdot1, double Ydot1, double Zdot1, double qdot10, double qdot11, double qdot12, double qdot13,
                double Xdot2, double Ydot2, double Zdot2, double qdot20, double qdot21, double qdot22, double qdot23);

  void DotJd2(double Xdot1, double Ydot1, double Zdot1, double qdot10, double qdot11, double qdot12, double qdot13,
              double X2, double Y2, double Z2, double qdot20, double qdot21, double qdot22, double qdot23);

};

TYPEDEF_SPTR(PrismaticJointR)
#endif  PrismaticJointRELATION_H
<commit_msg>[Mechanics] fix missing comment in file<commit_after>/* Siconos-Kernel  Copyright INRIA 2005-2012.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY siconos-team@lists.gforge.inria.fr
 */
/*! \file NewtonEulerR.hpp

*/
#ifndef PrismaticJointRELATION_H
#define PrismaticJointRELATION_H

#include "SiconosKernel.hpp"

/** \class PrismaticJointR
 *  \brief This class implements a prismatic joint between one or two Newton/Euler Dynamical system
 *
 * From a given axis, we construct two unit othorgonal vectors to the axis V1 and V2 such that
 *  (axis,V1,V2) is an orthogonal frame
 *
 *
 *
 */
class PrismaticJointR : public NewtonEulerR
{
public:
  /** Number of equalities that defines the jiont
   */
  static int _sNbEqualities;

public:
  /** Axis of the prismatic point in the inertial frame of reference
   */
  SP::SiconosVector _axis0;

  /** Pointers on the concerned dynamical systems*/
  SP::NewtonEulerDS _d1;
  SP::NewtonEulerDS _d2;

  /** _V1 is an unit vector that is orthogonal to the prismatic axis _axis0.
   * It forms with _V2 and _axis0 a base such that (_axis0,_V1,_v2) is an orthogonal
   * frame
   */
  SP::SiconosVector _V1;

  /** _V2 is an unit vector that is orthogonal to the prismatic axis _axis0.
   * It forms with _V2 and _axis0 a base such that (_axis0,_V1,_v2) is an orthogonal
   * frame
   */
  SP::SiconosVector _V2;

  /** Convenient storage of the components of _V1 and _V2
   */
  double _V1x;
  double _V1y;
  double _V1z;
  double _V2x;
  double _V2y;
  double _V2z;

  /**
   */
  double _G10G20d1x;
  double _G10G20d1y;
  double _G10G20d1z;

  double _q1cq202;
  double _q1cq203;
  double _q1cq204;

  /** constructor from two dynamical systems and an axis
   *  \param d1 first  DynamicalSystem link by the  joint
   *  \param d2 second  DynamicalSystem link by the joint
   * \param axis SiconosVector of size 3 that defines the prismatic axis
   *  in the body  frame of d1 ?
   */
  PrismaticJointR(SP::NewtonEulerDS d1, SP::NewtonEulerDS d2, SP::SiconosVector axis);

  /** constructor from one dynamical systems and an axis
   *  \param d1 the  DynamicalSystem link by the  joint
   * \param axis SiconosVector of size 3 that defines the prismatic axis
   *  in the inertial frame of reference
   */
  PrismaticJointR(SP::NewtonEulerDS d2, SP::SiconosVector axis);

  void computeFromInitialPosition();

  void displayInitialPosition();

  void computeV1V2FromAxis();

  /** destructor
   */
  virtual ~PrismaticJointR() {};

  virtual void computeJachq(const double time, Interaction& inter);

  virtual void computeh(const double time, Interaction& inter);

  virtual void computeDotJachq(const double time, Interaction& inter);

  /* The options were    : operatorarrow */
  double H1(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  /* The options were    : operatorarrow */
  double H2(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  /* The options were    : operatorarrow */
  double H3(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);
  /* The options were    : operatorarrow */
  double H5(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  /* The options were    : operatorarrow */
  double H4(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
            double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  void Jd1d2(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
             double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  void Jd2(double X1, double Y1, double Z1, double q10, double q11, double q12, double q13,
           double X2, double Y2, double Z2, double q20, double q21, double q22, double q23);

  void DotJd1d2(double Xdot1, double Ydot1, double Zdot1, double qdot10, double qdot11, double qdot12, double qdot13,
                double Xdot2, double Ydot2, double Zdot2, double qdot20, double qdot21, double qdot22, double qdot23);

  void DotJd2(double Xdot1, double Ydot1, double Zdot1, double qdot10, double qdot11, double qdot12, double qdot13,
              double X2, double Y2, double Z2, double qdot20, double qdot21, double qdot22, double qdot23);

};

TYPEDEF_SPTR(PrismaticJointR)
#endif  //PrismaticJointRELATION_H
<|endoftext|>