<commit_before>/* All or part of this file was contributed by Intel under license:
 *   Copyright (C) 2017-2018 Intel Corporation
 *   SPDX-License-Identifier: MIT
 */

#include "tensors/cpu/backend.h"
#include "tensors/tensor.h"
#include "tensors/tensor_allocator.h"

#include "prod_blas.h"
#include "sharp/int_gemm.h"

namespace marian {

namespace cpu {

void Prod(marian::Tensor C,
          const marian::Tensor& A,
          const marian::Tensor& B,
          bool transA,
          bool transB,
          float beta,
          float scalar) {
#if BLAS_FOUND
  float alpha = scalar;

  int m = A->shape().elements() / A->shape()[-1];
  int k = A->shape().back();
  if(transA)
    std::swap(m, k);

  int l = B->shape().elements() / B->shape()[-1];
  int n = B->shape()[-1];
  if(transB)
    std::swap(l, n);

  int lda = A->shape()[-1];
  int ldb = B->shape()[-1];
  int ldc = B->shape()[-1];

  if(transB)
    ldc = B->shape().elements() / B->shape()[-1];

  sgemm(transA,
        transB,
        m,
        n,
        k,
        alpha,
        A->data(),
        lda,
        B->data(),
        ldb,
        beta,
        C->data(),
        ldc);
#else
  C; A; B; transA; transB; beta; scalar;
  ABORT("You need to compile with MKL in order to use the CPU version");
#endif
}

void ProdBatched(marian::Tensor C,
                 Ptr<Allocator> /*allocator*/,
                 const marian::Tensor A,
                 const marian::Tensor B,
                 bool transA,
                 bool transB,
                 float beta,
                 float scalar) {
#if BLAS_FOUND
  float alpha = scalar;

  size_t batchA = A->shape().elements() / (A->shape()[-1] * A->shape()[-2]);
  size_t batchB = B->shape().elements() / (B->shape()[-1] * B->shape()[-2]);

  size_t m = A->shape()[-2];
  size_t k = A->shape()[-1];
  if(transA)
    std::swap(m, k);

  size_t l = B->shape()[-2];
  size_t n = B->shape()[-1];
  if(transB)
    std::swap(l, n);

  size_t lda = A->shape()[-1];
  size_t ldb = B->shape()[-1];
  size_t ldc = B->shape()[-1];

  if(transB)
    ldc = B->shape()[-2];

  auto strideB = batchB == 1 ? 0 : n * k;
  auto strideA = batchA == 1 ? 0 : m * k;
  auto strideC = n * m;

  auto batchC = std::max(batchA, batchB);
#if 0 // TODO Accuracy regression. Batched GEMM generate different output. Investigating and disable for now.
  CBLAS_TRANSPOSE transA_forarr = CblasNoTrans;
  CBLAS_TRANSPOSE transB_forarr = CblasNoTrans;

  if(transA)
    transA_forarr = CblasTrans;

  if(transB)
    transB_forarr = CblasTrans;

  /* cblas_sgemm_batch allows us to group all the small GEMMs that are done in a for loop with sgemm and compute
   * them in only one MKL call. For the API documentation refer to
   * https://software.intel.com/content/www/us/en/develop/documentation/mkl-developer-reference-c/top/blas-and-sparse-blas-routines/blas-like-extensions/cblas-gemm-batch.html
   * The API supports dependencies, where you can specify one "group" of GEMMs to be computed after another. (This controlled by the group_count parameter).
   * In our case, the operations are not dependent on one another so we hardcode one group. The rest of the arguments (with the exception of group_size) are
   * the same as the ones that cblas_sgemm expects, with the difference that we are supposed to provide an array pointer (One element per group).
   * Weirdly enough, we are required to to provide all of the integer arguments as the MKL_INT datatype
   */

  static const constexpr size_t group_count = 1; // We have one group
  const std::vector<CBLAS_TRANSPOSE> transa_arr(group_count, transA_forarr);
  const std::vector<CBLAS_TRANSPOSE> transb_arr(group_count, transB_forarr);
  const std::vector<MKL_INT> m_arr(group_count, (MKL_INT)m);
  const std::vector<MKL_INT> n_arr(group_count, (MKL_INT)n);
  const std::vector<MKL_INT> k_arr(group_count, (MKL_INT)k);
  const std::vector<float> alpha_arr(group_count, alpha);
  const std::vector<float> beta_arr(group_count, beta);
  const std::vector<MKL_INT> lda_arr(group_count, (MKL_INT)lda);
  const std::vector<MKL_INT> ldb_arr(group_count, (MKL_INT)ldb);
  const std::vector<MKL_INT> ldc_arr(group_count, (MKL_INT)ldc);
  const std::vector<MKL_INT> group_size(group_count, (MKL_INT)batchC); // Group size specifies number of GEMM operations per group (Which is batchC)

  std::vector<const float *> a_array(batchC, nullptr);
  std::vector<const float *> b_array(batchC, nullptr);
  std::vector<float *> c_array(batchC, nullptr);

  // This loop initializes the array pointers in the same way as the for loop
  // in the normal sgemm version a few lines below
  for(size_t i = 0; i < batchC; ++i) {
    a_array[i] = A->data() + (i % batchA) * strideA;
    b_array[i] = B->data() + (i % batchB) * strideB;
    c_array[i] = C->data() + i * strideC;
  }
  cblas_sgemm_batch (CblasRowMajor,
    &transa_arr[0],
    &transb_arr[0],
    &m_arr[0],
    &n_arr[0],
    &k_arr[0],
    &alpha_arr[0],
    &a_array[0],
    &lda_arr[0],
    &b_array[0],
    &ldb_arr[0],
    &beta_arr[0],
    &c_array[0],
    &ldc_arr[0],
    group_count,
    &group_size[0]);
#else
  for(size_t i = 0; i < batchC; ++i) {
    sgemm(transA,
          transB,
          (int)m,
          (int)n,
          (int)k,
          alpha,
          A->data() + (i % batchA) * strideA,
          (int)lda,
          B->data() + (i % batchB) * strideB,
          (int)ldb,
          beta,
          C->data() + i * strideC,
          (int)ldc);
  }
#endif
#else
  C; A; B; transA; transB; beta; scalar;
  ABORT("You need to compile with MKL in order to use the CPU version");
#endif
}

void ProdWithBias(marian::Tensor C,
                  const marian::Tensor& A,
                  const marian::Tensor& B,
                  const marian::Tensor& bias,
                  bool transA,
                  bool transB,
                  float beta,
                  float scalar) {
  cpu::Prod(C, A, B, transA, transB, beta, scalar);
  cpu::int16::AddBias(C, bias);
}

void CSRProd(marian::Tensor C,
             Ptr<Allocator> /*allocator*/,
             const marian::Tensor& S_values,
             const marian::Tensor& S_indices,
             const marian::Tensor& S_offsets,
             const marian::Tensor& D,
             bool transS,
             bool swapOperands,
             float beta) {
  C, S_values, S_indices, S_offsets, D;

  // Note: The CPU implementation currently only implements what's needed for decoding.

  // interpret tensor dimensions as matrix dimensions
  const auto& shapeC = C->shape();
  const auto& shapeD = D->shape();
  // If swapOperands, S and D are swapped (C = D x S instead of C = S x D).
  // In that case, in the next 6 lines, please read all dimensions as if they were reversed in order.
  auto rowsC = shapeC[-(int)swapOperands];
  auto colsC = shapeC.elements() / rowsC;
  auto rowsD = shapeD[-(int)swapOperands];
  auto colsD = shapeD.elements() / rowsD;
  auto rowsS = transS ? rowsD : rowsC;
  auto colsS = transS ? rowsC : rowsD;
  ABORT_IF(colsD != colsC, "Inconsistent outer dimensions in CSR product");
  if (swapOperands) { // make rowsX actual row dimensions again, likewise colsX
    std::swap(rowsC, colsC);
    std::swap(rowsD, colsD);
    std::swap(rowsS, colsS);
  }
  // sparse arrays
  auto numOffsets = S_offsets->shape().elements() - 1; // -1 since last value is length
  ABORT_IF(numOffsets != rowsS, "Unexpected number of rows in CSR argument"); numOffsets;
  ABORT_IF(S_values->shape() != S_indices->shape(), "CSR values and indices must have the same size");
  if (!transS && !swapOperands) {
    // C = S * D, where D = CSR matrix
    const auto* offsets = S_offsets->data<IndexType>();
    const auto* indices = S_indices->data<IndexType>();
    const auto* values  = S_values->data<float>();
    const auto* dataD   = D->data<float>();
    auto*       dataC   = C->data<float>();
    ABORT_IF(beta != 0 && beta != 1, "cpu::CSRProd only supports beta = 0 or 1");
    for (size_t i = 0; i < rowsC; i++) {
      auto add = (beta == 1); // first element: overwrite or add according to beta; subsequent elements: add
      for (size_t kk = offsets[i]; kk < offsets[i + 1]; kk++) {
        auto k = indices[kk];    // fetch the non-zero row
        auto valS = values[kk]; // and the value from that row
        // This code is written with the hope for good vectorization, and the hope
        // that adding to memory will be done efficiently by the caching system.
        if (valS == 1)
          if (!add)
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] = dataD[k * colsC/*==colsD*/ + j]; // this is a memcpy()
          else
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] += dataD[k * colsC/*==colsD*/ + j]; // this is a contiguous-vector addition
        else
          if (!add)
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] = valS * dataD[k * colsC/*==colsD*/ + j];
          else
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] += valS * dataD[k * colsC/*==colsD*/ + j]; // notice the +=
        add = true; // next iteration will add to existing result
      }
    }
  }
  else
    ABORT("CSRProd for transS={}, swapOperands={} is not yet implemented for CPU", transS, swapOperands);
}

}  // namespace cpu
}  // namespace marian
<commit_msg>Move batched GEMM back (#710)<commit_after>/* All or part of this file was contributed by Intel under license:
 *   Copyright (C) 2017-2018 Intel Corporation
 *   SPDX-License-Identifier: MIT
 */

#include "tensors/cpu/backend.h"
#include "tensors/tensor.h"
#include "tensors/tensor_allocator.h"

#include "prod_blas.h"
#include "sharp/int_gemm.h"

namespace marian {

namespace cpu {

void Prod(marian::Tensor C,
          const marian::Tensor& A,
          const marian::Tensor& B,
          bool transA,
          bool transB,
          float beta,
          float scalar) {
#if BLAS_FOUND
  float alpha = scalar;

  int m = A->shape().elements() / A->shape()[-1];
  int k = A->shape().back();
  if(transA)
    std::swap(m, k);

  int l = B->shape().elements() / B->shape()[-1];
  int n = B->shape()[-1];
  if(transB)
    std::swap(l, n);

  int lda = A->shape()[-1];
  int ldb = B->shape()[-1];
  int ldc = B->shape()[-1];

  if(transB)
    ldc = B->shape().elements() / B->shape()[-1];

  sgemm(transA,
        transB,
        m,
        n,
        k,
        alpha,
        A->data(),
        lda,
        B->data(),
        ldb,
        beta,
        C->data(),
        ldc);
#else
  C; A; B; transA; transB; beta; scalar;
  ABORT("You need to compile with MKL in order to use the CPU version");
#endif
}

void ProdBatched(marian::Tensor C,
                 Ptr<Allocator> /*allocator*/,
                 const marian::Tensor A,
                 const marian::Tensor B,
                 bool transA,
                 bool transB,
                 float beta,
                 float scalar) {
#if BLAS_FOUND
  float alpha = scalar;

  size_t batchA = A->shape().elements() / (A->shape()[-1] * A->shape()[-2]);
  size_t batchB = B->shape().elements() / (B->shape()[-1] * B->shape()[-2]);

  size_t m = A->shape()[-2];
  size_t k = A->shape()[-1];
  if(transA)
    std::swap(m, k);

  size_t l = B->shape()[-2];
  size_t n = B->shape()[-1];
  if(transB)
    std::swap(l, n);

  size_t lda = A->shape()[-1];
  size_t ldb = B->shape()[-1];
  size_t ldc = B->shape()[-1];

  if(transB)
    ldc = B->shape()[-2];

  auto strideB = batchB == 1 ? 0 : n * k;
  auto strideA = batchA == 1 ? 0 : m * k;
  auto strideC = n * m;

  auto batchC = std::max(batchA, batchB);
#if MKL_FOUND
  CBLAS_TRANSPOSE transA_forarr = CblasNoTrans;
  CBLAS_TRANSPOSE transB_forarr = CblasNoTrans;

  if(transA)
    transA_forarr = CblasTrans;

  if(transB)
    transB_forarr = CblasTrans;

  /* cblas_sgemm_batch allows us to group all the small GEMMs that are done in a for loop with sgemm and compute
   * them in only one MKL call. For the API documentation refer to
   * https://software.intel.com/content/www/us/en/develop/documentation/mkl-developer-reference-c/top/blas-and-sparse-blas-routines/blas-like-extensions/cblas-gemm-batch.html
   * The API supports dependencies, where you can specify one "group" of GEMMs to be computed after another. (This controlled by the group_count parameter).
   * In our case, the operations are not dependent on one another so we hardcode one group. The rest of the arguments (with the exception of group_size) are
   * the same as the ones that cblas_sgemm expects, with the difference that we are supposed to provide an array pointer (One element per group).
   * Weirdly enough, we are required to to provide all of the integer arguments as the MKL_INT datatype
   */

  static const constexpr size_t group_count = 1; // We have one group
  const std::vector<CBLAS_TRANSPOSE> transa_arr(group_count, transA_forarr);
  const std::vector<CBLAS_TRANSPOSE> transb_arr(group_count, transB_forarr);
  const std::vector<MKL_INT> m_arr(group_count, (MKL_INT)m);
  const std::vector<MKL_INT> n_arr(group_count, (MKL_INT)n);
  const std::vector<MKL_INT> k_arr(group_count, (MKL_INT)k);
  const std::vector<float> alpha_arr(group_count, alpha);
  const std::vector<float> beta_arr(group_count, beta);
  const std::vector<MKL_INT> lda_arr(group_count, (MKL_INT)lda);
  const std::vector<MKL_INT> ldb_arr(group_count, (MKL_INT)ldb);
  const std::vector<MKL_INT> ldc_arr(group_count, (MKL_INT)ldc);
  const std::vector<MKL_INT> group_size(group_count, (MKL_INT)batchC); // Group size specifies number of GEMM operations per group (Which is batchC)

  std::vector<const float *> a_array(batchC, nullptr);
  std::vector<const float *> b_array(batchC, nullptr);
  std::vector<float *> c_array(batchC, nullptr);

  // This loop initializes the array pointers in the same way as the for loop
  // in the normal sgemm version a few lines below
  for(size_t i = 0; i < batchC; ++i) {
    a_array[i] = A->data() + (i % batchA) * strideA;
    b_array[i] = B->data() + (i % batchB) * strideB;
    c_array[i] = C->data() + i * strideC;
  }
  cblas_sgemm_batch (CblasRowMajor,
    &transa_arr[0],
    &transb_arr[0],
    &m_arr[0],
    &n_arr[0],
    &k_arr[0],
    &alpha_arr[0],
    &a_array[0],
    &lda_arr[0],
    &b_array[0],
    &ldb_arr[0],
    &beta_arr[0],
    &c_array[0],
    &ldc_arr[0],
    group_count,
    &group_size[0]);
#else
  for(size_t i = 0; i < batchC; ++i) {
    sgemm(transA,
          transB,
          (int)m,
          (int)n,
          (int)k,
          alpha,
          A->data() + (i % batchA) * strideA,
          (int)lda,
          B->data() + (i % batchB) * strideB,
          (int)ldb,
          beta,
          C->data() + i * strideC,
          (int)ldc);
  }
#endif
#else
  C; A; B; transA; transB; beta; scalar;
  ABORT("You need to compile with MKL in order to use the CPU version");
#endif
}

void ProdWithBias(marian::Tensor C,
                  const marian::Tensor& A,
                  const marian::Tensor& B,
                  const marian::Tensor& bias,
                  bool transA,
                  bool transB,
                  float beta,
                  float scalar) {
  cpu::Prod(C, A, B, transA, transB, beta, scalar);
  cpu::int16::AddBias(C, bias);
}

void CSRProd(marian::Tensor C,
             Ptr<Allocator> /*allocator*/,
             const marian::Tensor& S_values,
             const marian::Tensor& S_indices,
             const marian::Tensor& S_offsets,
             const marian::Tensor& D,
             bool transS,
             bool swapOperands,
             float beta) {
  C, S_values, S_indices, S_offsets, D;

  // Note: The CPU implementation currently only implements what's needed for decoding.

  // interpret tensor dimensions as matrix dimensions
  const auto& shapeC = C->shape();
  const auto& shapeD = D->shape();
  // If swapOperands, S and D are swapped (C = D x S instead of C = S x D).
  // In that case, in the next 6 lines, please read all dimensions as if they were reversed in order.
  auto rowsC = shapeC[-(int)swapOperands];
  auto colsC = shapeC.elements() / rowsC;
  auto rowsD = shapeD[-(int)swapOperands];
  auto colsD = shapeD.elements() / rowsD;
  auto rowsS = transS ? rowsD : rowsC;
  auto colsS = transS ? rowsC : rowsD;
  ABORT_IF(colsD != colsC, "Inconsistent outer dimensions in CSR product");
  if (swapOperands) { // make rowsX actual row dimensions again, likewise colsX
    std::swap(rowsC, colsC);
    std::swap(rowsD, colsD);
    std::swap(rowsS, colsS);
  }
  // sparse arrays
  auto numOffsets = S_offsets->shape().elements() - 1; // -1 since last value is length
  ABORT_IF(numOffsets != rowsS, "Unexpected number of rows in CSR argument"); numOffsets;
  ABORT_IF(S_values->shape() != S_indices->shape(), "CSR values and indices must have the same size");
  if (!transS && !swapOperands) {
    // C = S * D, where D = CSR matrix
    const auto* offsets = S_offsets->data<IndexType>();
    const auto* indices = S_indices->data<IndexType>();
    const auto* values  = S_values->data<float>();
    const auto* dataD   = D->data<float>();
    auto*       dataC   = C->data<float>();
    ABORT_IF(beta != 0 && beta != 1, "cpu::CSRProd only supports beta = 0 or 1");
    for (size_t i = 0; i < rowsC; i++) {
      auto add = (beta == 1); // first element: overwrite or add according to beta; subsequent elements: add
      for (size_t kk = offsets[i]; kk < offsets[i + 1]; kk++) {
        auto k = indices[kk];    // fetch the non-zero row
        auto valS = values[kk]; // and the value from that row
        // This code is written with the hope for good vectorization, and the hope
        // that adding to memory will be done efficiently by the caching system.
        if (valS == 1)
          if (!add)
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] = dataD[k * colsC/*==colsD*/ + j]; // this is a memcpy()
          else
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] += dataD[k * colsC/*==colsD*/ + j]; // this is a contiguous-vector addition
        else
          if (!add)
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] = valS * dataD[k * colsC/*==colsD*/ + j];
          else
            for (size_t j = 0; j < colsC; j++)
              dataC[i * colsC/*==colsD*/ + j] += valS * dataD[k * colsC/*==colsD*/ + j]; // notice the +=
        add = true; // next iteration will add to existing result
      }
    }
  }
  else
    ABORT("CSRProd for transS={}, swapOperands={} is not yet implemented for CPU", transS, swapOperands);
}

}  // namespace cpu
}  // namespace marian
<|endoftext|>


