<commit_before>//---------------------------------------------------------------------------//
/*!
 * \file tstRendezvousMesh.cpp
 * \author Stuart R. Slattery
 * \brief RendezvousMesh unit tests.
 */
//---------------------------------------------------------------------------//

#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <cassert>

#include <DTK_RendezvousMesh.hpp>
#include <DTK_MeshTypes.hpp>
#include <DTK_MeshTraits.hpp>

#include <Teuchos_UnitTestHarness.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_DefaultMpiComm.hpp>
#include <Teuchos_RCP.hpp>
#include <Teuchos_OpaqueWrapper.hpp>
#include <Teuchos_TypeTraits.hpp>

#include <MBRange.hpp>

//---------------------------------------------------------------------------//
// MPI Setup
//---------------------------------------------------------------------------//

template<class Ordinal>
Teuchos::RCP<const Teuchos::Comm<Ordinal> > getDefaultComm()
{
#ifdef HAVE_MPI
    return Teuchos::DefaultComm<Ordinal>::getComm();
#else
    return Teuchos::rcp(new Teuchos::SerialComm<Ordinal>() );
#endif
}

//---------------------------------------------------------------------------//
// Mesh Implementation
//---------------------------------------------------------------------------//

class MyMesh
{
  public:

    typedef int    handle_type;

    MyMesh()
    { /* ... */ }

    MyMesh( const std::vector<int>& node_handles,
	    const std::vector<double>& coords,
	    const std::vector<int>& hex_handles,
	    const std::vector<int>& hex_connectivity )
	: d_node_handles( node_handles )
	, d_coords( coords )
	, d_hex_handles( hex_handles )
	, d_hex_connectivity( hex_connectivity )
    { /* ... */ }

    ~MyMesh()
    { /* ... */ }

    std::vector<int>::const_iterator nodesBegin() const
    { return d_node_handles.begin(); }

    std::vector<int>::const_iterator nodesEnd() const
    { return d_node_handles.end(); }

    std::vector<double>::const_iterator coordsBegin() const
    { return d_coords.begin(); }

    std::vector<double>::const_iterator coordsEnd() const
    { return d_coords.end(); }

    std::vector<int>::const_iterator hexesBegin() const
    { return d_hex_handles.begin(); }

    std::vector<int>::const_iterator hexesEnd() const
    { return d_hex_handles.end(); }

    std::vector<int>::const_iterator connectivityBegin() const
    { return d_hex_connectivity.begin(); }

    std::vector<int>::const_iterator connectivityEnd() const
    { return d_hex_connectivity.end(); }

  private:

    std::vector<int> d_node_handles;
    std::vector<double> d_coords;
    std::vector<int> d_hex_handles;
    std::vector<int> d_hex_connectivity;
};

//---------------------------------------------------------------------------//
// DTK Traits Specializations
//---------------------------------------------------------------------------//
namespace DataTransferKit
{

//---------------------------------------------------------------------------//
// Mesh traits specialization for MyMesh
template<>
class MeshTraits<MyMesh>
{
  public:

    typedef MyMesh::handle_type handle_type;
    typedef std::vector<int>::const_iterator const_node_iterator;
    typedef std::vector<double>::const_iterator const_coordinate_iterator;
    typedef std::vector<int>::const_iterator const_element_iterator;
    typedef std::vector<int>::const_iterator const_connectivity_iterator;

    static inline const_node_iterator nodesBegin( const MyMesh& mesh )
    { return mesh.nodesBegin(); }

    static inline const_node_iterator nodesEnd( const MyMesh& mesh )
    { return mesh.nodesEnd(); }

    static inline const_coordinate_iterator coordsBegin( const MyMesh& mesh )
    { return mesh.coordsBegin(); }

    static inline const_coordinate_iterator coordsEnd( const MyMesh& mesh )
    { return mesh.coordsEnd(); }

    static inline std::size_t elementType( const MyMesh& mesh )
    { return DTK_REGION; }

    static inline std::size_t elementTopology( const MyMesh& mesh )
    { return DTK_HEXAHEDRON; }

    static inline std::size_t nodesPerElement( const MyMesh& mesh )
    { return 8; }

    static inline const_element_iterator elementsBegin( const MyMesh& mesh )
    { return mesh.hexesBegin(); }

    static inline const_element_iterator elementsEnd( const MyMesh& mesh )
    { return mesh.hexesEnd(); }

    static inline const_connectivity_iterator connectivityBegin( const MyMesh& mesh )
    { return mesh.connectivityBegin(); }

    static inline const_connectivity_iterator connectivityEnd( const MyMesh& mesh )
    { return mesh.connectivityEnd(); }
};

} // end namespace DataTransferKit

//---------------------------------------------------------------------------//
// Mesh create funciton.
//---------------------------------------------------------------------------//
MyMesh buildMyMesh()
{
    // Make some nodes.
    std::vector<int> node_handles;
    std::vector<double> coords;

    node_handles.push_back( 0 );
    coords.push_back( 0.0 ); coords.push_back( 0.0 ); coords.push_back( 0.0 );

    node_handles.push_back( 4 );
    coords.push_back( 1.0 ); coords.push_back( 0.0 ); coords.push_back( 0.0 );

    node_handles.push_back( 9 );
    coords.push_back( 1.0 ); coords.push_back( 1.0 ); coords.push_back( 0.0 );

    node_handles.push_back( 2 );
    coords.push_back( 0.0 ); coords.push_back( 1.0 ); coords.push_back( 0.0 );

    node_handles.push_back( 3 );
    coords.push_back( 0.0 ); coords.push_back( 0.0 ); coords.push_back( 1.0 );

    node_handles.push_back( 8 );
    coords.push_back( 1.0 ); coords.push_back( 0.0 ); coords.push_back( 1.0 );

    node_handles.push_back( 1 );
    coords.push_back( 1.0 ); coords.push_back( 1.0 ); coords.push_back( 1.0 );

    node_handles.push_back( 6 );
    coords.push_back( 0.0 ); coords.push_back( 1.0 ); coords.push_back( 1.0 );

    node_handles.push_back( 12 );
    coords.push_back( 0.0 ); coords.push_back( 0.0 ); coords.push_back( 2.0 );

    node_handles.push_back( 7 );
    coords.push_back( 1.0 ); coords.push_back( 0.0 ); coords.push_back( 2.0 );

    node_handles.push_back( 13 );
    coords.push_back( 1.0 ); coords.push_back( 1.0 ); coords.push_back( 2.0 );

    node_handles.push_back( 5 );
    coords.push_back( 0.0 ); coords.push_back( 1.0 ); coords.push_back( 2.0 );

    // Make 2 hexahedrons.
    std::vector<int> hex_handles;
    std::vector<int> hex_connectivity;

    hex_handles.push_back( 0 );
    hex_connectivity.push_back( 0 ); hex_connectivity.push_back( 4 );
    hex_connectivity.push_back( 9 ); hex_connectivity.push_back( 2 );
    hex_connectivity.push_back( 3 ); hex_connectivity.push_back( 8 );
    hex_connectivity.push_back( 1 ); hex_connectivity.push_back( 6 );

    hex_handles.push_back( 1 );
    hex_connectivity.push_back( 3 ); hex_connectivity.push_back( 8 );
    hex_connectivity.push_back( 1 ); hex_connectivity.push_back( 6 );
    hex_connectivity.push_back( 12 ); hex_connectivity.push_back( 7 );
    hex_connectivity.push_back( 13 ); hex_connectivity.push_back( 5 );

    return MyMesh( node_handles, coords, hex_handles, hex_connectivity );
}

//---------------------------------------------------------------------------//
// Tests
//---------------------------------------------------------------------------//

TEUCHOS_UNIT_TEST( RendezvousMesh, rendezvous_mesh_test )
{
    using namespace DataTransferKit;

    // Create a mesh.
    typedef MeshTraits<MyMesh> MT;
    MyMesh my_mesh = buildMyMesh();
    Teuchos::RCP< RendezvousMesh<MyMesh::handle_type> > mesh =
	createRendezvousMesh( my_mesh );

    // Get the moab interface.
    moab::ErrorCode error;
    RendezvousMesh<MyMesh::handle_type>::RCP_Moab moab = mesh->getMoab();

    // Grab the elements.
    moab::Range mesh_elements = mesh->getElements();

    // Check the moab mesh element data.
    moab::Range::const_iterator element_iterator;
    MyMesh::handle_type native_handle = 0;
    for ( element_iterator = mesh_elements.begin();
	  element_iterator != mesh_elements.end();
	  ++element_iterator, ++native_handle )
    {
	TEST_ASSERT( mesh->getNativeHandle( *element_iterator ) ==
		     native_handle );

	TEST_ASSERT( moab->type_from_handle( *element_iterator ) ==
		     moab::MBHEX );
    }

    // Check the moab mesh vertex data.
    moab::Range connectivity;
    error = moab->get_connectivity( mesh_elements, connectivity );
    TEST_ASSERT( moab::MB_SUCCESS == error );

    std::vector<double> vertex_coords( 3 * connectivity.size() );
    error = moab->get_coords( connectivity, &vertex_coords[0] );
    TEST_ASSERT( moab::MB_SUCCESS == error );

    std::vector<double>::const_iterator moab_coord_iterator =
	vertex_coords.begin();
    typename MT::const_coordinate_iterator coord_iterator;

    for ( coord_iterator = MT::coordsBegin( my_mesh );
	  coord_iterator != MT::coordsEnd( my_mesh );
	  ++coord_iterator, ++moab_coord_iterator )
    {
	TEST_ASSERT( *coord_iterator == *moab_coord_iterator );
    }
}

