<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "motive/engine.h"
#include "motive/math/bulk_spline_evaluator.h"
#include "motive/math/compact_spline.h"
#include "motive/processor/spline_data.h"
#include "motive/spline_init.h"

namespace motive {

// Add some buffer to the y-range to allow for intermediate nodes
// that go above or below the supplied nodes.
static const float kYRangeBufferPercent = 1.2f;

class SplineMotiveProcessor : public MotiveProcessorNf {
 public:
  virtual ~SplineMotiveProcessor() {
    for (auto it = spline_pool_.begin(); it != spline_pool_.end(); ++it) {
      CompactSpline::Destroy(*it);
    }
  }

  virtual void AdvanceFrame(MotiveTime delta_time) {
    Defragment();
    interpolator_.AdvanceFrame(static_cast<float>(delta_time));
  }

  virtual MotivatorType Type() const { return SplineInit::kType; }
  virtual int Priority() const { return 0; }

  // Accessors to allow the user to get and set simluation values.
  virtual const float* Values(MotiveIndex index) const {
    return interpolator_.Ys(index);
  }
  virtual void Velocities(MotiveIndex index, MotiveDimension dimensions,
                          float* out) const {
    return interpolator_.Derivatives(index, dimensions, out);
  }
  virtual void Directions(MotiveIndex index, MotiveDimension dimensions,
                          float* out) const {
    return interpolator_.DerivativesWithoutPlayback(index, dimensions, out);
  }
  virtual void TargetValues(MotiveIndex index, MotiveDimension dimensions,
                            float* out) const {
    return interpolator_.EndYs(index, dimensions, out);
  }
  virtual void TargetVelocities(MotiveIndex index, MotiveDimension dimensions,
                                float* out) const {
    return interpolator_.EndDerivatives(index, dimensions, out);
  }
  virtual void Differences(MotiveIndex index, MotiveDimension dimensions,
                           float* out) const {
    return interpolator_.YDifferencesToEnd(index, dimensions, out);
  }
  virtual MotiveTime TargetTime(MotiveIndex index,
                                MotiveDimension dimensions) const {
    MotiveTime greatest = std::numeric_limits<MotiveTime>::min();
    for (MotiveDimension i = 0; i < dimensions; ++i) {
      greatest =
          std::max(greatest,
                   static_cast<MotiveTime>(interpolator_.EndX(index + i)
                                           - interpolator_.X(index + i)));
    }
    return greatest;
  }
  virtual MotiveTime SplineTime(MotiveIndex index) const {
    return static_cast<MotiveTime>(interpolator_.X(index));
  }

  virtual void SetTargets(MotiveIndex index, MotiveDimension dimensions,
                          const MotiveTarget1f* ts) {
    for (MotiveDimension i = 0; i < dimensions; ++i) {
      SetTarget(index + i, ts[i]);
    }
  }

  virtual void SetSplines(MotiveIndex index, MotiveDimension dimensions,
                          const CompactSpline* splines,
                          const SplinePlayback& playback) {
    // Return the local splines to the spline pool. We use external splines now.
    for (MotiveDimension i = index; i < index + dimensions; ++i) {
      FreeSplineForIndex(i);
    }

    // Initialize spline to follow way points.
    // Snaps the current value and velocity to the way point's start value
    // and velocity.
    interpolator_.SetSplines(index, dimensions, splines, playback);
  }

  virtual void SetSplinesAndTargets(MotiveIndex index,
                                    MotiveDimension dimensions,
                                    const CompactSpline* const* splines,
                                    const SplinePlayback& playback,
                                    const MotiveTarget1f* targets) {
    // Initialize either with a spline or a target.
    // We initialize one by one instead of in bulk. Not as efficient.
    for (MotiveDimension i = 0; i < dimensions; ++i) {
      if (splines[i] == nullptr) {
        SetTarget(index + i, targets[i]);
      } else {
        FreeSplineForIndex(index + i);
        interpolator_.SetSplines(index + i, 1, splines[i], playback);
      }
    }
  }

  virtual void Splines(MotiveIndex index, MotiveDimension dimensions,
                       const motive::CompactSpline** splines) const {
    // Get splines at index for dimensions.
    interpolator_.Splines(index, dimensions, splines);
  }

  // TODO: Push this loop into BulkSplineInterpolator.
  virtual void SetSplineTime(MotiveIndex index, MotiveDimension dimensions,
                             MotiveTime time) {
    interpolator_.SetXs(index, dimensions, static_cast<float>(time));
  }

  // TODO: Push this loop into BulkSplineInterpolator.
  virtual void SetSplinePlaybackRate(MotiveIndex index,
                                     MotiveDimension dimensions,
                                     float playback_rate) {
    interpolator_.SetPlaybackRates(index, dimensions, playback_rate);
  }

 protected:
  // TODO: Change to CreateSplineToTarget()
  void SetTarget(MotiveIndex index, const MotiveTarget1f& t) {
    SplineData& d = Data(index);

    // If the first node specifies time=0 or there is no valid data in the
    // interpolator, we want to override the current values with the values
    // specified in the first node.
    const MotiveNode1f& node0 = t.Node(0);
    const bool override_current =
        node0.time == 0 || !interpolator_.Valid(index);
    // TODO(b/65298927):  It seems that the animation pipeline can produce data
    // that is out of range.  Instead of just using node0.value directly, if
    // the interpolator is doing modular arithmetic, normalize the y value to
    // the modulator's range.
    const float start_y =
        override_current
            ? (interpolator_.ModularArithmetic(index)
                   ? interpolator_.ModularRange(index).Normalize(node0.value)
                   : node0.value)
            : interpolator_.NormalizedY(index);
    const float start_derivative =
        override_current ? node0.velocity : Velocity(index);
    const int start_node_index = override_current ? 1 : 0;

    // Ensure we have a local spline available, allocated from our pool of
    // splines.
    if (d.local_spline == nullptr) {
      // The default number of nodes is enough.
      d.local_spline = AllocateSpline(CompactSpline::kDefaultMaxNodes);
    }

    // Initialize the compact spline to hold the sequence of nodes in 't'.
    // Add the first node, which has the start condition.
    const float end_x = static_cast<float>(t.EndTime());
    const Range y_range = CalculateYRange(index, t, start_y);
    const float x_granularity = CompactSpline::RecommendXGranularity(end_x);
    d.local_spline->Init(y_range, x_granularity);
    d.local_spline->AddNode(0.0f, start_y, start_derivative);

    // Add subsequent nodes, in turn, taking care to respect the 'direction'
    // request when using modular arithmetic.
    float prev_y = start_y;
    for (int i = start_node_index; i < t.num_nodes(); ++i) {
      const MotiveNode1f& n = t.Node(i);
      const float y = interpolator_.NextY(index, prev_y, n.value, n.direction);
      d.local_spline->AddNode(static_cast<float>(n.time), y, n.velocity,
                              motive::kAddWithoutModification);
      prev_y = y;
    }

    // Point the interpolator at the spline we just created. Always start our
    // spline at time 0.
    interpolator_.SetSplines(index, 1, d.local_spline, SplinePlayback());
  }

  virtual void InitializeIndices(const MotivatorInit& init, MotiveIndex index,
                                 MotiveDimension dimensions,
                                 MotiveEngine* /*engine*/) {
    auto spline_init = static_cast<const SplineInit&>(init);
    interpolator_.SetYRanges(index, dimensions, spline_init.range());
  }

  bool SupportsCloning() override { return true; }

  void CloneIndices(MotiveIndex dst, MotiveIndex src,
                    MotiveDimension dimensions,
                    MotiveEngine* /*engine*/) override {
    interpolator_.CopyIndices(
        dst, src, dimensions,
        [this](MotiveIndex index, const CompactSpline* src_spline) {
          CompactSpline* dest_spline = AllocateSpline(src_spline->max_nodes());
          *dest_spline = *src_spline;
          Data(index).local_spline = dest_spline;
          return dest_spline;
        });
  }

  virtual void RemoveIndices(MotiveIndex index, MotiveDimension dimensions) {
    // Clear reference to this spline.
    interpolator_.ClearSplines(index, dimensions);

    // Return splines to the pool of splines.
    for (MotiveIndex i = index; i < index + dimensions; ++i) {
      SplineData& d = Data(i);
      FreeSpline(d.local_spline);
      d.local_spline = nullptr;
    }
  }

  virtual void MoveIndices(MotiveIndex old_index, MotiveIndex new_index,
                           MotiveDimension dimensions) {
    MotiveIndex old_i = old_index;
    MotiveIndex new_i = new_index;
    for (MotiveDimension i = 0; i < dimensions; ++i, ++new_i, ++old_i) {
      data_[new_i] = data_[old_i];
    }
    interpolator_.MoveIndices(old_index, new_index, dimensions);
  }

  virtual void SetNumIndices(MotiveIndex num_indices) {
    data_.resize(num_indices);
    interpolator_.SetNumIndices(num_indices);
  }

  const SplineData& Data(MotiveIndex index) const {
    assert(ValidIndex(index));
    return data_[index];
  }

  SplineData& Data(MotiveIndex index) {
    assert(ValidIndex(index));
    return data_[index];
  }

  CompactSpline* AllocateSpline(CompactSplineIndex max_nodes) {
    // Return a spline from the pool. Eventually we'll reach a high water mark
    // and we will stop allocating new splines. The returned spline must have
    // enough nodes.
    for (size_t i = 0; i < spline_pool_.size(); ++i) {
      CompactSpline* spline = spline_pool_[i];
      if (spline->max_nodes() >= max_nodes) {
        spline_pool_[i] = spline_pool_.back();
        spline_pool_.pop_back();
        return spline;
      }
    }

    // Create a spline with enough nodes otherwise.
    return CompactSpline::Create(max_nodes);
  }

  void FreeSplineForIndex(MotiveIndex index) {
    SplineData& d = Data(index);
    FreeSpline(d.local_spline);
    d.local_spline = nullptr;
  }

  void FreeSpline(CompactSpline* spline) {
    if (spline != nullptr) {
      spline_pool_.push_back(spline);
    }
  }

  Range CalculateYRange(MotiveIndex index, const MotiveTarget1f& t,
                        float start_y) const {
    if (interpolator_.ModularArithmetic(index)) {
      // For modular splines, we need to expand the spline's y-range to match
      // the number of nodes in the spline. It's possible for the spline to jump
      // up the entire range every node, so the range has to be broad enough
      // to hold it all.
      //
      // Note that we only normalize the first value of the spline, and
      // subsequent values are allowed to curve out of the normalized range.
      const float num_spline_nodes = static_cast<float>(t.num_nodes());
      return interpolator_.ModularRange(index).Lengthen(num_spline_nodes);
    }

    // Calculate the union of the y ranges in the target, then expand it a
    // little to allow for intermediate nodes that jump slightly beyond the
    // union's range.
    return t.ValueRange(start_y).Lengthen(kYRangeBufferPercent);
  }

  // Hold index-specific data, for example a pointer to the spline allocated
  // from 'spline_pool_'.
  std::vector<SplineData> data_;

  // Holds unused splines. When we need another local spline (because we're
  // supplied with target values but not the actual curve to get there),
  // try to recycle an old one from this pool first.
  std::vector<CompactSpline*> spline_pool_;

  // Perform the spline evaluation, over time. Indices in 'interpolator_'
  // are the same as the MotiveIndex values in this class.
  BulkSplineEvaluator interpolator_;
};

MOTIVE_INSTANCE(SplineInit, SplineMotiveProcessor);

}  // namespace motive
<commit_msg>Assume that constant/initial values of a curve may be 'wild' and normalize appropriately.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "motive/engine.h"
#include "motive/math/bulk_spline_evaluator.h"
#include "motive/math/compact_spline.h"
#include "motive/processor/spline_data.h"
#include "motive/spline_init.h"

namespace motive {

// Add some buffer to the y-range to allow for intermediate nodes
// that go above or below the supplied nodes.
static const float kYRangeBufferPercent = 1.2f;

class SplineMotiveProcessor : public MotiveProcessorNf {
 public:
  virtual ~SplineMotiveProcessor() {
    for (auto it = spline_pool_.begin(); it != spline_pool_.end(); ++it) {
      CompactSpline::Destroy(*it);
    }
  }