<commit_before>#include "../../include/catch/catch.hpp"

#include "libirc/wilson.h"

#include "libirc/atom.h"
#include "libirc/io.h"
#include "libirc/molecule.h"
#include "libirc/connectivity.h"
#include "libirc/conversion.h"

#include "config.h"

#include <cmath>
#include <iostream>

#ifdef HAVE_ARMA
#include <armadillo>
using vec3 = arma::vec3;
using vec = arma::vec;
using mat = arma::mat;
#elif HAVE_EIGEN3
#include <Eigen3/Eigen/Dense>
using vec3 = Eigen::Vector3d;
using vec = Eigen::VectorXd;
using mat = Eigen::MatrixXd;
#else
#error
#endif

using namespace irc;

TEST_CASE("Wilson B matrix","[wilson]"){

  bool verbose{true};

  using namespace std;

  using namespace connectivity;
  using namespace molecule;
  using namespace wilson;

  SECTION("H2 stretching"){

    // Define molecule
    Molecule<vec3> mol{{"H",{0.,0.,0.}},{"H",{1.,0.,0.}}};

    // Compute interatomic distances
    mat dd{ distances<vec3,mat>(mol)};

    // Compute adjacency matrix (graph)
    UGraph adj{ adjacency_matrix(dd, mol) };

    // Compute distance matrix and predecessor matrix
    mat dist, pred;
    tie(dist, pred) = distance_matrix<mat>(adj);

    // Compute bonds
    vector<Bond> B{ bonds(dist, mol) };

    REQUIRE(B.size() == 1);

    // Compute Wilson B matrix for H2 analytically
    mat Bwilson = wilson_matrix<vec3,vec,mat>(to_cartesian<vec3,vec>(mol),B);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(Bwilson) == 6 );

    if(verbose){
      cout << "Wilson B matrix (analytical):" << endl;
      cout << Bwilson << endl;
    }

    // Compute Wilson B matrix for H2 numerically
    mat BwilsonN = wilson_matrix_numerical<vec3,vec,mat>(to_cartesian<vec3,vec>(mol), B);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(BwilsonN) == 6 );

    if(verbose){
      cout << "Wilson B matrix (numerical):" << endl;
      cout << BwilsonN << endl;
    }

    // Check analytical and numerical Wilson matrices are the same
    SECTION("Analytical vs Numerical"){
      for(size_t i{0}; i < 6; i++ ){
        Approx target{BwilsonN(i)};
        target.margin(1e-6);

        REQUIRE( Bwilson(i) == target);
      }
    }

    // Set bond stretching
    double d{0.01};
    vec dx{-d, 0.00, 0.00, d, 0.00, 0.00};

    SECTION("Bond change (analytical)"){
      // Compute transformation in IRC
      vec transformation{Bwilson * dx};

      if(verbose){
        cout << "\nTransformation (analytical)" << endl;
        cout << Bwilson * dx << endl;
      }

      Approx target{2 * d};
      target.margin(1e-5);

      REQUIRE( transformation(0) == target );
    }

    SECTION("Bond change (numerical)"){
      // Compute transformation in IRC
      vec transformation{BwilsonN * dx};

      if(verbose){
        cout << "\nTransformation (numerical)" << endl;
        cout << Bwilson * dx << endl;
      }

      Approx target{2 * d};
      target.margin(1e-5);

      REQUIRE( transformation(0) == target );
    }
  } // H2 stretching

  SECTION("H2O bending"){

    double angle( 0.5 );
    double angle_rad( angle / 180. * tools::constants::pi );

    std::vector<mat> R{
        {
            // Rotation for H1
            {cos(angle_rad), -sin(angle_rad), 0},
            {sin(angle_rad),  cos(angle_rad), 0},
            {             0,               0, 1}
        },
        {
            // Rotation for O
            {1, 0, 0},
            {0, 1, 0},
            {0, 0, 1}
        },
        {
            // Rotation for H2
            {cos(-angle_rad), -sin(-angle_rad), 0},
            {sin(-angle_rad),  cos(-angle_rad), 0},
            {              0,                0, 1}
        },
    };

    molecule::Molecule<vec3> mol{
        {"H", { 1.43,  -1.10,  0.00}}, // H1
        {"O", { 0.00,   0.00,  0.00}}, // O
        {"H", {-1.43,  -1.10,  0.00}}  // H2
    };

    // Allocate displacements in cartesian coordinates
    vec dx{ linalg::zeros<vec>(3 * mol.size()) };

    // Compute displacements
    for(size_t i{0}; i < 3; i++){
      vec3 v{ R[i] * mol[i].position - mol[i].position};

      dx(3*i + 0) = v(0);
      dx(3*i + 1) = v(1);
      dx(3*i + 2) = v(2);
    }

    // Compute interatomic distances
    mat dd{ distances<vec3,mat>(mol)};

    // Compute adjacency matrix (graph)
    UGraph adj{ adjacency_matrix(dd, mol) };

    // Compute distance matrix and predecessor matrix
    mat dist, pred;
    tie(dist, pred) = distance_matrix<mat>(adj);

    // Compute bonds
    vector<Bond> B{ bonds(dist, mol) };

    // Check number of bonds
    REQUIRE(B.size() == 2);

    // Compute bonds
    vector<Angle> A{ angles(dist, pred, mol) };

    REQUIRE(A.size() == 1);

    // Compute Wilson B matrix for H2O analytically
    mat Bwilson = wilson_matrix<vec3,vec,mat>(to_cartesian<vec3,vec>(mol),B, A);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(Bwilson) == 27 );

    if(verbose){
      // Print Wilson B matrix
      cout << "\nWilson B matrix (analytical):" << endl;
      cout << Bwilson << endl;
    }

    // Compute Wilson B matrix for H2O numerically
    mat BwilsonN = wilson_matrix_numerical<vec3,vec,mat>(to_cartesian<vec3,vec>(mol),B, A);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(BwilsonN) == 27 );

    if(verbose){
      // Print Wilson B matrix
      cout << "\nWilson B matrix (numerical):" << endl;
      cout << BwilsonN << endl;
    }

    // Check analytical and numerical Wilson matrices are the same
    SECTION("Analytical vs Numerical"){
      for(size_t i{0}; i < 27; i++ ){
        Approx target{BwilsonN(i)};
        target.margin(1e-6);

        REQUIRE( Bwilson(i) == target);
      }
    }

    SECTION("Analytical displacement"){
      // Compute displacement in internal coordinates
      vec displacement{Bwilson * dx};
      cout << "\nDisplacement:" << endl;
      cout << displacement << endl;

      // Check that bonds do not change
      SECTION("Bond change"){
        Approx target{0};

        target.margin(1e-4);

        REQUIRE( displacement(0) == target );
        REQUIRE( displacement(1) == target );
      }

      // Check change in angle
      SECTION("Angle change"){
        Approx target{2 * angle};

        target.margin(1e-3);

        REQUIRE( displacement(2) * 180 / tools::constants::pi == target );
      }
    }
  }

  SECTION("H2O2 torsion"){

    double angle( 1.0 );
    double angle_rad( angle / 180. * tools::constants::pi );

    mat R{
        {cos(angle_rad), -sin(angle_rad), 0},
        {sin(angle_rad), cos(angle_rad),  0},
        {0,              0,               1}
    };

    molecule::Molecule<vec3> molecule{
        {"H", {  0.000,  0.947, -0.079}}, // H1
        {"O", {  0.000,  0.000,  0.000}}, // O1
        {"O", {  0.000,  0.000,  1.474}}, // O2
        {"H", { -0.854, -0.407,  1.553}}  // H2
    };

    // Transform molecular coordinates from angstrom to bohr
    molecule::multiply_positions(molecule,
                                 tools::conversion::angstrom_to_bohr);

    // Allocate displacements in cartesian coordinates
    vec dx{ linalg::zeros<vec>(3 * molecule.size()) };

    // Compute transformation for H1 rotation
    vec3 v{ R * molecule[0].position - molecule[0].position};
    dx(0) = v(0);
    dx(1) = v(1);
    dx(2) = v(2);

    // Compute old dihedral (before rotation)
    double d_old{ connectivity::dihedral<vec3>( molecule[0].position,
                                                molecule[1].position,
                                                molecule[2].position,
                                                molecule[3].position) };

    // Compute new dihedral angle (after rotation)
    double d_new{ connectivity::dihedral<vec3>( R * molecule[0].position,
                                                molecule[1].position,
                                                molecule[2].position,
                                                molecule[3].position) };

    // Compute dihedral variation
    double d_diff{ d_new - d_old };

    // Compute interatomic distances
    mat dd{ connectivity::distances<vec3, mat>(molecule) };

    // Compute adjacency matrix (graph)
    connectivity::UGraph adj{ connectivity::adjacency_matrix(dd, molecule) };

    // Compute distance matrix and predecessor matrix
    mat dist, predecessors;
    std::tie(dist, predecessors) = connectivity::distance_matrix<mat>(adj) ;

    // Compute bonds
    vector<connectivity::Bond> bonds{ connectivity::bonds(dist, molecule)};

    // Print bonds
    cout << "\nBonds:" << endl;
    for(const auto& b : bonds){
      cout << connectivity::bond(b, molecule) *
          tools::conversion::bohr_to_angstrom << endl;
    }

    // Check number of bonds
    REQUIRE( bonds.size() == 3 );

    // Compute angles
    vector<connectivity::Angle> angles{
        connectivity::angles(dist, predecessors, molecule)};

    // Print angles
    cout << "\nAngles:" << endl;
    for(const auto& a : angles){
      cout << connectivity::angle(a, molecule) << endl;
    }

    // Check number of angles
    REQUIRE( angles.size() == 2 );

    // Compute dihedrals
    vector<connectivity::Dihedral> dihedrals{
        connectivity::dihedrals(dist, predecessors, molecule)};

    // Print angles
    cout << "\nDihedrals:" << endl;
    for(const auto& d : dihedrals){
      cout << connectivity::dihedral(d, molecule) << endl;
    }

    // Check number of dihedrals
    REQUIRE( dihedrals.size() == 1 );

    // Compute Wilson's B matrix
    mat Bwilson = wilson_matrix<vec3,vec,mat>(
        molecule::to_cartesian<vec3,vec>(molecule),
        bonds, angles, dihedrals);

    // Print Wilson B matrix
    cout << "\nWilson B matrix:" << endl;
    cout << Bwilson << endl;

    // Compute displacement in internal coordinates
    vec displacement{Bwilson * dx};
    cout << "\nDisplacement:" << endl;
    cout << displacement << endl;

    // Check that bonds do not change
    SECTION("Bond change"){
      Approx target{0};

      target.margin(1e-3);

      REQUIRE( displacement(0) == target );
      REQUIRE( displacement(1) == target );
      REQUIRE( displacement(2) == target );
    }

    // Check change in angle
    SECTION("Angle change"){
      Approx target{0};

      target.margin(1e-3);

      REQUIRE( displacement(3) == target );
      REQUIRE( displacement(4) == target );
    }

    // Check change in angle
    SECTION("Dihedral change"){
      Approx target{d_diff};

      target.margin(1e-4);

      REQUIRE( displacement(5) == target );
    }
  }
}

