<commit_before>#include <cstdio>
#include <cstring>
#include <iostream>
#include <thread>
#include <chrono>
#include "print_tests.h"
#include "console_tests.h"
#include "file_tests.h"
#include "string_tests.h"

//
// buffers for stdout and files using setvbuf and pubsetbuf functions
//
const size_t stdout_buff_size = 1 << 16; //64Kb
const size_t file_buff_size = stdout_buff_size;
char stdout_buff[stdout_buff_size];
char file_buff[file_buff_size];

int main(int argc, char *argv[])
{
  std::ios::sync_with_stdio(false);
  bool use_setvbuf_stdout = false;
  size_t test_iters = 1;
  size_t stdout_test_iters = 1000;
  size_t file_test_iters = 1000000;
  size_t string_test_iters = 500000;

  try {
    for (int i = 1; i < argc; i++) {
      if (strcmp(argv[i], "--help") == 0) {
        printUsage();
        return EXIT_SUCCESS;
      } else if (strcmp(argv[i], "-use-setvbuf") == 0) {
        use_setvbuf_stdout = true;
      } else if (strcmp(argv[i], "-console") == 0 && i+1 < argc) {
        stdout_test_iters = strToUInt(argv[++i]);
      } else if (strcmp(argv[i], "-string") == 0 && i+1 < argc) {
        string_test_iters = strToUInt(argv[++i]);
      } else if (strcmp(argv[i], "-file") == 0 && i+1 < argc) {
        file_test_iters = strToUInt(argv[++i]);
      } else if (strcmp(argv[i], "-rerun") == 0 && i+1 < argc) {
        test_iters += strToUInt(argv[++i]);
      } else {
        printf("Error: Invalid option '%s'\n", argv[i]);
        printUsage();
        return EXIT_FAILURE;
      }
    }
  } catch (std::exception &e) {
    printf("\n%s\n", e.what());
    printUsage();
    return EXIT_FAILURE;
  }

  if (use_setvbuf_stdout) {
    setvbuf(stdout, stdout_buff, _IOFBF, stdout_buff_size);
  }

  Test stdout_tests[] = {
    // stdout tests
    Test(printfTest, stdout_test_iters, "printf"),
    Test(coutTest, stdout_test_iters, "cout"),
    Test(templatePrintfTest, stdout_test_iters, "template printf"),
    Test(templateCppPrintfTest, stdout_test_iters, "template cpp printf"),
  };

  Test string_tests[] = {
    // string tests
    Test(sprintfTest, string_test_iters, "sprintf"),
    Test(templateSprintfTest, string_test_iters, "template sprintf"),
    Test(heapSprintfTest, string_test_iters, "heap sprintf"),
    Test(ostringstreamTest, string_test_iters, "ostringstream"),
    Test(templateHeapSprintfTest, string_test_iters, "template heap sprintf")
  };

  FileTest file_tests[] = {
    // formatted file tests
    FileTest(fprintfTest, file_test_iters, "fprintf"),
    FileTest(buffered_fwriteTest, file_test_iters,
             "buffered (formatted) fwrite"),
    FileTest(ofstreamTest, file_test_iters, "ofstream"),
    FileTest(buffered_ofstreamWriteTest, file_test_iters,
             "buffered (formatted) ofstream write"),
    FileTest(templateFPrintfTest, file_test_iters, "template fprintf"),
    FileTest(templateCppFPrintfTest, file_test_iters, "template cpp fprintf"),
    // binary file tests
    FileTest(binary_fwriteTest, file_test_iters, "binary fwrite"),
    FileTest(bufferedBinary_fwriteTest, file_test_iters,
             "buffered binary fwrite"),
    FileTest(binary_ofstreamWriteTest, file_test_iters,
             "binary ofstream write"),
    FileTest(bufferedBinary_ofstreamWriteTest, file_test_iters,
             "buffered binary ofstream write")
  };

  // File tests using setvbuf/ofstream::pubsetbuf
  FileTest file_tests2[] = {
    // formatted file tests
    FileTest({fprintfTest, file_buff, file_buff_size}, file_test_iters,
             "fprintf"),
    FileTest({buffered_fwriteTest,  file_buff, file_buff_size},
             file_test_iters, "buffered (formatted) fwrite"),
    FileTest({ofstreamTest,  file_buff, file_buff_size},
             file_test_iters, "ofstream"),
    FileTest({buffered_ofstreamWriteTest,  file_buff, file_buff_size},
             file_test_iters, "buffered (formatted) ofstream write"),
    FileTest({templateFPrintfTest,  file_buff, file_buff_size},
             file_test_iters,"template fprintf"),
    FileTest({templateCppFPrintfTest, file_buff, file_buff_size},
             file_test_iters,"template cpp fprintf"),
    // binary file tests
    FileTest({binary_fwriteTest,  file_buff, file_buff_size},
             file_test_iters,"binary fwrite"),
    FileTest({bufferedBinary_fwriteTest, file_buff, file_buff_size},
             file_test_iters,"buffered binary fwrite"),
    FileTest({binary_ofstreamWriteTest,  file_buff, file_buff_size},
             file_test_iters,"binary ofstream write"),
    FileTest({bufferedBinary_ofstreamWriteTest,  file_buff, file_buff_size},
             file_test_iters, "buffered binary ofstream write")
  };

  for (size_t i = 0; i < test_iters; ++i) {
    if (stdout_test_iters > 0) {
      for (auto &test : stdout_tests) {
        printf("\n%s test\n", test.test_name);
        fflush(stdout);
        std::chrono::milliseconds ms(1500);
        std::this_thread::sleep_for(ms);
        test.run();
        fflush(stdout);
        std::cout.flush();
      }
    }

    if (file_test_iters > 0) {
      for (auto &test : file_tests) {
        printf("\n%s test\n", test.test_name);
        fflush(stdout);
        test.run();
      }

      for (auto &test : file_tests2) {
        printf("\n%s test (with setvbuf/ofstream::pubsetbuf\n",
               test.test_name);
        fflush(stdout);
        test.run();
      }
    }

    if (string_test_iters > 0) {
      for (auto &test : string_tests) {
        printf("\n%s test\n", test.test_name);
        fflush(stdout);
        test.run();
      }
    }

  }

  printf("\nstdout test iterations = %zu\n", stdout_test_iters);
  printf("file test iterations = %zu\n", file_test_iters);
  printf("string test iterations = %zu\n", string_test_iters);
  printf("number of times each test was run = %zu\n\n", test_iters);

  if (use_setvbuf_stdout)
    printf("stdout tests with buffer (setvbuf,pubsetbuf) = %zu bytes:\n",
           stdout_buff_size);
  else
    printf("stdout tests:\n");

  for (auto &test : stdout_tests)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  printf("\nfile tests:\n");
  for (auto &test : file_tests)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  printf("\nfile tests with buffer (setvbuf) = %zu bytes:\n",
         file_buff_size);
  for (auto &test : file_tests2)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  printf("\nstring tests:\n");
  for (auto &test : string_tests)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  return EXIT_SUCCESS;
}

void printUsage()
{
  printf("Usage: print-tests [--help] [-use-setvbuf] [-console COUNT] "
         "[-file COUNT]\n\t[-string COUNT] [-rerun COUNT]\n");
  printf("-use-setvbuf = Use setvbuf for stdout.\n");
  printf("-console COUNT = Run console tests COUNT times. This affects "
         "how much data is\n\twritten to console in each test.\n"
         "\tDefault is 1000.\n");
  printf("-file COUNT = Run file tests COUNT times. This affects how "
         "much data is written\n\tto the test file 'test.out' in each "
         "test.\n\tDefault is 1000000.\n");
  printf("-string COUNT = Run string tests COUNT times. This affects how "
         "much data is\n\twritten to the string in each test.\n"
         "\tDefault is 500000.\n");
  printf("-rerun COUNT = Run all tests again COUNT times for taking an "
         "average of each\n\ttest's duration.\n"
         "\tDefault is 0.\n");
}

size_t strToUInt(const char *str)
{
  char *str_end = nullptr; // for detecting errors in strtol
  size_t n = strtoul(str, &str_end, 10);
  if (errno == ERANGE){
    errno = 0;
    throw std::runtime_error("Error: Number entered is too large.");
  }
  if (str == str_end) {
    throw std::runtime_error("Error converting string to int");
  }
  return n;
}

<commit_msg>Readded exception for negative inputs in strToUInt<commit_after>#include <cstdio>
#include <cstring>
#include <iostream>
#include <thread>
#include <chrono>
#include "print_tests.h"
#include "console_tests.h"
#include "file_tests.h"
#include "string_tests.h"

//
// buffers for stdout and files using setvbuf and pubsetbuf functions
//
const size_t stdout_buff_size = 1 << 16; //64Kb
const size_t file_buff_size = stdout_buff_size;
char stdout_buff[stdout_buff_size];
char file_buff[file_buff_size];