  virtual void AdvanceFrame(MotiveTime delta_time) {
    Defragment();
    interpolator_.AdvanceFrame(static_cast<float>(delta_time));
  }

  virtual MotivatorType Type() const { return SplineInit::kType; }
  virtual int Priority() const { return 0; }

  // Accessors to allow the user to get and set simluation values.
  virtual const float* Values(MotiveIndex index) const {
    return interpolator_.Ys(index);
  }
  virtual void Velocities(MotiveIndex index, MotiveDimension dimensions,
                          float* out) const {
    return interpolator_.Derivatives(index, dimensions, out);
  }
  virtual void Directions(MotiveIndex index, MotiveDimension dimensions,
                          float* out) const {
    return interpolator_.DerivativesWithoutPlayback(index, dimensions, out);
  }
  virtual void TargetValues(MotiveIndex index, MotiveDimension dimensions,
                            float* out) const {
    return interpolator_.EndYs(index, dimensions, out);
  }
  virtual void TargetVelocities(MotiveIndex index, MotiveDimension dimensions,
                                float* out) const {
    return interpolator_.EndDerivatives(index, dimensions, out);
  }
  virtual void Differences(MotiveIndex index, MotiveDimension dimensions,
                           float* out) const {
    return interpolator_.YDifferencesToEnd(index, dimensions, out);
  }
  virtual MotiveTime TargetTime(MotiveIndex index,
                                MotiveDimension dimensions) const {
    MotiveTime greatest = std::numeric_limits<MotiveTime>::min();
    for (MotiveDimension i = 0; i < dimensions; ++i) {
      greatest =
          std::max(greatest,
                   static_cast<MotiveTime>(interpolator_.EndX(index + i)
                                           - interpolator_.X(index + i)));
    }
    return greatest;
  }
  virtual MotiveTime SplineTime(MotiveIndex index) const {
    return static_cast<MotiveTime>(interpolator_.X(index));
  }

  virtual void SetTargets(MotiveIndex index, MotiveDimension dimensions,
                          const MotiveTarget1f* ts) {
    for (MotiveDimension i = 0; i < dimensions; ++i) {
      SetTarget(index + i, ts[i]);
    }
  }

  virtual void SetSplines(MotiveIndex index, MotiveDimension dimensions,
                          const CompactSpline* splines,
                          const SplinePlayback& playback) {
    // Return the local splines to the spline pool. We use external splines now.
    for (MotiveDimension i = index; i < index + dimensions; ++i) {
      FreeSplineForIndex(i);
    }

    // Initialize spline to follow way points.
    // Snaps the current value and velocity to the way point's start value
    // and velocity.
    interpolator_.SetSplines(index, dimensions, splines, playback);
  }

  virtual void SetSplinesAndTargets(MotiveIndex index,
                                    MotiveDimension dimensions,
                                    const CompactSpline* const* splines,
                                    const SplinePlayback& playback,
                                    const MotiveTarget1f* targets) {
    // Initialize either with a spline or a target.
    // We initialize one by one instead of in bulk. Not as efficient.
    for (MotiveDimension i = 0; i < dimensions; ++i) {
      if (splines[i] == nullptr) {
        SetTarget(index + i, targets[i]);
      } else {
        FreeSplineForIndex(index + i);
        interpolator_.SetSplines(index + i, 1, splines[i], playback);
      }
    }
  }

  virtual void Splines(MotiveIndex index, MotiveDimension dimensions,
                       const motive::CompactSpline** splines) const {
    // Get splines at index for dimensions.
    interpolator_.Splines(index, dimensions, splines);
  }

  // TODO: Push this loop into BulkSplineInterpolator.
  virtual void SetSplineTime(MotiveIndex index, MotiveDimension dimensions,
                             MotiveTime time) {
    interpolator_.SetXs(index, dimensions, static_cast<float>(time));
  }

  // TODO: Push this loop into BulkSplineInterpolator.
  virtual void SetSplinePlaybackRate(MotiveIndex index,
                                     MotiveDimension dimensions,
                                     float playback_rate) {
    interpolator_.SetPlaybackRates(index, dimensions, playback_rate);
  }

 protected:
  // TODO: Change to CreateSplineToTarget()
  void SetTarget(MotiveIndex index, const MotiveTarget1f& t) {
    SplineData& d = Data(index);

    // If the first node specifies time=0 or there is no valid data in the
    // interpolator, we want to override the current values with the values
    // specified in the first node.
    const MotiveNode1f& node0 = t.Node(0);
    const bool override_current =
        node0.time == 0 || !interpolator_.Valid(index);
    // TODO(b/65298927):  It seems that the animation pipeline can produce data
    // that is out of range.  Instead of just using node0.value directly, if
    // the interpolator is doing modular arithmetic, normalize the y value to
    // the modulator's range.
    const float start_y =
        override_current
            ? (interpolator_.ModularArithmetic(index)
                   ? interpolator_.ModularRange(index).NormalizeWildValue(
                         node0.value)
                   : node0.value)
            : interpolator_.NormalizedY(index);
    const float start_derivative =
        override_current ? node0.velocity : Velocity(index);
    const int start_node_index = override_current ? 1 : 0;

    // Ensure we have a local spline available, allocated from our pool of
    // splines.
    if (d.local_spline == nullptr) {
      // The default number of nodes is enough.
      d.local_spline = AllocateSpline(CompactSpline::kDefaultMaxNodes);
    }

    // Initialize the compact spline to hold the sequence of nodes in 't'.
    // Add the first node, which has the start condition.
    const float end_x = static_cast<float>(t.EndTime());
    const Range y_range = CalculateYRange(index, t, start_y);
    const float x_granularity = CompactSpline::RecommendXGranularity(end_x);
    d.local_spline->Init(y_range, x_granularity);
    d.local_spline->AddNode(0.0f, start_y, start_derivative);

    // Add subsequent nodes, in turn, taking care to respect the 'direction'
    // request when using modular arithmetic.
    float prev_y = start_y;
    for (int i = start_node_index; i < t.num_nodes(); ++i) {
      const MotiveNode1f& n = t.Node(i);
      const float y = interpolator_.NextY(index, prev_y, n.value, n.direction);
      d.local_spline->AddNode(static_cast<float>(n.time), y, n.velocity,
                              motive::kAddWithoutModification);
      prev_y = y;
    }

    // Point the interpolator at the spline we just created. Always start our
    // spline at time 0.
    interpolator_.SetSplines(index, 1, d.local_spline, SplinePlayback());
  }

  virtual void InitializeIndices(const MotivatorInit& init, MotiveIndex index,
                                 MotiveDimension dimensions,
                                 MotiveEngine* /*engine*/) {
    auto spline_init = static_cast<const SplineInit&>(init);
    interpolator_.SetYRanges(index, dimensions, spline_init.range());
  }

  bool SupportsCloning() override { return true; }

  void CloneIndices(MotiveIndex dst, MotiveIndex src,
                    MotiveDimension dimensions,
                    MotiveEngine* /*engine*/) override {
    interpolator_.CopyIndices(
        dst, src, dimensions,
        [this](MotiveIndex index, const CompactSpline* src_spline) {
          CompactSpline* dest_spline = AllocateSpline(src_spline->max_nodes());
          *dest_spline = *src_spline;
          Data(index).local_spline = dest_spline;
          return dest_spline;
        });
  }

  virtual void RemoveIndices(MotiveIndex index, MotiveDimension dimensions) {
    // Clear reference to this spline.
    interpolator_.ClearSplines(index, dimensions);

    // Return splines to the pool of splines.
    for (MotiveIndex i = index; i < index + dimensions; ++i) {
      SplineData& d = Data(i);
      FreeSpline(d.local_spline);
      d.local_spline = nullptr;
    }
  }

  virtual void MoveIndices(MotiveIndex old_index, MotiveIndex new_index,
                           MotiveDimension dimensions) {
    MotiveIndex old_i = old_index;
    MotiveIndex new_i = new_index;
    for (MotiveDimension i = 0; i < dimensions; ++i, ++new_i, ++old_i) {
      data_[new_i] = data_[old_i];
    }
    interpolator_.MoveIndices(old_index, new_index, dimensions);
  }

  virtual void SetNumIndices(MotiveIndex num_indices) {
    data_.resize(num_indices);
    interpolator_.SetNumIndices(num_indices);
  }

  const SplineData& Data(MotiveIndex index) const {
    assert(ValidIndex(index));
    return data_[index];
  }

  SplineData& Data(MotiveIndex index) {
    assert(ValidIndex(index));
    return data_[index];
  }

  CompactSpline* AllocateSpline(CompactSplineIndex max_nodes) {
    // Return a spline from the pool. Eventually we'll reach a high water mark
    // and we will stop allocating new splines. The returned spline must have
    // enough nodes.
    for (size_t i = 0; i < spline_pool_.size(); ++i) {
      CompactSpline* spline = spline_pool_[i];
      if (spline->max_nodes() >= max_nodes) {
        spline_pool_[i] = spline_pool_.back();
        spline_pool_.pop_back();
        return spline;
      }
    }

    // Create a spline with enough nodes otherwise.
    return CompactSpline::Create(max_nodes);
  }

  void FreeSplineForIndex(MotiveIndex index) {
    SplineData& d = Data(index);
    FreeSpline(d.local_spline);
    d.local_spline = nullptr;
  }

  void FreeSpline(CompactSpline* spline) {
    if (spline != nullptr) {
      spline_pool_.push_back(spline);
    }
  }

  Range CalculateYRange(MotiveIndex index, const MotiveTarget1f& t,
                        float start_y) const {
    if (interpolator_.ModularArithmetic(index)) {
      // For modular splines, we need to expand the spline's y-range to match
      // the number of nodes in the spline. It's possible for the spline to jump
      // up the entire range every node, so the range has to be broad enough
      // to hold it all.
      //
      // Note that we only normalize the first value of the spline, and
      // subsequent values are allowed to curve out of the normalized range.
      const float num_spline_nodes = static_cast<float>(t.num_nodes());
      return interpolator_.ModularRange(index).Lengthen(num_spline_nodes);
    }

    // Calculate the union of the y ranges in the target, then expand it a
    // little to allow for intermediate nodes that jump slightly beyond the
    // union's range.
    return t.ValueRange(start_y).Lengthen(kYRangeBufferPercent);
  }

  // Hold index-specific data, for example a pointer to the spline allocated
  // from 'spline_pool_'.
  std::vector<SplineData> data_;

  // Holds unused splines. When we need another local spline (because we're
  // supplied with target values but not the actual curve to get there),
  // try to recycle an old one from this pool first.
  std::vector<CompactSpline*> spline_pool_;

  // Perform the spline evaluation, over time. Indices in 'interpolator_'
  // are the same as the MotiveIndex values in this class.
  BulkSplineEvaluator interpolator_;
};

MOTIVE_INSTANCE(SplineInit, SplineMotiveProcessor);

}  // namespace motive
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cppeditorplugin.h"

#include "cppautocompleter.h"
#include "cppcodemodelinspectordialog.h"
#include "cppeditorconstants.h"
#include "cppeditor.h"
#include "cppeditordocument.h"
#include "cpphighlighter.h"
#include "cpphoverhandler.h"
#include "cppincludehierarchy.h"
#include "cppoutline.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
#include "cppsnippetprovider.h"
#include "cpptypehierarchy.h"

#include <coreplugin/editormanager/editormanager.h>

#ifdef WITH_TESTS
#  include "cppdoxygen_test.h"
#endif

#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/icore.h>
#include <coreplugin/navigationwidget.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cpptoolsconstants.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>

#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/theme/theme.h>

#include <QCoreApplication>
#include <QStringList>

using namespace Core;
using namespace TextEditor;
using namespace Utils;