//---------------------------------------------------------------------------//
// end tstRendezvousMesh.cpp
//---------------------------------------------------------------------------//

<commit_msg>Updated RendezvousMesh unit tests for blocked data interface.<commit_after>//---------------------------------------------------------------------------//
/*!
 * \file tstRendezvousMesh.cpp
 * \author Stuart R. Slattery
 * \brief RendezvousMesh unit tests.
 */
//---------------------------------------------------------------------------//

#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <cassert>

#include <DTK_RendezvousMesh.hpp>
#include <DTK_MeshTypes.hpp>
#include <DTK_MeshTraits.hpp>

#include <Teuchos_UnitTestHarness.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_DefaultMpiComm.hpp>
#include <Teuchos_RCP.hpp>
#include <Teuchos_OpaqueWrapper.hpp>
#include <Teuchos_TypeTraits.hpp>

#include <MBRange.hpp>

//---------------------------------------------------------------------------//
// MPI Setup
//---------------------------------------------------------------------------//

template<class Ordinal>
Teuchos::RCP<const Teuchos::Comm<Ordinal> > getDefaultComm()
{
#ifdef HAVE_MPI
    return Teuchos::DefaultComm<Ordinal>::getComm();
#else
    return Teuchos::rcp(new Teuchos::SerialComm<Ordinal>() );
#endif
}

//---------------------------------------------------------------------------//
// Mesh Implementation
//---------------------------------------------------------------------------//

class MyMesh
{
  public:

    typedef int    handle_type;

    MyMesh()
    { /* ... */ }

    MyMesh( const std::vector<int>& node_handles,
	    const std::vector<double>& coords,
	    const std::vector<int>& hex_handles,
	    const std::vector<int>& hex_connectivity )
	: d_node_handles( node_handles )
	, d_coords( coords )
	, d_hex_handles( hex_handles )
	, d_hex_connectivity( hex_connectivity )
    { /* ... */ }

    ~MyMesh()
    { /* ... */ }

    std::vector<int>::const_iterator nodesBegin() const
    { return d_node_handles.begin(); }

    std::vector<int>::const_iterator nodesEnd() const
    { return d_node_handles.end(); }

    std::vector<double>::const_iterator coordsBegin() const
    { return d_coords.begin(); }

    std::vector<double>::const_iterator coordsEnd() const
    { return d_coords.end(); }

    std::vector<int>::const_iterator hexesBegin() const
    { return d_hex_handles.begin(); }

    std::vector<int>::const_iterator hexesEnd() const
    { return d_hex_handles.end(); }

    std::vector<int>::const_iterator connectivityBegin() const
    { return d_hex_connectivity.begin(); }

    std::vector<int>::const_iterator connectivityEnd() const
    { return d_hex_connectivity.end(); }

  private:

    std::vector<int> d_node_handles;
    std::vector<double> d_coords;
    std::vector<int> d_hex_handles;
    std::vector<int> d_hex_connectivity;
};

//---------------------------------------------------------------------------//
// DTK Traits Specializations
//---------------------------------------------------------------------------//
namespace DataTransferKit
{

//---------------------------------------------------------------------------//
// Mesh traits specialization for MyMesh
template<>
class MeshTraits<MyMesh>
{
  public:

    typedef MyMesh::handle_type handle_type;
    typedef std::vector<int>::const_iterator const_node_iterator;
    typedef std::vector<double>::const_iterator const_coordinate_iterator;
    typedef std::vector<int>::const_iterator const_element_iterator;
    typedef std::vector<int>::const_iterator const_connectivity_iterator;

    static inline const_node_iterator nodesBegin( const MyMesh& mesh )
    { return mesh.nodesBegin(); }

    static inline const_node_iterator nodesEnd( const MyMesh& mesh )
    { return mesh.nodesEnd(); }

    static inline const_coordinate_iterator coordsBegin( const MyMesh& mesh )
    { return mesh.coordsBegin(); }

    static inline const_coordinate_iterator coordsEnd( const MyMesh& mesh )
    { return mesh.coordsEnd(); }

    static inline std::size_t elementType( const MyMesh& mesh )
    { return DTK_REGION; }

    static inline std::size_t elementTopology( const MyMesh& mesh )
    { return DTK_HEXAHEDRON; }

    static inline std::size_t nodesPerElement( const MyMesh& mesh )
    { return 8; }

    static inline const_element_iterator elementsBegin( const MyMesh& mesh )
    { return mesh.hexesBegin(); }

    static inline const_element_iterator elementsEnd( const MyMesh& mesh )
    { return mesh.hexesEnd(); }

    static inline const_connectivity_iterator connectivityBegin( const MyMesh& mesh )
    { return mesh.connectivityBegin(); }

    static inline const_connectivity_iterator connectivityEnd( const MyMesh& mesh )
    { return mesh.connectivityEnd(); }
};

} // end namespace DataTransferKit

//---------------------------------------------------------------------------//
// Mesh create funciton.
//---------------------------------------------------------------------------//
MyMesh buildMyMesh()
{
    // Make some nodes.
    std::vector<int> node_handles;
    std::vector<double> coords;

    // handles
    node_handles.push_back( 0 );
    node_handles.push_back( 4 );
    node_handles.push_back( 9 );
    node_handles.push_back( 2 );
    node_handles.push_back( 3 );
    node_handles.push_back( 8 );
    node_handles.push_back( 1 );
    node_handles.push_back( 6 );
    node_handles.push_back( 12 );
    node_handles.push_back( 7 );
    node_handles.push_back( 13 );
    node_handles.push_back( 5 );

    // x
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 0.0 );

    // y
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );

    // z
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 0.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 1.0 );
    coords.push_back( 2.0 );
    coords.push_back( 2.0 );
    coords.push_back( 2.0 );
    coords.push_back( 2.0 );

    // Make 2 hexahedrons.
    std::vector<int> hex_handles;
    std::vector<int> hex_connectivity;

    // handles
    hex_handles.push_back( 0 );
    hex_handles.push_back( 1 );

    // 0
    hex_connectivity.push_back( 0 );
    hex_connectivity.push_back( 3 );

    // 1
    hex_connectivity.push_back( 4 );
    hex_connectivity.push_back( 8 );

    // 2
    hex_connectivity.push_back( 9 );
    hex_connectivity.push_back( 1 );

    // 3
    hex_connectivity.push_back( 2 );
    hex_connectivity.push_back( 6 );

    // 4
    hex_connectivity.push_back( 3 );
    hex_connectivity.push_back( 12 );

    // 5
    hex_connectivity.push_back( 8 );
    hex_connectivity.push_back( 7 );

    // 6
    hex_connectivity.push_back( 1 );
    hex_connectivity.push_back( 13 );

    // 7
    hex_connectivity.push_back( 6 );
    hex_connectivity.push_back( 5 );

    return MyMesh( node_handles, coords, hex_handles, hex_connectivity );
}

//---------------------------------------------------------------------------//
// Tests
//---------------------------------------------------------------------------//

TEUCHOS_UNIT_TEST( RendezvousMesh, rendezvous_mesh_test )
{
    using namespace DataTransferKit;

    // Create a mesh.
    typedef MeshTraits<MyMesh> MT;
    MyMesh my_mesh = buildMyMesh();
    Teuchos::RCP< RendezvousMesh<MyMesh::handle_type> > mesh =
	createRendezvousMesh( my_mesh );

    // Get the moab interface.
    moab::ErrorCode error;
    RendezvousMesh<MyMesh::handle_type>::RCP_Moab moab = mesh->getMoab();

    // Grab the elements.
    moab::Range mesh_elements = mesh->getElements();

    // Check the moab mesh element data.
    moab::Range::const_iterator element_iterator;
    MyMesh::handle_type native_handle = 0;
    for ( element_iterator = mesh_elements.begin();
	  element_iterator != mesh_elements.end();
	  ++element_iterator, ++native_handle )
    {
	TEST_ASSERT( mesh->getNativeHandle( *element_iterator ) ==
		     native_handle );

	TEST_ASSERT( moab->type_from_handle( *element_iterator ) ==
		     moab::MBHEX );
    }

    // Check the moab mesh vertex data.
    moab::Range connectivity;
    error = moab->get_connectivity( mesh_elements, connectivity );
    TEST_ASSERT( moab::MB_SUCCESS == error );

    std::vector<double> vertex_coords( 3 * connectivity.size() );
    error = moab->get_coords( connectivity, &vertex_coords[0] );
    TEST_ASSERT( moab::MB_SUCCESS == error );

    int num_nodes = connectivity.size();
    std::vector<double>::const_iterator moab_coord_iterator;
    typename MT::const_coordinate_iterator coord_iterator =
	MT::coordsBegin( my_mesh );
    int i = 0;
    for ( moab_coord_iterator = vertex_coords.begin();
	  moab_coord_iterator != vertex_coords.end(); ++i )
    {
	for ( int d = 0; d < 3; ++d, ++moab_coord_iterator )
	{
	    TEST_ASSERT( coord_iterator[d*num_nodes + i] ==
			 *moab_coord_iterator );
	}
    }
}