TEST_CASE("Wilson"){
  using namespace std;

  using namespace connectivity;
  using namespace molecule;
  using namespace tools;
  using namespace wilson;

  Molecule<vec3> mol{
      io::load_xyz<vec3>(config::molecules_dir + "hydrogen_peroxide.xyz")
  };

  // Transform molecule to bohr
  multiply_positions(mol, conversion::angstrom_to_bohr);

  // Compute interatomic distances
  mat dd{ distances<vec3,mat>(mol) };

  // Compute adjacency matrix (graph)
  UGraph adj{ adjacency_matrix(dd, mol) };

  // Compute distance matrix and predecessor matrix
  mat dist, predecessors;
  tie(dist, predecessors) = distance_matrix<mat>(adj);

  // Compute bonds
  vector<Bond> B{ bonds(dist, mol) };

  REQUIRE( B.size() == 3 );

  // Compute angles
  vector<Angle> A{ angles(dist, predecessors, mol)};

  REQUIRE( A.size() == 2 );

  // Compute dihedrals
  vector<Dihedral> D{ dihedrals(dist, predecessors, mol)};

  REQUIRE( D.size() == 1 );

  cout << "q =\n"
       << irc_from_bad<vec3,vec>(to_cartesian<vec3,vec>(mol),B,A,D) << endl;

  // Return Wilson's B matrix
  mat WB{
      wilson_matrix<vec3,vec,mat>(
          to_cartesian<vec3,vec>(mol),
          B,A,D)
  };

  cout << "B =\n" << WB << endl;
}<commit_msg>More tests on Wilson B matrix<commit_after>#include "../../include/catch/catch.hpp"

#include "libirc/wilson.h"

#include "libirc/atom.h"
#include "libirc/io.h"
#include "libirc/molecule.h"
#include "libirc/connectivity.h"
#include "libirc/conversion.h"

#include "config.h"

#include <cmath>
#include <iostream>

#ifdef HAVE_ARMA
#include <armadillo>
using vec3 = arma::vec3;
using vec = arma::vec;
using mat = arma::mat;
#elif HAVE_EIGEN3
#include <Eigen3/Eigen/Dense>
using vec3 = Eigen::Vector3d;
using vec = Eigen::VectorXd;
using mat = Eigen::MatrixXd;
#else
#error
#endif

using namespace irc;