namespace CppEditor {
namespace Internal {

void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);

enum { QUICKFIX_INTERVAL = 20 };

//////////////////////////// CppEditorFactory /////////////////////////////

class CppEditorFactory : public TextEditorFactory
{
public:
    CppEditorFactory()
    {
        setId(Constants::CPPEDITOR_ID);
        setDisplayName(qApp->translate("OpenWith::Editors", Constants::CPPEDITOR_DISPLAY_NAME));
        addMimeType(Constants::C_SOURCE_MIMETYPE);
        addMimeType(Constants::C_HEADER_MIMETYPE);
        addMimeType(Constants::CPP_SOURCE_MIMETYPE);
        addMimeType(Constants::CPP_HEADER_MIMETYPE);

        setDocumentCreator([]() { return new CppEditorDocument; });
        setEditorWidgetCreator([]() { return new CppEditorWidget; });
        setEditorCreator([]() { return new CppEditor; });
        setAutoCompleterCreator([]() { return new CppAutoCompleter; });
        setCommentStyle(CommentDefinition::CppStyle);
        setCodeFoldingSupported(true);
        setMarksVisible(true);
        setParenthesesMatchingEnabled(true);

        setEditorActionHandlers(TextEditorActionHandler::Format
                              | TextEditorActionHandler::UnCommentSelection
                              | TextEditorActionHandler::UnCollapseAll
                              | TextEditorActionHandler::FollowSymbolUnderCursor);

        addHoverHandler(new CppHoverHandler);

        if (!HostOsInfo::isMacHost() && !HostOsInfo::isWindowsHost()) {
            FileIconProvider::registerIconOverlayForMimeType(
                        QIcon(creatorTheme()->imageFile(Theme::IconOverlayCppSource, QLatin1String(":/cppeditor/images/qt_cpp.png"))),
                        Constants::CPP_SOURCE_MIMETYPE);
            FileIconProvider::registerIconOverlayForMimeType(
                        QIcon(creatorTheme()->imageFile(Theme::IconOverlayCSource, QLatin1String(":/cppeditor/images/qt_c.png"))),
                        Constants::C_SOURCE_MIMETYPE);
            FileIconProvider::registerIconOverlayForMimeType(
                        QIcon(creatorTheme()->imageFile(Theme::IconOverlayCppHeader, QLatin1String(":/cppeditor/images/qt_h.png"))),
                        Constants::CPP_HEADER_MIMETYPE);
        }
    }
};

///////////////////////////////// CppEditorPlugin //////////////////////////////////

CppEditorPlugin *CppEditorPlugin::m_instance = 0;

CppEditorPlugin::CppEditorPlugin() :
    m_renameSymbolUnderCursorAction(0),
    m_findUsagesAction(0),
    m_reparseExternallyChangedFiles(0),
    m_openTypeHierarchyAction(0),
    m_openIncludeHierarchyAction(0),
    m_quickFixProvider(0)
{
    m_instance = this;
}

CppEditorPlugin::~CppEditorPlugin()
{
    m_instance = 0;
}

CppEditorPlugin *CppEditorPlugin::instance()
{
    return m_instance;
}

CppQuickFixAssistProvider *CppEditorPlugin::quickFixProvider() const
{
    return m_quickFixProvider;
}

bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
{
    Q_UNUSED(errorMessage)
    Utils::MimeDatabase::addMimeTypes(QLatin1String(":/cppeditor/CppEditor.mimetypes.xml"));

    addAutoReleasedObject(new CppEditorFactory);
    addAutoReleasedObject(new CppOutlineWidgetFactory);
    addAutoReleasedObject(new CppTypeHierarchyFactory);
    addAutoReleasedObject(new CppIncludeHierarchyFactory);
    addAutoReleasedObject(new CppSnippetProvider);

    m_quickFixProvider = new CppQuickFixAssistProvider;
    addAutoReleasedObject(m_quickFixProvider);
    registerQuickFixes(this);

    Context context(Constants::CPPEDITOR_ID);

    ActionContainer *contextMenu = ActionManager::createMenu(Constants::M_CONTEXT);

    Command *cmd;
    ActionContainer *cppToolsMenu = ActionManager::actionContainer(CppTools::Constants::M_TOOLS_CPP);

    cmd = ActionManager::command(CppTools::Constants::SWITCH_HEADER_SOURCE);
    contextMenu->addAction(cmd);

    cmd = ActionManager::command(TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR);
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    QAction *openPreprocessorDialog = new QAction(tr("Additional Preprocessor Directives..."), this);
    cmd = ActionManager::registerAction(openPreprocessorDialog,
                                        Constants::OPEN_PREPROCESSOR_DIALOG, context);
    cmd->setDefaultKeySequence(QKeySequence());
    connect(openPreprocessorDialog, SIGNAL(triggered()), this, SLOT(showPreProcessorDialog()));
    cppToolsMenu->addAction(cmd);

    QAction *switchDeclarationDefinition = new QAction(tr("Switch Between Function Declaration/Definition"), this);
    cmd = ActionManager::registerAction(switchDeclarationDefinition,
        Constants::SWITCH_DECLARATION_DEFINITION, context, true);
    cmd->setDefaultKeySequence(QKeySequence(tr("Shift+F2")));
    connect(switchDeclarationDefinition, SIGNAL(triggered()),
            this, SLOT(switchDeclarationDefinition()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    cmd = ActionManager::command(TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT);
    cppToolsMenu->addAction(cmd);

    QAction *openDeclarationDefinitionInNextSplit =
            new QAction(tr("Open Function Declaration/Definition in Next Split"), this);
    cmd = ActionManager::registerAction(openDeclarationDefinitionInNextSplit,
        Constants::OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT, context, true);
    cmd->setDefaultKeySequence(QKeySequence(HostOsInfo::isMacHost()
                                            ? tr("Meta+E, Shift+F2")
                                            : tr("Ctrl+E, Shift+F2")));
    connect(openDeclarationDefinitionInNextSplit, SIGNAL(triggered()),
            this, SLOT(openDeclarationDefinitionInNextSplit()));
    cppToolsMenu->addAction(cmd);

    m_findUsagesAction = new QAction(tr("Find Usages"), this);
    cmd = ActionManager::registerAction(m_findUsagesAction, Constants::FIND_USAGES, context);
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+U")));
    connect(m_findUsagesAction, SIGNAL(triggered()), this, SLOT(findUsages()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    m_openTypeHierarchyAction = new QAction(tr("Open Type Hierarchy"), this);
    cmd = ActionManager::registerAction(m_openTypeHierarchyAction, Constants::OPEN_TYPE_HIERARCHY, context);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+T") : tr("Ctrl+Shift+T")));
    connect(m_openTypeHierarchyAction, SIGNAL(triggered()), this, SLOT(openTypeHierarchy()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    m_openIncludeHierarchyAction = new QAction(tr("Open Include Hierarchy"), this);
    cmd = ActionManager::registerAction(m_openIncludeHierarchyAction, Constants::OPEN_INCLUDE_HIERARCHY, context);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+I") : tr("Ctrl+Shift+I")));
    connect(m_openIncludeHierarchyAction, SIGNAL(triggered()), this, SLOT(openIncludeHierarchy()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    // Refactoring sub-menu
    Command *sep = contextMenu->addSeparator();
    sep->action()->setObjectName(QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT));
    contextMenu->addSeparator();

    m_renameSymbolUnderCursorAction = new QAction(tr("Rename Symbol Under Cursor"),
                                                  this);
    cmd = ActionManager::registerAction(m_renameSymbolUnderCursorAction,
                             Constants::RENAME_SYMBOL_UNDER_CURSOR,
                             context);
    cmd->setDefaultKeySequence(QKeySequence(tr("CTRL+SHIFT+R")));
    connect(m_renameSymbolUnderCursorAction, SIGNAL(triggered()),
            this, SLOT(renameSymbolUnderCursor()));
    cppToolsMenu->addAction(cmd);

    // Update context in global context
    cppToolsMenu->addSeparator();
    m_reparseExternallyChangedFiles = new QAction(tr("Reparse Externally Changed Files"), this);
    cmd = ActionManager::registerAction(m_reparseExternallyChangedFiles, Constants::UPDATE_CODEMODEL);
    CppTools::CppModelManager *cppModelManager = CppTools::CppModelManager::instance();
    connect(m_reparseExternallyChangedFiles, SIGNAL(triggered()), cppModelManager, SLOT(updateModifiedSourceFiles()));
    cppToolsMenu->addAction(cmd);

    cppToolsMenu->addSeparator();
    QAction *inspectCppCodeModel = new QAction(tr("Inspect C++ Code Model..."), this);
    cmd = ActionManager::registerAction(inspectCppCodeModel, Constants::INSPECT_CPP_CODEMODEL);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+F12") : tr("Ctrl+Shift+F12")));
    connect(inspectCppCodeModel, SIGNAL(triggered()), this, SLOT(inspectCppCodeModel()));
    cppToolsMenu->addAction(cmd);

    contextMenu->addSeparator(context);

    cmd = ActionManager::command(TextEditor::Constants::AUTO_INDENT_SELECTION);
    contextMenu->addAction(cmd);

    cmd = ActionManager::command(TextEditor::Constants::UN_COMMENT_SELECTION);
    contextMenu->addAction(cmd);

    connect(ProgressManager::instance(), SIGNAL(taskStarted(Core::Id)),
            this, SLOT(onTaskStarted(Core::Id)));
    connect(ProgressManager::instance(), SIGNAL(allTasksFinished(Core::Id)),
            this, SLOT(onAllTasksFinished(Core::Id)));

    return true;
}

void CppEditorPlugin::extensionsInitialized()
{
}

ExtensionSystem::IPlugin::ShutdownFlag CppEditorPlugin::aboutToShutdown()
{
    return SynchronousShutdown;
}

static CppEditorWidget *currentCppEditorWidget()
{
    if (IEditor *currentEditor = EditorManager::currentEditor())
        return qobject_cast<CppEditorWidget*>(currentEditor->widget());
    return 0;
}

void CppEditorPlugin::switchDeclarationDefinition()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->switchDeclarationDefinition(/*inNextSplit*/ false);
}

void CppEditorPlugin::openDeclarationDefinitionInNextSplit()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->switchDeclarationDefinition(/*inNextSplit*/ true);
}

void CppEditorPlugin::renameSymbolUnderCursor()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->renameSymbolUnderCursor();
}

void CppEditorPlugin::findUsages()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->findUsages();
}

void CppEditorPlugin::showPreProcessorDialog()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->showPreProcessorWidget();
}

void CppEditorPlugin::onTaskStarted(Id type)
{
    if (type == CppTools::Constants::TASK_INDEX) {
        m_renameSymbolUnderCursorAction->setEnabled(false);
        m_findUsagesAction->setEnabled(false);
        m_reparseExternallyChangedFiles->setEnabled(false);
        m_openTypeHierarchyAction->setEnabled(false);
        m_openIncludeHierarchyAction->setEnabled(false);
    }
}

void CppEditorPlugin::onAllTasksFinished(Id type)
{
    if (type == CppTools::Constants::TASK_INDEX) {
        m_renameSymbolUnderCursorAction->setEnabled(true);
        m_findUsagesAction->setEnabled(true);
        m_reparseExternallyChangedFiles->setEnabled(true);
        m_openTypeHierarchyAction->setEnabled(true);
        m_openIncludeHierarchyAction->setEnabled(true);
    }
}

void CppEditorPlugin::inspectCppCodeModel()
{
    if (m_cppCodeModelInspectorDialog) {
        ICore::raiseWindow(m_cppCodeModelInspectorDialog);
    } else {
        m_cppCodeModelInspectorDialog = new CppCodeModelInspectorDialog(ICore::mainWindow());
        m_cppCodeModelInspectorDialog->show();
    }
}

#ifdef WITH_TESTS
QList<QObject *> CppEditorPlugin::createTestObjects() const
{
    return QList<QObject *>()
        << new Tests::DoxygenTest
        ;
}
#endif

void CppEditorPlugin::openTypeHierarchy()
{
    if (currentCppEditorWidget()) {
        NavigationWidget *navigation = NavigationWidget::instance();
        navigation->activateSubWidget(Constants::TYPE_HIERARCHY_ID);
        emit typeHierarchyRequested();
    }
}

void CppEditorPlugin::openIncludeHierarchy()
{
    if (currentCppEditorWidget()) {
        NavigationWidget *navigation = NavigationWidget::instance();
        navigation->activateSubWidget(Id(Constants::INCLUDE_HIERARCHY_ID));
        emit includeHierarchyRequested();
    }
}

} // namespace Internal
} // namespace CppEditor
<commit_msg>CppEditorPlugin: remove extra forward declaration<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cppeditorplugin.h"

#include "cppautocompleter.h"
#include "cppcodemodelinspectordialog.h"
#include "cppeditorconstants.h"
#include "cppeditor.h"
#include "cppeditordocument.h"
#include "cpphighlighter.h"
#include "cpphoverhandler.h"
#include "cppincludehierarchy.h"
#include "cppoutline.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
#include "cppsnippetprovider.h"
#include "cpptypehierarchy.h"

#include <coreplugin/editormanager/editormanager.h>

#ifdef WITH_TESTS
#  include "cppdoxygen_test.h"
#endif

#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/icore.h>
#include <coreplugin/navigationwidget.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cpptoolsconstants.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>

#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/theme/theme.h>

#include <QCoreApplication>
#include <QStringList>

using namespace Core;
using namespace TextEditor;
using namespace Utils;

namespace CppEditor {
namespace Internal {

enum { QUICKFIX_INTERVAL = 20 };

//////////////////////////// CppEditorFactory /////////////////////////////

class CppEditorFactory : public TextEditorFactory
{
public:
    CppEditorFactory()
    {
        setId(Constants::CPPEDITOR_ID);
        setDisplayName(qApp->translate("OpenWith::Editors", Constants::CPPEDITOR_DISPLAY_NAME));
        addMimeType(Constants::C_SOURCE_MIMETYPE);
        addMimeType(Constants::C_HEADER_MIMETYPE);
        addMimeType(Constants::CPP_SOURCE_MIMETYPE);
        addMimeType(Constants::CPP_HEADER_MIMETYPE);

        setDocumentCreator([]() { return new CppEditorDocument; });
        setEditorWidgetCreator([]() { return new CppEditorWidget; });
        setEditorCreator([]() { return new CppEditor; });
        setAutoCompleterCreator([]() { return new CppAutoCompleter; });
        setCommentStyle(CommentDefinition::CppStyle);
        setCodeFoldingSupported(true);
        setMarksVisible(true);
        setParenthesesMatchingEnabled(true);

        setEditorActionHandlers(TextEditorActionHandler::Format
                              | TextEditorActionHandler::UnCommentSelection
                              | TextEditorActionHandler::UnCollapseAll
                              | TextEditorActionHandler::FollowSymbolUnderCursor);

        addHoverHandler(new CppHoverHandler);

        if (!HostOsInfo::isMacHost() && !HostOsInfo::isWindowsHost()) {
            FileIconProvider::registerIconOverlayForMimeType(
                        QIcon(creatorTheme()->imageFile(Theme::IconOverlayCppSource, QLatin1String(":/cppeditor/images/qt_cpp.png"))),
                        Constants::CPP_SOURCE_MIMETYPE);
            FileIconProvider::registerIconOverlayForMimeType(
                        QIcon(creatorTheme()->imageFile(Theme::IconOverlayCSource, QLatin1String(":/cppeditor/images/qt_c.png"))),
                        Constants::C_SOURCE_MIMETYPE);
            FileIconProvider::registerIconOverlayForMimeType(
                        QIcon(creatorTheme()->imageFile(Theme::IconOverlayCppHeader, QLatin1String(":/cppeditor/images/qt_h.png"))),
                        Constants::CPP_HEADER_MIMETYPE);
        }
    }
};

///////////////////////////////// CppEditorPlugin //////////////////////////////////

CppEditorPlugin *CppEditorPlugin::m_instance = 0;

CppEditorPlugin::CppEditorPlugin() :
    m_renameSymbolUnderCursorAction(0),
    m_findUsagesAction(0),
    m_reparseExternallyChangedFiles(0),
    m_openTypeHierarchyAction(0),
    m_openIncludeHierarchyAction(0),
    m_quickFixProvider(0)
{
    m_instance = this;
}

CppEditorPlugin::~CppEditorPlugin()
{
    m_instance = 0;
}

CppEditorPlugin *CppEditorPlugin::instance()
{
    return m_instance;
}

CppQuickFixAssistProvider *CppEditorPlugin::quickFixProvider() const
{
    return m_quickFixProvider;
}

bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
{
    Q_UNUSED(errorMessage)
    Utils::MimeDatabase::addMimeTypes(QLatin1String(":/cppeditor/CppEditor.mimetypes.xml"));

    addAutoReleasedObject(new CppEditorFactory);
    addAutoReleasedObject(new CppOutlineWidgetFactory);
    addAutoReleasedObject(new CppTypeHierarchyFactory);
    addAutoReleasedObject(new CppIncludeHierarchyFactory);
    addAutoReleasedObject(new CppSnippetProvider);

    m_quickFixProvider = new CppQuickFixAssistProvider;
    addAutoReleasedObject(m_quickFixProvider);
    registerQuickFixes(this);

    Context context(Constants::CPPEDITOR_ID);

    ActionContainer *contextMenu = ActionManager::createMenu(Constants::M_CONTEXT);

    Command *cmd;
    ActionContainer *cppToolsMenu = ActionManager::actionContainer(CppTools::Constants::M_TOOLS_CPP);

    cmd = ActionManager::command(CppTools::Constants::SWITCH_HEADER_SOURCE);
    contextMenu->addAction(cmd);

    cmd = ActionManager::command(TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR);
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    QAction *openPreprocessorDialog = new QAction(tr("Additional Preprocessor Directives..."), this);
    cmd = ActionManager::registerAction(openPreprocessorDialog,
                                        Constants::OPEN_PREPROCESSOR_DIALOG, context);
    cmd->setDefaultKeySequence(QKeySequence());
    connect(openPreprocessorDialog, SIGNAL(triggered()), this, SLOT(showPreProcessorDialog()));
    cppToolsMenu->addAction(cmd);

    QAction *switchDeclarationDefinition = new QAction(tr("Switch Between Function Declaration/Definition"), this);
    cmd = ActionManager::registerAction(switchDeclarationDefinition,
        Constants::SWITCH_DECLARATION_DEFINITION, context, true);
    cmd->setDefaultKeySequence(QKeySequence(tr("Shift+F2")));
    connect(switchDeclarationDefinition, SIGNAL(triggered()),
            this, SLOT(switchDeclarationDefinition()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    cmd = ActionManager::command(TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT);
    cppToolsMenu->addAction(cmd);

    QAction *openDeclarationDefinitionInNextSplit =
            new QAction(tr("Open Function Declaration/Definition in Next Split"), this);
    cmd = ActionManager::registerAction(openDeclarationDefinitionInNextSplit,
        Constants::OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT, context, true);
    cmd->setDefaultKeySequence(QKeySequence(HostOsInfo::isMacHost()
                                            ? tr("Meta+E, Shift+F2")
                                            : tr("Ctrl+E, Shift+F2")));
    connect(openDeclarationDefinitionInNextSplit, SIGNAL(triggered()),
            this, SLOT(openDeclarationDefinitionInNextSplit()));
    cppToolsMenu->addAction(cmd);

    m_findUsagesAction = new QAction(tr("Find Usages"), this);
    cmd = ActionManager::registerAction(m_findUsagesAction, Constants::FIND_USAGES, context);
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+U")));
    connect(m_findUsagesAction, SIGNAL(triggered()), this, SLOT(findUsages()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    m_openTypeHierarchyAction = new QAction(tr("Open Type Hierarchy"), this);
    cmd = ActionManager::registerAction(m_openTypeHierarchyAction, Constants::OPEN_TYPE_HIERARCHY, context);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+T") : tr("Ctrl+Shift+T")));
    connect(m_openTypeHierarchyAction, SIGNAL(triggered()), this, SLOT(openTypeHierarchy()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    m_openIncludeHierarchyAction = new QAction(tr("Open Include Hierarchy"), this);
    cmd = ActionManager::registerAction(m_openIncludeHierarchyAction, Constants::OPEN_INCLUDE_HIERARCHY, context);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+I") : tr("Ctrl+Shift+I")));
    connect(m_openIncludeHierarchyAction, SIGNAL(triggered()), this, SLOT(openIncludeHierarchy()));
    contextMenu->addAction(cmd);
    cppToolsMenu->addAction(cmd);

    // Refactoring sub-menu
    Command *sep = contextMenu->addSeparator();
    sep->action()->setObjectName(QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT));
    contextMenu->addSeparator();

    m_renameSymbolUnderCursorAction = new QAction(tr("Rename Symbol Under Cursor"),
                                                  this);
    cmd = ActionManager::registerAction(m_renameSymbolUnderCursorAction,
                             Constants::RENAME_SYMBOL_UNDER_CURSOR,
                             context);
    cmd->setDefaultKeySequence(QKeySequence(tr("CTRL+SHIFT+R")));
    connect(m_renameSymbolUnderCursorAction, SIGNAL(triggered()),
            this, SLOT(renameSymbolUnderCursor()));
    cppToolsMenu->addAction(cmd);

    // Update context in global context
    cppToolsMenu->addSeparator();
    m_reparseExternallyChangedFiles = new QAction(tr("Reparse Externally Changed Files"), this);
    cmd = ActionManager::registerAction(m_reparseExternallyChangedFiles, Constants::UPDATE_CODEMODEL);
    CppTools::CppModelManager *cppModelManager = CppTools::CppModelManager::instance();
    connect(m_reparseExternallyChangedFiles, SIGNAL(triggered()), cppModelManager, SLOT(updateModifiedSourceFiles()));
    cppToolsMenu->addAction(cmd);

    cppToolsMenu->addSeparator();
    QAction *inspectCppCodeModel = new QAction(tr("Inspect C++ Code Model..."), this);
    cmd = ActionManager::registerAction(inspectCppCodeModel, Constants::INSPECT_CPP_CODEMODEL);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+F12") : tr("Ctrl+Shift+F12")));
    connect(inspectCppCodeModel, SIGNAL(triggered()), this, SLOT(inspectCppCodeModel()));
    cppToolsMenu->addAction(cmd);

    contextMenu->addSeparator(context);

    cmd = ActionManager::command(TextEditor::Constants::AUTO_INDENT_SELECTION);
    contextMenu->addAction(cmd);

    cmd = ActionManager::command(TextEditor::Constants::UN_COMMENT_SELECTION);
    contextMenu->addAction(cmd);

    connect(ProgressManager::instance(), SIGNAL(taskStarted(Core::Id)),
            this, SLOT(onTaskStarted(Core::Id)));
    connect(ProgressManager::instance(), SIGNAL(allTasksFinished(Core::Id)),
            this, SLOT(onAllTasksFinished(Core::Id)));

    return true;
}

void CppEditorPlugin::extensionsInitialized()
{
}

ExtensionSystem::IPlugin::ShutdownFlag CppEditorPlugin::aboutToShutdown()
{
    return SynchronousShutdown;
}

static CppEditorWidget *currentCppEditorWidget()
{
    if (IEditor *currentEditor = EditorManager::currentEditor())
        return qobject_cast<CppEditorWidget*>(currentEditor->widget());
    return 0;
}

void CppEditorPlugin::switchDeclarationDefinition()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->switchDeclarationDefinition(/*inNextSplit*/ false);
}

void CppEditorPlugin::openDeclarationDefinitionInNextSplit()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->switchDeclarationDefinition(/*inNextSplit*/ true);
}

void CppEditorPlugin::renameSymbolUnderCursor()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->renameSymbolUnderCursor();
}

void CppEditorPlugin::findUsages()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->findUsages();
}

void CppEditorPlugin::showPreProcessorDialog()
{
    if (CppEditorWidget *editorWidget = currentCppEditorWidget())
        editorWidget->showPreProcessorWidget();
}

void CppEditorPlugin::onTaskStarted(Id type)
{
    if (type == CppTools::Constants::TASK_INDEX) {
        m_renameSymbolUnderCursorAction->setEnabled(false);
        m_findUsagesAction->setEnabled(false);
        m_reparseExternallyChangedFiles->setEnabled(false);
        m_openTypeHierarchyAction->setEnabled(false);
        m_openIncludeHierarchyAction->setEnabled(false);
    }
}

void CppEditorPlugin::onAllTasksFinished(Id type)
{
    if (type == CppTools::Constants::TASK_INDEX) {
        m_renameSymbolUnderCursorAction->setEnabled(true);
        m_findUsagesAction->setEnabled(true);
        m_reparseExternallyChangedFiles->setEnabled(true);
        m_openTypeHierarchyAction->setEnabled(true);
        m_openIncludeHierarchyAction->setEnabled(true);
    }
}

void CppEditorPlugin::inspectCppCodeModel()
{
    if (m_cppCodeModelInspectorDialog) {
        ICore::raiseWindow(m_cppCodeModelInspectorDialog);
    } else {
        m_cppCodeModelInspectorDialog = new CppCodeModelInspectorDialog(ICore::mainWindow());
        m_cppCodeModelInspectorDialog->show();
    }
}

#ifdef WITH_TESTS
QList<QObject *> CppEditorPlugin::createTestObjects() const
{
    return QList<QObject *>()
        << new Tests::DoxygenTest
        ;
}
#endif

void CppEditorPlugin::openTypeHierarchy()
{
    if (currentCppEditorWidget()) {
        NavigationWidget *navigation = NavigationWidget::instance();
        navigation->activateSubWidget(Constants::TYPE_HIERARCHY_ID);
        emit typeHierarchyRequested();
    }
}

void CppEditorPlugin::openIncludeHierarchy()
{
    if (currentCppEditorWidget()) {
        NavigationWidget *navigation = NavigationWidget::instance();
        navigation->activateSubWidget(Id(Constants::INCLUDE_HIERARCHY_ID));
        emit includeHierarchyRequested();
    }
}

} // namespace Internal
} // namespace CppEditor
<|endoftext|>


<commit_before>//+ Example on the  usage of the adaptive 1D integration algorithm of MathMore
// it calculates the numerically cumulative integral of a distribution (like in this case the BreitWigner)
// to execute the macro type it (you need to compile with AClic)
//
// root[0]: .x mathmoreIntegration.C+
//
// This tutorials require having libMathMore built with ROOT.
//
// To build mathmore you need to have a version of GSL >= 1.8 installed in your system
// The ROOT configure will automatically find GSL if the script gsl-config (from GSL) is in your PATH,.
// otherwise you need to configure root with the options --gsl-incdir and --gsl-libdir.
//
//
// Authors: M. Slawinska and L. Moneta

#include "TMath.h"
#include "TH1.h"
#include "TCanvas.h"
#include "TLegend.h"

//#include "TLabel.h"
#include "Math/Functor.h"
#include "Math/WrappedFunction.h"
#include "Math/IFunction.h"
#include "Math/Integrator.h"
#include <iostream>

#include "TStopwatch.h"
#include "TF1.h"

//!calculates exact integral of Breit Wigner distribution
//!and compares with existing methods

int nc = 0;
double exactIntegral( double a, double b) {

  return (TMath::ATan(2*b)- TMath::ATan(2*a))/ TMath::Pi();
}
double func( double x){
   nc++;
   return TMath::BreitWigner(x);
}
// TF1 requires the function to have the ( )( double *, double *) signature
double func2(const double *x, const double * = 0){
   nc++;
   return TMath::BreitWigner(x[0]);
}

void  testIntegPerf(double x1, double x2, int n = 100000){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Test integration performances in interval [ " << x1 << " , " << x2 << " ]\n\n";

  TStopwatch timer;

  double dx = (x2-x1)/double(n);

  //ROOT::Math::Functor1D<ROOT::Math::IGenFunction> f1(& TMath::BreitWigner);
  ROOT::Math::WrappedFunction<> f1(func);

  timer.Start();
  ROOT::Math::Integrator ig(f1 );
  double s1 = 0.0;
  nc = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s1+= ig.Integral(x1,x);
  }
  timer.Stop();
  std::cout << "Time using ROOT::Math::Integrator        :\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  int pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