//---------------------------------------------------------------------------//
// end tstRendezvousMesh.cpp
//---------------------------------------------------------------------------//

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//      https://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 "llvm/Support/Casting.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/Pass/Pass.h"
#include "tensorflow/compiler/mlir/xla/ir/hlo_ops.h"
#include "tensorflow/compiler/mlir/xla/transforms/rewriters.h"

namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace Flow {

namespace {

static bool isAllZero(DenseIntElementsAttr attr) {
  if (!attr.isSplat()) return false;
  return attr.getSplatValue<IntegerAttr>().getInt() == 0;
}

static bool isSplatConst(Value val) {
  auto op = val.getDefiningOp();
  if (!dyn_cast_or_null<xla_hlo::ConstOp>(op)) return false;
  Attribute attr = cast<xla_hlo::ConstOp>(op).value();
  if (auto x = attr.dyn_cast<DenseElementsAttr>()) return x.isSplat();
  return true;
}

// Returns true if a >= b. If the method can not evaluate or a < b, returns
// false.
static bool isGreaterThanOrEqualTo(Value a, Value b) {
  auto constOpA = dyn_cast_or_null<xla_hlo::ConstOp>(a.getDefiningOp());
  auto constOpB = dyn_cast_or_null<xla_hlo::ConstOp>(b.getDefiningOp());
  if (!constOpA || !constOpB) return false;
  Attribute attrA = constOpA.value();
  Attribute attrB = constOpB.value();
  assert(attrA.getType() == attrB.getType());

  if (attrA.isa<DenseFPElementsAttr>()) {
    auto valA =
        attrA.cast<DenseFPElementsAttr>().getSplatValue<FloatAttr>().getValue();
    auto valB =
        attrB.cast<DenseFPElementsAttr>().getSplatValue<FloatAttr>().getValue();
    return valA >= valB;
  }

  if (attrA.isa<DenseIntElementsAttr>()) {
    auto valA = attrA.cast<DenseIntElementsAttr>()
                    .getSplatValue<IntegerAttr>()
                    .getInt();
    auto valB = attrB.cast<DenseIntElementsAttr>()
                    .getSplatValue<IntegerAttr>()
                    .getInt();
    return valA >= valB;
  }

  llvm_unreachable("unknown value type");
}

// Returns the value of the given index. If `attr` is a nullptr, returns 0.
static int64_t getAttrValue(DenseIntElementsAttr attr,
                            ArrayRef<uint64_t> index) {
  if (!attr) return 0;
  return attr.getValue<int64_t>(index);
}

static DenseIntElementsAttr getPaddingAttrs(xla_hlo::PadOp padOp,
                                            DenseIntElementsAttr paddingAttr,
                                            Builder *builder) {
  int rank = padOp.operand().getType().cast<RankedTensorType>().getRank();
  SmallVector<int64_t, 8> padding;
  for (unsigned i = 0; i < rank; ++i) {
    padding.push_back(getAttrValue(paddingAttr, {i, 0}) +
                      padOp.edge_padding_low().getValue<int64_t>(i));
    padding.push_back(getAttrValue(paddingAttr, {i, 1}) +
                      padOp.edge_padding_high().getValue<int64_t>(i));
  }
  // paddingAttr.getType() doesn't work because it can be a nullptr.
  auto type = RankedTensorType::get({rank, 2}, builder->getIntegerType(64));
  return DenseIntElementsAttr::get(type, padding);
}

class FoldPadIntoMaxPool : public OpRewritePattern<xla_hlo::ReduceWindowOp> {
 public:
  using OpRewritePattern<xla_hlo::ReduceWindowOp>::OpRewritePattern;

  // Returns true if the region has a single block, and the block is formed as:
  // ^bb0(%lhs: tensor<f32>, %rhs: tensor<f32>):       // no predecessors
  //   %res = xla_hlo.maximum %lhs, %rhs : tensor<f32>
  //   "xla_hlo.return"(%res) : (tensor<f32>) -> ()
  bool isMaxPool(Region &region) const {
    if (region.getBlocks().size() != 1) return false;
    Block &block = region.front();
    if (block.getOperations().size() != 2) return false;
    auto op = block.begin();
    return isa<xla_hlo::MaxOp>(op);
  }

  // Returns true if there is a reduction window doesn't cover any elements.
  // ReudceWindow takes padding attributes. The leftmost pixel of the first
  // window is at "0 - pad_low[i]", and the rightmost pixel is at
  // "window_size - 1 - pad_low[i]". If there is a window doesn't cover any
  // elements, the result of the window is initial value.
  bool hasOutsideWindow(xla_hlo::ReduceWindowOp op) const {
    int rank = op.getType().cast<RankedTensorType>().getRank();
    for (unsigned i = 0; i < rank; ++i) {
      int rightmost = (getAttrValue(op.window_dimensions(), {i}) - 1) -
                      getAttrValue(op.paddingAttr(), {i, 0});
      if (rightmost >= 0) return false;
    }
    return true;
  }

  // Matches the following conditions, so we can fold the PadOp into the
  // following ReduceWindowOp:
  // 1) This is a max pooling operation.
  // 2) The operand of ReduceWindowOp is defined by a PadOp, and the operand of
  //    the PadOp is defined by a MaxOp.
  // 3) All the elements of the result of MaxOp are greater than or equal to
  //    padding value.
  // 4) There is no a window that just contains initial value of ReduceWindowOp.
  // 5) The initial value of ReduceWindowOp is less than or equal to the
  //    padding value.
  // These conditions imply that all the elements are greater than or equal to
  // the padding value, so we can fold the PadOp into the ReduceWindowOp, and
  // use the padding value as initial value.
  LogicalResult matchAndRewrite(xla_hlo::ReduceWindowOp op,
                                PatternRewriter &rewriter) const override {
    if (!isMaxPool(op.body())) return failure();
    if (!isSplatConst(op.init_value())) return failure();

    auto padOp = dyn_cast_or_null<xla_hlo::PadOp>(op.operand().getDefiningOp());
    if (!padOp) return failure();
    if (!isAllZero(padOp.interior_padding())) return failure();
    if (!isSplatConst(padOp.padding_value())) return failure();

    auto maxOp =
        dyn_cast_or_null<xla_hlo::MaxOp>(padOp.operand().getDefiningOp());
    if (!maxOp) return failure();
    Value maxConstOperand = maxOp.lhs();
    if (!isSplatConst(maxConstOperand)) maxConstOperand = maxOp.rhs();
    if (!isSplatConst(maxConstOperand)) return failure();

    // In case that max op isn't folded when it takes two constant attributes.
    if (isSplatConst(maxOp.rhs()) &&
        isGreaterThanOrEqualTo(maxOp.rhs(), maxConstOperand))
      maxConstOperand = maxOp.rhs();

    // If `maxConstOperand` is greater than or equal to the padding value, then
    // all the elements (in `op.operand()`) are greater than or equal to the
    // padding value.
    if (!isGreaterThanOrEqualTo(maxConstOperand, padOp.padding_value()))
      return failure();

    // If the padding value is greater than or equal to initial value and all
    // the windows cover at least one padding value, we can just make the
    // initial value as padding value.
    // There are two cases:
    //   1) There is no outside window, i.e., all the windows at least cover an
    //      element. Since all the elements are greater than or equal to the
    //      padding value, it implies that the result is always the same if
    //      "`op.init_value()` <= padding_value".
    //   2) There is a outside window, i.e., all the elements are
    //      `op.init_value()`. In this case, the result is `op.init_value()`. We
    //      can not make the initial value as padding value in this case.
    if (!isGreaterThanOrEqualTo(padOp.padding_value(), op.init_value()) ||
        hasOutsideWindow(op))
      return failure();

    auto resultType = op.getResult().getType();
    auto paddingAttr = getPaddingAttrs(padOp, op.paddingAttr(), &rewriter);
    auto newOp = rewriter.create<xla_hlo::ReduceWindowOp>(
        op.getLoc(), resultType, padOp.operand(), padOp.padding_value(),
        op.window_dimensionsAttr(), op.window_stridesAttr(),
        op.base_dilationsAttr(), op.window_dilationsAttr(), paddingAttr);
    newOp.body().takeBody(op.body());
    rewriter.replaceOp(op, newOp.getResult());

    return success();
  }
};

struct HLOToHLOPreprocessing
    : public PassWrapper<HLOToHLOPreprocessing, FunctionPass> {
  void runOnFunction() override {
    MLIRContext *context = &getContext();
    ConversionTarget conversionTarget(*context);
    OwningRewritePatternList conversionPatterns;

    conversionTarget
        .addLegalDialect<xla_hlo::XlaHloDialect, StandardOpsDialect>();
    conversionTarget.addIllegalOp<xla_hlo::BatchNormInferenceOp>();

    xla_hlo::PopulateUnfuseBatchNormPatterns(context, &conversionPatterns);
    if (failed(applyPartialConversion(getFunction(), conversionTarget,
                                      conversionPatterns))) {
      return signalPassFailure();
    }

    OwningRewritePatternList patterns;
    patterns.insert<FoldPadIntoMaxPool>(context);
    applyPatternsGreedily(getOperation(), patterns);
  }
};

}  // namespace

std::unique_ptr<OperationPass<FuncOp>> createHLOPreprocessingPass() {
  return std::make_unique<HLOToHLOPreprocessing>();
}

static PassRegistration<HLOToHLOPreprocessing> legalize_pass(
    "iree-flow-hlo-to-hlo-preprocessing",
    "Apply hlo to hlo transformations for some hlo ops");

}  // namespace Flow
}  // namespace IREE
}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>Fix the pass due to the change of xla_hlo::PopulateUnfuseBatchNormPatterns.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//      https://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 "llvm/Support/Casting.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/Pass/Pass.h"
#include "tensorflow/compiler/mlir/xla/ir/hlo_ops.h"
#include "tensorflow/compiler/mlir/xla/transforms/rewriters.h"

namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace Flow {

namespace {

static bool isAllZero(DenseIntElementsAttr attr) {
  if (!attr.isSplat()) return false;
  return attr.getSplatValue<IntegerAttr>().getInt() == 0;
}

static bool isSplatConst(Value val) {
  auto op = val.getDefiningOp();
  if (!dyn_cast_or_null<xla_hlo::ConstOp>(op)) return false;
  Attribute attr = cast<xla_hlo::ConstOp>(op).value();
  if (auto x = attr.dyn_cast<DenseElementsAttr>()) return x.isSplat();
  return true;
}

// Returns true if a >= b. If the method can not evaluate or a < b, returns
// false.
static bool isGreaterThanOrEqualTo(Value a, Value b) {
  auto constOpA = dyn_cast_or_null<xla_hlo::ConstOp>(a.getDefiningOp());
  auto constOpB = dyn_cast_or_null<xla_hlo::ConstOp>(b.getDefiningOp());
  if (!constOpA || !constOpB) return false;
  Attribute attrA = constOpA.value();
  Attribute attrB = constOpB.value();
  assert(attrA.getType() == attrB.getType());

  if (attrA.isa<DenseFPElementsAttr>()) {
    auto valA =
        attrA.cast<DenseFPElementsAttr>().getSplatValue<FloatAttr>().getValue();
    auto valB =
        attrB.cast<DenseFPElementsAttr>().getSplatValue<FloatAttr>().getValue();
    return valA >= valB;
  }

  if (attrA.isa<DenseIntElementsAttr>()) {
    auto valA = attrA.cast<DenseIntElementsAttr>()
                    .getSplatValue<IntegerAttr>()
                    .getInt();
    auto valB = attrB.cast<DenseIntElementsAttr>()
                    .getSplatValue<IntegerAttr>()
                    .getInt();
    return valA >= valB;
  }

  llvm_unreachable("unknown value type");
}

// Returns the value of the given index. If `attr` is a nullptr, returns 0.
static int64_t getAttrValue(DenseIntElementsAttr attr,
                            ArrayRef<uint64_t> index) {
  if (!attr) return 0;
  return attr.getValue<int64_t>(index);
}

static DenseIntElementsAttr getPaddingAttrs(xla_hlo::PadOp padOp,
                                            DenseIntElementsAttr paddingAttr,
                                            Builder *builder) {
  int rank = padOp.operand().getType().cast<RankedTensorType>().getRank();
  SmallVector<int64_t, 8> padding;
  for (unsigned i = 0; i < rank; ++i) {
    padding.push_back(getAttrValue(paddingAttr, {i, 0}) +
                      padOp.edge_padding_low().getValue<int64_t>(i));
    padding.push_back(getAttrValue(paddingAttr, {i, 1}) +
                      padOp.edge_padding_high().getValue<int64_t>(i));
  }
  // paddingAttr.getType() doesn't work because it can be a nullptr.
  auto type = RankedTensorType::get({rank, 2}, builder->getIntegerType(64));
  return DenseIntElementsAttr::get(type, padding);
}

class FoldPadIntoMaxPool : public OpRewritePattern<xla_hlo::ReduceWindowOp> {
 public:
  using OpRewritePattern<xla_hlo::ReduceWindowOp>::OpRewritePattern;

  // Returns true if the region has a single block, and the block is formed as:
  // ^bb0(%lhs: tensor<f32>, %rhs: tensor<f32>):       // no predecessors
  //   %res = xla_hlo.maximum %lhs, %rhs : tensor<f32>
  //   "xla_hlo.return"(%res) : (tensor<f32>) -> ()
  bool isMaxPool(Region &region) const {
    if (region.getBlocks().size() != 1) return false;
    Block &block = region.front();
    if (block.getOperations().size() != 2) return false;
    auto op = block.begin();
    return isa<xla_hlo::MaxOp>(op);
  }

  // Returns true if there is a reduction window doesn't cover any elements.
  // ReudceWindow takes padding attributes. The leftmost pixel of the first
  // window is at "0 - pad_low[i]", and the rightmost pixel is at
  // "window_size - 1 - pad_low[i]". If there is a window doesn't cover any
  // elements, the result of the window is initial value.
  bool hasOutsideWindow(xla_hlo::ReduceWindowOp op) const {
    int rank = op.getType().cast<RankedTensorType>().getRank();
    for (unsigned i = 0; i < rank; ++i) {
      int rightmost = (getAttrValue(op.window_dimensions(), {i}) - 1) -
                      getAttrValue(op.paddingAttr(), {i, 0});
      if (rightmost >= 0) return false;
    }
    return true;
  }

  // Matches the following conditions, so we can fold the PadOp into the
  // following ReduceWindowOp:
  // 1) This is a max pooling operation.
  // 2) The operand of ReduceWindowOp is defined by a PadOp, and the operand of
  //    the PadOp is defined by a MaxOp.
  // 3) All the elements of the result of MaxOp are greater than or equal to
  //    padding value.
  // 4) There is no a window that just contains initial value of ReduceWindowOp.
  // 5) The initial value of ReduceWindowOp is less than or equal to the
  //    padding value.
  // These conditions imply that all the elements are greater than or equal to
  // the padding value, so we can fold the PadOp into the ReduceWindowOp, and
  // use the padding value as initial value.
  LogicalResult matchAndRewrite(xla_hlo::ReduceWindowOp op,
                                PatternRewriter &rewriter) const override {
    if (!isMaxPool(op.body())) return failure();
    if (!isSplatConst(op.init_value())) return failure();

    auto padOp = dyn_cast_or_null<xla_hlo::PadOp>(op.operand().getDefiningOp());
    if (!padOp) return failure();
    if (!isAllZero(padOp.interior_padding())) return failure();
    if (!isSplatConst(padOp.padding_value())) return failure();

    auto maxOp =
        dyn_cast_or_null<xla_hlo::MaxOp>(padOp.operand().getDefiningOp());
    if (!maxOp) return failure();
    Value maxConstOperand = maxOp.lhs();
    if (!isSplatConst(maxConstOperand)) maxConstOperand = maxOp.rhs();
    if (!isSplatConst(maxConstOperand)) return failure();

    // In case that max op isn't folded when it takes two constant attributes.
    if (isSplatConst(maxOp.rhs()) &&
        isGreaterThanOrEqualTo(maxOp.rhs(), maxConstOperand))
      maxConstOperand = maxOp.rhs();

    // If `maxConstOperand` is greater than or equal to the padding value, then
    // all the elements (in `op.operand()`) are greater than or equal to the
    // padding value.
    if (!isGreaterThanOrEqualTo(maxConstOperand, padOp.padding_value()))
      return failure();

    // If the padding value is greater than or equal to initial value and all
    // the windows cover at least one padding value, we can just make the
    // initial value as padding value.
    // There are two cases:
    //   1) There is no outside window, i.e., all the windows at least cover an
    //      element. Since all the elements are greater than or equal to the
    //      padding value, it implies that the result is always the same if
    //      "`op.init_value()` <= padding_value".
    //   2) There is a outside window, i.e., all the elements are
    //      `op.init_value()`. In this case, the result is `op.init_value()`. We
    //      can not make the initial value as padding value in this case.
    if (!isGreaterThanOrEqualTo(padOp.padding_value(), op.init_value()) ||
        hasOutsideWindow(op))
      return failure();

    auto resultType = op.getResult().getType();
    auto paddingAttr = getPaddingAttrs(padOp, op.paddingAttr(), &rewriter);
    auto newOp = rewriter.create<xla_hlo::ReduceWindowOp>(
        op.getLoc(), resultType, padOp.operand(), padOp.padding_value(),
        op.window_dimensionsAttr(), op.window_stridesAttr(),
        op.base_dilationsAttr(), op.window_dilationsAttr(), paddingAttr);
    newOp.body().takeBody(op.body());
    rewriter.replaceOp(op, newOp.getResult());

    return success();
  }
};

struct HLOToHLOPreprocessing
    : public PassWrapper<HLOToHLOPreprocessing, FunctionPass> {
  void runOnFunction() override {
    MLIRContext *context = &getContext();
    OwningRewritePatternList patterns;
    xla_hlo::PopulateUnfuseBatchNormPatterns(context, &patterns);
    patterns.insert<FoldPadIntoMaxPool>(context);
    applyPatternsGreedily(getOperation(), patterns);
  }
};

}  // namespace

std::unique_ptr<OperationPass<FuncOp>> createHLOPreprocessingPass() {
  return std::make_unique<HLOToHLOPreprocessing>();
}

static PassRegistration<HLOToHLOPreprocessing> legalize_pass(
    "iree-flow-hlo-to-hlo-preprocessing",
    "Apply hlo to hlo transformations for some hlo ops");

}  // namespace Flow
}  // namespace IREE
}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>


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