int main(int argc, char *argv[])
{
  std::ios::sync_with_stdio(false);
  bool use_setvbuf_stdout = false;
  size_t test_iters = 1;
  size_t stdout_test_iters = 1000;
  size_t file_test_iters = 1000000;
  size_t string_test_iters = 500000;

  try {
    for (int i = 1; i < argc; i++) {
      if (strcmp(argv[i], "--help") == 0) {
        printUsage();
        return EXIT_SUCCESS;
      } else if (strcmp(argv[i], "-use-setvbuf") == 0) {
        use_setvbuf_stdout = true;
      } else if (strcmp(argv[i], "-console") == 0 && i+1 < argc) {
        stdout_test_iters = strToUInt(argv[++i]);
      } else if (strcmp(argv[i], "-string") == 0 && i+1 < argc) {
        string_test_iters = strToUInt(argv[++i]);
      } else if (strcmp(argv[i], "-file") == 0 && i+1 < argc) {
        file_test_iters = strToUInt(argv[++i]);
      } else if (strcmp(argv[i], "-rerun") == 0 && i+1 < argc) {
        test_iters += strToUInt(argv[++i]);
      } else {
        printf("Error: Invalid option '%s'\n", argv[i]);
        printUsage();
        return EXIT_FAILURE;
      }
    }
  } catch (std::exception &e) {
    printf("\n%s\n", e.what());
    printUsage();
    return EXIT_FAILURE;
  }

  if (use_setvbuf_stdout) {
    setvbuf(stdout, stdout_buff, _IOFBF, stdout_buff_size);
  }

  Test stdout_tests[] = {
    // stdout tests
    Test(printfTest, stdout_test_iters, "printf"),
    Test(coutTest, stdout_test_iters, "cout"),
    Test(templatePrintfTest, stdout_test_iters, "template printf"),
    Test(templateCppPrintfTest, stdout_test_iters, "template cpp printf"),
  };

  Test string_tests[] = {
    // string tests
    Test(sprintfTest, string_test_iters, "sprintf"),
    Test(templateSprintfTest, string_test_iters, "template sprintf"),
    Test(heapSprintfTest, string_test_iters, "heap sprintf"),
    Test(ostringstreamTest, string_test_iters, "ostringstream"),
    Test(templateHeapSprintfTest, string_test_iters, "template heap sprintf")
  };

  FileTest file_tests[] = {
    // formatted file tests
    FileTest(fprintfTest, file_test_iters, "fprintf"),
    FileTest(buffered_fwriteTest, file_test_iters,
             "buffered (formatted) fwrite"),
    FileTest(ofstreamTest, file_test_iters, "ofstream"),
    FileTest(buffered_ofstreamWriteTest, file_test_iters,
             "buffered (formatted) ofstream write"),
    FileTest(templateFPrintfTest, file_test_iters, "template fprintf"),
    FileTest(templateCppFPrintfTest, file_test_iters, "template cpp fprintf"),
    // binary file tests
    FileTest(binary_fwriteTest, file_test_iters, "binary fwrite"),
    FileTest(bufferedBinary_fwriteTest, file_test_iters,
             "buffered binary fwrite"),
    FileTest(binary_ofstreamWriteTest, file_test_iters,
             "binary ofstream write"),
    FileTest(bufferedBinary_ofstreamWriteTest, file_test_iters,
             "buffered binary ofstream write")
  };

  // File tests using setvbuf/ofstream::pubsetbuf
  FileTest file_tests2[] = {
    // formatted file tests
    FileTest({fprintfTest, file_buff, file_buff_size}, file_test_iters,
             "fprintf"),
    FileTest({buffered_fwriteTest,  file_buff, file_buff_size},
             file_test_iters, "buffered (formatted) fwrite"),
    FileTest({ofstreamTest,  file_buff, file_buff_size},
             file_test_iters, "ofstream"),
    FileTest({buffered_ofstreamWriteTest,  file_buff, file_buff_size},
             file_test_iters, "buffered (formatted) ofstream write"),
    FileTest({templateFPrintfTest,  file_buff, file_buff_size},
             file_test_iters,"template fprintf"),
    FileTest({templateCppFPrintfTest, file_buff, file_buff_size},
             file_test_iters,"template cpp fprintf"),
    // binary file tests
    FileTest({binary_fwriteTest,  file_buff, file_buff_size},
             file_test_iters,"binary fwrite"),
    FileTest({bufferedBinary_fwriteTest, file_buff, file_buff_size},
             file_test_iters,"buffered binary fwrite"),
    FileTest({binary_ofstreamWriteTest,  file_buff, file_buff_size},
             file_test_iters,"binary ofstream write"),
    FileTest({bufferedBinary_ofstreamWriteTest,  file_buff, file_buff_size},
             file_test_iters, "buffered binary ofstream write")
  };

  for (size_t i = 0; i < test_iters; ++i) {
    if (stdout_test_iters > 0) {
      for (auto &test : stdout_tests) {
        printf("\n%s test\n", test.test_name);
        fflush(stdout);
        std::chrono::milliseconds ms(1500);
        std::this_thread::sleep_for(ms);
        test.run();
        fflush(stdout);
        std::cout.flush();
      }
    }

    if (file_test_iters > 0) {
      for (auto &test : file_tests) {
        printf("\n%s test\n", test.test_name);
        fflush(stdout);
        test.run();
      }

      for (auto &test : file_tests2) {
        printf("\n%s test (with setvbuf/ofstream::pubsetbuf\n",
               test.test_name);
        fflush(stdout);
        test.run();
      }
    }

    if (string_test_iters > 0) {
      for (auto &test : string_tests) {
        printf("\n%s test\n", test.test_name);
        fflush(stdout);
        test.run();
      }
    }

  }

  printf("\nstdout test iterations = %zu\n", stdout_test_iters);
  printf("file test iterations = %zu\n", file_test_iters);
  printf("string test iterations = %zu\n", string_test_iters);
  printf("number of times each test was run = %zu\n\n", test_iters);

  if (use_setvbuf_stdout)
    printf("stdout tests with buffer (setvbuf,pubsetbuf) = %zu bytes:\n",
           stdout_buff_size);
  else
    printf("stdout tests:\n");

  for (auto &test : stdout_tests)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  printf("\nfile tests:\n");
  for (auto &test : file_tests)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  printf("\nfile tests with buffer (setvbuf) = %zu bytes:\n",
         file_buff_size);
  for (auto &test : file_tests2)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  printf("\nstring tests:\n");
  for (auto &test : string_tests)
    printf("%s test time = %.2fms\n", test.test_name, test.average());

  return EXIT_SUCCESS;
}

void printUsage()
{
  printf("Usage: print-tests [--help] [-use-setvbuf] [-console COUNT] "
         "[-file COUNT]\n\t[-string COUNT] [-rerun COUNT]\n");
  printf("-use-setvbuf = Use setvbuf for stdout.\n");
  printf("-console COUNT = Run console tests COUNT times. This affects "
         "how much data is\n\twritten to console in each test.\n"
         "\tDefault is 1000.\n");
  printf("-file COUNT = Run file tests COUNT times. This affects how "
         "much data is written\n\tto the test file 'test.out' in each "
         "test.\n\tDefault is 1000000.\n");
  printf("-string COUNT = Run string tests COUNT times. This affects how "
         "much data is\n\twritten to the string in each test.\n"
         "\tDefault is 500000.\n");
  printf("-rerun COUNT = Run all tests again COUNT times for taking an "
         "average of each\n\ttest's duration.\n"
         "\tDefault is 0.\n");
}

size_t strToUInt(const char *str)
{
  char *str_end = nullptr; // for detecting errors in strtol
  int n = strtol(str, &str_end, 10);
  if (n < 0) {
    throw std::runtime_error("Error: Negative number entered.");
  }
  if (errno == ERANGE){
    errno = 0;
    throw std::runtime_error("Error: Number entered is too large.");
  }
  if (str == str_end) {
    throw std::runtime_error("Error converting string to int");
  }
  return n;
}

<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/typedefs.hpp>
#include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
#include <stan/math/rev/scal/fun/value_of_rec.hpp>
#include <stan/math/rev/scal/fun/value_of.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/mat/fun/value_of_rec.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>

namespace stan {
  namespace math {

    class cholesky_decompose_v_vari : public vari {
    public:
      int M_;  // A.rows() = A.cols()
      vari** variRefA_;
      vari** variRefL_;

      /* ctor for cholesky function
       *
       * Stores varis for A
       * Instantiates and stores varis for L
       * Instantiates and stores dummy vari for
       * upper triangular part of var result returned
       * in cholesky_decompose function call
       *
       * variRefL aren't on the chainable
       * autodiff stack, only used for storage
       * and computation. Note that varis for
       * L are constructed externally in
       * cholesky_decompose.
       *
       * @param matrix A
       * @param matrix L, cholesky factor of A
       * */
      cholesky_decompose_v_vari(const Eigen::Matrix<var, -1, -1>& A,
                                const Eigen::Matrix<double, -1, -1>& L_A)
        : vari(0.0),
          M_(A.rows()),
          variRefA_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)),
          variRefL_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)) {
            size_t pos = 0;
        for (size_type i = 0; i < M_; ++i) {
          for (size_type j = 0; j <= i; ++j) {
            variRefA_[pos] = A.coeffRef(i, j).vi_;
            variRefL_[pos] = new vari(L_A.coeffRef(i, j), false);
            ++pos;
          }
        }
      }

      /* Reverse mode differentiation
       * algorithm refernce:
       *
       * Mike Giles. An extended collection of matrix
       * derivative results for forward and reverse mode AD.
       * Jan. 2008.
       *
       * Note algorithm  as laid out in Giles is
       * row-major, so Eigen::Matrices are explicitly storage
       * order RowMajor, whereas Eigen defaults to
       * ColumnMajor. Also note algorithm
       * starts by calculating the adjoint for
       * A(M_ - 1, M_ - 1), hence pos on line 94 is decremented
       * to start at pos = M_ * (M_ + 1) / 2.
       * */
      virtual void chain() {
        using Eigen::Matrix;
        using Eigen::RowMajor;
        Matrix<double, -1, -1, RowMajor> adjL(M_, M_);
        Matrix<double, -1, -1, RowMajor> LA(M_, M_);
        Matrix<double, -1, -1, RowMajor> adjA(M_, M_);
        size_t pos = 0;
        for (size_type i = 0; i < M_; ++i) {
          for (size_type j = 0; j <= i; ++j) {
            adjL.coeffRef(i, j) = variRefL_[pos]->adj_;
            LA.coeffRef(i, j) = variRefL_[pos]->val_;
            ++pos;
          }
        }

        --pos;
        for (int i = M_ - 1; i >= 0; --i) {
          for (int j = i; j >= 0; --j) {
            if (i == j) {
              adjA.coeffRef(i, j) = 0.5 * adjL.coeff(i, j)
                / LA.coeff(i, j);
            } else {
              adjA.coeffRef(i, j) = adjL.coeff(i, j)
                / LA.coeff(j, j);
              adjL.coeffRef(j, j) -= adjL.coeff(i, j)
                * LA.coeff(i, j) / LA.coeff(j, j);
            }
            for (int k = j - 1; k >=0; --k) {
              adjL.coeffRef(i, k) -= adjA.coeff(i, j)
                * LA.coeff(j, k);
              adjL.coeffRef(j, k) -= adjA.coeff(i, j)
                * LA.coeff(i, k);
            }
            variRefA_[pos--]->adj_ += adjA.coeffRef(i, j);
          }
        }
      }
    };

    /* Reverse mode specialization of
     * cholesky decomposition
     *
     * Internally calls llt rather than using
     * stan::math::cholesky_decompose in order
     * to use selfadjointView<Lower> optimization.
     *
     * Note chainable stack varis are created
     * below in Matrix<var, -1, -1>
     *
     * @param Matrix A
     * @return L cholesky factor of A
     */
    Eigen::Matrix<var, -1, -1>
    cholesky_decompose(const Eigen::Matrix<var, -1, -1> &A) {
      stan::math::check_square("cholesky_decompose", "A", A);
      stan::math::check_symmetric("cholesky_decompose", "A", A);

      Eigen::Matrix<double, -1, -1> L_A(value_of_rec(A));
      Eigen::LLT<Eigen::MatrixXd> L_factor
        = L_A.selfadjointView<Eigen::Lower>().llt();
      check_pos_definite("cholesky_decompose", "m", L_factor);
      L_A = L_factor.matrixL();

      // NOTE: this is not a memory leak, this vari is used in the
      // expression graph to evaluate the adjoint, but is not needed
      // for the returned matrix.  Memory will be cleaned up with the
      // arena allocator.
      cholesky_decompose_v_vari *baseVari
        = new cholesky_decompose_v_vari(A, L_A);
      stan::math::vari dummy(0.0, false);
      Eigen::Matrix<var, -1, -1> L(A.rows(), A.cols());
      size_t pos = 0;
      for (size_type i = 0; i < L.cols(); ++i) {
        for (size_type j = 0; j <= i; ++j)
          L.coeffRef(i, j).vi_ = baseVari->variRefL_[pos++];
        for (size_type k = (i + 1); k < L.cols(); ++k)
          L.coeffRef(i, k).vi_ = &dummy;
      }
      return L;
    }
  }
}
#endif
<commit_msg>Revert "back to non-memory locality preserving input/output"<commit_after>#ifndef STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/typedefs.hpp>
#include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
#include <stan/math/rev/scal/fun/value_of_rec.hpp>
#include <stan/math/rev/scal/fun/value_of.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/mat/fun/value_of_rec.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>

namespace stan {
  namespace math {