  //TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x)",x1, x2);  //  this is faster but cannot measure number of function calls
  TF1 *fBW = new TF1("fBW",func2,x1, x2,0);

  timer.Start();
  nc = 0;
  double s2 = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s2+= fBW->Integral(x1,x );
  }
  timer.Stop();
  std::cout << "Time using TF1::Integral :\t\t\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

}

void  DrawCumulative(double x1, double x2, int n = 100){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Drawing cumulatives of BreitWigner in interval [ " << x1 << " , " << x2 << " ]\n\n";

   double dx = (x2-x1)/double(n);

   TH1D *cum0 = new TH1D("cum0", "", n, x1, x2); //exact cumulative
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum0->SetBinContent(i, exactIntegral(x1, x));

   }

   // alternative method using ROOT::Math::Functor class
   ROOT::Math::Functor1D f1(& TMath::BreitWigner);

   ROOT::Math::Integrator ig(f1, ROOT::Math::IntegrationOneDim::kADAPTIVE,1.E-12,1.E-12);

   TH1D *cum1 = new TH1D("cum1", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum1->SetBinContent(i, ig.Integral(x1,x));
   }

   TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x, 0, 1)",x1, x2);

   TH1D *cum2 = new TH1D("cum2", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum2->SetBinContent(i, fBW->Integral(x1,x));
   }

   TH1D *cum10 = new TH1D("cum10", "", n, x1, x2); //difference between  1 and exact
   TH1D *cum20 = new TH1D("cum23", "", n, x1, x2); //difference between 2 and excact
   for (int i = 1; i <= n; ++i) {
      double delta  =  cum1->GetBinContent(i) - cum0->GetBinContent(i);
      double delta2 =  cum2->GetBinContent(i) - cum0->GetBinContent(i);
      //std::cout << " diff for " << x << " is " << delta << "  " << cum1->GetBinContent(i) << std::endl;
      cum10->SetBinContent(i, delta );
      cum10->SetBinError(i, std::numeric_limits<double>::epsilon() * cum1->GetBinContent(i) );
      cum20->SetBinContent(i, delta2 );
   }

   TCanvas *c1 = new TCanvas("c1","Integration example",20,10,800,500);
   c1->Divide(2,1);
   c1->Draw();

   cum0->SetLineColor(kBlack);
   cum0->SetTitle("BreitWigner - the cumulative");
   cum0->SetStats(0);
   cum1->SetLineStyle(2);
   cum2->SetLineStyle(3);
   cum1->SetLineColor(kBlue);
   cum2->SetLineColor(kRed);
   c1->cd(1);
   cum0->DrawCopy("h");
   cum1->DrawCopy("same");
   //cum2->DrawCopy("same");
   cum2->DrawCopy("same");

   c1->cd(2);
   cum10->SetTitle("Difference");
   cum10->SetStats(0);
   cum10->SetLineColor(kBlue);
   cum10->Draw("e0");
   cum20->SetLineColor(kRed);
   cum20->Draw("hsame");

   TLegend * l = new TLegend(0.11, 0.8, 0.7 ,0.89);
   l->AddEntry(cum10, "GSL integration - analytical ");
   l->AddEntry(cum20, "TF1::Integral  - analytical ");
   l->Draw();

   c1->Update();
   std::cout << "\n***************************************************************\n";

}