#include <QtDeclarative/qdeclarativeextensionplugin.h>
#include <QtDeclarative/qdeclarative.h>

QT_BEGIN_NAMESPACE

class QSystemInfoDeclarativeModule : public QDeclarativeExtensionPlugin
{
    Q_OBJECT

public:
    virtual void registerTypes(const char *uri)
    {
        Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.systeminfo"));
    }
};

QT_END_NAMESPACE

#include "qsysteminfo.moc"

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

#include <QtDeclarative/qdeclarativeextensionplugin.h>
#include <QtDeclarative/qdeclarative.h>

#include "qbatteryinfo.h"
#include "qdeviceinfo.h"
#include "qdeviceprofile.h"
#include "qdisplayinfo.h"
#include "qinputdeviceinfo.h"
#include "qnetworkinfo.h"
#include "qscreensaver.h"
#include "qstorageinfo.h"

QT_BEGIN_NAMESPACE

class QSystemInfoDeclarativeModule : public QDeclarativeExtensionPlugin
{
    Q_OBJECT

public:
    virtual void registerTypes(const char *uri)
    {
        Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.systeminfo"));

        int major = 1;
        int minor = 0;
        qmlRegisterType<QBatteryInfo>(uri, major, minor, "BatteryInfo");
        qmlRegisterType<QDeviceInfo>(uri, major, minor, "DeviceInfo");
        qmlRegisterType<QDeviceProfile>(uri, major, minor, "DeviceProfile");
        qmlRegisterType<QDisplayInfo>(uri, major, minor, "DisplayInfo");
        qmlRegisterType<QInputDeviceInfo>(uri, major, minor, "InputDeviceInfo");
        qmlRegisterType<QNetworkInfo>(uri, major, minor, "NetworkInfo");
        qmlRegisterType<QScreenSaver>(uri, major, minor, "ScreenSaver");
        qmlRegisterType<QStorageInfo>(uri, major, minor, "StorageInfo");
    }
};

QT_END_NAMESPACE

#include "qsysteminfo.moc"

Q_EXPORT_PLUGIN2(qsysteminfodeclarativemodule, QT_PREPEND_NAMESPACE(QSystemInfoDeclarativeModule))
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "scannerpluginmanager.h"

#include <logging/logger.h>
#include <logging/translator.h>
#include <tools/hostosinfo.h>

#include <QCoreApplication>
#include <QDirIterator>
#include <QLibrary>

namespace qbs {
namespace Internal {

ScannerPluginManager *ScannerPluginManager::instance()
{
    static ScannerPluginManager *i = new ScannerPluginManager;
    return i;
}

ScannerPluginManager::ScannerPluginManager()
{
}

QList<ScannerPlugin *> ScannerPluginManager::scannersForFileTag(const FileTag &fileTag)
{
    return instance()->m_scannerPlugins.value(fileTag);
}

void ScannerPluginManager::loadPlugins(const QStringList &pluginPaths, const Logger &logger)
{
    QStringList filters;

    if (HostOsInfo::isWindowsHost())
        filters << "*.dll";
    else if (HostOsInfo::isOsxHost())
        filters << "*.dylib";
    else
        filters << "*.so";

    foreach (const QString &pluginPath, pluginPaths) {
        logger.qbsTrace() << QString::fromLocal8Bit("pluginmanager: loading plugins from '%1'.")
                             .arg(QDir::toNativeSeparators(pluginPath));
        QDirIterator it(pluginPath, filters, QDir::Files);
        while (it.hasNext()) {
            const QString fileName = it.next();
            QScopedPointer<QLibrary> lib(new QLibrary(fileName));
            if (!lib->load()) {
                logger.qbsWarning() << Tr::tr("pluginmanager: couldn't load plugin '%1'.")
                                       .arg(QDir::toNativeSeparators(fileName));
                continue;
            }

            getScanners_f getScanners = reinterpret_cast<getScanners_f>(lib->resolve("getScanners"));
            if (!getScanners) {
                logger.qbsWarning() << Tr::tr("pluginmanager: couldn't resolve "
                        "symbol in '%1'.").arg(QDir::toNativeSeparators(fileName));
                continue;
            }

            ScannerPlugin **plugins = getScanners();
            if (plugins == 0) {
                logger.qbsWarning() << Tr::tr("pluginmanager: no scanners "
                        "returned from '%1'.").arg(QDir::toNativeSeparators(fileName));
                continue;
            }

            logger.qbsTrace() << QString::fromLocal8Bit("pluginmanager: scanner plugin '%1' "
                    "loaded.").arg(QDir::toNativeSeparators(fileName));

            for (int i = 0; plugins[i] != 0; ++i)
                m_scannerPlugins[FileTag(plugins[i]->fileTag)] += plugins[i];
            m_libs.append(lib.take());
        }
    }
}

} // namespace Internal
} // namespace qbs
<commit_msg>show QLibrary::errorString if plugin loading fails<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "scannerpluginmanager.h"

#include <logging/logger.h>
#include <logging/translator.h>
#include <tools/hostosinfo.h>

#include <QCoreApplication>
#include <QDirIterator>
#include <QLibrary>