TEST_CASE("Wilson B matrix","[wilson]"){

  bool verbose{true};

  using namespace std;

  using namespace connectivity;
  using namespace molecule;
  using namespace wilson;

  SECTION("H2 stretching"){

    // Define molecule
    Molecule<vec3> mol{{"H",{0.,0.,0.}},{"H",{1.,0.,0.}}};

    // Compute interatomic distances
    mat dd{ distances<vec3,mat>(mol)};

    // Compute adjacency matrix (graph)
    UGraph adj{ adjacency_matrix(dd, mol) };

    // Compute distance matrix and predecessor matrix
    mat dist, pred;
    tie(dist, pred) = distance_matrix<mat>(adj);

    // Compute bonds
    vector<Bond> B{ bonds(dist, mol) };

    REQUIRE(B.size() == 1);

    // Compute Wilson B matrix for H2 analytically
    mat Bwilson = wilson_matrix<vec3,vec,mat>(to_cartesian<vec3,vec>(mol),B);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(Bwilson) == 6 );

    if(verbose){
      cout << "Wilson B matrix (analytical):" << endl;
      cout << Bwilson << endl;
    }

    // Compute Wilson B matrix for H2 numerically
    mat BwilsonN = wilson_matrix_numerical<vec3,vec,mat>(to_cartesian<vec3,vec>(mol), B);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(BwilsonN) == 6 );

    if(verbose){
      cout << "Wilson B matrix (numerical):" << endl;
      cout << BwilsonN << endl;
    }

    // Check analytical and numerical Wilson matrices are the same
    SECTION("Analytical vs Numerical"){
      for(size_t i{0}; i < 6; i++ ){
        Approx target{BwilsonN(i)};
        target.margin(1e-6);

        REQUIRE( Bwilson(i) == target);
      }
    }

    // Set bond stretching
    double d{0.01};
    vec dx{-d, 0.00, 0.00, d, 0.00, 0.00};

    SECTION("Bond change (analytical)"){
      // Compute transformation in IRC
      vec transformation{Bwilson * dx};

      if(verbose){
        cout << "\nTransformation (analytical)" << endl;
        cout << Bwilson * dx << endl;
      }

      Approx target{2 * d};
      target.margin(1e-5);

      REQUIRE( transformation(0) == target );
    }

    SECTION("Bond change (numerical)"){
      // Compute transformation in IRC
      vec transformation{BwilsonN * dx};

      if(verbose){
        cout << "\nTransformation (numerical)" << endl;
        cout << Bwilson * dx << endl;
      }

      Approx target{2 * d};
      target.margin(1e-5);

      REQUIRE( transformation(0) == target );
    }
  } // H2 stretching

  SECTION("H2O bending"){

    double angle( 0.5 );
    double angle_rad( angle / 180. * tools::constants::pi );

    std::vector<mat> R{
        {
            // Rotation for H1
            {cos(angle_rad), -sin(angle_rad), 0},
            {sin(angle_rad),  cos(angle_rad), 0},
            {             0,               0, 1}
        },
        {
            // Rotation for O
            {1, 0, 0},
            {0, 1, 0},
            {0, 0, 1}
        },
        {
            // Rotation for H2
            {cos(-angle_rad), -sin(-angle_rad), 0},
            {sin(-angle_rad),  cos(-angle_rad), 0},
            {              0,                0, 1}
        },
    };

    molecule::Molecule<vec3> mol{
        {"H", { 1.43,  -1.10,  0.00}}, // H1
        {"O", { 0.00,   0.00,  0.00}}, // O
        {"H", {-1.43,  -1.10,  0.00}}  // H2
    };

    // Allocate displacements in cartesian coordinates
    vec dx{ linalg::zeros<vec>(3 * mol.size()) };

    // Compute displacements
    for(size_t i{0}; i < 3; i++){
      vec3 v{ R[i] * mol[i].position - mol[i].position};

      dx(3*i + 0) = v(0);
      dx(3*i + 1) = v(1);
      dx(3*i + 2) = v(2);
    }

    // Compute interatomic distances
    mat dd{ distances<vec3,mat>(mol)};

    // Compute adjacency matrix (graph)
    UGraph adj{ adjacency_matrix(dd, mol) };

    // Compute distance matrix and predecessor matrix
    mat dist, pred;
    tie(dist, pred) = distance_matrix<mat>(adj);

    // Compute bonds
    vector<Bond> B{ bonds(dist, mol) };

    // Check number of bonds
    REQUIRE(B.size() == 2);

    // Compute bonds
    vector<Angle> A{ angles(dist, pred, mol) };

    REQUIRE(A.size() == 1);

    // Compute Wilson B matrix for H2O analytically
    mat Bwilson = wilson_matrix<vec3,vec,mat>(to_cartesian<vec3,vec>(mol),B, A);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(Bwilson) == 27 );

    if(verbose){
      // Print Wilson B matrix
      cout << "\nWilson B matrix (analytical):" << endl;
      cout << Bwilson << endl;
    }

    // Compute Wilson B matrix for H2O numerically
    mat BwilsonN = wilson_matrix_numerical<vec3,vec,mat>(to_cartesian<vec3,vec>(mol),B, A);

    // Check Wilson B matrix size
    REQUIRE( linalg::size(BwilsonN) == 27 );

    if(verbose){
      // Print Wilson B matrix
      cout << "\nWilson B matrix (numerical):" << endl;
      cout << BwilsonN << endl;
    }

    // Check analytical and numerical Wilson matrices are the same
    SECTION("Analytical vs Numerical"){
      for(size_t i{0}; i < 27; i++ ){
        Approx target{BwilsonN(i)};
        target.margin(1e-6);

        REQUIRE( Bwilson(i) == target);
      }
    }

    SECTION("Analytical displacement"){
      // Compute displacement in internal coordinates
      vec displacement{Bwilson * dx};
      cout << "\nDisplacement:" << endl;
      cout << displacement << endl;

      // Check that bonds do not change
      SECTION("Bond change"){
        Approx target{0};

        target.margin(1e-4);

        REQUIRE( displacement(0) == target );
        REQUIRE( displacement(1) == target );
      }

      // Check change in angle
      SECTION("Angle change"){
        Approx target{2 * angle};

        target.margin(1e-3);

        REQUIRE( displacement(2) * 180 / tools::constants::pi == target );
      }
    }
  }

  SECTION("H2O2 torsion"){

    double angle( 1.0 );
    double angle_rad( angle / 180. * tools::constants::pi );

    mat R{
        {cos(angle_rad), -sin(angle_rad), 0},
        {sin(angle_rad), cos(angle_rad),  0},
        {0,              0,               1}
    };

    molecule::Molecule<vec3> molecule{
        {"H", {  0.000,  0.947, -0.079}}, // H1
        {"O", {  0.000,  0.000,  0.000}}, // O1
        {"O", {  0.000,  0.000,  1.474}}, // O2
        {"H", { -0.854, -0.407,  1.553}}  // H2
    };

    // Transform molecular coordinates from angstrom to bohr
    molecule::multiply_positions(molecule,
                                 tools::conversion::angstrom_to_bohr);

    // Allocate displacements in cartesian coordinates
    vec dx{ linalg::zeros<vec>(3 * molecule.size()) };

    // Compute transformation for H1 rotation
    vec3 v{ R * molecule[0].position - molecule[0].position};
    dx(0) = v(0);
    dx(1) = v(1);
    dx(2) = v(2);

    // Compute old dihedral (before rotation)
    double d_old{ connectivity::dihedral<vec3>( molecule[0].position,
                                                molecule[1].position,
                                                molecule[2].position,
                                                molecule[3].position) };

    // Compute new dihedral angle (after rotation)
    double d_new{ connectivity::dihedral<vec3>( R * molecule[0].position,
                                                molecule[1].position,
                                                molecule[2].position,
                                                molecule[3].position) };

    // Compute dihedral variation
    double d_diff{ d_new - d_old };

    // Compute interatomic distances
    mat dd{ connectivity::distances<vec3, mat>(molecule) };

    // Compute adjacency matrix (graph)
    connectivity::UGraph adj{ connectivity::adjacency_matrix(dd, molecule) };

    // Compute distance matrix and predecessor matrix
    mat dist, predecessors;
    std::tie(dist, predecessors) = connectivity::distance_matrix<mat>(adj) ;

    // Compute bonds
    vector<connectivity::Bond> bonds{ connectivity::bonds(dist, molecule)};

    // Check number of bonds
    REQUIRE( bonds.size() == 3 );

    // Compute angles
    vector<connectivity::Angle> angles{
        connectivity::angles(dist, predecessors, molecule)};

    // Check number of angles
    REQUIRE( angles.size() == 2 );

    // Compute dihedrals
    vector<connectivity::Dihedral> dihedrals{
        connectivity::dihedrals(dist, predecessors, molecule)};

    // Check number of dihedrals
    REQUIRE( dihedrals.size() == 1 );

    // Compute Wilson's B matrix
    mat Bwilson = wilson_matrix<vec3,vec,mat>(
        molecule::to_cartesian<vec3,vec>(molecule),
        bonds, angles, dihedrals);

    REQUIRE( linalg::size(Bwilson) == 72 );

    if(verbose){
      // Print Wilson B matrix
      cout << "\nWilson B matrix (analytical):" << endl;
      cout << Bwilson << endl;
    }

    // Compute Wilson's B matrix
    mat BwilsonN = wilson_matrix_numerical<vec3,vec,mat>(
        molecule::to_cartesian<vec3,vec>(molecule),
        bonds, angles, dihedrals);

    REQUIRE( linalg::size(BwilsonN) == 72 );

    if(verbose){
      // Print Wilson B matrix
      cout << "\nWilson B matrix (numerical):" << endl;
      cout << BwilsonN << endl;
    }

    // Check analytical and numerical Wilson matrices are the same
    SECTION("Analytical vs Numerical"){
      for(size_t i{0}; i < 72; i++ ){
        Approx target{BwilsonN(i)};
        target.margin(1e-6);

        REQUIRE( Bwilson(i) == target);
      }
    }

    SECTION("Analytical displacements"){
      // Compute displacement in internal coordinates
      vec displacement{Bwilson * dx};

      //Print displacements
      if(verbose){
        cout << "\nDisplacement (analytical):" << endl;
        cout << displacement << endl;
      }

      // Check that bonds do not change
      SECTION("Bonds change"){
        Approx target{0};

        target.margin(1e-3);

        REQUIRE( displacement(0) == target );
        REQUIRE( displacement(1) == target );
        REQUIRE( displacement(2) == target );
      }

      // Check change in angle
      SECTION("Angles change"){
        Approx target{0};

        target.margin(1e-4);

        REQUIRE( displacement(3) == target );
        REQUIRE( displacement(4) == target );
      }

      // Check change in angle
      SECTION("Dihedral change"){
        Approx target{d_diff};

        target.margin(1e-4);

        REQUIRE( displacement(5) == target );
      }
    }

    SECTION("Numerical displacements"){
      // Compute displacement in internal coordinates
      vec displacement{BwilsonN * dx};

      //Print displacements
      if(verbose){
        cout << "\nDisplacement (numerical):" << endl;
        cout << displacement << endl;
      }

      // Check that bonds do not change
      SECTION("Bonds change"){
        Approx target{0};

        target.margin(1e-3);

        REQUIRE( displacement(0) == target );
        REQUIRE( displacement(1) == target );
        REQUIRE( displacement(2) == target );
      }

      // Check change in angle
      SECTION("Angles change"){
        Approx target{0};

        target.margin(1e-4);

        REQUIRE( displacement(3) == target );
        REQUIRE( displacement(4) == target );
      }

      // Check change in angle
      SECTION("Dihedral change"){
        Approx target{d_diff};

        target.margin(1e-4);

        REQUIRE( displacement(5) == target );
      }
    }

  }
}

TEST_CASE("Wilson"){
  using namespace std;

  using namespace connectivity;
  using namespace molecule;
  using namespace tools;
  using namespace wilson;

  bool verbose{true};

  Molecule<vec3> mol{
      io::load_xyz<vec3>(config::molecules_dir + "hydrogen_peroxide.xyz")
  };

  // Transform molecule to bohr
  multiply_positions(mol, conversion::angstrom_to_bohr);

  // Compute interatomic distances
  mat dd{ distances<vec3,mat>(mol) };

  // Compute adjacency matrix (graph)
  UGraph adj{ adjacency_matrix(dd, mol) };

  // Compute distance matrix and predecessor matrix
  mat dist, predecessors;
  tie(dist, predecessors) = distance_matrix<mat>(adj);

  // Compute bonds
  vector<Bond> B{ bonds(dist, mol) };

  REQUIRE( B.size() == 3 );

  // Compute angles
  vector<Angle> A{ angles(dist, predecessors, mol)};

  REQUIRE( A.size() == 2 );

  // Compute dihedrals
  vector<Dihedral> D{ dihedrals(dist, predecessors, mol)};

  REQUIRE( D.size() == 1 );

  cout << "q =\n"
       << irc_from_bad<vec3,vec>(to_cartesian<vec3,vec>(mol),B,A,D) << endl;

  // Return Wilson's B matrix (analytical)
  mat WB{
      wilson_matrix<vec3,vec,mat>(
          to_cartesian<vec3,vec>(mol),
          B,A,D)
  };

  if(verbose){
    cout << "B (analytical) =\n" << WB << endl;
  }

  // Return Wilson's B matrix (numerical)
  mat WBN{
      wilson_matrix_numerical<vec3,vec,mat>(
          to_cartesian<vec3,vec>(mol),
          B,A,D)
  };

  if(verbose){
    cout << "B (numerical) =\n" << WBN << endl;
  }
}<|endoftext|>


<commit_before>#ifndef STAN_MATH_OPENCL_KERNELS_CATEGORICAL_LOGIT_GLM_LPMF_HPP
#define STAN_MATH_OPENCL_KERNELS_CATEGORICAL_LOGIT_GLM_LPMF_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/kernel_cl.hpp>
#include <string>