void mathmoreIntegration(double a = -2, double b = 2)
{

   DrawCumulative(a, b);
   testIntegPerf(a, b);
}

<commit_msg>fix a compilation error on some compiler<commit_after>//+ Example on the  usage of the adaptive 1D integration algorithm of MathMore
// it calculates the numerically cumulative integral of a distribution (like in this case the BreitWigner)
// to execute the macro type it (you need to compile with AClic)
//
// root[0]: .x mathmoreIntegration.C+
//
// This tutorials require having libMathMore built with ROOT.
//
// To build mathmore you need to have a version of GSL >= 1.8 installed in your system
// The ROOT configure will automatically find GSL if the script gsl-config (from GSL) is in your PATH,.
// otherwise you need to configure root with the options --gsl-incdir and --gsl-libdir.
//
//
// Authors: M. Slawinska and L. Moneta

#include "TMath.h"
#include "TH1.h"
#include "TCanvas.h"
#include "TLegend.h"

//#include "TLabel.h"
#include "Math/Functor.h"
#include "Math/WrappedFunction.h"
#include "Math/IFunction.h"
#include "Math/Integrator.h"
#include <iostream>

#include "TStopwatch.h"
#include "TF1.h"

#include <limits>

//!calculates exact integral of Breit Wigner distribution
//!and compares with existing methods

int nc = 0;
double exactIntegral( double a, double b) {

  return (TMath::ATan(2*b)- TMath::ATan(2*a))/ TMath::Pi();
}
double func( double x){
   nc++;
   return TMath::BreitWigner(x);
}
// TF1 requires the function to have the ( )( double *, double *) signature
double func2(const double *x, const double * = 0){
   nc++;
   return TMath::BreitWigner(x[0]);
}

void  testIntegPerf(double x1, double x2, int n = 100000){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Test integration performances in interval [ " << x1 << " , " << x2 << " ]\n\n";

  TStopwatch timer;

  double dx = (x2-x1)/double(n);

  //ROOT::Math::Functor1D<ROOT::Math::IGenFunction> f1(& TMath::BreitWigner);
  ROOT::Math::WrappedFunction<> f1(func);

  timer.Start();
  ROOT::Math::Integrator ig(f1 );
  double s1 = 0.0;
  nc = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s1+= ig.Integral(x1,x);
  }
  timer.Stop();
  std::cout << "Time using ROOT::Math::Integrator        :\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  int pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

  //TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x)",x1, x2);  //  this is faster but cannot measure number of function calls
  TF1 *fBW = new TF1("fBW",func2,x1, x2,0);

  timer.Start();
  nc = 0;
  double s2 = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s2+= fBW->Integral(x1,x );
  }
  timer.Stop();
  std::cout << "Time using TF1::Integral :\t\t\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

}

void  DrawCumulative(double x1, double x2, int n = 100){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Drawing cumulatives of BreitWigner in interval [ " << x1 << " , " << x2 << " ]\n\n";

   double dx = (x2-x1)/double(n);

   TH1D *cum0 = new TH1D("cum0", "", n, x1, x2); //exact cumulative
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum0->SetBinContent(i, exactIntegral(x1, x));

   }

   // alternative method using ROOT::Math::Functor class
   ROOT::Math::Functor1D f1(& func);

   ROOT::Math::Integrator ig(f1, ROOT::Math::IntegrationOneDim::kADAPTIVE,1.E-12,1.E-12);

   TH1D *cum1 = new TH1D("cum1", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum1->SetBinContent(i, ig.Integral(x1,x));
   }

   TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x, 0, 1)",x1, x2);

   TH1D *cum2 = new TH1D("cum2", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum2->SetBinContent(i, fBW->Integral(x1,x));
   }

   TH1D *cum10 = new TH1D("cum10", "", n, x1, x2); //difference between  1 and exact
   TH1D *cum20 = new TH1D("cum23", "", n, x1, x2); //difference between 2 and excact
   for (int i = 1; i <= n; ++i) {
      double delta  =  cum1->GetBinContent(i) - cum0->GetBinContent(i);
      double delta2 =  cum2->GetBinContent(i) - cum0->GetBinContent(i);
      //std::cout << " diff for " << x << " is " << delta << "  " << cum1->GetBinContent(i) << std::endl;
      cum10->SetBinContent(i, delta );
      cum10->SetBinError(i, std::numeric_limits<double>::epsilon() * cum1->GetBinContent(i) );
      cum20->SetBinContent(i, delta2 );
   }

   TCanvas *c1 = new TCanvas("c1","Integration example",20,10,800,500);
   c1->Divide(2,1);
   c1->Draw();

   cum0->SetLineColor(kBlack);
   cum0->SetTitle("BreitWigner - the cumulative");
   cum0->SetStats(0);
   cum1->SetLineStyle(2);
   cum2->SetLineStyle(3);
   cum1->SetLineColor(kBlue);
   cum2->SetLineColor(kRed);
   c1->cd(1);
   cum0->DrawCopy("h");
   cum1->DrawCopy("same");
   //cum2->DrawCopy("same");
   cum2->DrawCopy("same");

   c1->cd(2);
   cum10->SetTitle("Difference");
   cum10->SetStats(0);
   cum10->SetLineColor(kBlue);
   cum10->Draw("e0");
   cum20->SetLineColor(kRed);
   cum20->Draw("hsame");

   TLegend * l = new TLegend(0.11, 0.8, 0.7 ,0.89);
   l->AddEntry(cum10, "GSL integration - analytical ");
   l->AddEntry(cum20, "TF1::Integral  - analytical ");
   l->Draw();

   c1->Update();
   std::cout << "\n***************************************************************\n";

}