namespace qbs {
namespace Internal {

ScannerPluginManager *ScannerPluginManager::instance()
{
    static ScannerPluginManager *i = new ScannerPluginManager;
    return i;
}

ScannerPluginManager::ScannerPluginManager()
{
}

QList<ScannerPlugin *> ScannerPluginManager::scannersForFileTag(const FileTag &fileTag)
{
    return instance()->m_scannerPlugins.value(fileTag);
}

void ScannerPluginManager::loadPlugins(const QStringList &pluginPaths, const Logger &logger)
{
    QStringList filters;

    if (HostOsInfo::isWindowsHost())
        filters << "*.dll";
    else if (HostOsInfo::isOsxHost())
        filters << "*.dylib";
    else
        filters << "*.so";

    foreach (const QString &pluginPath, pluginPaths) {
        logger.qbsTrace() << QString::fromLocal8Bit("pluginmanager: loading plugins from '%1'.")
                             .arg(QDir::toNativeSeparators(pluginPath));
        QDirIterator it(pluginPath, filters, QDir::Files);
        while (it.hasNext()) {
            const QString fileName = it.next();
            QScopedPointer<QLibrary> lib(new QLibrary(fileName));
            if (!lib->load()) {
                logger.qbsWarning() << Tr::tr("pluginmanager: couldn't load plugin '%1': %2")
                                       .arg(QDir::toNativeSeparators(fileName), lib->errorString());
                continue;
            }

            getScanners_f getScanners = reinterpret_cast<getScanners_f>(lib->resolve("getScanners"));
            if (!getScanners) {
                logger.qbsWarning() << Tr::tr("pluginmanager: couldn't resolve "
                        "symbol in '%1'.").arg(QDir::toNativeSeparators(fileName));
                continue;
            }

            ScannerPlugin **plugins = getScanners();
            if (plugins == 0) {
                logger.qbsWarning() << Tr::tr("pluginmanager: no scanners "
                        "returned from '%1'.").arg(QDir::toNativeSeparators(fileName));
                continue;
            }

            logger.qbsTrace() << QString::fromLocal8Bit("pluginmanager: scanner plugin '%1' "
                    "loaded.").arg(QDir::toNativeSeparators(fileName));

            for (int i = 0; plugins[i] != 0; ++i)
                m_scannerPlugins[FileTag(plugins[i]->fileTag)] += plugins[i];
            m_libs.append(lib.take());
        }
    }
}

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


<commit_before>// Copyright (c) 2007, 2008 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <iostream>

#include "testing/testing.h"
#include "libmv/logging/logging.h"
#include "libmv/numeric/numeric.h"
#include "libmv/multiview/fundamental.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/five_point.h"

namespace {
using namespace libmv;

struct TestData {
  Mat3X X;
  Mat3 R;
  Vec3 t;
  Mat3 E;
  Mat34 P1, P2;
  Mat2X x1, x2;
};

TestData SomeTestData() {
  TestData d;
  d.X = Mat3X::Random(3,5);
  d.X.row(0).cwise() -= .5;
  d.X.row(1).cwise() -= .5;
  d.X.row(2).cwise() += 3;
  d.R = RotationAroundZ(0.3) * RotationAroundX(0.1) * RotationAroundY(0.2);
  d.t = Vec3::Random();

  EssentialFromRt(Mat3::Identity(), Vec3::Zero(), d.R, d.t, &d.E);

  P_From_KRt(Mat3::Identity(), Mat3::Identity(), Vec3::Zero(), &d.P1);
  P_From_KRt(Mat3::Identity(), d.R, d.t, &d.P2);
  Project(d.P1, d.X, &d.x1);
  Project(d.P2, d.X, &d.x2);
  return d;
}

TEST(FivePointsNullspaceBasis, SatisfyEpipolarConstraint) {
  TestData d = SomeTestData();

  Mat E_basis = FivePointsNullspaceBasis(d.x1, d.x2);

  for (int s = 0; s < 4; ++s) {
    Mat3 E;
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        E(i, j) = E_basis(3 * i + j, s);
      }
    }
    for (int i = 0; i < d.x1.cols(); ++i) {
      Vec3 x1(d.x1(0,i), d.x1(1,i), 1);
      Vec3 x2(d.x2(0,i), d.x2(1,i), 1);
      EXPECT_NEAR(0, x2.dot(E * x1), 1e-6);
    }
  }
}

double EvalPolynomial(Vec p, double x, double y, double z) {
  return p(coef_xxx) * x * x * x
       + p(coef_xxy) * x * x * y
       + p(coef_xxz) * x * x * z
       + p(coef_xyy) * x * y * y
       + p(coef_xyz) * x * y * z
       + p(coef_xzz) * x * z * z
       + p(coef_yyy) * y * y * y
       + p(coef_yyz) * y * y * z
       + p(coef_yzz) * y * z * z
       + p(coef_zzz) * z * z * z
       + p(coef_xx)  * x * x
       + p(coef_xy)  * x * y
       + p(coef_xz)  * x * z
       + p(coef_yy)  * y * y
       + p(coef_yz)  * y * z
       + p(coef_zz)  * z * z
       + p(coef_x)   * x
       + p(coef_y)   * y
       + p(coef_z)   * z
       + p(coef_1)   * 1;
}

TEST(o1, Evaluation) {
  Vec p1 = Vec::Zero(20), p2 = Vec::Zero(20);
  p1(coef_x) = double(rand()) / RAND_MAX;
  p1(coef_y) = double(rand()) / RAND_MAX;
  p1(coef_z) = double(rand()) / RAND_MAX;
  p1(coef_1) = double(rand()) / RAND_MAX;
  p2(coef_x) = double(rand()) / RAND_MAX;
  p2(coef_y) = double(rand()) / RAND_MAX;
  p2(coef_z) = double(rand()) / RAND_MAX;
  p2(coef_1) = double(rand()) / RAND_MAX;

  Vec p3 = o1(p1, p2);

  for (double z = -5; z < 5; ++z) {
    for (double y = -5; y < 5; ++y) {
      for (double x = -5; x < 5; ++x) {
        EXPECT_NEAR(EvalPolynomial(p3, x, y, z),
                    EvalPolynomial(p1, x, y, z) * EvalPolynomial(p2, x, y, z),
                    1e-8);
      }
    }
  }
}

TEST(o2, Evaluation) {
  Vec p1 = Vec::Zero(20), p2 = Vec::Zero(20);
  p1(coef_xx) = double(rand()) / RAND_MAX;
  p1(coef_xy) = double(rand()) / RAND_MAX;
  p1(coef_xz) = double(rand()) / RAND_MAX;
  p1(coef_yy) = double(rand()) / RAND_MAX;
  p1(coef_yz) = double(rand()) / RAND_MAX;
  p1(coef_zz) = double(rand()) / RAND_MAX;
  p1(coef_x) = double(rand()) / RAND_MAX;
  p1(coef_y) = double(rand()) / RAND_MAX;
  p1(coef_z) = double(rand()) / RAND_MAX;
  p1(coef_1) = double(rand()) / RAND_MAX;
  p2(coef_x) = double(rand()) / RAND_MAX;
  p2(coef_y) = double(rand()) / RAND_MAX;
  p2(coef_z) = double(rand()) / RAND_MAX;
  p2(coef_1) = double(rand()) / RAND_MAX;

  Vec p3 = o2(p1, p2);

  for (double z = -5; z < 5; ++z) {
    for (double y = -5; y < 5; ++y) {
      for (double x = -5; x < 5; ++x) {
        EXPECT_NEAR(EvalPolynomial(p3, x, y, z),
                    EvalPolynomial(p1, x, y, z) * EvalPolynomial(p2, x, y, z),
                    1e-8);
      }
    }
  }
}

TEST(FivePointsGaussJordan, RandomMatrix) {
  Mat M = Mat::Random(10, 20);
  FivePointsGaussJordan(&M);
  Mat I = Mat::Identity(10,10);
  Mat M1 = M.block<10,10>(0,0);
  EXPECT_MATRIX_NEAR(I, M1, 1e-8);
}

TEST(FivePointsRelativePose, Random) {
  TestData d = SomeTestData();

  vector<Mat3> Es;
  vector<Mat3> Rs;
  vector<Vec3> ts;
  FivePointsRelativePose(d.x1, d.x2, &Es);

  // Recover rotation and translation from E
  Rs.resize(Es.size());
  ts.resize(Es.size());
  for (int s = 0; s < Es.size(); ++s) {
    MotionFromEssentialAndCorrespondence(Es[s],
                                         Mat3::Identity(),
                                         d.x1.col(0),
                                         Mat3::Identity(),
                                         d.x2.col(0),
                                         &Rs[s],
                                         &ts[s]);
  }

  bool solution_found = false;
  for (int i = 0; i < Rs.size(); ++i) {
    // Check that E holds the essential matrix constraints.
    Mat3 E = Es[i];
    EXPECT_NEAR(0, E.determinant(), 1e-8);
    Mat3 O = 2 * E * E.transpose() * E - (E * E.transpose()).trace() * E;
    EXPECT_MATRIX_NEAR(Mat3::Zero(), O, 1e-8);

    // Check that we find the correct relative orientation.
    if (FrobeniusDistance(d.R, Rs[i]) < 1e-3
        && (d.t / d.t.norm() - ts[i] / ts[i].norm()).norm() < 1e-3) {
      solution_found = true;
      break;
    }
  }
  EXPECT_TRUE(solution_found);
}

} // namespace
<commit_msg>Alignment<commit_after>// Copyright (c) 2007, 2008 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <iostream>

#include "testing/testing.h"
#include "libmv/logging/logging.h"
#include "libmv/numeric/numeric.h"
#include "libmv/multiview/fundamental.h"
#include "libmv/multiview/projection.h"
#include "libmv/multiview/five_point.h"

namespace {
using namespace libmv;

struct TestData {
  Mat3X X;
  Mat3 R;
  Vec3 t;
  Mat3 E;
  Mat34 P1, P2;
  Mat2X x1, x2;
};

TestData SomeTestData() {
  TestData d;
  d.X = Mat3X::Random(3,5);
  d.X.row(0).cwise() -= .5;
  d.X.row(1).cwise() -= .5;
  d.X.row(2).cwise() += 3;
  d.R = RotationAroundZ(0.3) * RotationAroundX(0.1) * RotationAroundY(0.2);
  d.t = Vec3::Random();

  EssentialFromRt(Mat3::Identity(), Vec3::Zero(), d.R, d.t, &d.E);

  P_From_KRt(Mat3::Identity(), Mat3::Identity(), Vec3::Zero(), &d.P1);
  P_From_KRt(Mat3::Identity(), d.R, d.t, &d.P2);
  Project(d.P1, d.X, &d.x1);
  Project(d.P2, d.X, &d.x2);
  return d;
}

TEST(FivePointsNullspaceBasis, SatisfyEpipolarConstraint) {
  TestData d = SomeTestData();

  Mat E_basis = FivePointsNullspaceBasis(d.x1, d.x2);

  for (int s = 0; s < 4; ++s) {
    Mat3 E;
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        E(i, j) = E_basis(3 * i + j, s);
      }
    }
    for (int i = 0; i < d.x1.cols(); ++i) {
      Vec3 x1(d.x1(0,i), d.x1(1,i), 1);
      Vec3 x2(d.x2(0,i), d.x2(1,i), 1);
      EXPECT_NEAR(0, x2.dot(E * x1), 1e-6);
    }
  }
}

double EvalPolynomial(Vec p, double x, double y, double z) {
  return p(coef_xxx) * x * x * x
       + p(coef_xxy) * x * x * y
       + p(coef_xxz) * x * x * z
       + p(coef_xyy) * x * y * y
       + p(coef_xyz) * x * y * z
       + p(coef_xzz) * x * z * z
       + p(coef_yyy) * y * y * y
       + p(coef_yyz) * y * y * z
       + p(coef_yzz) * y * z * z
       + p(coef_zzz) * z * z * z
       + p(coef_xx)  * x * x
       + p(coef_xy)  * x * y
       + p(coef_xz)  * x * z
       + p(coef_yy)  * y * y
       + p(coef_yz)  * y * z
       + p(coef_zz)  * z * z
       + p(coef_x)   * x
       + p(coef_y)   * y
       + p(coef_z)   * z
       + p(coef_1)   * 1;
}

TEST(o1, Evaluation) {
  Vec p1 = Vec::Zero(20), p2 = Vec::Zero(20);
  p1(coef_x) = double(rand()) / RAND_MAX;
  p1(coef_y) = double(rand()) / RAND_MAX;
  p1(coef_z) = double(rand()) / RAND_MAX;
  p1(coef_1) = double(rand()) / RAND_MAX;
  p2(coef_x) = double(rand()) / RAND_MAX;
  p2(coef_y) = double(rand()) / RAND_MAX;
  p2(coef_z) = double(rand()) / RAND_MAX;
  p2(coef_1) = double(rand()) / RAND_MAX;

  Vec p3 = o1(p1, p2);

  for (double z = -5; z < 5; ++z) {
    for (double y = -5; y < 5; ++y) {
      for (double x = -5; x < 5; ++x) {
        EXPECT_NEAR(EvalPolynomial(p3, x, y, z),
                    EvalPolynomial(p1, x, y, z) * EvalPolynomial(p2, x, y, z),
                    1e-8);
      }
    }
  }
}