    class cholesky_decompose_v_vari : public vari {
    public:
      int M_;  // A.rows() = A.cols()
      vari** variRefA_;
      vari** variRefL_;

      /* ctor for cholesky function
       *
       * Stores varis for A
       * Instantiates and stores varis for L
       * Instantiates and stores dummy vari for
       * upper triangular part of var result returned
       * in cholesky_decompose function call
       *
       * variRefL aren't on the chainable
       * autodiff stack, only used for storage
       * and computation. Note that varis for
       * L are constructed externally in
       * cholesky_decompose.
       *
       * @param matrix A
       * @param matrix L, cholesky factor of A
       * */
      cholesky_decompose_v_vari(const Eigen::Matrix<var, -1, -1>& A,
                                const Eigen::Matrix<double, -1, -1>& L_A)
        : vari(0.0),
          M_(A.rows()),
          variRefA_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)),
          variRefL_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)) {
        size_t accum = 0;
        size_t accum_i = accum;
        for (size_type j = 0; j < M_; ++j) {
          for (size_type i = j; i < M_; ++i) {
            accum_i += i;
            size_t pos = j + accum_i;
            variRefA_[pos] = A.coeffRef(i, j).vi_;
            variRefL_[pos] = new vari(L_A.coeffRef(i, j), false);
          }
          accum += j;
          accum_i = accum;
        }
      }

      /* Reverse mode differentiation
       * algorithm refernce:
       *
       * Mike Giles. An extended collection of matrix
       * derivative results for forward and reverse mode AD.
       * Jan. 2008.
       *
       * Note algorithm  as laid out in Giles is
       * row-major, so Eigen::Matrices are explicitly storage
       * order RowMajor, whereas Eigen defaults to
       * ColumnMajor. Also note algorithm
       * starts by calculating the adjoint for
       * A(M_ - 1, M_ - 1), hence pos on line 94 is decremented
       * to start at pos = M_ * (M_ + 1) / 2.
       * */
      virtual void chain() {
        using Eigen::Matrix;
        using Eigen::RowMajor;
        Matrix<double, -1, -1, RowMajor> adjL(M_, M_);
        Matrix<double, -1, -1, RowMajor> LA(M_, M_);
        Matrix<double, -1, -1, RowMajor> adjA(M_, M_);
        size_t pos = 0;
        for (size_type i = 0; i < M_; ++i) {
          for (size_type j = 0; j <= i; ++j) {
            adjL.coeffRef(i, j) = variRefL_[pos]->adj_;
            LA.coeffRef(i, j) = variRefL_[pos]->val_;
            ++pos;
          }
        }

        --pos;
        for (int i = M_ - 1; i >= 0; --i) {
          for (int j = i; j >= 0; --j) {
            if (i == j) {
              adjA.coeffRef(i, j) = 0.5 * adjL.coeff(i, j)
                / LA.coeff(i, j);
            } else {
              adjA.coeffRef(i, j) = adjL.coeff(i, j)
                / LA.coeff(j, j);
              adjL.coeffRef(j, j) -= adjL.coeff(i, j)
                * LA.coeff(i, j) / LA.coeff(j, j);
            }
            for (int k = j - 1; k >=0; --k) {
              adjL.coeffRef(i, k) -= adjA.coeff(i, j)
                * LA.coeff(j, k);
              adjL.coeffRef(j, k) -= adjA.coeff(i, j)
                * LA.coeff(i, k);
            }
            variRefA_[pos--]->adj_ += adjA.coeffRef(i, j);
          }
        }
      }
    };

    /* Reverse mode specialization of
     * cholesky decomposition
     *
     * Internally calls llt rather than using
     * stan::math::cholesky_decompose in order
     * to use selfadjointView<Lower> optimization.
     *
     * Note chainable stack varis are created
     * below in Matrix<var, -1, -1>
     *
     * @param Matrix A
     * @return L cholesky factor of A
     */
    Eigen::Matrix<var, -1, -1>
    cholesky_decompose(const Eigen::Matrix<var, -1, -1> &A) {
      stan::math::check_square("cholesky_decompose", "A", A);
      stan::math::check_symmetric("cholesky_decompose", "A", A);

      Eigen::Matrix<double, -1, -1> L_A(value_of_rec(A));
      Eigen::LLT<Eigen::MatrixXd> L_factor
        = L_A.selfadjointView<Eigen::Lower>().llt();
      check_pos_definite("cholesky_decompose", "m", L_factor);
      L_A = L_factor.matrixL();

      // NOTE: this is not a memory leak, this vari is used in the
      // expression graph to evaluate the adjoint, but is not needed
      // for the returned matrix.  Memory will be cleaned up with the
      // arena allocator.
      cholesky_decompose_v_vari *baseVari
        = new cholesky_decompose_v_vari(A, L_A);
      stan::math::vari dummy(0.0, false);
      Eigen::Matrix<var, -1, -1> L(A.rows(), A.cols());
      size_t accum = 0;
      size_t accum_i = accum;
      for (size_type j = 0; j < L.cols(); ++j) {
        for (size_type i = j; i < L.cols(); ++i) {
          accum_i += i;
          size_t pos = j + accum_i;
          L.coeffRef(i, j).vi_ = baseVari->variRefL_[pos];
        }
        for (size_type k = 0; k < j; ++k)
          L.coeffRef(k, j).vi_ = &dummy;
        accum += j;
        accum_i = accum;
      }
      return L;
    }
  }
}
#endif
<|endoftext|>


<commit_before>/**
 * \file   dublin_traceroute.cc
 * \author Andrea Barberio <insomniac@slackware.it>
 * \copyright 2-clause BSD
 * \date   October 2015
 * \brief  Main class for the NAT-aware multipath traceroute
 *
 * This module contains the implementation of the NAT-aware multipath
 *  traceroute known as dublin-traceroute.
 *
 * \sa dublin_traceroute.h
 */

#include <vector>
#include <sstream>
#include <chrono>
#include <functional>
#include <unistd.h>

#include <tins/utils.h>

#include "dublintraceroute/dublin_traceroute.h"

/*
 * Dublin Traceroute
 * NAT-aware extension of paris-traceroute based on libtins
 *
 * https://dublin-traceroute.net
 * http://paris-traceroute.net
 * https://libtins.github.io
 */

#define SNIFFER_TIMEOUT_MS	5000

/** \brief Method that generates and returns the packets to send
 *
 * This method generates a map containing the packets to send in order to run a
 * multipath traceroute. The packets are grouped by flow, each identified by a
 * destination port. Each flow specifies a vector of IP packets, and its
 * position determines the TTL used for the packet. E.g. the packet at position
 * 0 has TTL 1, and so on.
 * The number of flows is determined by npaths(), which is passed to the
 * constructor.
 *
 * \sa traceroute()
 * \sa npaths()
 *
 * \return the packets to send
 */
std::shared_ptr<flow_map_t> DublinTraceroute::generate_per_flow_packets() {
	NetworkInterface iface = NetworkInterface::default_interface();
	NetworkInterface::Info info = iface.addresses();
	std::shared_ptr<flow_map_t> flows(new flow_map_t);

	/* The payload is used to manipulate the UDP checksum, that will be
	 * used as hop identifier.
	 * The last two bytes will be adjusted to influence the hop identifier,
	 * which for UDP traceroutes is the UDP checksum.
	 */
	unsigned char payload[] = {'N', 'S', 'M', 'N', 'C', 0x00, 0x00};

	// Resolve the target host
	// TODO support IPv6
	try {
		target(Utils::resolve_domain(dst()));
	} catch (std::runtime_error) {
		target(IPv4Address(dst()));
	}

	// forge the packets to send
	for (uint16_t dport = dstport(); dport < dstport() + npaths(); dport++) {
		hops_t hops(new std::vector<Hop>());
		flows->insert(std::make_pair(dport, hops));
		/* Forge the packets to send and append them to the packets
		 * vector.
		 * To force a packet through the same network flow, it has to
		 * maintain several constant fields that will be used for the
		 * ECMP hashing. These fields are, in the case of IP+UDP:
		 *
		 *   IPv4.tos
		 *   IPv4.proto
		 *   IPv4.src
		 *   IPv4.dst
		 *   UDP.sport
		 *   UDP.dport
		 */
		for (uint8_t ttl = 1; ttl <= max_ttl_; ttl++) {
			/*
		 	 * Adjust the payload for each flow to obtain the same UDP
		 	 * checksum. The UDP checksum is used to identify the flow.
		 	 */
			uint16_t identifier = dport + ttl;
			payload[5] = ((unsigned char *)&identifier)[0];
			payload[6] = ((unsigned char *)&identifier)[1];

			IP packet = IP(target(), info.ip_addr) /
				UDP(dport, srcport()) /
				RawPDU((char *)payload);
			packet.ttl(ttl);
			packet.flags(IP::DONT_FRAGMENT); // set DF bit

			// serialize the packet so that we can extract src IP
			// and checksum
			packet.serialize();

			// get our own IPv4 address - will be used by the sniffer thread to
			// sniff only the relevant traffic
			if (my_address == "0.0.0.0")
				my_address = IPv4Address(packet.src_addr());
			else {
				if (packet.src_addr() != my_address) {
					std::stringstream ss;
					ss << "Packets flowing through more than one interface, " << my_address << " and " << packet.src_addr();
					throw DublinTracerouteException(ss.str());
				}
			}
			packet.id(packet.rfind_pdu<UDP>().checksum());

			try {
				Hop hop;
				hop.sent(packet);
				hops->push_back(hop);
			} catch (std::runtime_error e) {
				std::stringstream ss;
				ss << "Cannot find flow: " << dport << ": " << e.what();
				throw DublinTracerouteException(ss.str());
			}
		}
	}

	return flows;
}

std::string DublinTraceroute::get_pcap_filter() {
	std::stringstream filter;
	filter << "(icmp[icmptype] == 3 and (icmp[icmpcode] == 3 or icmp[icmpcode] == 4)) or (icmp[icmptype] == 11 and icmp[icmpcode] == 0) and dst " << my_address;
	return filter.str();
}

/** \brief run the multipath traceroute
 *
 * This method will execute a multipath traceroute. The way it operates is by
 * crafting and sending packets suitable for a multipath traceroute, and
 * sniffind the network traffic for the replies.
 *
 * \sa TracerouteResults
 * \returns an instance of TracerouteResults
 */
TracerouteResults &DublinTraceroute::traceroute() {
	// avoid running multiple traceroutes
	if (mutex_tracerouting.try_lock() == false)
		throw DublinTracerouteInProgressException("Traceroute already in progress");

	auto flows = generate_per_flow_packets();

	// configure the sniffer
	SnifferConfiguration config;
	config.set_filter(get_pcap_filter());
	config.set_promisc_mode(false);
	config.set_snap_len(65535);

	Sniffer *_sniffer;
	try {
		_sniffer = new Sniffer(NetworkInterface::default_interface().name(), config);
	} catch (std::runtime_error &exc) {
		mutex_tracerouting.unlock();
		throw DublinTracerouteFailedException(exc.what());
	}
	std::shared_ptr<Sniffer> sniffer(_sniffer);

	TracerouteResults *results = new TracerouteResults(flows);

	// configure the sniffing handler
	auto handler = std::bind(
		&DublinTraceroute::sniffer_callback,
		this,
		std::placeholders::_1
	);

	// start the sniffing thread
	std::thread sniffer_thread(
		[&]() { sniffer->sniff_loop(handler); }
	);
	std::thread timer_thread(
		[&]() {
			std::this_thread::sleep_for(std::chrono::milliseconds(SNIFFER_TIMEOUT_MS));
			sniffer->stop_sniff();
		}
	);

	// send everything out
	send_all(flows);

	sniffer_thread.join();
	timer_thread.join();

	match_sniffed_packets(*results);
	match_hostnames(*results, flows);

	mutex_tracerouting.unlock();

	return *results;
}