namespace stan {
namespace math {
namespace opencl_kernels {

// \cond
static const std::string categorical_logit_glm_kernel_code = STRINGIFY(
    // \endcond
    /**
     * GPU implementation of Generalized Linear Model (GLM)
     * with categorical distribution and logit (softmax) link function.
     *
     * Must be run with at least N threads and local size equal to LOCAL_SIZE_.
     * @param[out] logp_global partially summed log probabiltiy (1 value per
     * work group)
     * @param[out] exp_lin_global exponentiation of sum of alpha and matrix
     * product of x and beta
     * @param[out] inv_sum_exp_lin_global inverse of rowwise sum of \c
     * exp_lin_global
     * @param[out] neg_softmax_lin_global negated softmax of sum of alpha and
     * matrix product of x and beta
     * @param[out] alpha_derivative derivative wrt alpha
     * @param[in] y_global a scalar or vector of classes.
     * @param[in] x_beta_global product of design matrix and weight matrix
     * @param[in] alpha_global intercept (in log odds)
     * @param N_instances number of instances
     * @param N_attributes number of attributes
     * @param N_classes number of classes
     * @param is_y_vector 0 or 1 - whether y is a vector (alternatively it is a
     * scalar)
     * @param need_alpha_derivative interpreted as boolean - whether
     * alpha_derivative needs to be computed
     * @param need_neg_softmax_lin_global interpreted as boolean - whether
     * neg_softmax_lin_global needs to be computed
     */
    __kernel void categorical_logit_glm(
        __global double* logp_global, __global double* exp_lin_global,
        __global double* inv_sum_exp_lin_global,
        __global double* neg_softmax_lin_global,
        __global double* alpha_derivative, const __global int* y_global,
        const __global double* x_beta_global,
        const __global double* alpha_global, const int N_instances,
        const int N_attributes, const int N_classes, const int is_y_vector,
        const int need_alpha_derivative,
        const int need_neg_softmax_lin_global) {
      const int gid = get_global_id(0);
      const int lid = get_local_id(0);
      const int lsize = get_local_size(0);
      const int wg_id = get_group_id(0);
      const int ngroups = get_num_groups(0);

      __local double local_storage[LOCAL_SIZE_];

      double logp = 0;
      double inv_sum_exp_lin;
      int class_idx = -1;
      // Most calculations only happen for relevant data within next if.
      // Exceptions are reductions between threads that need barriers.
      if (gid < N_instances) {
        double lin_max = -INFINITY;
        for (int i = 0; i < N_classes; i++) {
          double lin = x_beta_global[i * N_instances + gid] + alpha_global[i];
          if (lin > lin_max) {
            lin_max = lin;
          }
        }
        double alpha = alpha_global[gid];
        double sum_exp_lin = 0;
        for (int i = 0; i < N_classes; i++) {
          double lin = x_beta_global[i * N_instances + gid] + alpha_global[i];
          double exp_lin = exp(lin - lin_max);
          sum_exp_lin += exp_lin;
          exp_lin_global[i * N_instances + gid] = exp_lin;
        }
        inv_sum_exp_lin = 1 / sum_exp_lin;
        inv_sum_exp_lin_global[gid] = inv_sum_exp_lin;

        class_idx = y_global[gid * is_y_vector] - 1;
        if (class_idx < 0 || class_idx > N_classes) {
          logp = NAN;
        } else {
          logp = log(inv_sum_exp_lin) - lin_max
                 + x_beta_global[class_idx * N_instances + gid]
                 + alpha_global[class_idx];
        }
      }
      barrier(CLK_GLOBAL_MEM_FENCE);
      double neg_softmax_lin_sum = 0;
      if (need_alpha_derivative || need_neg_softmax_lin_global) {
        for (int i = 0; i < N_classes; i++) {
          double neg_softmax_lin = 0;
          if (gid < N_instances) {
            int idx = i * N_instances + gid;
            neg_softmax_lin = -exp_lin_global[idx] * inv_sum_exp_lin;
            if (need_neg_softmax_lin_global) {
              neg_softmax_lin_global[idx] = neg_softmax_lin;
            }
          }
          if (need_alpha_derivative) {
            local_storage[lid] = neg_softmax_lin + (class_idx == i);
            barrier(CLK_LOCAL_MEM_FENCE);
            for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
                 step /= REDUCTION_STEP_SIZE) {
              if (lid < step) {
                for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
                  local_storage[lid] += local_storage[lid + step * i];
                }
              }
              barrier(CLK_LOCAL_MEM_FENCE);
            }
            if (lid == 0) {
              alpha_derivative[i * ngroups + wg_id] = local_storage[0];
            }
            barrier(CLK_LOCAL_MEM_FENCE);
          }
        }
      }
      // Sum logp, calculated by different threads.
      // Since we can't sum between different work groups, we emit one number
      // per work group. These must be summed on CPU for final result.
      local_storage[lid] = logp;
      barrier(CLK_LOCAL_MEM_FENCE);
      for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
           step /= REDUCTION_STEP_SIZE) {
        if (lid < step) {
          for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
            local_storage[lid] += local_storage[lid + step * i];
          }
        }
        barrier(CLK_LOCAL_MEM_FENCE);
      }
      if (lid == 0) {
        logp_global[wg_id] = local_storage[0];
      }
    }
    // \cond
);
// \endcond

/**
 * See the docs for \link kernels/categorical_logit_glm_lpmf.hpp
 * categorical_logit_glm() \endlink
 */
const kernel_cl<out_buffer, out_buffer, out_buffer, out_buffer, out_buffer,
                in_buffer, in_buffer, in_buffer, int, int, int, int, int, int>
    categorical_logit_glm("categorical_logit_glm",
                          {categorical_logit_glm_kernel_code},
                          {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 64}});

// \cond
static const std::string categorical_logit_glm_beta_derivative_kernel_code
    = STRINGIFY(
        // \endcond
        /**
         * Calculates derivative wrt beta.
         *
         * Must be run with global size of local_size*N_attributes.
         * @param[in,out] beta_derivative derivative wrt beta
         * @param temp temporary workspace of size global_size*N_classes
         * @param[in] y a scalar or vector of classes
         * @param[in] x design matrix
         * @param N_instances number of instances
         * @param N_attributes number of attributes
         * @param N_classes number of classes
         * @param is_y_vector 0 or 1 - whether y is a vector (alternatively it
         * is a scalar)
         */
        __kernel void categorical_logit_glm_beta_derivative(
            __global double* beta_derivative, __global double* temp,
            const __global int* y, const __global double* x,
            const int N_instances, const int N_attributes, const int N_classes,
            const int is_y_vector) {
          const int gid = get_global_id(0);
          const int lid = get_local_id(0);
          const int lsize = get_local_size(0);
          const int wg_id = get_group_id(0);

          for (int i = 0; i < N_classes; i++) {
            temp[gid * N_classes + i] = 0;
          }
          for (int i = lid; i < N_instances; i += lsize) {
            int pos = y[i * is_y_vector] - 1;
            temp[gid * N_classes + pos] += x[wg_id * N_instances + i];
          }
          barrier(CLK_GLOBAL_MEM_FENCE);
          for (int i = lid; i < N_classes; i += lsize) {
            double res = 0;
            for (int j = 0; j < lsize; j++) {
              res += temp[(wg_id * lsize + j) * N_classes + i];
            }
            beta_derivative[i * N_attributes + wg_id] += res;
          }
        }
        // \cond
    ); // NOLINT
// \endcond

/**
 * See the docs for \link kernels/categorical_logit_glm_lpmf.hpp
 * categorical_logit_glm_beta_derivative() \endlink
 */
const kernel_cl<in_out_buffer, in_out_buffer, in_buffer, in_buffer, int, int,
                int, int>
    categorical_logit_glm_beta_derivative(
        "categorical_logit_glm_beta_derivative",
        {categorical_logit_glm_beta_derivative_kernel_code});

}  // namespace opencl_kernels

}  // namespace math
}  // namespace stan
#endif
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14)<commit_after>#ifndef STAN_MATH_OPENCL_KERNELS_CATEGORICAL_LOGIT_GLM_LPMF_HPP
#define STAN_MATH_OPENCL_KERNELS_CATEGORICAL_LOGIT_GLM_LPMF_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/kernel_cl.hpp>
#include <string>

namespace stan {
namespace math {
namespace opencl_kernels {

// \cond
static const std::string categorical_logit_glm_kernel_code = STRINGIFY(
    // \endcond
    /**
     * GPU implementation of Generalized Linear Model (GLM)
     * with categorical distribution and logit (softmax) link function.
     *
     * Must be run with at least N threads and local size equal to LOCAL_SIZE_.
     * @param[out] logp_global partially summed log probabiltiy (1 value per
     * work group)
     * @param[out] exp_lin_global exponentiation of sum of alpha and matrix
     * product of x and beta
     * @param[out] inv_sum_exp_lin_global inverse of rowwise sum of \c
     * exp_lin_global
     * @param[out] neg_softmax_lin_global negated softmax of sum of alpha and
     * matrix product of x and beta
     * @param[out] alpha_derivative derivative wrt alpha
     * @param[in] y_global a scalar or vector of classes.
     * @param[in] x_beta_global product of design matrix and weight matrix
     * @param[in] alpha_global intercept (in log odds)
     * @param N_instances number of instances
     * @param N_attributes number of attributes
     * @param N_classes number of classes
     * @param is_y_vector 0 or 1 - whether y is a vector (alternatively it is a
     * scalar)
     * @param need_alpha_derivative interpreted as boolean - whether
     * alpha_derivative needs to be computed
     * @param need_neg_softmax_lin_global interpreted as boolean - whether
     * neg_softmax_lin_global needs to be computed
     */
    __kernel void categorical_logit_glm(
        __global double* logp_global, __global double* exp_lin_global,
        __global double* inv_sum_exp_lin_global,
        __global double* neg_softmax_lin_global,
        __global double* alpha_derivative, const __global int* y_global,
        const __global double* x_beta_global,
        const __global double* alpha_global, const int N_instances,
        const int N_attributes, const int N_classes, const int is_y_vector,
        const int need_alpha_derivative,
        const int need_neg_softmax_lin_global) {
      const int gid = get_global_id(0);
      const int lid = get_local_id(0);
      const int lsize = get_local_size(0);
      const int wg_id = get_group_id(0);
      const int ngroups = get_num_groups(0);

      __local double local_storage[LOCAL_SIZE_];

      double logp = 0;
      double inv_sum_exp_lin;
      int class_idx = -1;
      // Most calculations only happen for relevant data within next if.
      // Exceptions are reductions between threads that need barriers.
      if (gid < N_instances) {
        double lin_max = -INFINITY;
        for (int i = 0; i < N_classes; i++) {
          double lin = x_beta_global[i * N_instances + gid] + alpha_global[i];
          if (lin > lin_max) {
            lin_max = lin;
          }
        }
        double alpha = alpha_global[gid];
        double sum_exp_lin = 0;
        for (int i = 0; i < N_classes; i++) {
          double lin = x_beta_global[i * N_instances + gid] + alpha_global[i];
          double exp_lin = exp(lin - lin_max);
          sum_exp_lin += exp_lin;
          exp_lin_global[i * N_instances + gid] = exp_lin;
        }
        inv_sum_exp_lin = 1 / sum_exp_lin;
        inv_sum_exp_lin_global[gid] = inv_sum_exp_lin;

        class_idx = y_global[gid * is_y_vector] - 1;
        if (class_idx < 0 || class_idx > N_classes) {
          logp = NAN;
        } else {
          logp = log(inv_sum_exp_lin) - lin_max
                 + x_beta_global[class_idx * N_instances + gid]
                 + alpha_global[class_idx];
        }
      }
      barrier(CLK_GLOBAL_MEM_FENCE);
      double neg_softmax_lin_sum = 0;
      if (need_alpha_derivative || need_neg_softmax_lin_global) {
        for (int i = 0; i < N_classes; i++) {
          double neg_softmax_lin = 0;
          if (gid < N_instances) {
            int idx = i * N_instances + gid;
            neg_softmax_lin = -exp_lin_global[idx] * inv_sum_exp_lin;
            if (need_neg_softmax_lin_global) {
              neg_softmax_lin_global[idx] = neg_softmax_lin;
            }
          }
          if (need_alpha_derivative) {
            local_storage[lid] = neg_softmax_lin + (class_idx == i);
            barrier(CLK_LOCAL_MEM_FENCE);
            for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
                 step /= REDUCTION_STEP_SIZE) {
              if (lid < step) {
                for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
                  local_storage[lid] += local_storage[lid + step * i];
                }
              }
              barrier(CLK_LOCAL_MEM_FENCE);
            }
            if (lid == 0) {
              alpha_derivative[i * ngroups + wg_id] = local_storage[0];
            }
            barrier(CLK_LOCAL_MEM_FENCE);
          }
        }
      }
      // Sum logp, calculated by different threads.
      // Since we can't sum between different work groups, we emit one number
      // per work group. These must be summed on CPU for final result.
      local_storage[lid] = logp;
      barrier(CLK_LOCAL_MEM_FENCE);
      for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
           step /= REDUCTION_STEP_SIZE) {
        if (lid < step) {
          for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
            local_storage[lid] += local_storage[lid + step * i];
          }
        }
        barrier(CLK_LOCAL_MEM_FENCE);
      }
      if (lid == 0) {
        logp_global[wg_id] = local_storage[0];
      }
    }
    // \cond
);
// \endcond

/**
 * See the docs for \link kernels/categorical_logit_glm_lpmf.hpp
 * categorical_logit_glm() \endlink
 */
const kernel_cl<out_buffer, out_buffer, out_buffer, out_buffer, out_buffer,
                in_buffer, in_buffer, in_buffer, int, int, int, int, int, int>
    categorical_logit_glm("categorical_logit_glm",
                          {categorical_logit_glm_kernel_code},
                          {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 64}});