TEST(o2, Evaluation) {
  Vec p1 = Vec::Zero(20), p2 = Vec::Zero(20);
  p1(coef_xx) = double(rand()) / RAND_MAX;
  p1(coef_xy) = double(rand()) / RAND_MAX;
  p1(coef_xz) = double(rand()) / RAND_MAX;
  p1(coef_yy) = double(rand()) / RAND_MAX;
  p1(coef_yz) = double(rand()) / RAND_MAX;
  p1(coef_zz) = double(rand()) / RAND_MAX;
  p1(coef_x)  = double(rand()) / RAND_MAX;
  p1(coef_y)  = double(rand()) / RAND_MAX;
  p1(coef_z)  = double(rand()) / RAND_MAX;
  p1(coef_1)  = double(rand()) / RAND_MAX;
  p2(coef_x)  = double(rand()) / RAND_MAX;
  p2(coef_y)  = double(rand()) / RAND_MAX;
  p2(coef_z)  = double(rand()) / RAND_MAX;
  p2(coef_1)  = double(rand()) / RAND_MAX;

  Vec p3 = o2(p1, p2);

  for (double z = -5; z < 5; ++z) {
    for (double y = -5; y < 5; ++y) {
      for (double x = -5; x < 5; ++x) {
        EXPECT_NEAR(EvalPolynomial(p3, x, y, z),
                    EvalPolynomial(p1, x, y, z) * EvalPolynomial(p2, x, y, z),
                    1e-8);
      }
    }
  }
}

TEST(FivePointsGaussJordan, RandomMatrix) {
  Mat M = Mat::Random(10, 20);
  FivePointsGaussJordan(&M);
  Mat I = Mat::Identity(10,10);
  Mat M1 = M.block<10,10>(0,0);
  EXPECT_MATRIX_NEAR(I, M1, 1e-8);
}

TEST(FivePointsRelativePose, Random) {
  TestData d = SomeTestData();

  vector<Mat3> Es;
  vector<Mat3> Rs;
  vector<Vec3> ts;
  FivePointsRelativePose(d.x1, d.x2, &Es);

  // Recover rotation and translation from E
  Rs.resize(Es.size());
  ts.resize(Es.size());
  for (int s = 0; s < Es.size(); ++s) {
    MotionFromEssentialAndCorrespondence(Es[s],
                                         Mat3::Identity(),
                                         d.x1.col(0),
                                         Mat3::Identity(),
                                         d.x2.col(0),
                                         &Rs[s],
                                         &ts[s]);
  }

  bool solution_found = false;
  for (int i = 0; i < Rs.size(); ++i) {
    // Check that E holds the essential matrix constraints.
    Mat3 E = Es[i];
    EXPECT_NEAR(0, E.determinant(), 1e-8);
    Mat3 O = 2 * E * E.transpose() * E - (E * E.transpose()).trace() * E;
    EXPECT_MATRIX_NEAR(Mat3::Zero(), O, 1e-8);

    // Check that we find the correct relative orientation.
    if (FrobeniusDistance(d.R, Rs[i]) < 1e-3
        && (d.t / d.t.norm() - ts[i] / ts[i].norm()).norm() < 1e-3) {
      solution_found = true;
      break;
    }
  }
  EXPECT_TRUE(solution_found);
}

} // namespace
<|endoftext|>


<commit_before>#include <string.h>
#include "pokeyDevice.h"

PokeyDevice::PokeyDevice(sPoKeysNetworkDeviceSummary deviceSummary, uint8_t index)
{
    _pokey = PK_ConnectToNetworkDevice(&deviceSummary);
    _index = index;
    _userId = deviceSummary.UserID;
    _serialNumber = std::to_string(deviceSummary.SerialNumber);
    _firwareVersionMajorMajor = (deviceSummary.FirmwareVersionMajor >> 4) + 1;
    _firwareVersionMajor = deviceSummary.FirmwareVersionMajor & 0x0F;
    _firwareVersionMinor = deviceSummary.FirmwareVersionMinor;
    memcpy(&_ipAddress, &deviceSummary.IPaddress, 4);
    _hardwareType = deviceSummary.HWtype;
    _dhcp = deviceSummary.DHCP;

    loadPinConfiguration();
}

/**
 *   @brief  Default  destructor for PokeyDevice
 *
 *   @return nothing
 */
PokeyDevice::~PokeyDevice()
{
    PK_DisconnectDevice(_pokey);
}

std::string PokeyDevice::hardwareTypeString()
{
    if (_hardwareType == 31) {
        return "Pokey 57E";
    }
    return "Unknown";
}

bool PokeyDevice::validatePinCapability(int number, std::string type)
{
    // assert(_pokey);
    bool retVal = true;

    return retVal;
}<commit_msg>re-order header<commit_after>#include "pokeyDevice.h"
#include <string.h>

PokeyDevice::PokeyDevice(sPoKeysNetworkDeviceSummary deviceSummary, uint8_t index)
{
    _pokey = PK_ConnectToNetworkDevice(&deviceSummary);
    _index = index;
    _userId = deviceSummary.UserID;
    _serialNumber = std::to_string(deviceSummary.SerialNumber);
    _firwareVersionMajorMajor = (deviceSummary.FirmwareVersionMajor >> 4) + 1;
    _firwareVersionMajor = deviceSummary.FirmwareVersionMajor & 0x0F;
    _firwareVersionMinor = deviceSummary.FirmwareVersionMinor;
    memcpy(&_ipAddress, &deviceSummary.IPaddress, 4);
    _hardwareType = deviceSummary.HWtype;
    _dhcp = deviceSummary.DHCP;

    loadPinConfiguration();
}

/**
 *   @brief  Default  destructor for PokeyDevice
 *
 *   @return nothing
 */
PokeyDevice::~PokeyDevice()
{
    PK_DisconnectDevice(_pokey);
}

std::string PokeyDevice::hardwareTypeString()
{
    if (_hardwareType == 31) {
        return "Pokey 57E";
    }
    return "Unknown";
}

bool PokeyDevice::validatePinCapability(int number, std::string type)
{
    // assert(_pokey);
    bool retVal = true;

    return retVal;
}<|endoftext|>


<commit_before>/***************************************************************************
  file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/modules/forecast/forecastsolver.cpp $
  version : $LastChangedRevision$  $LastChangedBy$
  date : $LastChangedDate$
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 * Copyright (C) 2007 by Johan De Taeye                                    *
 *                                                                         *
 * This library is free software; you can redistribute it and/or modify it *
 * under the terms of the GNU Lesser General Public License as published   *
 * by the Free Software Foundation; either version 2.1 of the License, or  *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This library is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
 * General Public License for more details.                                *
 *                                                                         *
 * You should have received a copy of the GNU Lesser General Public        *
 * License along with this library; if not, write to the Free Software     *
 * Foundation Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA *
 *                                                                         *
 ***************************************************************************/

#include "forecast.h"