void DublinTraceroute::send_all(std::shared_ptr<flow_map_t> flows) {
	NetworkInterface iface = NetworkInterface::default_interface();
	PacketSender sender;
	for (auto &iter: *flows) {
		auto packets = iter.second;
		for (auto &hop: *packets) {
			auto packet = hop.sent();

			sender.send(*packet, iface.name());
			hop.sent_timestamp(Tins::Timestamp::current_time());
		}
	}
}

bool DublinTraceroute::sniffer_callback(Packet &packet) {
	std::lock_guard<std::mutex> lock(mutex_sniffed_packets);
	sniffed_packets.push_back(std::make_shared<Packet>(Packet(packet)));
	return true;
}

void DublinTraceroute::match_sniffed_packets(TracerouteResults &results) {
	for (auto &packet: sniffed_packets)
		results.match_packet(*packet);
}

void DublinTraceroute::match_hostnames(TracerouteResults &results, std::shared_ptr<flow_map_t> flows) {
	// TODO make this asynchronous
	// TODO move this to a proxy method ::resolve() in TracerouteResults
	for (auto &iter: *flows) {
		auto packets = iter.second;
		for (auto &hop: *packets) {
			hop.resolve();
		}
	}
}

<commit_msg>Update dublin_traceroute.cc<commit_after>/**
 * \file   dublin_traceroute.cc
 * \author Andrea Barberio <insomniac@slackware.it>
 * \copyright 2-clause BSD
 * \date   October 2015
 * \brief  Main class for the NAT-aware multipath traceroute
 *
 * This module contains the implementation of the NAT-aware multipath
 * traceroute known as dublin-traceroute.
 *
 * \sa dublin_traceroute.h
 */

#include <vector>
#include <sstream>
#include <chrono>
#include <functional>
#include <unistd.h>

#include <tins/utils.h>

#include "dublintraceroute/dublin_traceroute.h"

/*
 * Dublin Traceroute
 * NAT-aware extension of paris-traceroute based on libtins
 *
 * https://dublin-traceroute.net
 * http://paris-traceroute.net
 * https://libtins.github.io
 */

#define SNIFFER_TIMEOUT_MS	5000

/** \brief Method that generates and returns the packets to send
 *
 * This method generates a map containing the packets to send in order to run a
 * multipath traceroute. The packets are grouped by flow, each identified by a
 * destination port. Each flow specifies a vector of IP packets, and its
 * position determines the TTL used for the packet. E.g. the packet at position
 * 0 has TTL 1, and so on.
 * The number of flows is determined by npaths(), which is passed to the
 * constructor.
 *
 * \sa traceroute()
 * \sa npaths()
 *
 * \return the packets to send
 */
std::shared_ptr<flow_map_t> DublinTraceroute::generate_per_flow_packets() {
	NetworkInterface iface = NetworkInterface::default_interface();
	NetworkInterface::Info info = iface.addresses();
	std::shared_ptr<flow_map_t> flows(new flow_map_t);

	/* The payload is used to manipulate the UDP checksum, that will be
	 * used as hop identifier.
	 * The last two bytes will be adjusted to influence the hop identifier,
	 * which for UDP traceroutes is the UDP checksum.
	 */
	unsigned char payload[] = {'N', 'S', 'M', 'N', 'C', 0x00, 0x00};

	// Resolve the target host
	// TODO support IPv6
	try {
		target(Utils::resolve_domain(dst()));
	} catch (std::runtime_error) {
		target(IPv4Address(dst()));
	}

	// forge the packets to send
	for (uint16_t dport = dstport(); dport < dstport() + npaths(); dport++) {
		hops_t hops(new std::vector<Hop>());
		flows->insert(std::make_pair(dport, hops));
		/* Forge the packets to send and append them to the packets
		 * vector.
		 * To force a packet through the same network flow, it has to
		 * maintain several constant fields that will be used for the
		 * ECMP hashing. These fields are, in the case of IP+UDP:
		 *
		 *   IPv4.tos
		 *   IPv4.proto
		 *   IPv4.src
		 *   IPv4.dst
		 *   UDP.sport
		 *   UDP.dport
		 */
		for (uint8_t ttl = 1; ttl <= max_ttl_; ttl++) {
			/*
		 	 * Adjust the payload for each flow to obtain the same UDP
		 	 * checksum. The UDP checksum is used to identify the flow.
		 	 */
			uint16_t identifier = dport + ttl;
			payload[5] = ((unsigned char *)&identifier)[0];
			payload[6] = ((unsigned char *)&identifier)[1];

			IP packet = IP(target(), info.ip_addr) /
				UDP(dport, srcport()) /
				RawPDU((char *)payload);
			packet.ttl(ttl);
			packet.flags(IP::DONT_FRAGMENT); // set DF bit

			// serialize the packet so that we can extract src IP
			// and checksum
			packet.serialize();

			// get our own IPv4 address - will be used by the sniffer thread to
			// sniff only the relevant traffic
			if (my_address == "0.0.0.0")
				my_address = IPv4Address(packet.src_addr());
			else {
				if (packet.src_addr() != my_address) {
					std::stringstream ss;
					ss << "Packets flowing through more than one interface, " << my_address << " and " << packet.src_addr();
					throw DublinTracerouteException(ss.str());
				}
			}
			packet.id(packet.rfind_pdu<UDP>().checksum());

			try {
				Hop hop;
				hop.sent(packet);
				hops->push_back(hop);
			} catch (std::runtime_error e) {
				std::stringstream ss;
				ss << "Cannot find flow: " << dport << ": " << e.what();
				throw DublinTracerouteException(ss.str());
			}
		}
	}

	return flows;
}

std::string DublinTraceroute::get_pcap_filter() {
	std::stringstream filter;
	filter << "(icmp[icmptype] == 3 and (icmp[icmpcode] == 3 or icmp[icmpcode] == 4)) or (icmp[icmptype] == 11 and icmp[icmpcode] == 0) and dst " << my_address;
	return filter.str();
}

/** \brief run the multipath traceroute
 *
 * This method will execute a multipath traceroute. The way it operates is by
 * crafting and sending packets suitable for a multipath traceroute, and
 * sniffind the network traffic for the replies.
 *
 * \sa TracerouteResults
 * \returns an instance of TracerouteResults
 */
TracerouteResults &DublinTraceroute::traceroute() {
	// avoid running multiple traceroutes
	if (mutex_tracerouting.try_lock() == false)
		throw DublinTracerouteInProgressException("Traceroute already in progress");

	auto flows = generate_per_flow_packets();

	// configure the sniffer
	SnifferConfiguration config;
	config.set_filter(get_pcap_filter());
	config.set_promisc_mode(false);
	config.set_snap_len(65535);

	Sniffer *_sniffer;
	try {
		_sniffer = new Sniffer(NetworkInterface::default_interface().name(), config);
	} catch (std::runtime_error &exc) {
		mutex_tracerouting.unlock();
		throw DublinTracerouteFailedException(exc.what());
	}
	std::shared_ptr<Sniffer> sniffer(_sniffer);

	TracerouteResults *results = new TracerouteResults(flows);

	// configure the sniffing handler
	auto handler = std::bind(
		&DublinTraceroute::sniffer_callback,
		this,
		std::placeholders::_1
	);

	// start the sniffing thread
	std::thread sniffer_thread(
		[&]() { sniffer->sniff_loop(handler); }
	);
	std::thread timer_thread(
		[&]() {
			std::this_thread::sleep_for(std::chrono::milliseconds(SNIFFER_TIMEOUT_MS));
			sniffer->stop_sniff();
		}
	);

	// send everything out
	send_all(flows);

	sniffer_thread.join();
	timer_thread.join();

	match_sniffed_packets(*results);
	match_hostnames(*results, flows);

	mutex_tracerouting.unlock();

	return *results;
}

void DublinTraceroute::send_all(std::shared_ptr<flow_map_t> flows) {
	NetworkInterface iface = NetworkInterface::default_interface();
	PacketSender sender;
	for (auto &iter: *flows) {
		auto packets = iter.second;
		for (auto &hop: *packets) {
			auto packet = hop.sent();

			sender.send(*packet, iface.name());
			hop.sent_timestamp(Tins::Timestamp::current_time());
		}
	}
}

bool DublinTraceroute::sniffer_callback(Packet &packet) {
	std::lock_guard<std::mutex> lock(mutex_sniffed_packets);
	sniffed_packets.push_back(std::make_shared<Packet>(Packet(packet)));
	return true;
}

void DublinTraceroute::match_sniffed_packets(TracerouteResults &results) {
	for (auto &packet: sniffed_packets)
		results.match_packet(*packet);
}

void DublinTraceroute::match_hostnames(TracerouteResults &results, std::shared_ptr<flow_map_t> flows) {
	// TODO make this asynchronous
	// TODO move this to a proxy method ::resolve() in TracerouteResults
	for (auto &iter: *flows) {
		auto packets = iter.second;
		for (auto &hop: *packets) {
			hop.resolve();
		}
	}
}

<|endoftext|>


<commit_before>#include "ScriptParser.hpp"

proZPRd::ScriptParser::ScriptParser(const std::string & ParserExecutable): ParserExecutable(ParserExecutable)
{

}
std::string proZPRd::ScriptParser::Parse(const std::string & ScriptName)
{
	//1. Sprawdź, czy ParserExecutable istnieje. Nie -> wyjątek

	//2. Uruchamiasz proces parsera, przekierowujesz jego wyjście na swoje wejście.
	//Jakiś względnie sprawny, ACZKOLWIEK NIE DO SKOPIOWANIA pomysł jest tu: http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c

	//3. Sprawdzasz kod wyjścia programu -> zły -> wyjątek

	//4. Jeśli ok - zwracasz to, co zwrócił program

	return std::string();
}<commit_msg>Uzupełnienie metody Parse<commit_after>#include "ScriptParser.hpp"
#include "File.hpp"
#include "Tools/Exception.hpp"

#ifdef _WIN32
  #define popen _popen
  #define pclose _pclose
#endif