void mathmoreIntegration(double a = -2, double b = 2)
{

   DrawCumulative(a, b);
   testIntegPerf(a, b);
}

<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2014 Parijat Mazumdar
 */

#include <shogun/clustering/KMeansMiniBatch.h>
#include <shogun/mathematics/Math.h>
#include <shogun/distance/Distance.h>
#include <shogun/features/DenseFeatures.h>

#ifdef _WIN32
#undef far
#undef near
#endif

using namespace shogun;

namespace shogun
{
CKMeansMiniBatch::CKMeansMiniBatch():CKMeansBase()
{
	init_mb_params();
}

CKMeansMiniBatch::CKMeansMiniBatch(int32_t k_i, CDistance* d_i, bool use_kmpp_i):CKMeansBase(k_i, d_i, use_kmpp_i)
{
	init_mb_params();
}

CKMeansMiniBatch::CKMeansMiniBatch(int32_t k_i, CDistance* d_i, SGMatrix<float64_t> centers_i):CKMeansBase(k_i, d_i, centers_i)
{
	init_mb_params();
}

CKMeansMiniBatch::~CKMeansMiniBatch()
{
}

void CKMeansMiniBatch::set_batch_size(int32_t b)
{
	REQUIRE(b>0, "Parameter bach size should be > 0");
	batch_size=b;
}

int32_t CKMeansMiniBatch::get_batch_size() const
{
	return batch_size;
}

void CKMeansMiniBatch::set_mb_iter(int32_t i)
{
	REQUIRE(i>0, "Parameter number of iterations should be > 0");
	minib_iter=i;
}

int32_t CKMeansMiniBatch::get_mb_iter() const
{
	return minib_iter;
}

void CKMeansMiniBatch::set_mb_params(int32_t b, int32_t t)
{
	REQUIRE(b>0, "Parameter bach size should be > 0");
	REQUIRE(t>0, "Parameter number of iterations should be > 0");
	batch_size=b;
	minib_iter=t;
}

void CKMeansMiniBatch::minibatch_KMeans()
{
	REQUIRE(batch_size>0,
		"batch size not set to positive value. Current batch size %d \n", batch_size);
	REQUIRE(minib_iter>0,
		"number of iterations not set to positive value. Current iterations %d \n", minib_iter);

	CDenseFeatures<float64_t>* lhs=
		CDenseFeatures<float64_t>::obtain_from_generic(distance->get_lhs());
	CDenseFeatures<float64_t>* rhs_mus=new CDenseFeatures<float64_t>(0);
	CFeatures* rhs_cache=distance->replace_rhs(rhs_mus);
	rhs_mus->set_feature_matrix(mus);
	int32_t XSize=lhs->get_num_vectors();
	int32_t dims=lhs->get_num_features();

	SGVector<float64_t> v=SGVector<float64_t>(k);
	v.zero();

	for (int32_t i=0; i<minib_iter; i++)
	{
		SGVector<int32_t> M=mbchoose_rand(batch_size,XSize);
		SGVector<int32_t> ncent=SGVector<int32_t>(batch_size);
		for (int32_t j=0; j<batch_size; j++)
		{
			SGVector<float64_t> dists=SGVector<float64_t>(k);
			for (int32_t p=0; p<k; p++)
				dists[p]=distance->distance(M[j],p);

			int32_t imin=0;
			float64_t min=dists[0];
			for (int32_t p=1; p<k; p++)
			{
				if (dists[p]<min)
				{
					imin=p;
					min=dists[p];
				}
			}
			ncent[j]=imin;
		}
		for (int32_t j=0; j<batch_size; j++)
		{
			int32_t near=ncent[j];
			SGVector<float64_t> c_alive=rhs_mus->get_feature_vector(near);
			SGVector<float64_t> x=lhs->get_feature_vector(M[j]);
			v[near]+=1.0;
			float64_t eta=1.0/v[near];
			for (int32_t c=0; c<dims; c++)
			{
				c_alive[c]=(1.0-eta)*c_alive[c]+eta*x[c];
			}
		}
	}
	SG_UNREF(lhs);
	distance->replace_rhs(rhs_cache);
	delete rhs_mus;
}

SGVector<int32_t> CKMeansMiniBatch::mbchoose_rand(int32_t b, int32_t num)
{
	SGVector<int32_t> chosen=SGVector<int32_t>(num);
	SGVector<int32_t> ret=SGVector<int32_t>(b);
	chosen.zero();
	int32_t ch=0;
	while (ch<b)
	{
		const int32_t n=CMath::random(0,num-1);
		if (chosen[n]==0)
		{
			chosen[n]+=1;
			ret[ch]=n;
			ch++;
		}
	}
	return ret;
}

void CKMeansMiniBatch::init_mb_params()
{
	batch_size=-1;
	minib_iter=-1;
}

bool CKMeansMiniBatch::train_machine(CFeatures* data)
{
	initialize_training(data);
	minibatch_KMeans();
	compute_cluster_variances();
	return true;
}

}
<commit_msg>Fix KMeansMiniBatch memcheck error<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2014 Parijat Mazumdar
 */

#include <shogun/clustering/KMeansMiniBatch.h>
#include <shogun/mathematics/Math.h>
#include <shogun/distance/Distance.h>
#include <shogun/features/DenseFeatures.h>

#ifdef _WIN32
#undef far
#undef near
#endif

using namespace shogun;

namespace shogun
{
CKMeansMiniBatch::CKMeansMiniBatch():CKMeansBase()
{
	init_mb_params();
}

CKMeansMiniBatch::CKMeansMiniBatch(int32_t k_i, CDistance* d_i, bool use_kmpp_i):CKMeansBase(k_i, d_i, use_kmpp_i)
{
	init_mb_params();
}

CKMeansMiniBatch::CKMeansMiniBatch(int32_t k_i, CDistance* d_i, SGMatrix<float64_t> centers_i):CKMeansBase(k_i, d_i, centers_i)
{
	init_mb_params();
}

CKMeansMiniBatch::~CKMeansMiniBatch()
{
}

void CKMeansMiniBatch::set_batch_size(int32_t b)
{
	REQUIRE(b>0, "Parameter bach size should be > 0");
	batch_size=b;
}

int32_t CKMeansMiniBatch::get_batch_size() const
{
	return batch_size;
}

void CKMeansMiniBatch::set_mb_iter(int32_t i)
{
	REQUIRE(i>0, "Parameter number of iterations should be > 0");
	minib_iter=i;
}

int32_t CKMeansMiniBatch::get_mb_iter() const
{
	return minib_iter;
}

void CKMeansMiniBatch::set_mb_params(int32_t b, int32_t t)
{
	REQUIRE(b>0, "Parameter bach size should be > 0");
	REQUIRE(t>0, "Parameter number of iterations should be > 0");
	batch_size=b;
	minib_iter=t;
}

void CKMeansMiniBatch::minibatch_KMeans()
{
	REQUIRE(batch_size>0,
		"batch size not set to positive value. Current batch size %d \n", batch_size);
	REQUIRE(minib_iter>0,
		"number of iterations not set to positive value. Current iterations %d \n", minib_iter);

	CDenseFeatures<float64_t>* lhs=
		CDenseFeatures<float64_t>::obtain_from_generic(distance->get_lhs());
	CDenseFeatures<float64_t>* rhs_mus=new CDenseFeatures<float64_t>(mus);
	CFeatures* rhs_cache=distance->replace_rhs(rhs_mus);
	int32_t XSize=lhs->get_num_vectors();
	int32_t dims=lhs->get_num_features();

	SGVector<float64_t> v=SGVector<float64_t>(k);
	v.zero();

	for (int32_t i=0; i<minib_iter; i++)
	{
		SGVector<int32_t> M=mbchoose_rand(batch_size,XSize);
		SGVector<int32_t> ncent=SGVector<int32_t>(batch_size);
		for (int32_t j=0; j<batch_size; j++)
		{
			SGVector<float64_t> dists=SGVector<float64_t>(k);
			for (int32_t p=0; p<k; p++)
				dists[p]=distance->distance(M[j],p);

			int32_t imin=0;
			float64_t min=dists[0];
			for (int32_t p=1; p<k; p++)
			{
				if (dists[p]<min)
				{
					imin=p;
					min=dists[p];
				}
			}
			ncent[j]=imin;
		}
		for (int32_t j=0; j<batch_size; j++)
		{
			int32_t near=ncent[j];
			SGVector<float64_t> c_alive=rhs_mus->get_feature_vector(near);
			SGVector<float64_t> x=lhs->get_feature_vector(M[j]);
			v[near]+=1.0;
			float64_t eta=1.0/v[near];
			for (int32_t c=0; c<dims; c++)
			{
				c_alive[c]=(1.0-eta)*c_alive[c]+eta*x[c];
			}
		}
	}
	SG_UNREF(lhs);
	distance->replace_rhs(rhs_cache);
	delete rhs_mus;
}

SGVector<int32_t> CKMeansMiniBatch::mbchoose_rand(int32_t b, int32_t num)
{
	SGVector<int32_t> chosen=SGVector<int32_t>(num);
	SGVector<int32_t> ret=SGVector<int32_t>(b);
	chosen.zero();
	int32_t ch=0;
	while (ch<b)
	{
		const int32_t n=CMath::random(0,num-1);
		if (chosen[n]==0)
		{
			chosen[n]+=1;
			ret[ch]=n;
			ch++;
		}
	}
	return ret;
}

void CKMeansMiniBatch::init_mb_params()
{
	batch_size=-1;
	minib_iter=-1;
}

bool CKMeansMiniBatch::train_machine(CFeatures* data)
{
	initialize_training(data);
	minibatch_KMeans();
	compute_cluster_variances();
	return true;
}

}
<|endoftext|>


<commit_before>#include <cmath>
#include <stdexcept>
#include <gtest/gtest.h>
#include "stan/maths/special_functions.hpp"

TEST(maths_test, binomial_coefficient_log) {
  EXPECT_FLOAT_EQ(1.0, exp(stan::maths::binomial_coefficient_log(2.0,2.0)));
  EXPECT_FLOAT_EQ(2.0, exp(stan::maths::binomial_coefficient_log(2.0,1.0)));
  EXPECT_FLOAT_EQ(3.0, exp(stan::maths::binomial_coefficient_log(3.0,1.0)));
  EXPECT_NEAR(3.0, exp(stan::maths::binomial_coefficient_log(3.0,2.0)),0.0001);
}

TEST(maths_test, fma) {
  EXPECT_FLOAT_EQ(3.0 * 5.0 + 7.0, stan::maths::fma(3.0,5.0,7.0));
}

TEST(maths_test, beta_log) {
  EXPECT_FLOAT_EQ(0.0, stan::maths::beta_log(1.0,1.0));
  EXPECT_FLOAT_EQ(2.981361, stan::maths::beta_log(0.1,0.1));
  EXPECT_FLOAT_EQ(-4.094345, stan::maths::beta_log(3.0,4.0));
  EXPECT_FLOAT_EQ(-4.094345, stan::maths::beta_log(4.0,3.0));
}

TEST(maths_test, inv_logit) {
  EXPECT_FLOAT_EQ(0.5, stan::maths::inv_logit(0.0));
  EXPECT_FLOAT_EQ(1.0/(1.0 + exp(-5.0)), stan::maths::inv_logit(5.0));
}

TEST(maths_test, log1m) {
  EXPECT_FLOAT_EQ(log1p(-0.1),stan::maths::log1m(0.1));
}