// \cond
static const std::string categorical_logit_glm_beta_derivative_kernel_code
    = STRINGIFY(
        // \endcond
        /**
         * Calculates derivative wrt beta.
         *
         * Must be run with global size of local_size*N_attributes.
         * @param[in,out] beta_derivative derivative wrt beta
         * @param temp temporary workspace of size global_size*N_classes
         * @param[in] y a scalar or vector of classes
         * @param[in] x design matrix
         * @param N_instances number of instances
         * @param N_attributes number of attributes
         * @param N_classes number of classes
         * @param is_y_vector 0 or 1 - whether y is a vector (alternatively it
         * is a scalar)
         */
        __kernel void categorical_logit_glm_beta_derivative(
            __global double* beta_derivative, __global double* temp,
            const __global int* y, const __global double* x,
            const int N_instances, const int N_attributes, const int N_classes,
            const int is_y_vector) {
          const int gid = get_global_id(0);
          const int lid = get_local_id(0);
          const int lsize = get_local_size(0);
          const int wg_id = get_group_id(0);

          for (int i = 0; i < N_classes; i++) {
            temp[gid * N_classes + i] = 0;
          }
          for (int i = lid; i < N_instances; i += lsize) {
            int pos = y[i * is_y_vector] - 1;
            temp[gid * N_classes + pos] += x[wg_id * N_instances + i];
          }
          barrier(CLK_GLOBAL_MEM_FENCE);
          for (int i = lid; i < N_classes; i += lsize) {
            double res = 0;
            for (int j = 0; j < lsize; j++) {
              res += temp[(wg_id * lsize + j) * N_classes + i];
            }
            beta_derivative[i * N_attributes + wg_id] += res;
          }
        }
        // \cond
    );  // NOLINT
// \endcond

/**
 * See the docs for \link kernels/categorical_logit_glm_lpmf.hpp
 * categorical_logit_glm_beta_derivative() \endlink
 */
const kernel_cl<in_out_buffer, in_out_buffer, in_buffer, in_buffer, int, int,
                int, int>
    categorical_logit_glm_beta_derivative(
        "categorical_logit_glm_beta_derivative",
        {categorical_logit_glm_beta_derivative_kernel_code});

}  // namespace opencl_kernels

}  // namespace math
}  // namespace stan
#endif
#endif
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------------
** This software is implemented as part of the course Dynamic Algorithms
** (Q4 2015) at Aarhus Univerity Denmark.
**
** performance.h
** Implementation of the performance tests.
**
** Author: Martin Storgaard and Konstantinos Mampentzidis
** -------------------------------------------------------------------------*/
#include "performance.h"

#include <iostream>
#include <fstream>

const std::string outputDir("output/");
const std::string insSuffix("-ins.stat");
const std::string delSuffix("-del.stat");
const std::string querySuffix("-query.stat");
const std::string queryOutSuffix(".out");