proZPRd::ScriptParser::ScriptParser(const std::string & ParserExecutable): ParserExecutable(ParserExecutable)
{

}
std::string proZPRd::ScriptParser::Parse(const std::string & ScriptName)
{
	if(!proZPRd::File::Exists(ScriptName))
		throw Tools::Exception(EXCEPTION_PARAMS, "file: " + ScriptName + "not found!");

	FILE* ParserProcess = popen(ScriptName.c_str(), "r");
    if (!ParserProcess)
		throw Tools::Exception(EXCEPTION_PARAMS, "popen() failed!");

    char Buffer[128];
    std::string Result("");

    while(!feof(ParserProcess))
	{
    	if(fgets(Buffer, 128, ParserProcess) != NULL)
    		Result += Buffer;
    }

    if(!pclose(ParserProcess))
		throw Tools::Exception(EXCEPTION_PARAMS, ScriptName + " process returned an error!");

	return Result;
}<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4  -*- */
/* ex: set shiftwidth=4 tabstop=4 expandtab: */
/*
 * Copyright (c) 2010-2011, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Neil T. Dantam <ntd@gatech.edu>
 * Georgia Tech Humanoid Robotics Lab
 * Under Direction of Prof. Mike Stilman <mstilman@cc.gatech.edu>
 *
 *
 * This file is provided under the following "BSD-style" License:
 *
 *
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef AMINO_HPP
#define AMINO_HPP
/**
 * \file amino.hpp
 * \author Neil T. Dantam
 */

#include "amino.h"
#include "amino/mem.hpp"

//namespace amino {
//#include "amino/mat.hpp"
//}

/// amino namespace
namespace amino {

    /// Locks mutex on construction, unlocks on destruction
    class ScopedMutex {
    public:
        /// costruct this and lock m
        ScopedMutex( pthread_mutex_t *m ) :
            mutex(m)
        {
            pthread_mutex_lock(mutex);
        }
        /// costruct this and lock m
        ScopedMutex( pthread_mutex_t &m ) :
            mutex(&m)
        {
            pthread_mutex_lock(mutex);
        }
        /// destroy this and unlock m
        ~ScopedMutex() {
            pthread_mutex_unlock(mutex);
        }

    private:
        /// the mutex
        pthread_mutex_t *mutex;
    };
}

#endif //AMINO_HPP
<commit_msg>Add iterator next() and prev() functions<commit_after>/* -*- mode: C++; c-basic-offset: 4  -*- */
/* ex: set shiftwidth=4 tabstop=4 expandtab: */
/*
 * Copyright (c) 2010-2011, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Neil T. Dantam <ntd@gatech.edu>
 * Georgia Tech Humanoid Robotics Lab
 * Under Direction of Prof. Mike Stilman <mstilman@cc.gatech.edu>
 *
 *
 * This file is provided under the following "BSD-style" License:
 *
 *
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef AMINO_HPP
#define AMINO_HPP
/**
 * \file amino.hpp
 * \author Neil T. Dantam
 */

#include "amino.h"
#include "amino/mem.hpp"

//namespace amino {
//#include "amino/mat.hpp"
//}

/// amino namespace
namespace amino {

/// Locks mutex on construction, unlocks on destruction
class ScopedMutex {
public:
    /// costruct this and lock m
    ScopedMutex( pthread_mutex_t *m ) :
    mutex(m)
    {
        pthread_mutex_lock(mutex);
    }
    /// costruct this and lock m
    ScopedMutex( pthread_mutex_t &m ) :
    mutex(&m)
    {
        pthread_mutex_lock(mutex);
    }
    /// destroy this and unlock m
    ~ScopedMutex() {
        pthread_mutex_unlock(mutex);
    }

private:
    /// the mutex
    pthread_mutex_t *mutex;
};

template<typename T>
T next( T p )
{
    T q = p;
    q++;
    return q;
}

template<typename T>
T prev( T p )
{
    T q = p;
    q--;
    return q;
}

}

#endif //AMINO_HPP
<|endoftext|>


<commit_before>// MIT License

// Copyright (c) 2017 Simon Pettersson

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once

#include <stdexcept>

namespace cmap {

/*
  The underlying model for the binary tree
 */
namespace _model {
  /*
    A map is built like a binary tree as illustrated below.

            f1(k)
             / \
            /   \
         f2(k)  f3(k)
                 / \
                /   \
             f4(k)  f5(k)

    Each subtree f1,f2,f3,f4,f5 is a function which
    evaluates a key and returns an `outcome` which contains
    information about whether the subtree contained the key,
    and in that case what the associated value was.

    To construct the tree we utilize two factory functions

    * One called `make_terminal(k,v)` which creates a function that
      evaluates a key and returns an whether it matches a particular
      constant and the associated value.

    * One called `make_branch(left,right)` which creates a branch
      node, a function that first evaluats and returns the result of
      evaluating the left subtree if successful. If unsuccessful it
      evaluates the right subtree and returns the result of the
      evaluation of the right subtree.

    Example: Construct the tree above

      const auto f5 = make_terminal(5,15);
      const auto f4 = make_terminal(4,14);
      const auto f2 = make_terminal(3,13);
      const auto f3 = make_branch(f4, f5);
      const auto f1 = make_branch(f2, f3);

      // Performing a lookup for the value `5` would
      // produce the stacktrace
      f1(5)
        f2(5) -> {false, 13}
        f3(5)
          f4(5) -> {false, 14}
          f5(5) -> {true, 15}
        ...
      -> {true, 15}

    In order to easily chain together multiple subtrees there is a
    utility function called `merge(node1, ...)` which takes all the
    terminal nodes as arguments and automatically creates the branches.

    To reproduce the previous example using the merge function one could do
    the following.

    Example: Construct the same tree using the `merge` function

      const auto f5 = make_terminal(5,15);
      const auto f4 = make_terminal(4,14);
      const auto f2 = make_terminal(3,13);
      const auto f1 = merge(f2,f4,f5);

    Since the whole model is completely independent of the datatype stored
    there is literally no limit to what you can store in the map, as long
    as it is copy constructible. That means that you can nest maps and store
    complex types.
  */
  template<typename V> struct outcome {
    constexpr outcome(bool s, const V v) : success{s}, value{v} {}
    const bool success;
    const V value;
  };

  template<typename K, typename V>
  constexpr auto make_terminal(const K key, const V value) {
    return [key,value](const auto _key) -> outcome<decltype(value)> {
      return {_key == key, value};
    };
  };

  constexpr auto make_branch(const auto left, const auto right) {
    return [left,right](auto key) -> decltype(left(key)) {
      const auto result = left(key);
      if(result.success) {
        return {true, result.value};
      }
      return right(key);
    };
  }

  constexpr auto merge(const auto node) {
    return node;
  }

  constexpr auto merge(const auto left, const auto ... rest) {
    return make_branch(left, merge(rest...));
  }

}

/*
  Functional interface

  Example:
    constexpr auto map = make_map(map(13,43), map(14,44));
    constexpr auto fourty_three = lookup(map, 13);
    constexpr auto fourty_four  = lookup(map, 14);
 */

constexpr auto make_map(const auto ... rest) {
  return _model::merge(rest...);
}

constexpr auto map(const auto key, const auto value) {
  return _model::make_terminal(key, value);
}

constexpr auto join(const auto left_map, const auto right_map) {
  return _model::merge(left_map, right_map);
}

constexpr auto lookup(const auto tree, const auto key) {
  const auto result = tree(key);
  return result.success ? result.value : throw std::out_of_range("No such key");
}

/*
  Class interface

  Example:
    constexpr auto map = make_lookup(map(13,43), map(14,44));
    constexpr auto fourty_three = map[13];
    constexpr auto fourty_four  = map[14];
 */

template<typename TLookup>
struct lookup_type {
  constexpr lookup_type(const TLookup m) : map{m} {}
  constexpr auto operator[](const auto key) const { return lookup(map, key); }
  const TLookup map;
};

constexpr auto make_lookup(const auto ... rest) {
  return lookup_type{make_map(rest...)};
}

} // namespace cmap
<commit_msg>Removed `join()` and added specialized `make_lookup`<commit_after>// MIT License

// Copyright (c) 2017 Simon Pettersson

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once

#include <stdexcept>

namespace cmap {

/*
  The underlying model for the binary tree
 */
namespace _model {
  /*
    A map is built like a binary tree as illustrated below.

            f1(k)
             / \
            /   \
         f2(k)  f3(k)
                 / \
                /   \
             f4(k)  f5(k)

    Each subtree f1,f2,f3,f4,f5 is a function which
    evaluates a key and returns an `outcome` which contains
    information about whether the subtree contained the key,
    and in that case what the associated value was.

    To construct the tree we utilize two factory functions

    * One called `make_terminal(k,v)` which creates a function that
      evaluates a key and returns an whether it matches a particular
      constant and the associated value.

    * One called `make_branch(left,right)` which creates a branch
      node, a function that first evaluats and returns the result of
      evaluating the left subtree if successful. If unsuccessful it
      evaluates the right subtree and returns the result of the
      evaluation of the right subtree.

    Example: Construct the tree above

      const auto f5 = make_terminal(5,15);
      const auto f4 = make_terminal(4,14);
      const auto f2 = make_terminal(3,13);
      const auto f3 = make_branch(f4, f5);
      const auto f1 = make_branch(f2, f3);

      // Performing a lookup for the value `5` would
      // produce the stacktrace
      f1(5)
        f2(5) -> {false, 13}
        f3(5)
          f4(5) -> {false, 14}
          f5(5) -> {true, 15}
        ...
      -> {true, 15}

    In order to easily chain together multiple subtrees there is a
    utility function called `merge(node1, ...)` which takes all the
    terminal nodes as arguments and automatically creates the branches.

    To reproduce the previous example using the merge function one could do
    the following.

    Example: Construct the same tree using the `merge` function

      const auto f5 = make_terminal(5,15);
      const auto f4 = make_terminal(4,14);
      const auto f2 = make_terminal(3,13);
      const auto f1 = merge(f2,f4,f5);

    Since the whole model is completely independent of the datatype stored
    there is literally no limit to what you can store in the map, as long
    as it is copy constructible. That means that you can nest maps and store
    complex types.
  */
  template<typename V> struct outcome {
    constexpr outcome(bool s, const V v) : success{s}, value{v} {}
    const bool success;
    const V value;
  };

  template<typename K, typename V>
  constexpr auto make_terminal(const K key, const V value) {
    return [key,value](const auto _key) -> outcome<decltype(value)> {
      return {_key == key, value};
    };
  };

  constexpr auto make_branch(const auto left, const auto right) {
    return [left,right](auto key) -> decltype(left(key)) {
      const auto result = left(key);
      if(result.success) {
        return {true, result.value};
      }
      return right(key);
    };
  }

  constexpr auto merge(const auto node) {
    return node;
  }

  constexpr auto merge(const auto left, const auto ... rest) {
    return make_branch(left, merge(rest...));
  }

}

/*
  Functional interface

  Example:
    constexpr auto map = make_map(map(13,43), map(14,44));
    constexpr auto fourty_three = lookup(map, 13);
    constexpr auto fourty_four  = lookup(map, 14);
 */

constexpr auto make_map(const auto ... rest) {
  return _model::merge(rest...);
}

constexpr auto map(const auto key, const auto value) {
  return _model::make_terminal(key, value);
}

constexpr auto lookup(const auto tree, const auto key) {
  const auto result = tree(key);
  return result.success ? result.value : throw std::out_of_range("No such key");
}

/*
  Class interface

  Example:
    constexpr auto map = make_lookup(map(13,43), map(14,44));
    constexpr auto fourty_three = map[13];
    constexpr auto fourty_four  = map[14];
 */

template<typename TLookup>
struct lookup_type {
  constexpr lookup_type(const TLookup m) : map{m} {}
  constexpr auto operator[](const auto key) const { return lookup(map, key); }
  const TLookup map;
};

constexpr auto make_lookup(lookup_type<auto> ... rest) {
  return lookup_type{make_map(rest.map...)};
}

constexpr auto make_lookup(const auto ... rest) {
  return lookup_type{make_map(rest...)};
}

} // namespace cmap
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/typedefs.hpp>
#include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
#include <stan/math/rev/scal/fun/value_of_rec.hpp>
#include <stan/math/rev/scal/fun/value_of.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/mat/fun/value_of_rec.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>
#include <algorithm>