TEST(maths_test, log_loss) {
  EXPECT_FLOAT_EQ(0.0, stan::maths::binary_log_loss(0,0.0));
  EXPECT_FLOAT_EQ(0.0, stan::maths::binary_log_loss(1,1.0));
  EXPECT_FLOAT_EQ(-log(0.5), stan::maths::binary_log_loss(0,0.5));
  EXPECT_FLOAT_EQ(-log(0.5), stan::maths::binary_log_loss(1,0.5));
  EXPECT_FLOAT_EQ(-log(0.75), stan::maths::binary_log_loss(0,0.25));
  EXPECT_FLOAT_EQ(-log(0.75), stan::maths::binary_log_loss(1,0.75));
}

TEST(maths_test, exp2) {
  EXPECT_FLOAT_EQ(std::pow(2.0,3.0), stan::maths::exp2(3.0));
  EXPECT_FLOAT_EQ(1, stan::maths::exp2(0.0));
}

TEST(maths_test, log2) {
  EXPECT_FLOAT_EQ(0.0, stan::maths::log2(1.0));
  EXPECT_FLOAT_EQ(3.0, stan::maths::log2(8.0));
  EXPECT_FLOAT_EQ(std::log(5.0)/std::log(2.0), stan::maths::log2(5.0));
}

TEST(maths_test, fdim) {
  EXPECT_FLOAT_EQ(1.0, stan::maths::fdim(3.0,2.0));
  EXPECT_FLOAT_EQ(0.0, stan::maths::fdim(2.0,3.0));
}

TEST(maths_test, step) {
  EXPECT_EQ(1, stan::maths::step(3.7));
  EXPECT_EQ(1, stan::maths::step(0.0));
  EXPECT_EQ(0, stan::maths::step(-2.93));
}

TEST(maths_test, inv_cloglog) {
  EXPECT_EQ(std::exp(-std::exp(3.7)), stan::maths::inv_cloglog(3.7));
  EXPECT_EQ(std::exp(-std::exp(0.0)), stan::maths::inv_cloglog(0.0));
  EXPECT_EQ(std::exp(-std::exp(-2.93)), stan::maths::inv_cloglog(-2.93));
}

TEST(maths_test, Phi) {
  EXPECT_EQ(0.5 + 0.5 * boost::math::erf(0.0), stan::maths::Phi(0.0));
  EXPECT_EQ(0.5 + 0.5 * boost::math::erf(0.9/std::sqrt(2.0)), stan::maths::Phi(0.9));
  EXPECT_EQ(0.5 + 0.5 * boost::math::erf(-5.0/std::sqrt(2.0)), stan::maths::Phi(-5.0));
}

TEST(maths_test, softmax) {
  std::vector<double> x;
  x.push_back(1.0);
  x.push_back(-1.0);
  x.push_back(2.0);
  std::vector<double> simplex(3);
  stan::maths::softmax<std::vector<double>,double>(x,simplex);
  EXPECT_FLOAT_EQ(1.0, simplex[0] + simplex[1] + simplex[2]);
  double sum = exp(1.0) + exp(-1.0) + exp(2.0);
  EXPECT_FLOAT_EQ(exp(1.0)/sum, simplex[0]);
  EXPECT_FLOAT_EQ(exp(-1.0)/sum, simplex[1]);
  EXPECT_FLOAT_EQ(exp(2.0)/sum, simplex[2]);
}
TEST(maths_test, softmax_exception) {
  std::vector<double> x;
  x.push_back(1.0);
  x.push_back(-1.0);
  x.push_back(2.0);
  std::vector<double> simplex(2);

  // dl: EXPECT_THROW is not able to handle this templating
  //EXPECT_THROW(stan::maths::softmax<std::vector<double>,double>(x,simplex), std::invalid_argument);
  try{
    stan::maths::softmax<std::vector<double>,double>(x,simplex);
    FAIL();
  } catch (std::invalid_argument e) {
    SUCCEED();
  }
}
TEST(maths_test, inverse_softmax_exception) {
  std::vector<double> simplex(2);
  std::vector<double> y(3);
  EXPECT_THROW(stan::maths::inverse_softmax< std::vector<double> >(simplex, y), std::invalid_argument);
}
TEST(maths_test, log1p) {
  double x;

  x = 0;
  EXPECT_FLOAT_EQ (0.0, stan::maths::log1p(x));
  x = 0.0000001;
  EXPECT_FLOAT_EQ (0.0000001, stan::maths::log1p(x));
  x = 0.001;
  EXPECT_FLOAT_EQ (0.0009995003, stan::maths::log1p(x));
  x = 0.1;
  EXPECT_FLOAT_EQ (0.09531018, stan::maths::log1p(x));
  x = 1;
  EXPECT_FLOAT_EQ (0.6931472, stan::maths::log1p(x));
  x = 10;
  EXPECT_FLOAT_EQ (2.397895, stan::maths::log1p(x));

  x = -0.0000001;
  EXPECT_FLOAT_EQ (-0.0000001, stan::maths::log1p(x));
  x = -0.001;
  EXPECT_FLOAT_EQ (-0.0010005, stan::maths::log1p(x));
  x = -0.1;
  EXPECT_FLOAT_EQ (-0.1053605, stan::maths::log1p(x));
  x = -0.999;
  EXPECT_FLOAT_EQ (-6.907755, stan::maths::log1p(x));
  x = -1;
  EXPECT_FLOAT_EQ (-std::numeric_limits<double>::infinity(), stan::maths::log1p(x));
}
TEST(maths_test, log1p_exception) {
  double x;

  x = -2;
  EXPECT_THROW (stan::maths::log1p(x), std::domain_error);
}
TEST(maths_test, lmgamma) {
  unsigned int k = 1;
  double x = 2.5;
  double result = k * (k - 1) * log(boost::math::constants::pi<double>()) / 4.0;
  result += lgamma(x); // j = 1
  EXPECT_FLOAT_EQ(result, stan::maths::lmgamma(k,x));

  k = 2;
  x = 3.0;
  result = k * (k - 1) * log(boost::math::constants::pi<double>()) / 4.0;
  result += lgamma(x); // j = 1
  result += lgamma(x + (1.0 - 2.0)/2.0); // j = 2
  EXPECT_FLOAT_EQ(result, stan::maths::lmgamma(k,x));
}

TEST(maths_test, if_else) {
  unsigned int c = 5;
  double x = 1.0;
  double y = -1.0;
  EXPECT_FLOAT_EQ(x, stan::maths::if_else(c,x,y));
  c = 0;
  EXPECT_FLOAT_EQ(y, stan::maths::if_else(c,x,y));

  bool d = true;
  int u = 1;
  int v = -1;
  EXPECT_EQ(1, stan::maths::if_else(d,u,v));
  d = false;
  EXPECT_EQ(-1, stan::maths::if_else(d,u,v));
}

TEST(maths_test, square) {
  double y = 2.0;
  EXPECT_FLOAT_EQ(y * y, stan::maths::square(y));

  y = 0.0;
  EXPECT_FLOAT_EQ(y * y, stan::maths::square(y));

  y = -32.7;
  EXPECT_FLOAT_EQ(y * y, stan::maths::square(y));
}
<commit_msg>updated special_functions test in math<commit_after>#include <cmath>
#include <stdexcept>
#include <gtest/gtest.h>
#include "stan/maths/special_functions.hpp"

TEST(maths_test, binomial_coefficient_log) {
  EXPECT_FLOAT_EQ(1.0, exp(stan::maths::binomial_coefficient_log(2.0,2.0)));
  EXPECT_FLOAT_EQ(2.0, exp(stan::maths::binomial_coefficient_log(2.0,1.0)));
  EXPECT_FLOAT_EQ(3.0, exp(stan::maths::binomial_coefficient_log(3.0,1.0)));
  EXPECT_NEAR(3.0, exp(stan::maths::binomial_coefficient_log(3.0,2.0)),0.0001);
}

TEST(maths_test, fma) {
  EXPECT_FLOAT_EQ(3.0 * 5.0 + 7.0, stan::maths::fma(3.0,5.0,7.0));
}

TEST(maths_test, beta_log) {
  EXPECT_FLOAT_EQ(0.0, stan::maths::beta_log(1.0,1.0));
  EXPECT_FLOAT_EQ(2.981361, stan::maths::beta_log(0.1,0.1));
  EXPECT_FLOAT_EQ(-4.094345, stan::maths::beta_log(3.0,4.0));
  EXPECT_FLOAT_EQ(-4.094345, stan::maths::beta_log(4.0,3.0));
}

TEST(maths_test, inv_logit) {
  EXPECT_FLOAT_EQ(0.5, stan::maths::inv_logit(0.0));
  EXPECT_FLOAT_EQ(1.0/(1.0 + exp(-5.0)), stan::maths::inv_logit(5.0));
}

TEST(maths_test, log1m) {
  EXPECT_FLOAT_EQ(log1p(-0.1),stan::maths::log1m(0.1));
}

TEST(maths_test, log_loss) {
  EXPECT_FLOAT_EQ(0.0, stan::maths::binary_log_loss(0,0.0));
  EXPECT_FLOAT_EQ(0.0, stan::maths::binary_log_loss(1,1.0));
  EXPECT_FLOAT_EQ(-log(0.5), stan::maths::binary_log_loss(0,0.5));
  EXPECT_FLOAT_EQ(-log(0.5), stan::maths::binary_log_loss(1,0.5));
  EXPECT_FLOAT_EQ(-log(0.75), stan::maths::binary_log_loss(0,0.25));
  EXPECT_FLOAT_EQ(-log(0.75), stan::maths::binary_log_loss(1,0.75));
}

TEST(maths_test, exp2) {
  EXPECT_FLOAT_EQ(std::pow(2.0,3.0), stan::maths::exp2(3.0));
  EXPECT_FLOAT_EQ(1, stan::maths::exp2(0.0));
}

TEST(maths_test, log2) {
  EXPECT_FLOAT_EQ(0.0, stan::maths::log2(1.0));
  EXPECT_FLOAT_EQ(3.0, stan::maths::log2(8.0));
  EXPECT_FLOAT_EQ(std::log(5.0)/std::log(2.0), stan::maths::log2(5.0));
}

TEST(maths_test, fdim) {
  EXPECT_FLOAT_EQ(1.0, stan::maths::fdim(3.0,2.0));
  EXPECT_FLOAT_EQ(0.0, stan::maths::fdim(2.0,3.0));
}

TEST(maths_test, step) {
  EXPECT_EQ(1, stan::maths::step(3.7));
  EXPECT_EQ(1, stan::maths::step(0.0));
  EXPECT_EQ(0, stan::maths::step(-2.93));
}

TEST(maths_test, inv_cloglog) {
  EXPECT_EQ(std::exp(-std::exp(3.7)), stan::maths::inv_cloglog(3.7));
  EXPECT_EQ(std::exp(-std::exp(0.0)), stan::maths::inv_cloglog(0.0));
  EXPECT_EQ(std::exp(-std::exp(-2.93)), stan::maths::inv_cloglog(-2.93));
}

TEST(maths_test, Phi) {
  EXPECT_EQ(0.5 + 0.5 * boost::math::erf(0.0), stan::maths::Phi(0.0));
  EXPECT_FLOAT_EQ(0.5 + 0.5 * boost::math::erf(0.9/std::sqrt(2.0)), stan::maths::Phi(0.9));
  EXPECT_EQ(0.5 + 0.5 * boost::math::erf(-5.0/std::sqrt(2.0)), stan::maths::Phi(-5.0));
}