namespace module_forecast
{

double Forecast::generateFutureValues(const double history[], unsigned int count, bool debug)
{
  // Validate presence of history
  if (!history) throw RuntimeException("Null argument to forecast function");

  // Create a list of forecasting methods.    @todo list should be dynamic, based on availability of hsitory
  // We create the forecasting objects in stack memory for best performance.
  SingleExponential single_exp;
  DoubleExponential double_exp;
  int numberOfMethods = 2;
  ForecastMethod* methods[2];
  methods[0] = &single_exp;
  methods[1] = &double_exp;

  // Evaluate each forecast method
  double best_error = DBL_MAX;
  int best_method = 0;
  double error;
  for (int i=0; i<numberOfMethods; ++i)
  {
    error = methods[i]->generateForecast(history, count, debug);
    if (error<best_error)
    {
      best_error = error;
      best_method = i;
    }
  }

  // Apply the most appropriate forecasting method

  return best_error;
}

double Forecast::SingleExponential::initial_alfa = 0.2;
double Forecast::SingleExponential::min_alfa = 0.0;
double Forecast::SingleExponential::max_alfa = 1.0;
unsigned int Forecast::SingleExponential::skip = 7;

double Forecast::SingleExponential::generateForecast
  (const double history[], unsigned int count, bool debug)
{
  // Verify whether this is a valid forecast method.
  //   - We need at least 10 buckets after the warmup period.
  if (count < skip + 10)
    return DBL_MAX;

  unsigned int iteration = 1;
  bool upperboundarytested = false;
  bool lowerboundarytested = false;
  double error_mad, delta, df_dalfa_i, sum_11, sum_12;
  for (; iteration <= Forecast::getForecastIterations(); ++iteration)
  {
    // Initialize the iteration
    f_i = history[0];
    df_dalfa_i = 0;
    sum_11 = 0;
    sum_12 = 0;
    error_mad = 0;

    // Calculate the forecast and forecast error.
    // We also compute the sums required for the Marquardt optimization.
    for (unsigned long i = 0; i < count; ++i)
    {
      df_dalfa_i = history[i-1] - f_i + (1 - alfa) * df_dalfa_i;
      f_i = history[i-1] * alfa + (1 - alfa) * f_i;
      sum_12 += df_dalfa_i * (history[i] - f_i);
      sum_11 += df_dalfa_i * df_dalfa_i;
      if (i > skip) // Don't measure during the warmup period
        error_mad += fabs(f_i - history[i]);
    }

    // Calculate a delta for the alfa parameter
    delta = sum_11 ? sum_12 / sum_11 : sum_12;
    alfa += delta;

    // Stop when we repeatedly bounce against the limits.
    // Testing a limits once is allowed.
    if (alfa > max_alfa)
    {
      alfa = max_alfa;
      if (upperboundarytested) break;
      upperboundarytested = true;
    }
    else if (alfa < min_alfa)
    {
      alfa = min_alfa;
      if (lowerboundarytested) break;
      lowerboundarytested = true;
    }

    // Stop when we are close enough
    if (fabs(delta) < 0.01) break;
  }

  // Echo the result
  if (debug)
    logger << "single exponential" //"Forecast "  << fcst.getName() xxx
      << ": alfa " << alfa
      << ", mad " << error_mad
      << ", " << iteration << " iterations"
      << ", delta alfa " << delta
      << ", forecast " << f_i << endl;
  return error_mad;
}

double Forecast::DoubleExponential::initial_alfa = 0.2;
double Forecast::DoubleExponential::min_alfa = 0.0;
double Forecast::DoubleExponential::max_alfa = 1.0;
double Forecast::DoubleExponential::initial_gamma = 0.05;
double Forecast::DoubleExponential::min_gamma = 0.0;
double Forecast::DoubleExponential::max_gamma = 1.0;
unsigned int Forecast::DoubleExponential::skip = 7;

double Forecast::DoubleExponential::generateForecast  /* @todo optimization not implemented yet*/
  (const double history[], unsigned int count, bool debug)
{
  // Verify whether this is a valid forecast method.
  //   - We need at least 10 buckets after the warmup period.
  if (count < skip + 10)
    return DBL_MAX;

  unsigned int iteration = 1;
  double error_mad, trend_i, constant_i, constant_i_minus_1;
  //xxxfor (; iteration <= Forecast::getForecastIterations(); ++iteration)
  for (; iteration <= 1; ++iteration)
  {
    // Initialize the iteration
    constant_i = history[0];
    trend_i = history[1] - history[0];
    error_mad = 0;

    // Calculate the forecast and forecast error.
    // We also compute the sums required for the Marquardt optimization.
    for (unsigned long i = 0; i < count; ++i)
    {
      constant_i_minus_1 = constant_i;
      constant_i = history[i-1] * alfa + (1 - alfa) * (constant_i + trend_i);
      trend_i = gamma * (constant_i - constant_i_minus_1) + (1 - gamma) * trend_i;
      if (i > skip) // Don't measure during the warmup period
        error_mad += fabs(constant_i + trend_i - history[i]);
    }
  }

  // Echo the result
  if (debug)
    logger << "double exponential" //"Forecast "  << fcst.getName() xxx
      << ": alfa " << alfa
      << ", gamma " << gamma
      << ", mad " << error_mad
      << ", " << iteration << " iterations"
      << ", constant " << constant_i
      << ", trend " << trend_i
      << ", forecast " << (trend_i + constant_i) << endl;
  return error_mad;
}

}       // end namespace
<commit_msg>- tune minimum alfa to increase the stability of the forecasting optimization <commit_after>/***************************************************************************
  file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/modules/forecast/forecastsolver.cpp $
  version : $LastChangedRevision$  $LastChangedBy$
  date : $LastChangedDate$
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 * Copyright (C) 2007 by Johan De Taeye                                    *
 *                                                                         *
 * This library is free software; you can redistribute it and/or modify it *
 * under the terms of the GNU Lesser General Public License as published   *
 * by the Free Software Foundation; either version 2.1 of the License, or  *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This library is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
 * General Public License for more details.                                *
 *                                                                         *
 * You should have received a copy of the GNU Lesser General Public        *
 * License along with this library; if not, write to the Free Software     *
 * Foundation Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA *
 *                                                                         *
 ***************************************************************************/

#include "forecast.h"

namespace module_forecast
{

double Forecast::generateFutureValues(const double history[], unsigned int count, bool debug)
{
  // Validate presence of history
  if (!history) throw RuntimeException("Null argument to forecast function");

  // Create a list of forecasting methods.    @todo list should be dynamic, based on availability of hsitory
  // We create the forecasting objects in stack memory for best performance.
  SingleExponential single_exp;
  DoubleExponential double_exp;
  int numberOfMethods = 2;
  ForecastMethod* methods[2];
  methods[0] = &single_exp;
  methods[1] = &double_exp;

  // Evaluate each forecast method
  double best_error = DBL_MAX;
  int best_method = 0;
  double error;
  for (int i=0; i<numberOfMethods; ++i)
  {
    error = methods[i]->generateForecast(history, count, debug);
    if (error<best_error)
    {
      best_error = error;
      best_method = i;
    }
  }

  // Apply the most appropriate forecasting method

  return best_error;
}

double Forecast::SingleExponential::initial_alfa = 0.2;
double Forecast::SingleExponential::min_alfa = 0.03;
double Forecast::SingleExponential::max_alfa = 1.0;
unsigned int Forecast::SingleExponential::skip = 7;

double Forecast::SingleExponential::generateForecast
  (const double history[], unsigned int count, bool debug)
{
  // Verify whether this is a valid forecast method.
  //   - We need at least 10 buckets after the warmup period.
  if (count < skip + 10)
    return DBL_MAX;

  unsigned int iteration = 1;
  bool upperboundarytested = false;
  bool lowerboundarytested = false;
  double error_mad, delta, df_dalfa_i, sum_11, sum_12;
  for (; iteration <= Forecast::getForecastIterations(); ++iteration)
  {
    // Initialize the iteration
    f_i = history[0];
    df_dalfa_i = 0;
    sum_11 = 0;
    sum_12 = 0;
    error_mad = 0;

    // Calculate the forecast and forecast error.
    // We also compute the sums required for the Marquardt optimization.
    for (unsigned long i = 0; i < count; ++i)
    {
      df_dalfa_i = history[i-1] - f_i + (1 - alfa) * df_dalfa_i;
      f_i = history[i-1] * alfa + (1 - alfa) * f_i;
      sum_12 += df_dalfa_i * (history[i] - f_i);
      sum_11 += df_dalfa_i * df_dalfa_i;
      if (i > skip) // Don't measure during the warmup period
        error_mad += fabs(f_i - history[i]);
    }

    // Calculate a delta for the alfa parameter
    delta = sum_11 ? sum_12 / sum_11 : sum_12;
    alfa += delta;

    // Stop when we repeatedly bounce against the limits.
    // Testing a limits once is allowed.
    if (alfa > max_alfa)
    {
      alfa = max_alfa;
      if (upperboundarytested) break;
      upperboundarytested = true;
    }
    else if (alfa < min_alfa)
    {
      alfa = min_alfa;
      if (lowerboundarytested) break;
      lowerboundarytested = true;
    }

    // Stop when we are close enough
    if (fabs(delta) < 0.01) break;
  }

  // Echo the result
  if (debug)
    logger << "single exponential" //"Forecast "  << fcst.getName() xxx
      << ": alfa " << alfa
      << ", mad " << error_mad
      << ", " << iteration << " iterations"
      << ", delta alfa " << delta
      << ", forecast " << f_i << endl;
  return error_mad;
}

double Forecast::DoubleExponential::initial_alfa = 0.2;
double Forecast::DoubleExponential::min_alfa = 0.03;
double Forecast::DoubleExponential::max_alfa = 1.0;
double Forecast::DoubleExponential::initial_gamma = 0.05;
double Forecast::DoubleExponential::min_gamma = 0.0;
double Forecast::DoubleExponential::max_gamma = 1.0;
unsigned int Forecast::DoubleExponential::skip = 7;

double Forecast::DoubleExponential::generateForecast  /* @todo optimization not implemented yet*/
  (const double history[], unsigned int count, bool debug)
{
  // Verify whether this is a valid forecast method.
  //   - We need at least 10 buckets after the warmup period.
  if (count < skip + 10)
    return DBL_MAX;

  unsigned int iteration = 1;
  double error_mad, trend_i, constant_i, constant_i_minus_1;
  //xxxfor (; iteration <= Forecast::getForecastIterations(); ++iteration)
  for (; iteration <= 1; ++iteration)
  {
    // Initialize the iteration
    constant_i = history[0];
    trend_i = history[1] - history[0];
    error_mad = 0;

    // Calculate the forecast and forecast error.
    // We also compute the sums required for the Marquardt optimization.
    for (unsigned long i = 0; i < count; ++i)
    {
      constant_i_minus_1 = constant_i;
      constant_i = history[i-1] * alfa + (1 - alfa) * (constant_i + trend_i);
      trend_i = gamma * (constant_i - constant_i_minus_1) + (1 - gamma) * trend_i;
      if (i > skip) // Don't measure during the warmup period
        error_mad += fabs(constant_i + trend_i - history[i]);
    }
  }

  // Echo the result
  if (debug)
    logger << "double exponential" //"Forecast "  << fcst.getName() xxx
      << ": alfa " << alfa
      << ", gamma " << gamma
      << ", mad " << error_mad
      << ", " << iteration << " iterations"
      << ", constant " << constant_i
      << ", trend " << trend_i
      << ", forecast " << (trend_i + constant_i) << endl;
  return error_mad;
}

}       // end namespace
<|endoftext|>