namespace stan {
  namespace math {

    class cholesky_decompose_v_vari : public vari {
    public:
      int M_;  // A.rows() = A.cols()
      int block_size_;
      typedef Eigen::Block<Eigen::MatrixXd> Block_;
      vari** variRefA_;
      vari** variRefL_;

      /**
       * Constructor for cholesky function.
       *
       * Stores varis for A.
       * Instantiates and stores varis for L.
       * Instantiates and stores dummy vari for
       * upper triangular part of var result returned
       * in cholesky_decompose function call
       *
       * variRefL aren't on the chainable
       * autodiff stack, only used for storage
       * and computation. Note that varis for
       * L are constructed externally in
       * cholesky_decompose.
       *
       * block_size_ determined using the same
       * calculation Eigen/LLT.h
       *
       * @param matrix A
       * @param matrix L, cholesky factor of A
       */
      cholesky_decompose_v_vari(const Eigen::Matrix<var, -1, -1>& A,
                                const Eigen::Matrix<double, -1, -1>& L_A)
        : vari(0.0),
          M_(A.rows()),
          variRefA_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)),
          variRefL_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)) {
            size_t pos = 0;
            block_size_ = M_/8;
            block_size_ = (block_size_/16)*16;
            block_size_ = (std::min)((std::max)(block_size_, 8), 128);
            for (size_type j = 0; j < M_; ++j) {
              for (size_type i = j; i < M_; ++i) {
                variRefA_[pos] = A.coeffRef(i, j).vi_;
                variRefL_[pos] = new vari(L_A.coeffRef(i, j), false);
                ++pos;
              }
            }
          }

      inline void symbolic_rev(Block_& L,
                               Block_& Lbar,
                               int size) {
        using Eigen::Lower;
        using Eigen::Upper;
        using Eigen::StrictlyUpper;
        L.transposeInPlace();
        Lbar = (L * Lbar.triangularView<Lower>()).eval();
        Lbar.triangularView<StrictlyUpper>()
          = Lbar.adjoint().triangularView<StrictlyUpper>();
        L.triangularView<Upper>().solveInPlace(Lbar);
        L.triangularView<Upper>().solveInPlace(Lbar.transpose());
      }

      /**
       * Reverse mode differentiation
       * algorithm refernce:
       *
       * Iain Murray: Differentiation of
       * the Cholesky decomposition, 2016.
       *
       */
      virtual void chain() {
        using Eigen::MatrixXd;
        using Eigen::Lower;
        using Eigen::Block;
        using Eigen::Upper;
        using Eigen::StrictlyUpper;
        MatrixXd Lbar(M_, M_);
        MatrixXd L(M_, M_);

        Lbar.setZero();
        L.setZero();
        size_t pos = 0;
        for (size_type j = 0; j < M_; ++j) {
          for (size_type i = j; i < M_; ++i) {
            Lbar.coeffRef(i, j) = variRefL_[pos]->adj_;
            L.coeffRef(i, j) = variRefL_[pos]->val_;
            ++pos;
          }
        }

        for (int k = M_; k > 0; k -= block_size_) {
          int j = std::max(0, k - block_size_);
          Block_ R = L.block(j, 0, k - j, j);
          Block_ D = L.block(j, j, k - j, k - j);
          Block_ B = L.block(k, 0, M_ - k, j);
          Block_ C = L.block(k, j, M_ - k, k - j);
          Block_ Rbar = Lbar.block(j, 0, k - j, j);
          Block_ Dbar = Lbar.block(j, j, k - j, k - j);
          Block_ Bbar = Lbar.block(k, 0, M_ - k, j);
          Block_ Cbar = Lbar.block(k, j, M_ - k, k - j);
          if (Cbar.size() > 0) {
            Cbar
              = D.transpose().triangularView<Upper>()
              .solve(Cbar.transpose()).transpose();
            Bbar.noalias() -= Cbar * R;
            Dbar.noalias() -= Cbar.transpose() * C;
          }
          symbolic_rev(D, Dbar, D.rows());
          Rbar.noalias() -= Cbar.transpose() * B;
          Rbar.noalias() -= Dbar.selfadjointView<Lower>() * R;
          Dbar.diagonal().array() *= 0.5;
          Dbar.triangularView<StrictlyUpper>().setZero();
        }
        pos = 0;
        for (size_type j = 0; j < M_; ++j)
          for (size_type i = j; i < M_; ++i)
            variRefA_[pos++]->adj_ += Lbar.coeffRef(i, j);
      }
    };

    /**
     * Reverse mode specialization of
     * cholesky decomposition
     *
     * Internally calls llt rather than using
     * cholesky_decompose in order
     * to use selfadjointView<Lower> optimization.
     *
     * TODO(rtrangucci): Use Eigen 3.3 inplace Cholesky
     * when possible
     *
     * Note chainable stack varis are created
     * below in Matrix<var, -1, -1>
     *
     * @param Matrix A
     * @return L cholesky factor of A
     */
    inline Eigen::Matrix<var, -1, -1>
      cholesky_decompose(const Eigen::Matrix<var, -1, -1> &A) {
      check_square("cholesky_decompose", "A", A);
      check_symmetric("cholesky_decompose", "A", A);

      Eigen::Matrix<double, -1, -1> L_A(value_of_rec(A));
      Eigen::LLT<Eigen::MatrixXd> L_factor
        = L_A.selfadjointView<Eigen::Lower>().llt();
      check_pos_definite("cholesky_decompose", "m", L_factor);
      L_A = L_factor.matrixL();

      // Memory allocated in arena.
      cholesky_decompose_v_vari *baseVari
        = new cholesky_decompose_v_vari(A, L_A);
      vari* dummy = new vari(0.0, false);
      Eigen::Matrix<var, -1, -1> L(A.rows(), A.cols());
      size_t pos = 0;
      for (size_type j = 0; j < L.cols(); ++j) {
        for (size_type i = j; i < L.cols(); ++i) {
          L.coeffRef(i, j).vi_ = baseVari->variRefL_[pos++];
        }
        for (size_type k = 0; k < j; ++k)
          L.coeffRef(k, j).vi_ = dummy;
      }
      return L;
    }
  }
}
#endif
<commit_msg>Branches on size of matrix<commit_after>#ifndef STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/typedefs.hpp>
#include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
#include <stan/math/rev/scal/fun/value_of_rec.hpp>
#include <stan/math/rev/scal/fun/value_of.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/mat/fun/value_of_rec.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>
#include <algorithm>

namespace stan {
  namespace math {

    class cholesky_block : public vari {
    public:
      int M_;
      int block_size_;
      typedef Eigen::Block<Eigen::MatrixXd> Block_;
      vari** variRefA_;
      vari** variRefL_;