TEST(maths_test, softmax) {
  std::vector<double> x;
  x.push_back(1.0);
  x.push_back(-1.0);
  x.push_back(2.0);
  std::vector<double> simplex(3);
  stan::maths::softmax<std::vector<double>,double>(x,simplex);
  EXPECT_FLOAT_EQ(1.0, simplex[0] + simplex[1] + simplex[2]);
  double sum = exp(1.0) + exp(-1.0) + exp(2.0);
  EXPECT_FLOAT_EQ(exp(1.0)/sum, simplex[0]);
  EXPECT_FLOAT_EQ(exp(-1.0)/sum, simplex[1]);
  EXPECT_FLOAT_EQ(exp(2.0)/sum, simplex[2]);
}
TEST(maths_test, softmax_exception) {
  std::vector<double> x;
  x.push_back(1.0);
  x.push_back(-1.0);
  x.push_back(2.0);
  std::vector<double> simplex(2);

  // dl: EXPECT_THROW is not able to handle this templating
  //EXPECT_THROW(stan::maths::softmax<std::vector<double>,double>(x,simplex), std::invalid_argument);
  try{
    stan::maths::softmax<std::vector<double>,double>(x,simplex);
    FAIL();
  } catch (std::invalid_argument e) {
    SUCCEED();
  }
}
TEST(maths_test, inverse_softmax_exception) {
  std::vector<double> simplex(2);
  std::vector<double> y(3);
  EXPECT_THROW(stan::maths::inverse_softmax< std::vector<double> >(simplex, y), std::invalid_argument);
}
TEST(maths_test, log1p) {
  double x;

  x = 0;
  EXPECT_FLOAT_EQ (0.0, stan::maths::log1p(x));
  x = 0.0000001;
  EXPECT_FLOAT_EQ (0.0000001, stan::maths::log1p(x));
  x = 0.001;
  EXPECT_FLOAT_EQ (0.0009995003, stan::maths::log1p(x));
  x = 0.1;
  EXPECT_FLOAT_EQ (0.09531018, stan::maths::log1p(x));
  x = 1;
  EXPECT_FLOAT_EQ (0.6931472, stan::maths::log1p(x));
  x = 10;
  EXPECT_FLOAT_EQ (2.397895, stan::maths::log1p(x));

  x = -0.0000001;
  EXPECT_FLOAT_EQ (-0.0000001, stan::maths::log1p(x));
  x = -0.001;
  EXPECT_FLOAT_EQ (-0.0010005, stan::maths::log1p(x));
  x = -0.1;
  EXPECT_FLOAT_EQ (-0.1053605, stan::maths::log1p(x));
  x = -0.999;
  EXPECT_FLOAT_EQ (-6.907755, stan::maths::log1p(x));
  x = -1;
  EXPECT_FLOAT_EQ (-std::numeric_limits<double>::infinity(), stan::maths::log1p(x));
}
TEST(maths_test, log1p_exception) {
  double x;

  x = -2;
  EXPECT_THROW (stan::maths::log1p(x), std::domain_error);
}
TEST(maths_test, lmgamma) {
  unsigned int k = 1;
  double x = 2.5;
  double result = k * (k - 1) * log(boost::math::constants::pi<double>()) / 4.0;
  result += lgamma(x); // j = 1
  EXPECT_FLOAT_EQ(result, stan::maths::lmgamma(k,x));

  k = 2;
  x = 3.0;
  result = k * (k - 1) * log(boost::math::constants::pi<double>()) / 4.0;
  result += lgamma(x); // j = 1
  result += lgamma(x + (1.0 - 2.0)/2.0); // j = 2
  EXPECT_FLOAT_EQ(result, stan::maths::lmgamma(k,x));
}

TEST(maths_test, if_else) {
  unsigned int c = 5;
  double x = 1.0;
  double y = -1.0;
  EXPECT_FLOAT_EQ(x, stan::maths::if_else(c,x,y));
  c = 0;
  EXPECT_FLOAT_EQ(y, stan::maths::if_else(c,x,y));

  bool d = true;
  int u = 1;
  int v = -1;
  EXPECT_EQ(1, stan::maths::if_else(d,u,v));
  d = false;
  EXPECT_EQ(-1, stan::maths::if_else(d,u,v));
}

TEST(maths_test, square) {
  double y = 2.0;
  EXPECT_FLOAT_EQ(y * y, stan::maths::square(y));

  y = 0.0;
  EXPECT_FLOAT_EQ(y * y, stan::maths::square(y));

  y = -32.7;
  EXPECT_FLOAT_EQ(y * y, stan::maths::square(y));
}
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2016, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#include <tuple>

#include "gtest/gtest.h"

#include "nupic/types/Types.hpp"
#include "nupic/utils/MovingAverage.hpp"
#include "nupic/utils/SlidingWindow.hpp"

using namespace std;
using namespace nupic;
using namespace nupic::util;

TEST(MovingAverage, Instance)
{
  MovingAverage m{3};
  Real32 newAverage;

  {
    std::vector<Real32> expectedWindow = {3.0};
    m.compute(3);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 3.0);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 3.0);
  }

  {
    std::vector<Real32> expectedWindow = {3.0, 4.0};
    m.compute(4);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 3.5);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 7.0);
  }

  {
    std::vector<Real32> expectedWindow = {3.0, 4.0, 5.0};
    m.compute(5);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 4.0);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 12.0);
  }

  {
    std::vector<Real32> expectedWindow = {6.0 ,4.0, 5.0};
    m.compute(6);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 5.0);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 15.0);
  }
};

TEST(MovingAverage, SlidingWindowInit)
{
  std::vector<Real32> existingHistorical = {3.0, 4.0, 5.0};
  MovingAverage m{3, existingHistorical};
  ASSERT_EQ(m.getData(), existingHistorical);

  MovingAverage m2{3};
  std::vector<Real32> emptyVector;
  ASSERT_EQ(m2.getData(), emptyVector);
}

TEST(MovingAverage, EqualsOperator)
{
  MovingAverage ma{3};
  MovingAverage maP{3};
  ASSERT_EQ(ma, maP);

  MovingAverage maN{10};
  ASSERT_NE(ma, maN);

  std::vector<Real32> croppedV =  nupic::util::SlidingWindow<Real32>::getLastNValues(std::vector<Real32>{3.0, 4.0, 5.0}, 2); //use Real32 as MA internally uses that too
  MovingAverage mb{2, croppedV};
  MovingAverage mbP{2, {4.0, 5.0}};
  ASSERT_EQ(mb, mbP);

  mbP.compute(6);
  mb.compute(6);
  ASSERT_EQ(mb, mbP);
}
<commit_msg>fix test<commit_after>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2016, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#include <tuple>

#include "gtest/gtest.h"

#include "nupic/types/Types.hpp"
#include "nupic/utils/MovingAverage.hpp"
#include "nupic/utils/SlidingWindow.hpp"

using namespace std;
using namespace nupic;
using namespace nupic::util;

TEST(MovingAverage, Instance)
{
  MovingAverage m{3};
  Real32 newAverage;

  {
    std::vector<Real32> expectedWindow = {3.0};
    m.compute(3);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 3.0);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 3.0);
  }

  {
    std::vector<Real32> expectedWindow = {3.0, 4.0};
    m.compute(4);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 3.5);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 7.0);
  }

  {
    std::vector<Real32> expectedWindow = {3.0, 4.0, 5.0};
    m.compute(5);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 4.0);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 12.0);
  }

  {
    std::vector<Real32> expectedWindow = {6.0 ,4.0, 5.0};
    m.compute(6);
    newAverage = m.getCurrentAvg();
    ASSERT_EQ(newAverage, 5.0);
    ASSERT_EQ(m.getData(), expectedWindow);
    ASSERT_EQ(m.getTotal(), 15.0);
  }
};

TEST(MovingAverage, SlidingWindowInit)
{
  std::vector<Real32> existingHistorical = {3.0, 4.0, 5.0};
  MovingAverage m{3, existingHistorical};
  ASSERT_EQ(m.getData(), existingHistorical);

  MovingAverage m2{3};
  std::vector<Real32> emptyVector;
  ASSERT_EQ(m2.getData(), emptyVector);
}

TEST(MovingAverage, EqualsOperator)
{
  MovingAverage ma{3};
  MovingAverage maP{3};
  ASSERT_EQ(ma, maP);

  MovingAverage maN{10};
  ASSERT_NE(ma, maN);

  mbP.compute(6);
  mb.compute(6);
  ASSERT_EQ(mb, mbP);
}
<|endoftext|>


<commit_before>#pragma once

#include "blackhole/sink/files/rotation/watcher/config.hpp"

namespace blackhole {

namespace sink {

namespace rotation {

namespace watcher {

struct time_picker_t {
    inline std::tm now() const {
        std::time_t time = std::time(nullptr);
        std::tm timeinfo;
        ::localtime_r(&time, &timeinfo);
        return timeinfo;
    }
};

template<class TimePicker = time_picker_t>
class datetime_t {
    typedef typename config_t<datetime_t<TimePicker>>::period_t period_t;

    TimePicker m_picker;
    const period_t m_period;
    mutable int previous;

public:
    datetime_t(period_t period = period_t::daily) :
        m_period(period),
        previous(watch())
    {}

    datetime_t(const std::string& period) :
        m_period(make_period(period)),
        previous(watch())
    {}

    datetime_t(const config_t<datetime_t<TimePicker>>& config) :
        m_period(make_period(config.period)),
        previous(watch())
    {}

    const TimePicker& picker() const {
        return m_picker;
    }

    period_t period() const {
        return m_period;
    }

    template<typename Backend>
    bool operator ()(Backend&, const std::string&) const {
        int current = watch();
        if (current != previous) {
            previous = current;
            return true;
        }

        return false;
    }

private:
    int watch() const {
        const std::tm& timeinfo = m_picker.now();

        switch (m_period) {
        case period_t::hourly:
            return timeinfo.tm_hour;
        case period_t::daily:
            return timeinfo.tm_mday;
        case period_t::weekly:
            return timeinfo.tm_wday;
        case period_t::monthly:
            return timeinfo.tm_mon;
        default:
            break;
        }

        return timeinfo.tm_mday;
    }

    //!@todo: rename?
    static period_t make_period(const std::string& period) {
        if (period == "H") {
            return period_t::hourly;
        } else if (period == "d") {
            return period_t::daily;
        } else if (period == "w") {
            return period_t::weekly;
        } else if (period == "M") {
            return period_t::monthly;
        }

        return period_t::daily;
    }
};

} // namespace watcher

} // namespace rotation

} // namespace sink

} // namespace blackhole
<commit_msg>Decomposition over datetime watcher’s period factory.<commit_after>#pragma once

#include "blackhole/sink/files/rotation/watcher/config.hpp"

namespace blackhole {

namespace sink {

namespace rotation {

namespace watcher {

struct time_picker_t {
    inline std::tm now() const {
        std::time_t time = std::time(nullptr);
        std::tm timeinfo;
        ::localtime_r(&time, &timeinfo);
        return timeinfo;
    }
};

template<class TimePicker = time_picker_t>
class datetime_t {
    typedef typename config_t<datetime_t<TimePicker>>::period_t period_t;

    TimePicker m_picker;
    const period_t m_period;
    mutable int previous;

public:
    datetime_t(period_t period = period_t::daily) :
        m_period(period),
        previous(watch())
    {}

    datetime_t(const std::string& period) :
        m_period(period_factory_t::get(period)),
        previous(watch())
    {}

    datetime_t(const config_t<datetime_t<TimePicker>>& config) :
        m_period(period_factory_t::get(config.period)),
        previous(watch())
    {}

    const TimePicker& picker() const {
        return m_picker;
    }

    period_t period() const {
        return m_period;
    }

    template<typename Backend>
    bool operator ()(Backend&, const std::string&) const {
        int current = watch();
        if (current != previous) {
            previous = current;
            return true;
        }

        return false;
    }

private:
    int watch() const {
        const std::tm& timeinfo = m_picker.now();

        switch (m_period) {
        case period_t::hourly:
            return timeinfo.tm_hour;
        case period_t::daily:
            return timeinfo.tm_mday;
        case period_t::weekly:
            return timeinfo.tm_wday;
        case period_t::monthly:
            return timeinfo.tm_mon;
        default:
            break;
        }

        return timeinfo.tm_mday;
    }

    class period_factory_t {
    public:
        static period_t get(const std::string& period) {
            if (period == "H") {
                return period_t::hourly;
            } else if (period == "d") {
                return period_t::daily;
            } else if (period == "w") {
                return period_t::weekly;
            } else if (period == "M") {
                return period_t::monthly;
            }

            return period_t::daily;
        }
    };
};

} // namespace watcher

} // namespace rotation

} // namespace sink

} // namespace blackhole
<|endoftext|>


<commit_before><commit_msg>[DF] Prefer moving to copying a local variable into a data member<commit_after><|endoftext|>


<commit_before><commit_msg>[TreeProcMT][NFC] Simplify cluster boundaries merging logic<commit_after><|endoftext|>