void Performance::run(
	std::vector<TC*> algs,		//< Algorithms to be executed
	std::vector<Input> changes, //< Changes as defined in project description
	std::string output_prefix)	//< e.g. output/changefile3-ins.stat
{

	// Open output streams
	std::ofstream insFile(outputDir + output_prefix + insSuffix);
	std::ofstream delFile(outputDir + output_prefix + delSuffix);
	std::ofstream queryFile(outputDir + output_prefix + querySuffix);

	//
	unsigned int querySize;
	long long cpuClock;
	for(auto &alg : algs) {
		const char* name = alg->get_name();
		std::string strName(name, strlen(name));
		std::ofstream queryOutFile(outputDir + output_prefix + strName + queryOutSuffix);
		for (auto &change : changes) {
			switch(change.type) {
			case 3:
				alg->init(change.i);
				break;
			case 2:
				// Reset counters
				ioctl(this->fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
				// Start counting
				ioctl(this->fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
				// Run query
				querySize = alg->query();
				// Stop counting
				ioctl(this->fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
				// Get CPU clock count
				cpuClock = _get(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
				// Write cpu time
				queryFile << name << "," << cpuClock << "\n";
				// Write output (for correctness)
				queryOutFile << querySize << "\n";
				break;
			case 1:
				// Reset counters
				ioctl(this->fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
				// Start counting
				ioctl(this->fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
				// Run query
				alg->del(change.i, change.j);
				// Stop counting
				ioctl(this->fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
				// Get CPU clock count
				cpuClock = _get(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
				// Write cpu time
				delFile << name << "," << cpuClock << "\n";
				break;
			case 0:
				// Reset counters
				ioctl(this->fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
				// Start counting
				ioctl(this->fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
				// Run query
				alg->ins(change.i, change.j);
				// Stop counting
				ioctl(this->fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
				// Get CPU clock count
				cpuClock = _get(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
				// Write cpu time
				insFile << name << "," << cpuClock << "\n";
				break;
			default:
				std::cout << "ERROR!!" << std::endl;
				// Close all files
				queryOutFile.close();
				insFile.close();
				delFile.close();
				queryFile.close();
				return;
			}
		}
		queryOutFile.close();
		std::cout << std::endl;
	}
	insFile.close();
	delFile.close();
	queryFile.close();
}

static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) {
	int ret;

	ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);

	return ret;
}

void Performance::_add(perf_type_id type, long long config){
	struct perf_event_attr pe;
	memset(&pe, 0, sizeof(struct perf_event_attr));
	pe.size = sizeof(struct perf_event_attr);
	pe.exclude_kernel = 1;
	pe.exclude_hv = 1;

	pe.type = type;
	pe.config = config;

	order[events].type = type;
	order[events].config = config;
	events++;

	if (fd == -1){
		/* if changed: change calculations in get */
		pe.read_format = PERF_FORMAT_GROUP;
		pe.disabled = 1;

		fd = perf_event_open(&pe, 0, -1, -1, 0);
		if (fd < 0) {
			fprintf(stderr, "Error opening leader for %llx / %llx\n", (long long) type, config);
			exit(EXIT_FAILURE);
		}
	}else{
		int ret = perf_event_open(&pe, 0, -1, fd, 0);
		if (ret < 0) {
			fprintf(stderr, "Error connecting to leader for %llx / %llx\n", (long long) type, config);
			exit(EXIT_FAILURE);
		}
	}
}

long long Performance::_get(perf_type_id type, long long config){
	long long buffer[1 /* <nr> */ + (1 /* <value> */ * perf_size /* [nr] */)];
	int readSize = (1 + (1 * perf_size)) * sizeof(long long);
	int r = read(fd, &buffer, readSize);
	if(r == -1) {
		fprintf(stderr, "Error reading from fd\n");
		exit(EXIT_FAILURE);
	}
	for (int index = 0; index < events; index++){
		if(order[index].config == config && order[index].type == type){
			return buffer[1 + index];
		}
	}
	fprintf(stderr, "Could not find sw config: %llx\n", (long long)config);
	exit(EXIT_FAILURE);
}
<commit_msg>Removed a new line print<commit_after>/* ---------------------------------------------------------------------------
** This software is implemented as part of the course Dynamic Algorithms
** (Q4 2015) at Aarhus Univerity Denmark.
**
** performance.h
** Implementation of the performance tests.
**
** Author: Martin Storgaard and Konstantinos Mampentzidis
** -------------------------------------------------------------------------*/
#include "performance.h"

#include <iostream>
#include <fstream>

const std::string outputDir("output/");
const std::string insSuffix("-ins.stat");
const std::string delSuffix("-del.stat");
const std::string querySuffix("-query.stat");
const std::string queryOutSuffix(".out");

void Performance::run(
	std::vector<TC*> algs,		//< Algorithms to be executed
	std::vector<Input> changes, //< Changes as defined in project description
	std::string output_prefix)	//< e.g. output/changefile3-ins.stat
{

	// Open output streams
	std::ofstream insFile(outputDir + output_prefix + insSuffix);
	std::ofstream delFile(outputDir + output_prefix + delSuffix);
	std::ofstream queryFile(outputDir + output_prefix + querySuffix);

	//
	unsigned int querySize;
	long long cpuClock;
	for(auto &alg : algs) {
		const char* name = alg->get_name();
		std::string strName(name, strlen(name));
		std::ofstream queryOutFile(outputDir + output_prefix + strName + queryOutSuffix);
		for (auto &change : changes) {
			switch(change.type) {
			case 3:
				alg->init(change.i);
				break;
			case 2:
				// Reset counters
				ioctl(this->fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
				// Start counting
				ioctl(this->fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
				// Run query
				querySize = alg->query();
				// Stop counting
				ioctl(this->fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
				// Get CPU clock count
				cpuClock = _get(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
				// Write cpu time
				queryFile << name << "," << cpuClock << "\n";
				// Write output (for correctness)
				queryOutFile << querySize << "\n";
				break;
			case 1:
				// Reset counters
				ioctl(this->fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
				// Start counting
				ioctl(this->fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
				// Run query
				alg->del(change.i, change.j);
				// Stop counting
				ioctl(this->fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
				// Get CPU clock count
				cpuClock = _get(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
				// Write cpu time
				delFile << name << "," << cpuClock << "\n";
				break;
			case 0:
				// Reset counters
				ioctl(this->fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
				// Start counting
				ioctl(this->fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
				// Run query
				alg->ins(change.i, change.j);
				// Stop counting
				ioctl(this->fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
				// Get CPU clock count
				cpuClock = _get(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
				// Write cpu time
				insFile << name << "," << cpuClock << "\n";
				break;
			default:
				std::cout << "ERROR!!" << std::endl;
				// Close all files
				queryOutFile.close();
				insFile.close();
				delFile.close();
				queryFile.close();
				return;
			}
		}
		queryOutFile.close();
	}
	insFile.close();
	delFile.close();
	queryFile.close();
}

static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) {
	int ret;

	ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);

	return ret;
}

void Performance::_add(perf_type_id type, long long config){
	struct perf_event_attr pe;
	memset(&pe, 0, sizeof(struct perf_event_attr));
	pe.size = sizeof(struct perf_event_attr);
	pe.exclude_kernel = 1;
	pe.exclude_hv = 1;

	pe.type = type;
	pe.config = config;

	order[events].type = type;
	order[events].config = config;
	events++;

	if (fd == -1){
		/* if changed: change calculations in get */
		pe.read_format = PERF_FORMAT_GROUP;
		pe.disabled = 1;

		fd = perf_event_open(&pe, 0, -1, -1, 0);
		if (fd < 0) {
			fprintf(stderr, "Error opening leader for %llx / %llx\n", (long long) type, config);
			exit(EXIT_FAILURE);
		}
	}else{
		int ret = perf_event_open(&pe, 0, -1, fd, 0);
		if (ret < 0) {
			fprintf(stderr, "Error connecting to leader for %llx / %llx\n", (long long) type, config);
			exit(EXIT_FAILURE);
		}
	}
}

long long Performance::_get(perf_type_id type, long long config){
	long long buffer[1 /* <nr> */ + (1 /* <value> */ * perf_size /* [nr] */)];
	int readSize = (1 + (1 * perf_size)) * sizeof(long long);
	int r = read(fd, &buffer, readSize);
	if(r == -1) {
		fprintf(stderr, "Error reading from fd\n");
		exit(EXIT_FAILURE);
	}
	for (int index = 0; index < events; index++){
		if(order[index].config == config && order[index].type == type){
			return buffer[1 + index];
		}
	}
	fprintf(stderr, "Could not find sw config: %llx\n", (long long)config);
	exit(EXIT_FAILURE);
}
<|endoftext|>


<commit_before>#ifdef __LINUX__
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#else
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __LINUX__
#define CONSOLE_COLOR_NORMAL  "\x1B[0m"
#define CONSOLE_COLOR_RED  "\x1B[31m"
#define CONSOLE_COLOR_GREEN  "\x1B[32m"
#define CONSOLE_COLOR_YELLOW  "\x1B[33m"
#define CONSOLE_COLOR_BLUE  "\x1B[34m"
#define CONSOLE_COLOR_MAGENTA  "\x1B[35m"
#define CONSOLE_COLOR_CYAN  "\x1B[36m"
#define CONSOLE_COLOR_WHITE  "\x1B[37m"
#define CONSOLE_COLOR_RESET "\033[0m"
#define CONSOLE_COLOR_BOLD "\x1B[1m"
#define CONSOLE_COLOR_WHITE_BOLD "\x1B[1;37m"
#else
#define CONSOLE_COLOR_NORMAL
#define CONSOLE_COLOR_RED
#define CONSOLE_COLOR_GREEN
#define CONSOLE_COLOR_YELLOW
#define CONSOLE_COLOR_BLUE
#define CONSOLE_COLOR_MAGENTA
#define CONSOLE_COLOR_CYAN
#define CONSOLE_COLOR_WHITE
#define CONSOLE_COLOR_RESET
#define CONSOLE_COLOR_BOLD
#define CONSOLE_COLOR_WHITE_BOLD
#endif

const char * LogError[]={CONSOLE_COLOR_BOLD CONSOLE_COLOR_RED "ERROR" ,
			 CONSOLE_COLOR_YELLOW "WARNING" ,
			 CONSOLE_COLOR_BLUE "INFORMATION",
			 CONSOLE_COLOR_GREEN "DEBUG"};
enum
{
    LOG_ERROR,
    LOG_WARNING,
    LOG_INFORMATION,
    LOG_DEBUG
};
const int LOG_LEVEL=LOG_DEBUG; //controls up to what level of errors is logged
#define Log(ll,fmt,...) __LOG(ll,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogError(fmt,...)__LOG(LOG_ERROR,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogWarning(fmt,...) __LOG(LOG_WARNING,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogInformation(fmt,...) __LOG(LOG_INFORMATION,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogDebug(fmt,...) __LOG(LOG_DEBUG,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)

void __LOG(int loglevel,const char * fmt, const char* caller , int line,const char * file,...)
{
    if (loglevel>LOG_LEVEL)
        return;
    va_list argptr;
    va_start(argptr,file);
    char * tmp;
    int size=vsnprintf(NULL, 0, fmt, argptr);
    tmp=(char*)malloc(size+1);
    va_end(argptr);
    va_start(argptr,file);
    vsnprintf(tmp,size+1,fmt,argptr);
    //TODO(Christof): Update this to use a log file at some point
    printf("%s:" CONSOLE_COLOR_WHITE_BOLD " %s " CONSOLE_COLOR_RESET "line " CONSOLE_COLOR_WHITE_BOLD "%d" CONSOLE_COLOR_RESET " - %s : %s\n",LogError[loglevel],file,line,caller,tmp);
    va_end(argptr);
    free(tmp);
}

#ifdef __WINDOWS__
int64_t PerformaceCounterFrequency;
#endif

int64_t GetTimeMillis()
{
    #ifdef __LINUX__
    //TODO(Christof): check clock res and do something (warn maybe?) if insufficient
    struct timespec time;
    clock_gettime(CLOCK_REALTIME,&time);
    return (time.tv_sec*1000)+(time.tv_nsec/1000/1000);
    #endif
    #ifdef __WINDOWS__
    LARGE_INTEGER time;
    QueryPerformanceCounter(&time);
    return time.QuadPart/(PerformaceCounterFrequency/1000);
    #endif
}

struct MemoryMappedFile
{
#ifdef __WINDOWS__
    HANDLE MMFile;
    HANDLE File;
#else
    int File;
#endif
    unsigned char * MMapBuffer;
    int64_t FileSize;
};

MemoryMappedFile MemoryMapFile(const char * FileName)
{
    MemoryMappedFile MMFile={0};
#ifdef __LINUX__
    struct stat64 filestats;

    if(stat64(FileName,&filestats)==-1)
	return {0};
    MMFile.FileSize=filestats.st_size;

    MMFile.File=open(FileName,O_RDONLY);
    if(MMFile.File==-1)
	return {0};

    MMFile.MMapBuffer=static_cast<unsigned char *>(mmap(MMFile.MMapBuffer,MMFile.FileSize,PROT_READ,MAP_SHARED,MMFile.File,0));
#else
#ifdef __WINDOWS__
    OFSTRUCT of;
    MMFile.File=(HANDLE)OpenFile(FileName,&of,OF_READ);
    if(MMFile.File==(HANDLE)HFILE_ERROR)
    {
	return {0};
    }

    DWORD high=0;
    DWORD low=GetFileSize(MMFile.File,&high);
    MMFile.FileSize = low | (((int64_t)high) << 32);
    MMFile.MMFile=CreateFileMapping(MMFile.File,NULL,PAGE_READONLY,0,0,NULL);
    if(!MMFile.MMFile)
    {
	return {0};
    }
    MMFile.MMapBuffer=static_cast<unsigned char *>(MapViewOfFile(MMFile.MMFile,FILE_MAP_READ,0,0,0));
#endif
#endif

    return MMFile;
}

void UnMapFile(MemoryMappedFile MMFile)
{
#ifdef __WINDOWS__
    UnmapViewOfFile(MMFile.MMapBuffer);
    CloseHandle(MMFile.MMFile);
    CloseHandle(MMFile.File);
#else
    close(MMFile.File);
    munmap(MMFile.MMapBuffer,MMFile.FileSize);
#endif
}

#include <png.h>
#include "zlib.h"

void SaveDataToPng(char * ImageData, char * FileName, int Width, int Height)
{
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL);
    if (!png_ptr)
    {
        LogError("Could not create PNG write stucture for %s",FileName);
	return;
    }
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
        LogError("Could not create PNG info stucture for %s",FileName);
	return;
    }
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        LogError("Could not set PNG jmp ptr for %s",FileName);
	return;
    }
    FILE *fp = fopen(FileName, "wb");
    if (!fp)
    {
        LogError("Failed to open %s",FileName);
	return;
    }
    png_init_io(png_ptr, fp);
    png_set_filter(png_ptr, 0,PNG_ALL_FILTERS);
    png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
    png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY);
    png_set_IHDR(png_ptr, info_ptr, Width, Height,8,PNG_COLOR_TYPE_RGB , PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT) ;
    png_write_info(png_ptr, info_ptr);
    png_write_flush(png_ptr);

    unsigned char ** row_pointers =new unsigned char*[Height];
    for (int i=0; i<Height; i++)
        row_pointers[i]=(unsigned char *)&(ImageData[(Height-1-i)*Width*3]);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);

    delete[] row_pointers;

}
<commit_msg>more consistant mem management.<commit_after>#ifdef __LINUX__
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#else
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __LINUX__
#define CONSOLE_COLOR_NORMAL  "\x1B[0m"
#define CONSOLE_COLOR_RED  "\x1B[31m"
#define CONSOLE_COLOR_GREEN  "\x1B[32m"
#define CONSOLE_COLOR_YELLOW  "\x1B[33m"
#define CONSOLE_COLOR_BLUE  "\x1B[34m"
#define CONSOLE_COLOR_MAGENTA  "\x1B[35m"
#define CONSOLE_COLOR_CYAN  "\x1B[36m"
#define CONSOLE_COLOR_WHITE  "\x1B[37m"
#define CONSOLE_COLOR_RESET "\033[0m"
#define CONSOLE_COLOR_BOLD "\x1B[1m"
#define CONSOLE_COLOR_WHITE_BOLD "\x1B[1;37m"
#else
#define CONSOLE_COLOR_NORMAL
#define CONSOLE_COLOR_RED
#define CONSOLE_COLOR_GREEN
#define CONSOLE_COLOR_YELLOW
#define CONSOLE_COLOR_BLUE
#define CONSOLE_COLOR_MAGENTA
#define CONSOLE_COLOR_CYAN
#define CONSOLE_COLOR_WHITE
#define CONSOLE_COLOR_RESET
#define CONSOLE_COLOR_BOLD
#define CONSOLE_COLOR_WHITE_BOLD
#endif

const char * LogError[]={CONSOLE_COLOR_BOLD CONSOLE_COLOR_RED "ERROR" ,
			 CONSOLE_COLOR_YELLOW "WARNING" ,
			 CONSOLE_COLOR_BLUE "INFORMATION",
			 CONSOLE_COLOR_GREEN "DEBUG"};
enum
{
    LOG_ERROR,
    LOG_WARNING,
    LOG_INFORMATION,
    LOG_DEBUG
};
const int LOG_LEVEL=LOG_DEBUG; //controls up to what level of errors is logged
#define Log(ll,fmt,...) __LOG(ll,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogError(fmt,...)__LOG(LOG_ERROR,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogWarning(fmt,...) __LOG(LOG_WARNING,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogInformation(fmt,...) __LOG(LOG_INFORMATION,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)
#define LogDebug(fmt,...) __LOG(LOG_DEBUG,fmt,__func__,__LINE__,__FILE__,##__VA_ARGS__)

void __LOG(int loglevel,const char * fmt, const char* caller , int line,const char * file,...)
{
    if (loglevel>LOG_LEVEL)
        return;
    va_list argptr;
    va_start(argptr,file);
    int size=vsnprintf(NULL, 0, fmt, argptr);
    char tmp[size];
    va_end(argptr);
    va_start(argptr,file);
    vsnprintf(tmp,size+1,fmt,argptr);
    //TODO(Christof): Update this to use a log file at some point
    printf("%s:" CONSOLE_COLOR_WHITE_BOLD " %s " CONSOLE_COLOR_RESET "line " CONSOLE_COLOR_WHITE_BOLD "%d" CONSOLE_COLOR_RESET " - %s : %s\n",LogError[loglevel],file,line,caller,tmp);
    va_end(argptr);
}

#ifdef __WINDOWS__
int64_t PerformaceCounterFrequency;
#endif

int64_t GetTimeMillis()
{
    #ifdef __LINUX__
    //TODO(Christof): check clock res and do something (warn maybe?) if insufficient
    struct timespec time;
    clock_gettime(CLOCK_REALTIME,&time);
    return (time.tv_sec*1000)+(time.tv_nsec/1000/1000);
    #endif
    #ifdef __WINDOWS__
    LARGE_INTEGER time;
    QueryPerformanceCounter(&time);
    return time.QuadPart/(PerformaceCounterFrequency/1000);
    #endif
}

struct MemoryMappedFile
{
#ifdef __WINDOWS__
    HANDLE MMFile;
    HANDLE File;
#else
    int File;
#endif
    unsigned char * MMapBuffer;
    int64_t FileSize;
};

MemoryMappedFile MemoryMapFile(const char * FileName)
{
    MemoryMappedFile MMFile={0};
#ifdef __LINUX__
    struct stat64 filestats;

    if(stat64(FileName,&filestats)==-1)
	return {0};
    MMFile.FileSize=filestats.st_size;

    MMFile.File=open(FileName,O_RDONLY);
    if(MMFile.File==-1)
	return {0};

    MMFile.MMapBuffer=static_cast<unsigned char *>(mmap(MMFile.MMapBuffer,MMFile.FileSize,PROT_READ,MAP_SHARED,MMFile.File,0));
#else
#ifdef __WINDOWS__
    OFSTRUCT of;
    MMFile.File=(HANDLE)OpenFile(FileName,&of,OF_READ);
    if(MMFile.File==(HANDLE)HFILE_ERROR)
    {
	return {0};
    }

    DWORD high=0;
    DWORD low=GetFileSize(MMFile.File,&high);
    MMFile.FileSize = low | (((int64_t)high) << 32);
    MMFile.MMFile=CreateFileMapping(MMFile.File,NULL,PAGE_READONLY,0,0,NULL);
    if(!MMFile.MMFile)
    {
	return {0};
    }
    MMFile.MMapBuffer=static_cast<unsigned char *>(MapViewOfFile(MMFile.MMFile,FILE_MAP_READ,0,0,0));
#endif
#endif

    return MMFile;
}

void UnMapFile(MemoryMappedFile MMFile)
{
#ifdef __WINDOWS__
    UnmapViewOfFile(MMFile.MMapBuffer);
    CloseHandle(MMFile.MMFile);
    CloseHandle(MMFile.File);
#else
    close(MMFile.File);
    munmap(MMFile.MMapBuffer,MMFile.FileSize);
#endif
}

#include <png.h>
#include "zlib.h"

void SaveDataToPng(char * ImageData, char * FileName, int Width, int Height)
{
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL);
    if (!png_ptr)
    {
        LogError("Could not create PNG write stucture for %s",FileName);
	return;
    }
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
        LogError("Could not create PNG info stucture for %s",FileName);
	return;
    }
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        LogError("Could not set PNG jmp ptr for %s",FileName);
	return;
    }
    FILE *fp = fopen(FileName, "wb");
    if (!fp)
    {
        LogError("Failed to open %s",FileName);
	return;
    }
    png_init_io(png_ptr, fp);
    png_set_filter(png_ptr, 0,PNG_ALL_FILTERS);
    png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
    png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY);
    png_set_IHDR(png_ptr, info_ptr, Width, Height,8,PNG_COLOR_TYPE_RGB , PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT) ;
    png_write_info(png_ptr, info_ptr);
    png_write_flush(png_ptr);

    unsigned char ** row_pointers =new unsigned char*[Height];
    for (int i=0; i<Height; i++)
        row_pointers[i]=(unsigned char *)&(ImageData[(Height-1-i)*Width*3]);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);

    delete[] row_pointers;

}
<|endoftext|>


<commit_before>/*
 * mpt C++ library
 *   event operations
 */

#include <limits>

#include <stdlib.h>

#include <poll.h>

#include "array.h"
#include "output.h"

#include "event.h"

__MPT_NAMESPACE_BEGIN

// event reply andling
reply_context *reply_context::defer()
{
    return 0;
}
inline bool reply_data::setData(size_t len, const void *data)
{
    if (len && active()) return false;
    return (mpt_reply_set(this, len, data) < 0) ? false : true;
}

// command array
bool command::array::set(uintptr_t id, EventHandler cmd, void *arg)
{
    dispatch *d = static_cast<dispatch *>(this);
    return mpt_dispatch_set(d, id, cmd, arg) >= 0;
}
command *command::array::get(uintptr_t id)
{
    return mpt_command_get(this, id);
}
command *command::array::next(size_t len)
{
    return mpt_command_nextid(this, len);
}
// dispatcher
dispatch::dispatch()
{ mpt_dispatch_init(this); }
dispatch::~dispatch()
{ mpt_dispatch_fini(this); }
bool dispatch::setDefault(uintptr_t id)
{
    if (!get(id)) return false;
    _def = id;
    return true;
}
void dispatch::setError(int (*cmd)(void *, event *), void *arg)
{
    if (_err.cmd) {
        _err.cmd(_err.arg, 0);
    }
    _err.cmd = cmd;
    _err.arg = arg;
}

// message source interface
int MessageSource::reply(const message *)
{
    return 0;
}

__MPT_NAMESPACE_END
<commit_msg>fix: no inline for reply data assignment<commit_after>/*
 * mpt C++ library
 *   event operations
 */

#include <limits>

#include <stdlib.h>

#include <poll.h>

#include "array.h"
#include "output.h"

#include "event.h"

__MPT_NAMESPACE_BEGIN

// event reply andling
reply_context *reply_context::defer()
{
    return 0;
}
bool reply_data::setData(size_t len, const void *data)
{
    if (len && active()) return false;
    return (mpt_reply_set(this, len, data) < 0) ? false : true;
}

// command array
bool command::array::set(uintptr_t id, EventHandler cmd, void *arg)
{
    dispatch *d = static_cast<dispatch *>(this);
    return mpt_dispatch_set(d, id, cmd, arg) >= 0;
}
command *command::array::get(uintptr_t id)
{
    return mpt_command_get(this, id);
}
command *command::array::next(size_t len)
{
    return mpt_command_nextid(this, len);
}
// dispatcher
dispatch::dispatch()
{ mpt_dispatch_init(this); }
dispatch::~dispatch()
{ mpt_dispatch_fini(this); }
bool dispatch::setDefault(uintptr_t id)
{
    if (!get(id)) return false;
    _def = id;
    return true;
}
void dispatch::setError(int (*cmd)(void *, event *), void *arg)
{
    if (_err.cmd) {
        _err.cmd(_err.arg, 0);
    }
    _err.cmd = cmd;
    _err.arg = arg;
}

// message source interface
int MessageSource::reply(const message *)
{
    return 0;
}

__MPT_NAMESPACE_END
<|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  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 2 of the License, or
  (at your option) any later version.

  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 General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventviewer.h"
#include "urihandler.h"

#include <libkdepim/kdepimprotocols.h>

#include <kcal/incidence.h>
#include <kcal/incidenceformatter.h>

#ifndef KORG_NODBUS
#include <kapplication.h>
#include "korganizerinterface.h"
#endif
#include <kdebug.h>
#include <koglobals.h>
#include <ktoolinvocation.h>
#include <kconfiggroup.h>

#include <QRegExp>

KOEventViewer::KOEventViewer( QWidget *parent )
  : KTextBrowser( parent ), mDefaultText("")
{
  mIncidence = 0;
  setNotifyClick( true );
}

KOEventViewer::~KOEventViewer()
{
}

void KOEventViewer::readSettings( KConfig * config )
{
  if ( config ) {
// With each restart of KOrganizer the font site gets halfed. What should this
// be good for?
#if 0
    config->setGroup( QString("EventViewer-%1").arg( name() )  );
    int zoomFactor = config->readEntry("ZoomFactor", pointSize() );
    zoomTo( zoomFactor/2 );
    kDebug(5850) <<" KOEventViewer: restoring the pointSize:"<< pointSize()
      << ", zoomFactor: " << zoomFactor;
#endif
  }
}

void KOEventViewer::writeSettings( KConfig * config )
{
  if ( config ) {
    kDebug(5850) <<" KOEventViewer: saving the zoomFactor:"<< pointSize();
    KConfigGroup configGroup( config, QString("EventViewer-%1").arg( objectName() ) );
    configGroup.writeEntry("ZoomFactor", pointSize() );
  }
}

void KOEventViewer::setSource( const QString &n )
{
  QString uri = n;
  // QTextBrowser for some reason insists on putting // in links,
  // this is a crude workaround
  if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ||
       uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ||
       uri.startsWith( QString( KDEPIMPROTOCOL_INCIDENCE ).
                                                  section( ':', 0, 0 ) ) ||
       uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) )
    uri.replace( QRegExp( "^([^:]*:)//" ), "\\1" );

  UriHandler::process( uri );
}

bool KOEventViewer::appendIncidence( Incidence *incidence )
{
  QString codeForIncidence =
                        IncidenceFormatter::extensiveDisplayString( incidence );
/*  kDebug( 5850 ) <<" KOEventViewer: appending incidence, HTML code:" << endl
                  << "-------------------FROM HERE--------------------" << endl
                  << codeForIncidence << endl
                  << "--------------------TO HERE---------------------"; */
  addText( codeForIncidence );
  return true;
}

void KOEventViewer::setIncidence( Incidence *incidence )
{
  clearEvents();
  if( incidence ) {
    appendIncidence( incidence );
    mIncidence = incidence;
  } else {
    clearEvents( true );
    mIncidence = 0;
  }
}

void KOEventViewer::clearEvents( bool now )
{
  mText = "";
  if ( now ) setText( mDefaultText );
}

void KOEventViewer::addText( const QString &text )
{
  mText.append( text );
  setText( mText );
}

void KOEventViewer::setDefaultText( const QString &text )
{
  mDefaultText = text;
}

void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, int action )
{
  if ( mIncidence && ( incidence->uid() == mIncidence->uid() ) ) {
    switch (action ) {
      case KOGlobals::INCIDENCEEDITED:{
        setIncidence( incidence );
        break;
      }
      case KOGlobals::INCIDENCEDELETED: {
        setIncidence( 0 );
        break;
      }
    }
  }
}

void KOEventViewer::editIncidence()
{
  if ( mIncidence ) {
#ifndef KORG_NODBUS
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath("korganizer");

    OrgKdeKorganizerKorganizerInterface korganizerIface("org.kde.korganizer.Korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.editIncidence( mIncidence->uid() );
#endif
  }
}

void KOEventViewer::showIncidenceContext()
{
#ifndef KORG_NODBUS
  if ( mIncidence ) {
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath("korganizer");

    OrgKdeKorganizerKorganizerInterface korganizerIface("org.kde.korganizer.Korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.showIncidenceContext( mIncidence->uid() );
  }
#endif
}

#include "koeventviewer.moc"
<commit_msg>deprecated-- pointSize() -> fontPointSize()<commit_after>/*
  This file is part of KOrganizer.

  Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
  Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  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 2 of the License, or
  (at your option) any later version.

  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 General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "koeventviewer.h"
#include "urihandler.h"

#include <libkdepim/kdepimprotocols.h>

#include <kcal/incidence.h>
#include <kcal/incidenceformatter.h>

#ifndef KORG_NODBUS
#include <kapplication.h>
#include "korganizerinterface.h"
#endif
#include <kdebug.h>
#include <koglobals.h>
#include <ktoolinvocation.h>
#include <kconfiggroup.h>

#include <QRegExp>

KOEventViewer::KOEventViewer( QWidget *parent )
  : KTextBrowser( parent ), mDefaultText("")
{
  mIncidence = 0;
  setNotifyClick( true );
}

KOEventViewer::~KOEventViewer()
{
}

void KOEventViewer::readSettings( KConfig * config )
{
  if ( config ) {
// With each restart of KOrganizer the font site gets halfed. What should this
// be good for?
#if 0
    config->setGroup( QString("EventViewer-%1").arg( name() )  );
    int zoomFactor = config->readEntry("ZoomFactor", fontPointSize() );
    zoomTo( zoomFactor/2 );
    kDebug(5850) <<" KOEventViewer: restoring the fontPointSize:"<< fontPointSize()
      << ", zoomFactor: " << zoomFactor;
#endif
  }
}

void KOEventViewer::writeSettings( KConfig * config )
{
  if ( config ) {
    kDebug(5850) << " KOEventViewer: saving the zoomFactor:" << fontPointSize();
    KConfigGroup configGroup( config, QString("EventViewer-%1").arg( objectName() ) );
    configGroup.writeEntry("ZoomFactor", fontPointSize() );
  }
}

void KOEventViewer::setSource( const QString &n )
{
  QString uri = n;
  // QTextBrowser for some reason insists on putting // in links,
  // this is a crude workaround
  if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ||
       uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ||
       uri.startsWith( QString( KDEPIMPROTOCOL_INCIDENCE ).
                                                  section( ':', 0, 0 ) ) ||
       uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) )
    uri.replace( QRegExp( "^([^:]*:)//" ), "\\1" );

  UriHandler::process( uri );
}

bool KOEventViewer::appendIncidence( Incidence *incidence )
{
  QString codeForIncidence =
                        IncidenceFormatter::extensiveDisplayString( incidence );
/*  kDebug( 5850 ) <<" KOEventViewer: appending incidence, HTML code:" << endl
                  << "-------------------FROM HERE--------------------" << endl
                  << codeForIncidence << endl
                  << "--------------------TO HERE---------------------"; */
  addText( codeForIncidence );
  return true;
}

void KOEventViewer::setIncidence( Incidence *incidence )
{
  clearEvents();
  if( incidence ) {
    appendIncidence( incidence );
    mIncidence = incidence;
  } else {
    clearEvents( true );
    mIncidence = 0;
  }
}

void KOEventViewer::clearEvents( bool now )
{
  mText = "";
  if ( now ) setText( mDefaultText );
}

void KOEventViewer::addText( const QString &text )
{
  mText.append( text );
  setText( mText );
}

void KOEventViewer::setDefaultText( const QString &text )
{
  mDefaultText = text;
}

void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, int action )
{
  if ( mIncidence && ( incidence->uid() == mIncidence->uid() ) ) {
    switch (action ) {
      case KOGlobals::INCIDENCEEDITED:{
        setIncidence( incidence );
        break;
      }
      case KOGlobals::INCIDENCEDELETED: {
        setIncidence( 0 );
        break;
      }
    }
  }
}

void KOEventViewer::editIncidence()
{
  if ( mIncidence ) {
#ifndef KORG_NODBUS
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath("korganizer");

    OrgKdeKorganizerKorganizerInterface korganizerIface("org.kde.korganizer.Korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.editIncidence( mIncidence->uid() );
#endif
  }
}

void KOEventViewer::showIncidenceContext()
{
#ifndef KORG_NODBUS
  if ( mIncidence ) {
    // make sure korganizer is running or the part is shown
    KToolInvocation::startServiceByDesktopPath("korganizer");

    OrgKdeKorganizerKorganizerInterface korganizerIface("org.kde.korganizer.Korganizer", "/Korganizer", QDBusConnection::sessionBus() );
    korganizerIface.showIncidenceContext( mIncidence->uid() );
  }
#endif
}

#include "koeventviewer.moc"
<|endoftext|>