      /**
       * Constructor for cholesky function.
       *
       * Stores varis for A.  Instantiates and stores varis for L.
       * Instantiates and stores dummy vari for upper triangular part of var
       * result returned in cholesky_decompose function call
       *
       * variRefL aren't on the chainable autodiff stack, only used for storage
       * and computation. Note that varis for L are constructed externally in
       * cholesky_decompose.
       *
       * block_size_ determined using the same calculation Eigen/LLT.h
       *
       * @param matrix A
       * @param matrix L, cholesky factor of A
       */
      cholesky_block(const Eigen::Matrix<var, -1, -1>& A,
                                const Eigen::Matrix<double, -1, -1>& L_A)
        : vari(0.0),
          M_(A.rows()),
          variRefA_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)),
          variRefL_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)) {
            size_t pos = 0;
            block_size_ = std::max((M_ / 8 / 16) * 16, 8);
            block_size_ = std::min(block_size_, 128);
            for (size_type j = 0; j < M_; ++j) {
              for (size_type i = j; i < M_; ++i) {
                variRefA_[pos] = A.coeffRef(i, j).vi_;
                variRefL_[pos] = new vari(L_A.coeffRef(i, j), false); ++pos;
              }
            }
          }

      inline void symbolic_rev(Block_& L,
                               Block_& Lbar,
                               int size) {
        using Eigen::Lower;
        using Eigen::Upper;
        using Eigen::StrictlyUpper;
        L.transposeInPlace();
        Lbar = (L * Lbar.triangularView<Lower>()).eval();
        Lbar.triangularView<StrictlyUpper>()
          = Lbar.adjoint().triangularView<StrictlyUpper>();
        L.triangularView<Upper>().solveInPlace(Lbar);
        L.triangularView<Upper>().solveInPlace(Lbar.transpose());
      }

      /**
       * Reverse mode differentiation algorithm refernce:
       *
       * Iain Murray: Differentiation of the Cholesky decomposition, 2016.
       *
       */
      virtual void chain() {
        using Eigen::MatrixXd;
        using Eigen::Lower;
        using Eigen::Block;
        using Eigen::Upper;
        using Eigen::StrictlyUpper;
        MatrixXd Lbar(M_, M_);
        MatrixXd L(M_, M_);

        Lbar.setZero();
        L.setZero();
        size_t pos = 0;
        for (size_type j = 0; j < M_; ++j) {
          for (size_type i = j; i < M_; ++i) {
            Lbar.coeffRef(i, j) = variRefL_[pos]->adj_;
            L.coeffRef(i, j) = variRefL_[pos]->val_;
            ++pos;
          }
        }

        for (int k = M_; k > 0; k -= block_size_) {
          int j = std::max(0, k - block_size_);
          Block_ R = L.block(j, 0, k - j, j);
          Block_ D = L.block(j, j, k - j, k - j);
          Block_ B = L.block(k, 0, M_ - k, j);
          Block_ C = L.block(k, j, M_ - k, k - j);
          Block_ Rbar = Lbar.block(j, 0, k - j, j);
          Block_ Dbar = Lbar.block(j, j, k - j, k - j);
          Block_ Bbar = Lbar.block(k, 0, M_ - k, j);
          Block_ Cbar = Lbar.block(k, j, M_ - k, k - j);
          if (Cbar.size() > 0) {
            Cbar
              = D.transpose().triangularView<Upper>()
              .solve(Cbar.transpose()).transpose();
            Bbar.noalias() -= Cbar * R;
            Dbar.noalias() -= Cbar.transpose() * C;
          }
          symbolic_rev(D, Dbar, D.rows());
          Rbar.noalias() -= Cbar.transpose() * B;
          Rbar.noalias() -= Dbar.selfadjointView<Lower>() * R;
          Dbar.diagonal() *= 0.5;
          Dbar.triangularView<StrictlyUpper>().setZero();
        }
        pos = 0;
        for (size_type j = 0; j < M_; ++j)
          for (size_type i = j; i < M_; ++i)
            variRefA_[pos++]->adj_ += Lbar.coeffRef(i, j);
      }
    };

    class cholesky_scalar : public vari {
    public:
      int M_;
      vari** variRefA_;
      vari** variRefL_;

      /**
       * Constructor for cholesky function.
       *
       * Stores varis for A Instantiates and stores varis for L Instantiates
       * and stores dummy vari for upper triangular part of var result returned
       * in cholesky_decompose function call
       *
       * variRefL aren't on the chainable autodiff stack, only used for storage
       * and computation. Note that varis for L are constructed externally in
       * cholesky_decompose.
       *
       * @param matrix A
       * @param matrix L, cholesky factor of A
       */
      cholesky_scalar(const Eigen::Matrix<var, -1, -1>& A,
                      const Eigen::Matrix<double, -1, -1>& L_A)
        : vari(0.0),
          M_(A.rows()),
          variRefA_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)),
          variRefL_(ChainableStack::memalloc_.alloc_array<vari*>
                    (A.rows() * (A.rows() + 1) / 2)) {
        size_t accum = 0;
        size_t accum_i = accum;
        for (size_type j = 0; j < M_; ++j) {
          for (size_type i = j; i < M_; ++i) {
            accum_i += i;
            size_t pos = j + accum_i;
            variRefA_[pos] = A.coeffRef(i, j).vi_;
            variRefL_[pos] = new vari(L_A.coeffRef(i, j), false);
          }
          accum += j;
          accum_i = accum;
        }
      }

      /**
       * Reverse mode differentiation algorithm refernce:
       *
       * Mike Giles. An extended collection of matrix derivative results for
       * forward and reverse mode AD.  Jan. 2008.
       *
       * Note algorithm  as laid out in Giles is row-major, so Eigen::Matrices
       * are explicitly storage order RowMajor, whereas Eigen defaults to
       * ColumnMajor. Also note algorithm starts by calculating the adjoint for
       * A(M_ - 1, M_ - 1), hence pos on line 94 is decremented to start at pos
       * = M_ * (M_ + 1) / 2.
       */
      virtual void chain() {
        using Eigen::Matrix;
        using Eigen::RowMajor;
        Matrix<double, -1, -1, RowMajor> adjL(M_, M_);
        Matrix<double, -1, -1, RowMajor> LA(M_, M_);
        Matrix<double, -1, -1, RowMajor> adjA(M_, M_);
        size_t pos = 0;
        for (size_type i = 0; i < M_; ++i) {
          for (size_type j = 0; j <= i; ++j) {
            adjL.coeffRef(i, j) = variRefL_[pos]->adj_;
            LA.coeffRef(i, j) = variRefL_[pos]->val_;
            ++pos;
          }
        }

        --pos;
        for (int i = M_ - 1; i >= 0; --i) {
          for (int j = i; j >= 0; --j) {
            if (i == j) {
              adjA.coeffRef(i, j) = 0.5 * adjL.coeff(i, j)
                / LA.coeff(i, j);
            } else {
              adjA.coeffRef(i, j) = adjL.coeff(i, j)
                / LA.coeff(j, j);
              adjL.coeffRef(j, j) -= adjL.coeff(i, j)
                * LA.coeff(i, j) / LA.coeff(j, j);
            }
            for (int k = j - 1; k >=0; --k) {
              adjL.coeffRef(i, k) -= adjA.coeff(i, j)
                * LA.coeff(j, k);
              adjL.coeffRef(j, k) -= adjA.coeff(i, j)
                * LA.coeff(i, k);
            }
            variRefA_[pos--]->adj_ += adjA.coeffRef(i, j);
          }
        }
      }
    };

    /**
     * Reverse mode specialization of cholesky decomposition
     *
     * Internally calls llt rather than using cholesky_decompose in order to
     * use selfadjointView<Lower> optimization.
     *
     * TODO(rtrangucci): Use Eigen 3.3 inplace Cholesky when possible
     *
     * Note chainable stack varis are created below in Matrix<var, -1, -1>
     *
     * @param A Matrix
     * @return L cholesky factor of A
     */
    inline Eigen::Matrix<var, -1, -1>
      cholesky_decompose(const Eigen::Matrix<var, -1, -1> &A) {
      check_square("cholesky_decompose", "A", A);
      check_symmetric("cholesky_decompose", "A", A);

      Eigen::Matrix<double, -1, -1> L_A(value_of_rec(A));
      Eigen::LLT<Eigen::MatrixXd> L_factor
        = L_A.selfadjointView<Eigen::Lower>().llt();
      check_pos_definite("cholesky_decompose", "m", L_factor);
      L_A = L_factor.matrixL();

      // Memory allocated in arena.
      // cholesky_scalar gradient faster for small matrices compared to
      // cholesky_block
      vari* dummy = new vari(0.0, false);
      Eigen::Matrix<var, -1, -1> L(A.rows(), A.cols());
      if (L_A.rows() <= 35) {
        cholesky_scalar *baseVari
          = new cholesky_scalar(A, L_A);
        size_t accum = 0;
        size_t accum_i = accum;
        for (size_type j = 0; j < L.cols(); ++j) {
          for (size_type i = j; i < L.cols(); ++i) {
            accum_i += i;
            size_t pos = j + accum_i;
            L.coeffRef(i, j).vi_ = baseVari->variRefL_[pos];
          }
          for (size_type k = 0; k < j; ++k)
            L.coeffRef(k, j).vi_ = dummy;
          accum += j;
          accum_i = accum;
        }
      } else {
        cholesky_block *baseVari
          = new cholesky_block(A, L_A);
        size_t pos = 0;
        for (size_type j = 0; j < L.cols(); ++j) {
          for (size_type i = j; i < L.cols(); ++i) {
            L.coeffRef(i, j).vi_ = baseVari->variRefL_[pos++];
          }
          for (size_type k = 0; k < j; ++k)
            L.coeffRef(k, j).vi_ = dummy;
        }
      }
      return L;
    }
  }
}
#endif
<|endoftext|>


<commit_before>#include <Engine/Renderer/OpenGL/OpenGL.hpp>
#include <GuiBase/Viewer/CameraInterface.hpp>
#include <GuiBase/Viewer/Gizmo/GizmoManager.hpp>
#include <GuiBase/Viewer/Gizmo/RotateGizmo.hpp>
#include <GuiBase/Viewer/Gizmo/ScaleGizmo.hpp>
#include <GuiBase/Viewer/Gizmo/TranslateGizmo.hpp>

#include <Engine/Managers/SystemDisplay/SystemDisplay.hpp>
#include <Engine/Renderer/Camera/Camera.hpp>

#include <GuiBase/Utils/KeyMappingManager.hpp>

namespace Ra {
namespace Gui {
/*
 * FIXME : Mathias -- Creating gizmos by default is not a good idea.
 * implies that all applications developped on top of the engine will have them.
 * This is not a good idea. Applications mus be able to define and
 * create their their own gizmos
 *
 * \see issue #194
 */
GizmoManager::GizmoManager( QObject* parent ) :
    QObject( parent ),
    m_currentGizmoType( NONE ),
    m_mode( Gizmo::GLOBAL ) {
    m_gizmos[0].reset( new TranslateGizmo( Engine::SystemEntity::uiCmp(),
                                           Ra::Core::Transform::Identity(), m_transform, m_mode ) );
    m_gizmos[1].reset( new RotateGizmo( Engine::SystemEntity::uiCmp(),
                                        Ra::Core::Transform::Identity(), m_transform, m_mode ) );
    m_gizmos[2].reset( new ScaleGizmo( Engine::SystemEntity::uiCmp(),
                                       Ra::Core::Transform::Identity(), m_transform, m_mode ) );
    for ( auto& g : m_gizmos )
    {
        if ( g )
        {
            g->show( false );
        }
    }
}

GizmoManager::~GizmoManager() {}

void GizmoManager::setEditable( const Engine::ItemEntry& ent ) {
    TransformEditor::setEditable( ent );
    updateGizmo();
}

void GizmoManager::updateGizmo() {
    for ( auto& g : m_gizmos )
    {
        if ( g )
        {
            g->show( false );
        }
    }

    if ( canEdit() )
    {
        Core::Transform worldTransform = getWorldTransform();
        auto g = currentGizmo();
        if ( g )
        {
            g->updateTransform( m_mode, worldTransform, m_transform );
            g->show( true );
        }
    }
}

void GizmoManager::setLocal( bool useLocal ) {
    m_mode = useLocal ? Gizmo::LOCAL : Gizmo::GLOBAL;
    updateGizmo();
}

void GizmoManager::changeGizmoType( GizmoManager::GizmoType type ) {
    m_currentGizmoType = type;
    updateGizmo();
}

void GizmoManager::updateValues() {
    if ( canEdit() )
    {
        getTransform();
        if ( currentGizmo() )
        {
            currentGizmo()->updateTransform( m_mode, getWorldTransform(), m_transform );
        }
    }
}

bool GizmoManager::handleMousePressEvent( QMouseEvent* event ) {
    if ( !( Gui::KeyMappingManager::getInstance()->actionTriggered(
             event, Gui::KeyMappingManager::GIZMOMANAGER_MANIPULATION ) ) ||
         !canEdit() || m_currentGizmoType == NONE )
    {
        return false;
    }
    // If we are there it means that we should have a valid gizmo.
    CORE_ASSERT( currentGizmo(), "Gizmo is not there !" );

    const Engine::Camera& cam = CameraInterface::getCameraFromViewer( parent() );
    currentGizmo()->setInitialState( cam,
                                     Core::Vector2( Scalar( event->x() ), Scalar( event->y() ) ) );

    return true;
}

bool GizmoManager::handleMouseReleaseEvent( QMouseEvent* event ) {
    if ( currentGizmo() )
    {
        currentGizmo()->selectConstraint( -1 );
    }
    return ( currentGizmo() != nullptr );
}

bool GizmoManager::handleMouseMoveEvent( QMouseEvent* event ) {
    auto keyMap = Gui::KeyMappingManager::getInstance();
    // cannot call actionTriggered because event->button returns Qt::NO_BUTTON for moves
    if ( ( event->buttons() &
           keyMap->getKeyFromAction( Gui::KeyMappingManager::GIZMOMANAGER_MANIPULATION ) ) &&
         currentGizmo() )
    {
        Core::Vector2 currentXY( event->x(), event->y() );
        const Engine::Camera& cam = CameraInterface::getCameraFromViewer( parent() );
        bool step = ( int( event->buttons() ) | event->modifiers() ) ==
                    keyMap->getKeyFromAction( Gui::KeyMappingManager::GIZMOMANAGER_STEP );
        Core::Transform newTransform = currentGizmo()->mouseMove( cam, currentXY, step );
        setTransform( newTransform );
    }
    return ( currentGizmo() != nullptr );
}

void GizmoManager::handlePickingResult( int drawableId ) {
    if ( currentGizmo() )
    {
        currentGizmo()->selectConstraint( drawableId );
    }
}

Gizmo* GizmoManager::currentGizmo() {
    return ( m_currentGizmoType == NONE ) ? nullptr : m_gizmos[m_currentGizmoType - 1].get();
}

void GizmoManager::cleanup() {
    for ( auto& g : m_gizmos )
    {
        g.reset( nullptr );
    }
}
} // namespace Gui
} // namespace Ra
<commit_msg>Cleanup mouseMoveEvent management ;<commit_after>#include <Engine/Renderer/OpenGL/OpenGL.hpp>
#include <GuiBase/Viewer/CameraInterface.hpp>
#include <GuiBase/Viewer/Gizmo/GizmoManager.hpp>
#include <GuiBase/Viewer/Gizmo/RotateGizmo.hpp>
#include <GuiBase/Viewer/Gizmo/ScaleGizmo.hpp>
#include <GuiBase/Viewer/Gizmo/TranslateGizmo.hpp>

#include <Engine/Managers/SystemDisplay/SystemDisplay.hpp>
#include <Engine/Renderer/Camera/Camera.hpp>

#include <GuiBase/Utils/KeyMappingManager.hpp>

namespace Ra {
namespace Gui {
/*
 * FIXME : Mathias -- Creating gizmos by default is not a good idea.
 * implies that all applications developped on top of the engine will have them.
 * This is not a good idea. Applications mus be able to define and
 * create their their own gizmos
 *
 * \see issue #194
 */
GizmoManager::GizmoManager( QObject* parent ) :
    QObject( parent ),
    m_currentGizmoType( NONE ),
    m_mode( Gizmo::GLOBAL ) {
    m_gizmos[0].reset( new TranslateGizmo( Engine::SystemEntity::uiCmp(),
                                           Ra::Core::Transform::Identity(), m_transform, m_mode ) );
    m_gizmos[1].reset( new RotateGizmo( Engine::SystemEntity::uiCmp(),
                                        Ra::Core::Transform::Identity(), m_transform, m_mode ) );
    m_gizmos[2].reset( new ScaleGizmo( Engine::SystemEntity::uiCmp(),
                                       Ra::Core::Transform::Identity(), m_transform, m_mode ) );
    for ( auto& g : m_gizmos )
    {
        if ( g )
        {
            g->show( false );
        }
    }
}

GizmoManager::~GizmoManager() {}

void GizmoManager::setEditable( const Engine::ItemEntry& ent ) {
    TransformEditor::setEditable( ent );
    updateGizmo();
}

void GizmoManager::updateGizmo() {
    for ( auto& g : m_gizmos )
    {
        if ( g )
        {
            g->show( false );
        }
    }

    if ( canEdit() )
    {
        Core::Transform worldTransform = getWorldTransform();
        auto g = currentGizmo();
        if ( g )
        {
            g->updateTransform( m_mode, worldTransform, m_transform );
            g->show( true );
        }
    }
}

void GizmoManager::setLocal( bool useLocal ) {
    m_mode = useLocal ? Gizmo::LOCAL : Gizmo::GLOBAL;
    updateGizmo();
}

void GizmoManager::changeGizmoType( GizmoManager::GizmoType type ) {
    m_currentGizmoType = type;
    updateGizmo();
}

void GizmoManager::updateValues() {
    if ( canEdit() )
    {
        getTransform();
        if ( currentGizmo() )
        {
            currentGizmo()->updateTransform( m_mode, getWorldTransform(), m_transform );
        }
    }
}

bool GizmoManager::handleMousePressEvent( QMouseEvent* event ) {
    if ( !( Gui::KeyMappingManager::getInstance()->actionTriggered(
             event, Gui::KeyMappingManager::GIZMOMANAGER_MANIPULATION ) ) ||
         !canEdit() || m_currentGizmoType == NONE )
    {
        return false;
    }
    // If we are there it means that we should have a valid gizmo.
    CORE_ASSERT( currentGizmo(), "Gizmo is not there !" );

    const Engine::Camera& cam = CameraInterface::getCameraFromViewer( parent() );
    currentGizmo()->setInitialState( cam,
                                     Core::Vector2( Scalar( event->x() ), Scalar( event->y() ) ) );

    return true;
}

bool GizmoManager::handleMouseReleaseEvent( QMouseEvent* event ) {
    if ( currentGizmo() )
    {
        currentGizmo()->selectConstraint( -1 );
    }
    return ( currentGizmo() != nullptr );
}

bool GizmoManager::handleMouseMoveEvent( QMouseEvent* event ) {
    auto keyMap = Gui::KeyMappingManager::getInstance();
    // cannot call actionTriggered because event->button returns Qt::NO_BUTTON for moves
    if ( ( keyMap->actionTriggered( event, Gui::KeyMappingManager::GIZMOMANAGER_MANIPULATION ) ||
           keyMap->actionTriggered( event, Gui::KeyMappingManager::GIZMOMANAGER_STEP ) ) &&
         currentGizmo() )
    {
        Core::Vector2 currentXY( event->x(), event->y() );
        const Engine::Camera& cam = CameraInterface::getCameraFromViewer( parent() );
        bool step = keyMap->actionTriggered( event, Gui::KeyMappingManager::GIZMOMANAGER_STEP );
        Core::Transform newTransform = currentGizmo()->mouseMove( cam, currentXY, step );
        setTransform( newTransform );
    }
    return ( currentGizmo() != nullptr );
}

void GizmoManager::handlePickingResult( int drawableId ) {
    if ( currentGizmo() )
    {
        currentGizmo()->selectConstraint( drawableId );
    }
}

Gizmo* GizmoManager::currentGizmo() {
    return ( m_currentGizmoType == NONE ) ? nullptr : m_gizmos[m_currentGizmoType - 1].get();
}

void GizmoManager::cleanup() {
    for ( auto& g : m_gizmos )
    {
        g.reset( nullptr );
    }
}
} // namespace Gui
} // namespace Ra
<|endoftext|>


<commit_before>#include <efsw/efsw.hpp>
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/FileWatcherGeneric.hpp>

#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#	include <efsw/FileWatcherWin32.hpp>
#	define FILEWATCHER_IMPL FileWatcherWin32
#	define BACKEND_NAME "Win32"
#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
#	include <efsw/FileWatcherInotify.hpp>
#	define FILEWATCHER_IMPL FileWatcherInotify
#	define BACKEND_NAME "Inotify"
#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
#	include <efsw/FileWatcherKqueue.hpp>
#	define FILEWATCHER_IMPL FileWatcherKqueue
#	define BACKEND_NAME "Kqueue"
#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#	include <efsw/FileWatcherFSEvents.hpp>
#	define FILEWATCHER_IMPL FileWatcherFSEvents
#	define BACKEND_NAME "FSEvents"
#else
#	define FILEWATCHER_IMPL FileWatcherGeneric
#	define BACKEND_NAME "Generic"
#endif

#include <efsw/Debug.hpp>

namespace efsw {

FileWatcher::FileWatcher() :
	mFollowSymlinks(false),
	mOutOfScopeLinks(false)
{
	efDEBUG( "Using backend: %s\n", BACKEND_NAME );

	mImpl = new FILEWATCHER_IMPL( this );

	if ( !mImpl->initOK() )
	{
		efSAFE_DELETE( mImpl );

		efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );

		mImpl = new FileWatcherGeneric( this );
	}
}

FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
	mFollowSymlinks(false),
	mOutOfScopeLinks(false)
{
	if ( useGenericFileWatcher )
	{
		efDEBUG( "Using backend: Generic\n" );

		mImpl = new FileWatcherGeneric( this );
	}
	else
	{
		efDEBUG( "Using backend: %s\n", BACKEND_NAME );

		mImpl = new FILEWATCHER_IMPL( this );

		if ( !mImpl->initOK() )
		{
			efSAFE_DELETE( mImpl );

			efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );

			mImpl = new FileWatcherGeneric( this );
		}
	}
}

FileWatcher::~FileWatcher()
{
	efSAFE_DELETE( mImpl );
}

WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher)
{
	return mImpl->addWatch(directory, watcher, false);
}

WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
	return mImpl->addWatch(directory, watcher, recursive);
}

void FileWatcher::removeWatch(const std::string& directory)
{
	mImpl->removeWatch(directory);
}

void FileWatcher::removeWatch(WatchID watchid)
{
	mImpl->removeWatch(watchid);
}

void FileWatcher::watch()
{
	mImpl->watch();
}

void FileWatcher::followSymlinks( bool follow )
{
	mFollowSymlinks = follow;
}

const bool& FileWatcher::followSymlinks() const
{
	return mFollowSymlinks;
}

void FileWatcher::allowOutOfScopeLinks( bool allow )
{
	mOutOfScopeLinks = allow;
}

const bool& FileWatcher::allowOutOfScopeLinks() const
{
	return mOutOfScopeLinks;
}

}
<commit_msg>Fixed Issue #15. Thanks Petr Vanek!<commit_after>#include <efsw/efsw.hpp>
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/FileWatcherGeneric.hpp>

#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#	include <efsw/FileWatcherWin32.hpp>
#	define FILEWATCHER_IMPL FileWatcherWin32
#	define BACKEND_NAME "Win32"
#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
#	include <efsw/FileWatcherInotify.hpp>
#	define FILEWATCHER_IMPL FileWatcherInotify
#	define BACKEND_NAME "Inotify"
#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
#	include <efsw/FileWatcherKqueue.hpp>
#	define FILEWATCHER_IMPL FileWatcherKqueue
#	define BACKEND_NAME "Kqueue"
#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#	include <efsw/FileWatcherFSEvents.hpp>
#	define FILEWATCHER_IMPL FileWatcherFSEvents
#	define BACKEND_NAME "FSEvents"
#else
#	define FILEWATCHER_IMPL FileWatcherGeneric
#	define BACKEND_NAME "Generic"
#endif

#include <efsw/Debug.hpp>

namespace efsw {

FileWatcher::FileWatcher() :
	mFollowSymlinks(false),
	mOutOfScopeLinks(false)
{
	efDEBUG( "Using backend: %s\n", BACKEND_NAME );

	mImpl = new FILEWATCHER_IMPL( this );

	if ( !mImpl->initOK() )
	{
		efSAFE_DELETE( mImpl );

		efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );

		mImpl = new FileWatcherGeneric( this );
	}
}

FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
	mFollowSymlinks(false),
	mOutOfScopeLinks(false)
{
	if ( useGenericFileWatcher )
	{
		efDEBUG( "Using backend: Generic\n" );

		mImpl = new FileWatcherGeneric( this );
	}
	else
	{
		efDEBUG( "Using backend: %s\n", BACKEND_NAME );

		mImpl = new FILEWATCHER_IMPL( this );

		if ( !mImpl->initOK() )
		{
			efSAFE_DELETE( mImpl );

			efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );

			mImpl = new FileWatcherGeneric( this );
		}
	}
}

FileWatcher::~FileWatcher()
{
	efSAFE_DELETE( mImpl );
}

WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher)
{
	return mImpl->addWatch(directory, watcher, false);
}

WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
	return mImpl->addWatch(directory, watcher, recursive);
}

void FileWatcher::removeWatch(const std::string& directory)
{
	mImpl->removeWatch(directory);
}

void FileWatcher::removeWatch(WatchID watchid)
{
	mImpl->removeWatch(watchid);
}

void FileWatcher::watch()
{
	mImpl->watch();
}

std::list<std::string> FileWatcher::directories()
{
	return mImpl->directories();
}

void FileWatcher::followSymlinks( bool follow )
{
	mFollowSymlinks = follow;
}

const bool& FileWatcher::followSymlinks() const
{
	return mFollowSymlinks;
}

void FileWatcher::allowOutOfScopeLinks( bool allow )
{
	mOutOfScopeLinks = allow;
}

const bool& FileWatcher::allowOutOfScopeLinks() const
{
	return mOutOfScopeLinks;
}

}
<|endoftext|>