<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#define EIGEN_USE_THREADS

#include "main.h"
#include <iostream>
#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;

static void test_multithread_elementwise()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPool tp(internal::random<int>(3, 11));
  Eigen::ThreadPoolDevice thread_pool_device(&tp, internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1 + in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

static void test_multithread_compound_assignment()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPool tp(internal::random<int>(3, 11));
  Eigen::ThreadPoolDevice thread_pool_device(&tp, internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1;
  out.device(thread_pool_device) += in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

template<int DataLayout>
static void test_multithread_contraction()
{
  Tensor<float, 4, DataLayout> t_left(30, 50, 37, 31);
  Tensor<float, 5, DataLayout> t_right(37, 31, 70, 2, 10);
  Tensor<float, 5, DataLayout> t_result(30, 50, 70, 2, 10);

  t_left.setRandom();
  t_right.setRandom();

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 1500, 1147);
  MapXf m_right(t_right.data(), 1147, 1400);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(1500, 1400);

  Eigen::ThreadPool tp(4);
  Eigen::ThreadPoolDevice thread_pool_device(&tp, 4);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left * m_right;

 for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    VERIFY(&t_result.data()[i] != &m_result.data()[i]);
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
static void test_contraction_corner_cases()
{
  Tensor<float, 2, DataLayout> t_left(32, 500);
  Tensor<float, 2, DataLayout> t_right(32, 28*28);
  Tensor<float, 2, DataLayout> t_result(500, 28*28);

  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result = t_result.constant(NAN);

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims{{DimPair(0, 0)}};

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 32, 500);
  MapXf m_right(t_right.data(), 32, 28*28);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(500, 28*28);

  Eigen::ThreadPool tp(12);
  Eigen::ThreadPoolDevice thread_pool_device(&tp, 12);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left.transpose() * m_right;

  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected at index " << i << " : " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_result.resize (1, 28*28);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 500);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (500, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 500);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (1, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
static void test_multithread_contraction_agrees_with_singlethread() {
  int contract_size = internal::random<int>(1, 5000);

  Tensor<float, 3, DataLayout> left(internal::random<int>(1, 80),
                                    contract_size,
                                    internal::random<int>(1, 100));

  Tensor<float, 4, DataLayout> right(internal::random<int>(1, 25),
                                     internal::random<int>(1, 37),
                                     contract_size,
                                     internal::random<int>(1, 51));

  left.setRandom();
  right.setRandom();

  // add constants to shift values away from 0 for more precision
  left += left.constant(1.5f);
  right += right.constant(1.5f);

  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims({{DimPair(1, 2)}});

  Eigen::ThreadPool tp(internal::random<int>(2, 11));
  Eigen::ThreadPoolDevice thread_pool_device(&tp, internal::random<int>(2, 11));

  Tensor<float, 5, DataLayout> st_result;
  st_result = left.contract(right, dims);

  Tensor<float, 5, DataLayout> tp_result(st_result.dimensions());
  tp_result.device(thread_pool_device) = left.contract(right, dims);

  VERIFY(dimensions_match(st_result.dimensions(), tp_result.dimensions()));
  for (ptrdiff_t i = 0; i < st_result.size(); i++) {
    // if both of the values are very small, then do nothing (because the test will fail
    // due to numerical precision issues when values are small)
    if (fabs(st_result.data()[i] - tp_result.data()[i]) >= 1e-4) {
      VERIFY_IS_APPROX(st_result.data()[i], tp_result.data()[i]);
    }
  }
}

template<int DataLayout>
static void test_multithreaded_reductions() {
  const int num_threads = internal::random<int>(3, 11);
  ThreadPool thread_pool(num_threads);
  Eigen::ThreadPoolDevice thread_pool_device(&thread_pool, num_threads);

  const int num_rows = internal::random<int>(13, 732);
  const int num_cols = internal::random<int>(13, 732);
  Tensor<float, 2, DataLayout> t1(num_rows, num_cols);
  t1.setRandom();

  Tensor<float, 1, DataLayout> full_redux(1);
  full_redux = t1.sum();

  Tensor<float, 1, DataLayout> full_redux_tp(1);
  full_redux_tp.device(thread_pool_device) = t1.sum();

  // Check that the single threaded and the multi threaded reductions return
  // the same result.
  VERIFY_IS_APPROX(full_redux(0), full_redux_tp(0));
}

static void test_memcpy() {

  for (int i = 0; i < 5; ++i) {
    const int num_threads = internal::random<int>(3, 11);
    Eigen::ThreadPool tp(num_threads);
    Eigen::ThreadPoolDevice thread_pool_device(&tp, num_threads);

    const int size = internal::random<int>(13, 7632);
    Tensor<float, 1> t1(size);
    t1.setRandom();
    std::vector<float> result(size);
    thread_pool_device.memcpy(&result[0], t1.data(), size*sizeof(float));
    for (int j = 0; j < size; j++) {
      VERIFY_IS_EQUAL(t1(j), result[j]);
    }
  }
}

static void test_multithread_random()
{
  Eigen::ThreadPool tp(2);
  Eigen::ThreadPoolDevice device(&tp, 2);
  Tensor<float, 1> t(1 << 20);
  t.device(device) = t.random<Eigen::internal::NormalRandomGenerator<float>>();
}

void test_cxx11_tensor_thread_pool()
{
  CALL_SUBTEST(test_multithread_elementwise());
  CALL_SUBTEST(test_multithread_compound_assignment());

  CALL_SUBTEST(test_multithread_contraction<ColMajor>());
  CALL_SUBTEST(test_multithread_contraction<RowMajor>());

  CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<ColMajor>());
  CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<RowMajor>());

  // Exercise various cases that have been problematic in the past.
  CALL_SUBTEST(test_contraction_corner_cases<ColMajor>());
  CALL_SUBTEST(test_contraction_corner_cases<RowMajor>());

  CALL_SUBTEST(test_multithreaded_reductions<ColMajor>());
  CALL_SUBTEST(test_multithreaded_reductions<RowMajor>());

  CALL_SUBTEST(test_memcpy());

  CALL_SUBTEST(test_multithread_random());
}
<commit_msg>Sharded the tensor thread pool test<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#define EIGEN_USE_THREADS

#include "main.h"
#include <iostream>
#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;

void test_multithread_elementwise()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPool tp(internal::random<int>(3, 11));
  Eigen::ThreadPoolDevice thread_pool_device(&tp, internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1 + in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

void test_multithread_compound_assignment()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPool tp(internal::random<int>(3, 11));
  Eigen::ThreadPoolDevice thread_pool_device(&tp, internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1;
  out.device(thread_pool_device) += in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

template<int DataLayout>
void test_multithread_contraction()
{
  Tensor<float, 4, DataLayout> t_left(30, 50, 37, 31);
  Tensor<float, 5, DataLayout> t_right(37, 31, 70, 2, 10);
  Tensor<float, 5, DataLayout> t_result(30, 50, 70, 2, 10);

  t_left.setRandom();
  t_right.setRandom();

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 1500, 1147);
  MapXf m_right(t_right.data(), 1147, 1400);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(1500, 1400);

  Eigen::ThreadPool tp(4);
  Eigen::ThreadPoolDevice thread_pool_device(&tp, 4);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left * m_right;

 for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    VERIFY(&t_result.data()[i] != &m_result.data()[i]);
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
void test_contraction_corner_cases()
{
  Tensor<float, 2, DataLayout> t_left(32, 500);
  Tensor<float, 2, DataLayout> t_right(32, 28*28);
  Tensor<float, 2, DataLayout> t_result(500, 28*28);

  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result = t_result.constant(NAN);

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims{{DimPair(0, 0)}};

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 32, 500);
  MapXf m_right(t_right.data(), 32, 28*28);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(500, 28*28);

  Eigen::ThreadPool tp(12);
  Eigen::ThreadPoolDevice thread_pool_device(&tp, 12);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left.transpose() * m_right;

  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected at index " << i << " : " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_result.resize (1, 28*28);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 500);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (500, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 500);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (1, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!(numext::isnan)(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
void test_multithread_contraction_agrees_with_singlethread() {
  int contract_size = internal::random<int>(1, 5000);

  Tensor<float, 3, DataLayout> left(internal::random<int>(1, 80),
                                    contract_size,
                                    internal::random<int>(1, 100));

  Tensor<float, 4, DataLayout> right(internal::random<int>(1, 25),
                                     internal::random<int>(1, 37),
                                     contract_size,
                                     internal::random<int>(1, 51));

  left.setRandom();
  right.setRandom();

  // add constants to shift values away from 0 for more precision
  left += left.constant(1.5f);
  right += right.constant(1.5f);

  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims({{DimPair(1, 2)}});

  Eigen::ThreadPool tp(internal::random<int>(2, 11));
  Eigen::ThreadPoolDevice thread_pool_device(&tp, internal::random<int>(2, 11));

  Tensor<float, 5, DataLayout> st_result;
  st_result = left.contract(right, dims);

  Tensor<float, 5, DataLayout> tp_result(st_result.dimensions());
  tp_result.device(thread_pool_device) = left.contract(right, dims);

  VERIFY(dimensions_match(st_result.dimensions(), tp_result.dimensions()));
  for (ptrdiff_t i = 0; i < st_result.size(); i++) {
    // if both of the values are very small, then do nothing (because the test will fail
    // due to numerical precision issues when values are small)
    if (fabs(st_result.data()[i] - tp_result.data()[i]) >= 1e-4) {
      VERIFY_IS_APPROX(st_result.data()[i], tp_result.data()[i]);
    }
  }
}

template<int DataLayout>
void test_multithreaded_reductions() {
  const int num_threads = internal::random<int>(3, 11);
  ThreadPool thread_pool(num_threads);
  Eigen::ThreadPoolDevice thread_pool_device(&thread_pool, num_threads);

  const int num_rows = internal::random<int>(13, 732);
  const int num_cols = internal::random<int>(13, 732);
  Tensor<float, 2, DataLayout> t1(num_rows, num_cols);
  t1.setRandom();

  Tensor<float, 1, DataLayout> full_redux(1);
  full_redux = t1.sum();

  Tensor<float, 1, DataLayout> full_redux_tp(1);
  full_redux_tp.device(thread_pool_device) = t1.sum();

  // Check that the single threaded and the multi threaded reductions return
  // the same result.
  VERIFY_IS_APPROX(full_redux(0), full_redux_tp(0));
}

void test_memcpy() {

  for (int i = 0; i < 5; ++i) {
    const int num_threads = internal::random<int>(3, 11);
    Eigen::ThreadPool tp(num_threads);
    Eigen::ThreadPoolDevice thread_pool_device(&tp, num_threads);

    const int size = internal::random<int>(13, 7632);
    Tensor<float, 1> t1(size);
    t1.setRandom();
    std::vector<float> result(size);
    thread_pool_device.memcpy(&result[0], t1.data(), size*sizeof(float));
    for (int j = 0; j < size; j++) {
      VERIFY_IS_EQUAL(t1(j), result[j]);
    }
  }
}

void test_multithread_random()
{
  Eigen::ThreadPool tp(2);
  Eigen::ThreadPoolDevice device(&tp, 2);
  Tensor<float, 1> t(1 << 20);
  t.device(device) = t.random<Eigen::internal::NormalRandomGenerator<float>>();
}

void test_cxx11_tensor_thread_pool()
{
  CALL_SUBTEST_1(test_multithread_elementwise());
  CALL_SUBTEST_1(test_multithread_compound_assignment());

  CALL_SUBTEST_2(test_multithread_contraction<ColMajor>());
  CALL_SUBTEST_2(test_multithread_contraction<RowMajor>());

  CALL_SUBTEST_3(test_multithread_contraction_agrees_with_singlethread<ColMajor>());
  CALL_SUBTEST_3(test_multithread_contraction_agrees_with_singlethread<RowMajor>());

  // Exercise various cases that have been problematic in the past.
  CALL_SUBTEST_4(test_contraction_corner_cases<ColMajor>());
  CALL_SUBTEST_4(test_contraction_corner_cases<RowMajor>());

  CALL_SUBTEST_5(test_multithreaded_reductions<ColMajor>());
  CALL_SUBTEST_5(test_multithreaded_reductions<RowMajor>());

  CALL_SUBTEST_6(test_memcpy());
  CALL_SUBTEST_6(test_multithread_random());
}
<|endoftext|>


<commit_before>#ifndef PARALLEL_LINES_HPP_
#define PARALLEL_LINES_HPP_

#include <cmath>
#include <limits>
#include <iostream>

#define PI 3.14159265

// Given two lines on a Cartesian plane, determine whether the two lines
// would intersect

class Point
{
public:
    explicit Point(double xValue = 0.0, double yValue = 0.0) :
        x(xValue), y(yValue) {}

    friend bool operator==(const Point& left, const Point& right);

    double x;
    double y;
};

bool operator==(const Point& left, const Point& right)
{
    if (std::abs(left.x - right.x) <= std::numeric_limits<double>::epsilon() &&
        std::abs(left.y - right.y) <= std::numeric_limits<double>::epsilon())
    {
        return true;
    }

    return false;
}

class Line
{
public:
    explicit Line(const Point& first, Point& second) :
            p1(first), p2(second) {}

    double GetAngle() const
    {
        // Check if points are the same
        if (p1 == p2)
        {
            return 0.0;
        }

        // Check if X coordinates are equal
        if (std::abs(p1.x - p2.x) <= std::numeric_limits<double>::epsilon())
        {
            return 0.0;
        }

        double tang = (p2.y - p1.y) / (p2.x - p1.x);
        return std::atan(tang) * 180 / PI;
    }

private:
    Point p1;
    Point p2;
};

bool AreLinesParallel(const Line& first, const Line& second)
{
    double firstAngle = first.GetAngle();
    double secondAngle = second.GetAngle();
    double diff = std::abs(firstAngle - secondAngle);
    if (std::numeric_limits<double>::epsilon() < diff &&
            std::numeric_limits<double>::epsilon() < (180.0 -diff))
    {
        return false;
    }

    return true;
}

#endif /* PARALLEL_LINES_HPP_ */
<commit_msg>Add links to parallel_lines.hpp<commit_after>#ifndef PARALLEL_LINES_HPP_
#define PARALLEL_LINES_HPP_

#include <cmath>
#include <limits>
#include <iostream>

#define PI 3.14159265

// Given two lines on a Cartesian plane, determine whether the two lines
// would intersect

// http://www.wikihow.com/Find-the-Slope-of-a-Line
// http://matematikalegko.ru/koordinatnaya-ploskost/uglovoj-koefficient-pryamoj-i-ne-tolko.html

class Point
{
public:
    explicit Point(double xValue = 0.0, double yValue = 0.0) :
        x(xValue), y(yValue) {}

    friend bool operator==(const Point& left, const Point& right);

    double x;
    double y;
};

bool operator==(const Point& left, const Point& right)
{
    if (std::abs(left.x - right.x) <= std::numeric_limits<double>::epsilon() &&
        std::abs(left.y - right.y) <= std::numeric_limits<double>::epsilon())
    {
        return true;
    }

    return false;
}

class Line
{
public:
    explicit Line(const Point& first, Point& second) :
            p1(first), p2(second) {}

    double GetAngle() const
    {
        // Check if points are the same
        if (p1 == p2)
        {
            return 0.0;
        }

        // Check if X coordinates are equal
        if (std::abs(p1.x - p2.x) <= std::numeric_limits<double>::epsilon())
        {
            return 0.0;
        }

        double tang = (p2.y - p1.y) / (p2.x - p1.x);
        return std::atan(tang) * 180 / PI;
    }

private:
    Point p1;
    Point p2;
};

bool AreLinesParallel(const Line& first, const Line& second)
{
    double firstAngle = first.GetAngle();
    double secondAngle = second.GetAngle();
    double diff = std::abs(firstAngle - secondAngle);
    if (std::numeric_limits<double>::epsilon() < diff &&
            std::numeric_limits<double>::epsilon() < (180.0 -diff))
    {
        return false;
    }

    return true;
}

#endif /* PARALLEL_LINES_HPP_ */
<|endoftext|>


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

#include "debugger_commons.h"

#include "system/globalenv.h"

#include "compiler/api/compilercb.h"
#include "context/static_context.h"
#include "context/dynamic_context.h"
#include "diagnostics/assert.h"

#include "runtime/debug/debug_iterator.h"
#include "runtime/visitors/planiter_visitor.h"

#include "store/api/item_factory.h"

#include "zorbatypes/URI.h"

#include "types/typeimpl.h"

#include "zorba/util/uri.h"

namespace zorba {

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(Breakable)
END_SERIALIZABLE_CLASS_VERSIONS(Breakable)

void
Breakable::serialize(serialization::Archiver& ar)
{
  ar & theLocation;
  ar & theEnabled;
}

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(QueryLocComparator)
END_SERIALIZABLE_CLASS_VERSIONS(QueryLocComparator)

void
QueryLocComparator::serialize(serialization::Archiver& ar) {
}

bool
QueryLocComparator::operator()(const QueryLoc& a, const QueryLoc& b) const
{
  // check the file names
  // smaller has priority
  int c;
  if ((c = a.getFilename().compare(b.getFilename())) != 0) {
    return c < 0;
  }

  int ai, bi;

  // check line numbers
  // smaller has priority
  ai = a.getLineBegin();
  bi = b.getLineBegin();
  if (ai != bi) {
    return ai < bi;
  }

  // check column begin numbers
  // smaller has priority
  ai = a.getColumnBegin();
  bi = b.getColumnBegin();
  if (ai == 0 || bi == 0) {
    return false;
  }
  if (ai != bi) {
    return ai < bi;
  }

  // check line end numbers
  // larger has priority
  ai = a.getLineEnd();
  bi = b.getLineEnd();
  if (ai != bi) {
    return ai > bi;
  }

  // check column end numbers
  // larger has priority
  ai = a.getColumnEnd();
  bi = b.getColumnEnd();
  if (ai == 0 || bi == 0) {
    return false;
  }

  return a.getColumnEnd() > b.getColumnEnd();
}

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(DebuggerSingletonIterator)
END_SERIALIZABLE_CLASS_VERSIONS(DebuggerSingletonIterator)

DebuggerSingletonIterator::DebuggerSingletonIterator(
  static_context* sctx, QueryLoc loc, DebuggerCommons* lCommons)
  : NoaryBaseIterator<DebuggerSingletonIterator, PlanIteratorState>(sctx, loc),
    theCommons(lCommons)
{
}

void
DebuggerSingletonIterator::serialize(::zorba::serialization::Archiver& ar)
{
  serialize_baseclass(ar, (NoaryBaseIterator<DebuggerSingletonIterator,PlanIteratorState>*)this);
  ar & theCommons;
}

NOARY_ACCEPT(DebuggerSingletonIterator);

bool
DebuggerSingletonIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  PlanIteratorState* state;
  DEFAULT_STACK_INIT ( PlanIteratorState, state, planState );
  result = theCommons->getEvalItem();
  STACK_PUSH ( result != NULL, state );
  STACK_END (state);
}

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(DebuggerCommons)
END_SERIALIZABLE_CLASS_VERSIONS(DebuggerCommons)

DebuggerCommons::DebuggerCommons(static_context* sctx)
  : theBreak(false),
    theCause(0),
    theExecEval(false),
    theBreakCondition(0),
    theStepping(false)

{
  theRuntime = NULL;
  theCurrentStaticContext = NULL;
  theCurrentDynamicContext = NULL;
  thePlanState = NULL;
  theDebugIteratorState = NULL;
}

DebuggerCommons::~DebuggerCommons()
{
}

void
DebuggerCommons::serialize(::zorba::serialization::Archiver& ar)
{
  ar & theBreakables;
  ar & theBreakableIDs;
  ar & theStackTrace;
  ar & theUriFileMappingMap;

  if(ar.is_serializing_out())
    theRuntime = NULL;
  ar & theCurrentStaticContext;
  if(ar.is_serializing_out())
    theCurrentDynamicContext = NULL;

  ar & theBreak;
  ar & theCause;
  ar & theIteratorStack;
  ar & theBreakCondition;

  if(ar.is_serializing_out())
    thePlanState = NULL;
  if(ar.is_serializing_out())
    theDebugIteratorState = NULL;
  ar & theEvalItem;
  ar & theExecEval;
  ar & theStepping;
}

void
DebuggerCommons::setRuntime(DebuggerRuntime* aRuntime)
{
  theRuntime = aRuntime;
}

DebuggerRuntime*
DebuggerCommons::getRuntime()
{
  return theRuntime;
}

void
DebuggerCommons::setCurrentStaticContext(static_context* aStaticContext)
{
  theCurrentStaticContext = aStaticContext;
}

void
DebuggerCommons::setCurrentDynamicContext(dynamic_context* aDynamicContext)
{
 theCurrentDynamicContext = aDynamicContext;
}

dynamic_context*
DebuggerCommons::getCurrentDynamicContext() const
{
  return theCurrentDynamicContext;
}

static_context*
DebuggerCommons::getCurrentStaticContext() const
{
  return theCurrentStaticContext;
}

unsigned int
DebuggerCommons::addBreakpoint(const QueryLoc& aLocation, bool aEnabled)
{
  BreakableIdMap::iterator lIter = theBreakableIDs.find(aLocation);

  if (lIter == theBreakableIDs.end()) {
    std::stringstream lSs;
    lSs << "The breakpoint could not be set at line " << aLocation.getLineBegin()
      << " in file: " << aLocation.getFilename();
    throw lSs.str();
  }
  unsigned int lId = lIter->second;
  theBreakables[lId].setSet(true);
  theBreakables[lId].setEnabled(aEnabled);
  return lId;
}

Breakable
DebuggerCommons::getBreakpoint(unsigned int aId)
{
  checkBreakpoint(aId);
  return theBreakables[aId];
}

void
DebuggerCommons::checkBreakpoint(unsigned int aId)
{
  if (aId >= theBreakables.size() || !theBreakables[aId].isSet()) {
    std::stringstream lSs;
    lSs << "No such breakpoint: " << aId;
    throw lSs.str();
  }
}

void
DebuggerCommons::updateBreakpoint(
  unsigned int aId,
  bool aEnabled)
{
  checkBreakpoint(aId);
  theBreakables[aId].setEnabled(aEnabled);
}

void
DebuggerCommons::updateBreakpoint(
  unsigned int aId,
  bool aEnabled,
  std::string aCondition,
  unsigned int aHitValue)
{
  checkBreakpoint(aId);
  theBreakables[aId].setEnabled(aEnabled);
  // TODO: set condition
}

void
DebuggerCommons::removeBreakpoint(unsigned int aId)
{
  checkBreakpoint(aId);
  theBreakables[aId].setSet(false);
}

bool
DebuggerCommons::canBreak()
{
  return !theExecEval;
}

bool
DebuggerCommons::mustBreak(SuspensionCause& aCause)
{
  if (theBreak) {
    aCause = CAUSE_STEP;
    return true;
  } else if (theStepping) {
    std::size_t lSize = theIteratorStack.size();

    // either we meet the step condition
    if (lSize <= theBreakCondition) {
      // reset the break conditions
      theBreakCondition = 0;
      theStepping = false;
      return true;
    }
    // or we have stepped over from a function declaration breakpoint
    // we have for sure at least the following stack of debug iterators:
    // MainModule DI -> FunctionCall DI -> FunctionDecl DI -> current DI
    if (lSize > 3 && lSize == theBreakCondition + 1 && theIteratorStack.at(lSize - 2)->getDebuggerParent() == NULL) {
      // reset the break conditions
      theBreakCondition = 0;
      theStepping = false;
      return true;
    }
    // or we have stepped over and we reached another variable declaration
    // TODO: still to check and stop only at declarations on the same level
    if (lSize <= theBreakCondition && theIteratorStack.back()->isVarDeclaration()) {
      // reset the break conditions
      theBreakCondition = 0;
      theStepping = false;
      return true;
    }
  }

  return false;
}

bool
DebuggerCommons::hasToBreakAt(QueryLoc aLocation)
{
  adjustLocationFilePath(aLocation);

  BreakableIdMap::const_iterator lIter = theBreakableIDs.find(aLocation);
  if (lIter == theBreakableIDs.end()) {
    return false;
  }

  Breakable lBreakable = theBreakables[lIter->second];
  return lBreakable.isSet() && lBreakable.isEnabled();
}

bool
DebuggerCommons::hasToBreakAt(const DebugIterator* aIter)
{
  return false;
}

void
DebuggerCommons::setBreak(bool lBreak, SuspensionCause aCause)
{
#ifndef NDEBUG
  //Check preconditions
  ZORBA_ASSERT(lBreak ? aCause != 0 : true);
#endif // NDEBUG
  theBreak = lBreak;
  theCause = aCause;
#ifndef NDEBUG
  // Check post conditions
  ZORBA_ASSERT(theBreak == lBreak);
  ZORBA_ASSERT(theCause == aCause);
#endif //NDEBUG
}

void
DebuggerCommons::setCurrentIterator(const DebugIterator* aIterator)
{
  // don't modify the iterator stack during expression evaluation
  if (theExecEval) {
    return;
  }

  const DebugIterator* lParent = aIterator->getDebuggerParent();

  // when the stack is empty (main module debug iterator) or
  // when the parent is NULL but not a variable declaration (function declaration iterator) or
  // when the parent is the last in the stack
  if (theIteratorStack.empty() ||
      (lParent == NULL && !aIterator->isVarDeclaration()) ||
      theIteratorStack.back() == lParent) {
    theIteratorStack.push_back((DebugIterator*)aIterator);
    return;
  }

  // avoid multiple calls to this function
  // recursive functions always insert at least 2 iterators
  if (theIteratorStack.back() == aIterator) {
    return;
  }

  // now we remove the iterators from the stack until we find the parent
  theIteratorStack.pop_back();
  while (!theIteratorStack.empty()) {
    if (theIteratorStack.back() == aIterator->getDebuggerParent()) {
      theIteratorStack.push_back((DebugIterator*)aIterator);
      return;
    }
    theIteratorStack.pop_back();
  }

  // noe the stack is empty, so push this iterator in the stack
  theIteratorStack.push_back((DebugIterator*)aIterator);
}

const DebugIterator*
DebuggerCommons::getCurrentIterator() const
{
  if (theIteratorStack.empty()) {
    return NULL;
  }
  return theIteratorStack.back();
}

void
DebuggerCommons::makeStepOver()
{
  theStepping = true;
  if (!theIteratorStack.empty()) {
    theBreakCondition = theIteratorStack.size();
  } else {
    theBreakCondition = 0;
  }
}

void DebuggerCommons::makeStepOut()
{
  theStepping = true;
  if (!theIteratorStack.empty()) {
    theBreakCondition = theIteratorStack.size() - 1;
  } else {
    theBreakCondition = 0;
  }
}

void
DebuggerCommons::setPlanState(PlanState* aPlanState)
{
  thePlanState = aPlanState;
  //Check postconditions
  ZORBA_ASSERT(thePlanState == aPlanState);
}

void
DebuggerCommons::setDebugIteratorState(DebugIteratorState* aState)
{
  theDebugIteratorState = aState;
  //Check postconditions
  ZORBA_ASSERT(theDebugIteratorState == aState);
}

std::list<std::pair<zstring, zstring> >
DebuggerCommons::eval(const zstring& aExpr, Zorba_SerializerOptions& aSerOpts)
{
  theExecEval = true;
  zstring lStore = aExpr;
  GlobalEnvironment::getInstance().getItemFactory()->createString(theEvalItem,
                                                                  lStore);
  std::list<std::pair<zstring, zstring> > lRes =
    theIteratorStack.back()->eval(thePlanState, &aSerOpts);

  theExecEval = false;
  return lRes;
}

store::Item_t
DebuggerCommons::getEvalItem()
{
  return theEvalItem;
}

void
DebuggerCommons::addModuleUriMapping(std::string aUri, std::string aFileUri)
{
  ZORBA_ASSERT(theUriFileMappingMap.find(aUri) == theUriFileMappingMap.end());
  theUriFileMappingMap.insert(
    std::pair<std::string, std::string>(aUri, aFileUri));
  ZORBA_ASSERT(theUriFileMappingMap.find(aUri) != theUriFileMappingMap.end());
}

std::string
DebuggerCommons::getFilepathOfURI(const std::string& aUri) const
{
  std::map<std::string, std::string>::const_iterator lIter;
  lIter = theUriFileMappingMap.find(aUri);
  zstring lString;
  if (lIter == theUriFileMappingMap.end())
  {
    lString = aUri;
  }
  else
  {
    lString = lIter->second;
  }
  zstring lRes;
  URI::decode_file_URI(lString, lRes);
  return lRes.str();
}

void
DebuggerCommons::addBreakable(Breakable& aBreakable)
{
  adjustLocationFilePath(aBreakable.getLocation());

  unsigned int lId = theBreakables.size();
  theBreakables.push_back(aBreakable);
  theBreakableIDs[aBreakable.getLocation()] = lId;
}

void
DebuggerCommons::pushStackFrame(QueryLoc aLocation, std::string& aFunctionName)
{
  theStackTrace.push_back(std::pair<QueryLoc, std::string>(aLocation, aFunctionName));
}

void
DebuggerCommons::popStackFrame()
{
  theStackTrace.pop_back();
}

std::vector<std::pair<QueryLoc, std::string> >
DebuggerCommons::getStackFrames() const
{
  return theStackTrace;
}

void
DebuggerCommons::adjustLocationFilePath(QueryLoc& aLocation)
{
  if (aLocation.getFilename().substr(0, 7) == "file://") {
    // adjust the file paths by removing the schema and encoding
    zstring lOldFilename(aLocation.getFilename());
    const String lNewFilename = URIHelper::decodeFileURI(lOldFilename.str());
    aLocation.setFilename(lNewFilename.str());
  }
}

} // namespace zorba
<commit_msg>Fixed Warning on Windows.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "debugger_commons.h"

#include "system/globalenv.h"

#include "compiler/api/compilercb.h"
#include "context/static_context.h"
#include "context/dynamic_context.h"
#include "diagnostics/assert.h"

#include "runtime/debug/debug_iterator.h"
#include "runtime/visitors/planiter_visitor.h"

#include "store/api/item_factory.h"

#include "zorbatypes/URI.h"

#include "types/typeimpl.h"

#include "zorba/util/uri.h"

namespace zorba {

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(Breakable)
END_SERIALIZABLE_CLASS_VERSIONS(Breakable)

void
Breakable::serialize(serialization::Archiver& ar)
{
  ar & theLocation;
  ar & theEnabled;
}

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(QueryLocComparator)
END_SERIALIZABLE_CLASS_VERSIONS(QueryLocComparator)

void
QueryLocComparator::serialize(serialization::Archiver& ar) {
}

bool
QueryLocComparator::operator()(const QueryLoc& a, const QueryLoc& b) const
{
  // check the file names
  // smaller has priority
  int c;
  if ((c = a.getFilename().compare(b.getFilename())) != 0) {
    return c < 0;
  }

  int ai, bi;

  // check line numbers
  // smaller has priority
  ai = a.getLineBegin();
  bi = b.getLineBegin();
  if (ai != bi) {
    return ai < bi;
  }

  // check column begin numbers
  // smaller has priority
  ai = a.getColumnBegin();
  bi = b.getColumnBegin();
  if (ai == 0 || bi == 0) {
    return false;
  }
  if (ai != bi) {
    return ai < bi;
  }

  // check line end numbers
  // larger has priority
  ai = a.getLineEnd();
  bi = b.getLineEnd();
  if (ai != bi) {
    return ai > bi;
  }

  // check column end numbers
  // larger has priority
  ai = a.getColumnEnd();
  bi = b.getColumnEnd();
  if (ai == 0 || bi == 0) {
    return false;
  }

  return a.getColumnEnd() > b.getColumnEnd();
}

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(DebuggerSingletonIterator)
END_SERIALIZABLE_CLASS_VERSIONS(DebuggerSingletonIterator)

DebuggerSingletonIterator::DebuggerSingletonIterator(
  static_context* sctx, QueryLoc loc, DebuggerCommons* lCommons)
  : NoaryBaseIterator<DebuggerSingletonIterator, PlanIteratorState>(sctx, loc),
    theCommons(lCommons)
{
}

void
DebuggerSingletonIterator::serialize(::zorba::serialization::Archiver& ar)
{
  serialize_baseclass(ar, (NoaryBaseIterator<DebuggerSingletonIterator,PlanIteratorState>*)this);
  ar & theCommons;
}

NOARY_ACCEPT(DebuggerSingletonIterator);

bool
DebuggerSingletonIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  PlanIteratorState* state;
  DEFAULT_STACK_INIT ( PlanIteratorState, state, planState );
  result = theCommons->getEvalItem();
  STACK_PUSH ( result != NULL, state );
  STACK_END (state);
}

// ****************************************************************************

SERIALIZABLE_CLASS_VERSIONS(DebuggerCommons)
END_SERIALIZABLE_CLASS_VERSIONS(DebuggerCommons)

DebuggerCommons::DebuggerCommons(static_context* sctx)
  : theBreak(false),
    theCause(0),
    theBreakCondition(0),
    theExecEval(false),
    theStepping(false)

{
  theRuntime = NULL;
  theCurrentStaticContext = NULL;
  theCurrentDynamicContext = NULL;
  thePlanState = NULL;
  theDebugIteratorState = NULL;
}

DebuggerCommons::~DebuggerCommons()
{
}

void
DebuggerCommons::serialize(::zorba::serialization::Archiver& ar)
{
  ar & theBreakables;
  ar & theBreakableIDs;
  ar & theStackTrace;
  ar & theUriFileMappingMap;

  if(ar.is_serializing_out())
    theRuntime = NULL;
  ar & theCurrentStaticContext;
  if(ar.is_serializing_out())
    theCurrentDynamicContext = NULL;

  ar & theBreak;
  ar & theCause;
  ar & theIteratorStack;
  ar & theBreakCondition;

  if(ar.is_serializing_out())
    thePlanState = NULL;
  if(ar.is_serializing_out())
    theDebugIteratorState = NULL;
  ar & theEvalItem;
  ar & theExecEval;
  ar & theStepping;
}

void
DebuggerCommons::setRuntime(DebuggerRuntime* aRuntime)
{
  theRuntime = aRuntime;
}

DebuggerRuntime*
DebuggerCommons::getRuntime()
{
  return theRuntime;
}

void
DebuggerCommons::setCurrentStaticContext(static_context* aStaticContext)
{
  theCurrentStaticContext = aStaticContext;
}

void
DebuggerCommons::setCurrentDynamicContext(dynamic_context* aDynamicContext)
{
 theCurrentDynamicContext = aDynamicContext;
}

dynamic_context*
DebuggerCommons::getCurrentDynamicContext() const
{
  return theCurrentDynamicContext;
}

static_context*
DebuggerCommons::getCurrentStaticContext() const
{
  return theCurrentStaticContext;
}

unsigned int
DebuggerCommons::addBreakpoint(const QueryLoc& aLocation, bool aEnabled)
{
  BreakableIdMap::iterator lIter = theBreakableIDs.find(aLocation);

  if (lIter == theBreakableIDs.end()) {
    std::stringstream lSs;
    lSs << "The breakpoint could not be set at line " << aLocation.getLineBegin()
      << " in file: " << aLocation.getFilename();
    throw lSs.str();
  }
  unsigned int lId = lIter->second;
  theBreakables[lId].setSet(true);
  theBreakables[lId].setEnabled(aEnabled);
  return lId;
}

Breakable
DebuggerCommons::getBreakpoint(unsigned int aId)
{
  checkBreakpoint(aId);
  return theBreakables[aId];
}

void
DebuggerCommons::checkBreakpoint(unsigned int aId)
{
  if (aId >= theBreakables.size() || !theBreakables[aId].isSet()) {
    std::stringstream lSs;
    lSs << "No such breakpoint: " << aId;
    throw lSs.str();
  }
}

void
DebuggerCommons::updateBreakpoint(
  unsigned int aId,
  bool aEnabled)
{
  checkBreakpoint(aId);
  theBreakables[aId].setEnabled(aEnabled);
}

void
DebuggerCommons::updateBreakpoint(
  unsigned int aId,
  bool aEnabled,
  std::string aCondition,
  unsigned int aHitValue)
{
  checkBreakpoint(aId);
  theBreakables[aId].setEnabled(aEnabled);
  // TODO: set condition
}

void
DebuggerCommons::removeBreakpoint(unsigned int aId)
{
  checkBreakpoint(aId);
  theBreakables[aId].setSet(false);
}

bool
DebuggerCommons::canBreak()
{
  return !theExecEval;
}

bool
DebuggerCommons::mustBreak(SuspensionCause& aCause)
{
  if (theBreak) {
    aCause = CAUSE_STEP;
    return true;
  } else if (theStepping) {
    std::size_t lSize = theIteratorStack.size();

    // either we meet the step condition
    if (lSize <= theBreakCondition) {
      // reset the break conditions
      theBreakCondition = 0;
      theStepping = false;
      return true;
    }
    // or we have stepped over from a function declaration breakpoint
    // we have for sure at least the following stack of debug iterators:
    // MainModule DI -> FunctionCall DI -> FunctionDecl DI -> current DI
    if (lSize > 3 && lSize == theBreakCondition + 1 && theIteratorStack.at(lSize - 2)->getDebuggerParent() == NULL) {
      // reset the break conditions
      theBreakCondition = 0;
      theStepping = false;
      return true;
    }
    // or we have stepped over and we reached another variable declaration
    // TODO: still to check and stop only at declarations on the same level
    if (lSize <= theBreakCondition && theIteratorStack.back()->isVarDeclaration()) {
      // reset the break conditions
      theBreakCondition = 0;
      theStepping = false;
      return true;
    }
  }

  return false;
}

bool
DebuggerCommons::hasToBreakAt(QueryLoc aLocation)
{
  adjustLocationFilePath(aLocation);

  BreakableIdMap::const_iterator lIter = theBreakableIDs.find(aLocation);
  if (lIter == theBreakableIDs.end()) {
    return false;
  }

  Breakable lBreakable = theBreakables[lIter->second];
  return lBreakable.isSet() && lBreakable.isEnabled();
}

bool
DebuggerCommons::hasToBreakAt(const DebugIterator* aIter)
{
  return false;
}

void
DebuggerCommons::setBreak(bool lBreak, SuspensionCause aCause)
{
#ifndef NDEBUG
  //Check preconditions
  ZORBA_ASSERT(lBreak ? aCause != 0 : true);
#endif // NDEBUG
  theBreak = lBreak;
  theCause = aCause;
#ifndef NDEBUG
  // Check post conditions
  ZORBA_ASSERT(theBreak == lBreak);
  ZORBA_ASSERT(theCause == aCause);
#endif //NDEBUG
}

void
DebuggerCommons::setCurrentIterator(const DebugIterator* aIterator)
{
  // don't modify the iterator stack during expression evaluation
  if (theExecEval) {
    return;
  }

  const DebugIterator* lParent = aIterator->getDebuggerParent();

  // when the stack is empty (main module debug iterator) or
  // when the parent is NULL but not a variable declaration (function declaration iterator) or
  // when the parent is the last in the stack
  if (theIteratorStack.empty() ||
      (lParent == NULL && !aIterator->isVarDeclaration()) ||
      theIteratorStack.back() == lParent) {
    theIteratorStack.push_back((DebugIterator*)aIterator);
    return;
  }

  // avoid multiple calls to this function
  // recursive functions always insert at least 2 iterators
  if (theIteratorStack.back() == aIterator) {
    return;
  }

  // now we remove the iterators from the stack until we find the parent
  theIteratorStack.pop_back();
  while (!theIteratorStack.empty()) {
    if (theIteratorStack.back() == aIterator->getDebuggerParent()) {
      theIteratorStack.push_back((DebugIterator*)aIterator);
      return;
    }
    theIteratorStack.pop_back();
  }

  // noe the stack is empty, so push this iterator in the stack
  theIteratorStack.push_back((DebugIterator*)aIterator);
}

const DebugIterator*
DebuggerCommons::getCurrentIterator() const
{
  if (theIteratorStack.empty()) {
    return NULL;
  }
  return theIteratorStack.back();
}

void
DebuggerCommons::makeStepOver()
{
  theStepping = true;
  if (!theIteratorStack.empty()) {
    theBreakCondition = theIteratorStack.size();
  } else {
    theBreakCondition = 0;
  }
}

void DebuggerCommons::makeStepOut()
{
  theStepping = true;
  if (!theIteratorStack.empty()) {
    theBreakCondition = theIteratorStack.size() - 1;
  } else {
    theBreakCondition = 0;
  }
}

void
DebuggerCommons::setPlanState(PlanState* aPlanState)
{
  thePlanState = aPlanState;
  //Check postconditions
  ZORBA_ASSERT(thePlanState == aPlanState);
}

void
DebuggerCommons::setDebugIteratorState(DebugIteratorState* aState)
{
  theDebugIteratorState = aState;
  //Check postconditions
  ZORBA_ASSERT(theDebugIteratorState == aState);
}

std::list<std::pair<zstring, zstring> >
DebuggerCommons::eval(const zstring& aExpr, Zorba_SerializerOptions& aSerOpts)
{
  theExecEval = true;
  zstring lStore = aExpr;
  GlobalEnvironment::getInstance().getItemFactory()->createString(theEvalItem,
                                                                  lStore);
  std::list<std::pair<zstring, zstring> > lRes =
    theIteratorStack.back()->eval(thePlanState, &aSerOpts);

  theExecEval = false;
  return lRes;
}

store::Item_t
DebuggerCommons::getEvalItem()
{
  return theEvalItem;
}

void
DebuggerCommons::addModuleUriMapping(std::string aUri, std::string aFileUri)
{
  ZORBA_ASSERT(theUriFileMappingMap.find(aUri) == theUriFileMappingMap.end());
  theUriFileMappingMap.insert(
    std::pair<std::string, std::string>(aUri, aFileUri));
  ZORBA_ASSERT(theUriFileMappingMap.find(aUri) != theUriFileMappingMap.end());
}

std::string
DebuggerCommons::getFilepathOfURI(const std::string& aUri) const
{
  std::map<std::string, std::string>::const_iterator lIter;
  lIter = theUriFileMappingMap.find(aUri);
  zstring lString;
  if (lIter == theUriFileMappingMap.end())
  {
    lString = aUri;
  }
  else
  {
    lString = lIter->second;
  }
  zstring lRes;
  URI::decode_file_URI(lString, lRes);
  return lRes.str();
}

void
DebuggerCommons::addBreakable(Breakable& aBreakable)
{
  adjustLocationFilePath(aBreakable.getLocation());

  unsigned int lId = theBreakables.size();
  theBreakables.push_back(aBreakable);
  theBreakableIDs[aBreakable.getLocation()] = lId;
}

void
DebuggerCommons::pushStackFrame(QueryLoc aLocation, std::string& aFunctionName)
{
  theStackTrace.push_back(std::pair<QueryLoc, std::string>(aLocation, aFunctionName));
}

void
DebuggerCommons::popStackFrame()
{
  theStackTrace.pop_back();
}

std::vector<std::pair<QueryLoc, std::string> >
DebuggerCommons::getStackFrames() const
{
  return theStackTrace;
}

void
DebuggerCommons::adjustLocationFilePath(QueryLoc& aLocation)
{
  if (aLocation.getFilename().substr(0, 7) == "file://") {
    // adjust the file paths by removing the schema and encoding
    zstring lOldFilename(aLocation.getFilename());
    const String lNewFilename = URIHelper::decodeFileURI(lOldFilename.str());
    aLocation.setFilename(lNewFilename.str());
  }
}

} // namespace zorba
<|endoftext|>


<commit_before>#include "doofit/plotting/Plot/Plot.h"

// STL
#include <string>
#include <sstream>
#include <vector>

// boost
#include <boost/regex.hpp>

// ROOT
#include "TIterator.h"

// from RooFit
#include "RooArgList.h"
#include "RooAbsRealLValue.h"
#include "RooAbsData.h"
#include "RooAbsPdf.h"
#include "RooPlot.h"

// from Project
#include "doocore/io/MsgStream.h"
#include "doocore/lutils/lutils.h"
#include "doofit/plotting/Plot/PlotConfig.h"

using namespace ROOT;
using namespace RooFit;
using namespace doocore::io;

namespace doofit {
namespace plotting {

Plot::Plot(const PlotConfig& cfg_plot, const RooAbsRealLValue& dimension, const RooAbsData& dataset, const RooArgList& pdfs, const std::string& plot_name)
: config_plot_(cfg_plot),
  dimension_(dimension),
  datasets_(),
  plot_name_(plot_name)
{
  datasets_.push_back(&dataset);
  pdf_ = dynamic_cast<RooAbsPdf*>(pdfs.first());

  if (&dimension_ == NULL) {
    serr << "Plot::Plot(): Dimension is invalid." << endmsg;
    throw 1;
  }
  if (datasets_.front() == NULL) {
    serr << "Plot::Plot(): Dataset is invalid." << endmsg;
    throw 1;
  }
  if (plot_name_ == "") {
    plot_name_ = dimension_.GetName();
  }

  for (int i=1; i<pdfs.getSize(); ++i) {
    RooAbsArg* sub_arg = pdfs.at(i);
    const RooAbsPdf* sub_pdf = dynamic_cast<RooAbsPdf*>(sub_arg);

    if (sub_pdf != NULL) {
      components_.push_back(RooArgSet(*sub_pdf));
    }
  }
}

Plot::Plot(const PlotConfig& cfg_plot, const RooAbsRealLValue& dimension, const RooAbsData& dataset, const RooAbsPdf& pdf, const std::vector<std::string>& components, const std::string& plot_name)
: config_plot_(cfg_plot),
  dimension_(dimension),
  datasets_(),
  plot_name_(plot_name)
{
  datasets_.push_back(&dataset);
  pdf_ = &pdf;

  if (pdf_ == NULL) {
    serr << "Plot::Plot(): Main PDF is invalid." << endmsg;
    throw 1;
  }
  if (&dimension_ == NULL) {
    serr << "Plot::Plot(): Dimension is invalid." << endmsg;
    throw 1;
  }
  if (datasets_.front() == NULL) {
    serr << "Plot::Plot(): Dataset is invalid." << endmsg;
    throw 1;
  }
  if (plot_name_ == "") {
    plot_name_ = dimension_.GetName();
  }

  // iterate over sub PDFs and match supplied regular expressions
  RooArgSet nodes;
  pdf.branchNodeServerList(&nodes);

  for (std::vector<std::string>::const_iterator it = components.begin();
       it != components.end(); ++it) {
    boost::regex r(*it);
    components_.push_back(RooArgSet());

    TIterator* it_nodes = nodes.createIterator();
    RooAbsArg* node = NULL;

    while ((node = dynamic_cast<RooAbsArg*>(it_nodes->Next()))) {
      RooAbsPdf* pdf_node = dynamic_cast<RooAbsPdf*>(node);
      if (pdf_node != NULL) {
        std::string pdf_name = pdf_node->GetName();

        // exclude resolution models generated by RooFit and match the rest
        if (pdf_name.find("_conv_") == -1 && regex_match(pdf_name,r)) {
          components_.back().add(*pdf_node);
        }
      }
    }
    delete it_nodes;
  }
}

void Plot::PlotHandler(ScaleType sc_y, std::string suffix) const {
  if (suffix == "") suffix = "_log";

  std::string plot_name = plot_name_;

  std::stringstream log_plot_name_sstr;
  log_plot_name_sstr << plot_name << suffix;
  std::string log_plot_name = log_plot_name_sstr.str();

  std::stringstream pull_plot_sstr;
  pull_plot_sstr << plot_name << "_pull";
  std::string pull_plot_name = pull_plot_sstr.str();

  std::stringstream log_pull_plot_sstr;
  log_pull_plot_sstr << plot_name << "_pull" << suffix;
  std::string log_pull_plot_name = log_pull_plot_sstr.str();

  sinfo << "Plotting " << dimension_.GetName() << " into " << config_plot_.plot_directory() << plot_name << endmsg;

  doocore::lutils::setStyle("LHCb");

  RooCmdArg range_arg;
  if (!dimension_.hasMin() && !dimension_.hasMax()) {
    double min, max;

    // ugly const_cast because RooFit is stupid (RooDataSet::getRange needs non-const RooRealVar)
    RooRealVar* dimension_non_const = const_cast<RooRealVar*>(dynamic_cast<const RooRealVar*>(&dimension_));
    datasets_.front()->getRange(*dimension_non_const, min, max);

    double min_t, max_t;
    for (std::vector<const RooAbsData*>::const_iterator it = datasets_.begin()+1;
         it != datasets_.end(); ++it) {
      (*it)->getRange(*dimension_non_const, min_t, max_t);
      if (min_t < min) min = min_t;
      if (max_t > max) max = max_t;
    }

    range_arg = Range(min, max);
  }
  RooPlot* plot_frame = dimension_.frame(range_arg);

  for (std::vector<const RooAbsData*>::const_iterator it = datasets_.begin();
       it != datasets_.end(); ++it) {
    (*it)->plotOn(plot_frame/*, Rescale(1.0/(*it)->sumEntries())*/);
  }

  config_plot_.OnDemandOpenPlotStack();
  if (pdf_ != NULL) {
    RooPlot* plot_frame_pull = dimension_.frame(range_arg);
    for (std::vector<const RooAbsData*>::const_iterator it = datasets_.begin();
         it != datasets_.end(); ++it) {
      (*it)->plotOn(plot_frame_pull);
    }

    // I feel so tupid doing this but apparently RooFit leaves me no other way...
    RooCmdArg arg1, arg2, arg3, arg4, arg5, arg6, arg7;
    if (plot_args_.size() > 0) arg1 = plot_args_[0];
    if (plot_args_.size() > 1) arg2 = plot_args_[1];
    if (plot_args_.size() > 2) arg3 = plot_args_[2];
    if (plot_args_.size() > 3) arg4 = plot_args_[3];
    if (plot_args_.size() > 4) arg5 = plot_args_[4];
    if (plot_args_.size() > 5) arg6 = plot_args_[5];
    if (plot_args_.size() > 6) arg7 = plot_args_[6];

    int i=1;
    for (std::vector<RooArgSet>::const_iterator it = components_.begin();
         it != components_.end(); ++it) {
      if (it->getSize() > 0) {
        sinfo << "Plotting component " << it->first()->GetName() << endmsg;
        pdf_->plotOn(plot_frame, Components(*it), LineColor(config_plot_.GetPdfLineColor(i)), LineStyle(config_plot_.GetPdfLineStyle(i)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        pdf_->plotOn(plot_frame_pull, Components(*it), LineColor(config_plot_.GetPdfLineColor(i)), LineStyle(config_plot_.GetPdfLineStyle(i)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        ++i;
      }
    }

    pdf_->plotOn(plot_frame, LineColor(config_plot_.GetPdfLineColor(0)), LineStyle(config_plot_.GetPdfLineStyle(0)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    pdf_->plotOn(plot_frame_pull, LineColor(config_plot_.GetPdfLineColor(0)), LineStyle(config_plot_.GetPdfLineStyle(0)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    plot_frame_pull->SetMinimum(0.5);
    plot_frame_pull->SetMaximum(1.3*plot_frame_pull->GetMaximum());

    if (sc_y == kLinear || sc_y == kBoth) {
      doocore::lutils::PlotPulls(pull_plot_name, plot_frame_pull, config_plot_.plot_directory(), false, false, true, NULL);
      doocore::lutils::PlotPulls("AllPlots", plot_frame_pull, config_plot_.plot_directory(), false, false, true, NULL);
    }
    if (sc_y == kLogarithmic || sc_y == kBoth) {
      doocore::lutils::PlotPulls(log_pull_plot_name, plot_frame_pull, config_plot_.plot_directory(), true, false, true, NULL);
      doocore::lutils::PlotPulls("AllPlots", plot_frame_pull, config_plot_.plot_directory(), true, false, true, NULL);
    }

    delete plot_frame_pull;
  }
  plot_frame->SetMinimum(0.5);
  plot_frame->SetMaximum(1.3*plot_frame->GetMaximum());
  if (sc_y == kLinear || sc_y == kBoth) {
    doocore::lutils::PlotSimple(plot_name, plot_frame, config_plot_.plot_directory(), false);
    doocore::lutils::PlotSimple("AllPlots", plot_frame, config_plot_.plot_directory(), false);
  }
  if (sc_y == kLogarithmic || sc_y == kBoth) {
    doocore::lutils::PlotSimple(log_plot_name, plot_frame, config_plot_.plot_directory(), true);
    doocore::lutils::PlotSimple("AllPlots", plot_frame, config_plot_.plot_directory(), true);
  }

  delete plot_frame;
}

Plot::~Plot() {}

} // namespace plotting
} // namespace doofit
<commit_msg>Plotting: for all plots gaussian plots should go into AllPlots.pdf<commit_after>#include "doofit/plotting/Plot/Plot.h"

// STL
#include <string>
#include <sstream>
#include <vector>

// boost
#include <boost/regex.hpp>

// ROOT
#include "TIterator.h"

// from RooFit
#include "RooArgList.h"
#include "RooAbsRealLValue.h"
#include "RooAbsData.h"
#include "RooAbsPdf.h"
#include "RooPlot.h"

// from Project
#include "doocore/io/MsgStream.h"
#include "doocore/lutils/lutils.h"
#include "doofit/plotting/Plot/PlotConfig.h"

using namespace ROOT;
using namespace RooFit;
using namespace doocore::io;

namespace doofit {
namespace plotting {

Plot::Plot(const PlotConfig& cfg_plot, const RooAbsRealLValue& dimension, const RooAbsData& dataset, const RooArgList& pdfs, const std::string& plot_name)
: config_plot_(cfg_plot),
  dimension_(dimension),
  datasets_(),
  plot_name_(plot_name)
{
  datasets_.push_back(&dataset);
  pdf_ = dynamic_cast<RooAbsPdf*>(pdfs.first());

  if (&dimension_ == NULL) {
    serr << "Plot::Plot(): Dimension is invalid." << endmsg;
    throw 1;
  }
  if (datasets_.front() == NULL) {
    serr << "Plot::Plot(): Dataset is invalid." << endmsg;
    throw 1;
  }
  if (plot_name_ == "") {
    plot_name_ = dimension_.GetName();
  }

  for (int i=1; i<pdfs.getSize(); ++i) {
    RooAbsArg* sub_arg = pdfs.at(i);
    const RooAbsPdf* sub_pdf = dynamic_cast<RooAbsPdf*>(sub_arg);

    if (sub_pdf != NULL) {
      components_.push_back(RooArgSet(*sub_pdf));
    }
  }
}

Plot::Plot(const PlotConfig& cfg_plot, const RooAbsRealLValue& dimension, const RooAbsData& dataset, const RooAbsPdf& pdf, const std::vector<std::string>& components, const std::string& plot_name)
: config_plot_(cfg_plot),
  dimension_(dimension),
  datasets_(),
  plot_name_(plot_name)
{
  datasets_.push_back(&dataset);
  pdf_ = &pdf;

  if (pdf_ == NULL) {
    serr << "Plot::Plot(): Main PDF is invalid." << endmsg;
    throw 1;
  }
  if (&dimension_ == NULL) {
    serr << "Plot::Plot(): Dimension is invalid." << endmsg;
    throw 1;
  }
  if (datasets_.front() == NULL) {
    serr << "Plot::Plot(): Dataset is invalid." << endmsg;
    throw 1;
  }
  if (plot_name_ == "") {
    plot_name_ = dimension_.GetName();
  }

  // iterate over sub PDFs and match supplied regular expressions
  RooArgSet nodes;
  pdf.branchNodeServerList(&nodes);

  for (std::vector<std::string>::const_iterator it = components.begin();
       it != components.end(); ++it) {
    boost::regex r(*it);
    components_.push_back(RooArgSet());

    TIterator* it_nodes = nodes.createIterator();
    RooAbsArg* node = NULL;

    while ((node = dynamic_cast<RooAbsArg*>(it_nodes->Next()))) {
      RooAbsPdf* pdf_node = dynamic_cast<RooAbsPdf*>(node);
      if (pdf_node != NULL) {
        std::string pdf_name = pdf_node->GetName();

        // exclude resolution models generated by RooFit and match the rest
        if (pdf_name.find("_conv_") == -1 && regex_match(pdf_name,r)) {
          components_.back().add(*pdf_node);
        }
      }
    }
    delete it_nodes;
  }
}

void Plot::PlotHandler(ScaleType sc_y, std::string suffix) const {
  if (suffix == "") suffix = "_log";

  std::string plot_name = plot_name_;

  std::stringstream log_plot_name_sstr;
  log_plot_name_sstr << plot_name << suffix;
  std::string log_plot_name = log_plot_name_sstr.str();

  std::stringstream pull_plot_sstr;
  pull_plot_sstr << plot_name << "_pull";
  std::string pull_plot_name = pull_plot_sstr.str();

  std::stringstream log_pull_plot_sstr;
  log_pull_plot_sstr << plot_name << "_pull" << suffix;
  std::string log_pull_plot_name = log_pull_plot_sstr.str();

  sinfo << "Plotting " << dimension_.GetName() << " into " << config_plot_.plot_directory() << plot_name << endmsg;

  doocore::lutils::setStyle("LHCb");

  RooCmdArg range_arg;
  if (!dimension_.hasMin() && !dimension_.hasMax()) {
    double min, max;

    // ugly const_cast because RooFit is stupid (RooDataSet::getRange needs non-const RooRealVar)
    RooRealVar* dimension_non_const = const_cast<RooRealVar*>(dynamic_cast<const RooRealVar*>(&dimension_));
    datasets_.front()->getRange(*dimension_non_const, min, max);

    double min_t, max_t;
    for (std::vector<const RooAbsData*>::const_iterator it = datasets_.begin()+1;
         it != datasets_.end(); ++it) {
      (*it)->getRange(*dimension_non_const, min_t, max_t);
      if (min_t < min) min = min_t;
      if (max_t > max) max = max_t;
    }

    range_arg = Range(min, max);
  }
  RooPlot* plot_frame = dimension_.frame(range_arg);

  for (std::vector<const RooAbsData*>::const_iterator it = datasets_.begin();
       it != datasets_.end(); ++it) {
    (*it)->plotOn(plot_frame/*, Rescale(1.0/(*it)->sumEntries())*/);
  }

  config_plot_.OnDemandOpenPlotStack();
  if (pdf_ != NULL) {
    RooPlot* plot_frame_pull = dimension_.frame(range_arg);
    for (std::vector<const RooAbsData*>::const_iterator it = datasets_.begin();
         it != datasets_.end(); ++it) {
      (*it)->plotOn(plot_frame_pull);
    }

    // I feel so tupid doing this but apparently RooFit leaves me no other way...
    RooCmdArg arg1, arg2, arg3, arg4, arg5, arg6, arg7;
    if (plot_args_.size() > 0) arg1 = plot_args_[0];
    if (plot_args_.size() > 1) arg2 = plot_args_[1];
    if (plot_args_.size() > 2) arg3 = plot_args_[2];
    if (plot_args_.size() > 3) arg4 = plot_args_[3];
    if (plot_args_.size() > 4) arg5 = plot_args_[4];
    if (plot_args_.size() > 5) arg6 = plot_args_[5];
    if (plot_args_.size() > 6) arg7 = plot_args_[6];

    int i=1;
    for (std::vector<RooArgSet>::const_iterator it = components_.begin();
         it != components_.end(); ++it) {
      if (it->getSize() > 0) {
        sinfo << "Plotting component " << it->first()->GetName() << endmsg;
        pdf_->plotOn(plot_frame, Components(*it), LineColor(config_plot_.GetPdfLineColor(i)), LineStyle(config_plot_.GetPdfLineStyle(i)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        pdf_->plotOn(plot_frame_pull, Components(*it), LineColor(config_plot_.GetPdfLineColor(i)), LineStyle(config_plot_.GetPdfLineStyle(i)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        ++i;
      }
    }

    pdf_->plotOn(plot_frame, LineColor(config_plot_.GetPdfLineColor(0)), LineStyle(config_plot_.GetPdfLineStyle(0)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    pdf_->plotOn(plot_frame_pull, LineColor(config_plot_.GetPdfLineColor(0)), LineStyle(config_plot_.GetPdfLineStyle(0)), arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    plot_frame_pull->SetMinimum(0.5);
    plot_frame_pull->SetMaximum(1.3*plot_frame_pull->GetMaximum());

    if (sc_y == kLinear || sc_y == kBoth) {
      doocore::lutils::PlotPulls(pull_plot_name, plot_frame_pull, config_plot_.plot_directory(), false, false, true, NULL);
      doocore::lutils::PlotPulls("AllPlots", plot_frame_pull, config_plot_.plot_directory(), false, false, true, NULL, "");
    }
    if (sc_y == kLogarithmic || sc_y == kBoth) {
      doocore::lutils::PlotPulls(log_pull_plot_name, plot_frame_pull, config_plot_.plot_directory(), true, false, true, NULL);
      doocore::lutils::PlotPulls("AllPlots", plot_frame_pull, config_plot_.plot_directory(), true, false, true, NULL, "");
    }

    delete plot_frame_pull;
  }
  plot_frame->SetMinimum(0.5);
  plot_frame->SetMaximum(1.3*plot_frame->GetMaximum());
  if (sc_y == kLinear || sc_y == kBoth) {
    doocore::lutils::PlotSimple(plot_name, plot_frame, config_plot_.plot_directory(), false);
    doocore::lutils::PlotSimple("AllPlots", plot_frame, config_plot_.plot_directory(), false);
  }
  if (sc_y == kLogarithmic || sc_y == kBoth) {
    doocore::lutils::PlotSimple(log_plot_name, plot_frame, config_plot_.plot_directory(), true);
    doocore::lutils::PlotSimple("AllPlots", plot_frame, config_plot_.plot_directory(), true);
  }

  delete plot_frame;
}

Plot::~Plot() {}

} // namespace plotting
} // namespace doofit
<|endoftext|>


<commit_before>/****************************************************************************
 *
 * Copyright (c) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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 OWNER 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.
 *
 ****************************************************************************/

/**
 * @file vdev_posix.cpp
 *
 * POSIX-like API for virtual character device
 */

#include <px4_posix.h>
#include <px4_time.h>
#include "device.h"
#include "vfile.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define PX4_DEBUG(...)

using namespace device;

extern "C" {

struct timerData {
	sem_t &sem;
	struct timespec &ts;

	timerData(sem_t &s, struct timespec &t) : sem(s), ts(t) {}
	~timerData() {}
};

static void *timer_handler(void *data)
{
	struct timerData *td = (struct timerData *)data;

	if (td->ts.tv_sec) {
		sleep(td->ts.tv_sec);
	}
	usleep(td->ts.tv_nsec/1000);
	sem_post(&(td->sem));

	PX4_DEBUG("timer_handler: Timer expired\n");
	return 0;
}

#define PX4_MAX_FD 100
static device::file_t *filemap[PX4_MAX_FD] = {};

int px4_errno;

inline bool valid_fd(int fd)
{
	return (fd < PX4_MAX_FD && fd >= 0 && filemap[fd] != NULL);
}

int px4_open(const char *path, int flags, ...)
{
	printf("px4_open\n");
	VDev *dev = VDev::getDev(path);
	int ret = 0;
	int i;
	mode_t mode;

	if (!dev && (flags & (PX4_F_WRONLY|PX4_F_CREAT)) != 0)
	{
		va_list p;
		va_start(p, flags);
 		mode = va_arg(p, mode_t);
		va_end(p);

		// Create the file
		warnx("Creating virtual file %s\n", path);
		dev = VFile::createFile(path, mode);
	}
	if (dev) {
		for (i=0; i<PX4_MAX_FD; ++i) {
			if (filemap[i] == 0) {
				filemap[i] = new device::file_t(flags,dev,i);
				break;
			}
		}
		if (i < PX4_MAX_FD) {
			ret = dev->open(filemap[i]);
		}
		else {
			ret = -ENOENT;
		}
	}
	else {
		ret = -EINVAL;
	}
	if (ret < 0) {
		px4_errno = -ret;
		return -1;
	}
	PX4_DEBUG("px4_open fd = %d", filemap[i]->fd);
	return filemap[i]->fd;
}

int px4_close(int fd)
{
	int ret;
	if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_close fd = %d\n", fd);
		ret = dev->close(filemap[fd]);
		filemap[fd] = NULL;
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
	}
	return ret;
}

ssize_t px4_read(int fd, void *buffer, size_t buflen)
{
	int ret;
	if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_read fd = %d\n", fd);
		ret = dev->read(filemap[fd], (char *)buffer, buflen);
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
	}
	return ret;
}

ssize_t px4_write(int fd, const void *buffer, size_t buflen)
{
	int ret = PX4_ERROR;
        if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_write fd = %d\n", fd);
		ret = dev->write(filemap[fd], (const char *)buffer, buflen);
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
	}
        return ret;
}

int px4_ioctl(int fd, int cmd, unsigned long arg)
{
	int ret = PX4_ERROR;
        if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_ioctl fd = %d\n", fd);
		ret = dev->ioctl(filemap[fd], cmd, arg);
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
	}
	else {
                px4_errno = -EINVAL;
        }
        return ret;
}

int px4_poll(px4_pollfd_struct_t *fds, nfds_t nfds, int timeout)
{
	sem_t sem;
	int count = 0;
	int ret;
	unsigned int i;
	struct timespec ts;

	PX4_DEBUG("Called px4_poll timeout = %d\n", timeout);
	sem_init(&sem, 0, 0);

	// For each fd
	for (i=0; i<nfds; ++i)
	{
		fds[i].sem     = &sem;
		fds[i].revents = 0;
		fds[i].priv    = NULL;

		// If fd is valid
		if (valid_fd(fds[i].fd))
		{
			VDev *dev = (VDev *)(filemap[fds[i].fd]->vdev);;
			PX4_DEBUG("px4_poll: VDev->poll(setup) %d\n", fds[i].fd);
			ret = dev->poll(filemap[fds[i].fd], &fds[i], true);

			if (ret < 0)
				break;
		}
	}

	if (ret >= 0)
	{
		if (timeout >= 0)
		{
			pthread_t pt;
			void *res;

			ts.tv_sec = timeout/1000;
			ts.tv_nsec = (timeout % 1000)*1000;

			// Create a timer to unblock
			struct timerData td(sem, ts);
			int rv = pthread_create(&pt, NULL, timer_handler, (void *)&td);
			if (rv != 0) {
				count = -1;
				goto cleanup;
			}
			sem_wait(&sem);

			// Make sure timer thread is killed before sem goes
			// out of scope
			(void)pthread_cancel(pt);
			(void)pthread_join(pt, &res);
        	}
		else
		{
			sem_wait(&sem);
		}

		// For each fd
		for (i=0; i<nfds; ++i)
		{
			// If fd is valid
			if (valid_fd(fds[i].fd))
			{
				VDev *dev = (VDev *)(filemap[fds[i].fd]->vdev);;
				PX4_DEBUG("px4_poll: VDev->poll(teardown) %d\n", fds[i].fd);
				ret = dev->poll(filemap[fds[i].fd], &fds[i], false);

				if (ret < 0)
					break;

				if (fds[i].revents)
				count += 1;
			}
		}
	}

cleanup:
	sem_destroy(&sem);

	return count;
}

int px4_fsync(int fd)
{
	return 0;
}

void px4_show_devices()
{
	VDev::showDevices();
}

void px4_show_topics()
{
	VDev::showTopics();
}

void px4_show_files()
{
	VDev::showFiles();
}

const char * px4_get_device_names(unsigned int *handle)
{
	return VDev::devList(handle);
}

const char * px4_get_topic_names(unsigned int *handle)
{
	return VDev::topicList(handle);
}

}

<commit_msg>POSIX: fixed return values to be posix compliant<commit_after>/****************************************************************************
 *
 * Copyright (c) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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 OWNER 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.
 *
 ****************************************************************************/

/**
 * @file vdev_posix.cpp
 *
 * POSIX-like API for virtual character device
 */

#include <px4_posix.h>
#include <px4_time.h>
#include "device.h"
#include "vfile.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define PX4_DEBUG(...)

using namespace device;

extern "C" {

struct timerData {
	sem_t &sem;
	struct timespec &ts;

	timerData(sem_t &s, struct timespec &t) : sem(s), ts(t) {}
	~timerData() {}
};

static void *timer_handler(void *data)
{
	struct timerData *td = (struct timerData *)data;

	if (td->ts.tv_sec) {
		sleep(td->ts.tv_sec);
	}
	usleep(td->ts.tv_nsec/1000);
	sem_post(&(td->sem));

	PX4_DEBUG("timer_handler: Timer expired\n");
	return 0;
}

#define PX4_MAX_FD 100
static device::file_t *filemap[PX4_MAX_FD] = {};

int px4_errno;

inline bool valid_fd(int fd)
{
	return (fd < PX4_MAX_FD && fd >= 0 && filemap[fd] != NULL);
}

int px4_open(const char *path, int flags, ...)
{
	printf("px4_open\n");
	VDev *dev = VDev::getDev(path);
	int ret = 0;
	int i;
	mode_t mode;

	if (!dev && (flags & (PX4_F_WRONLY|PX4_F_CREAT)) != 0)
	{
		va_list p;
		va_start(p, flags);
 		mode = va_arg(p, mode_t);
		va_end(p);

		// Create the file
		warnx("Creating virtual file %s\n", path);
		dev = VFile::createFile(path, mode);
	}
	if (dev) {
		for (i=0; i<PX4_MAX_FD; ++i) {
			if (filemap[i] == 0) {
				filemap[i] = new device::file_t(flags,dev,i);
				break;
			}
		}
		if (i < PX4_MAX_FD) {
			ret = dev->open(filemap[i]);
		}
		else {
			ret = -ENOENT;
		}
	}
	else {
		ret = -EINVAL;
	}
	if (ret < 0) {
		px4_errno = -ret;
		return -1;
	}
	PX4_DEBUG("px4_open fd = %d", filemap[i]->fd);
	return filemap[i]->fd;
}

int px4_close(int fd)
{
	int ret;
	if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_close fd = %d\n", fd);
		ret = dev->close(filemap[fd]);
		filemap[fd] = NULL;
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
		ret = PX4_ERROR;
	}
	return ret;
}

ssize_t px4_read(int fd, void *buffer, size_t buflen)
{
	int ret;
	if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_read fd = %d\n", fd);
		ret = dev->read(filemap[fd], (char *)buffer, buflen);
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
		ret = PX4_ERROR;
	}
	return ret;
}

ssize_t px4_write(int fd, const void *buffer, size_t buflen)
{
	int ret;
        if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_write fd = %d\n", fd);
		ret = dev->write(filemap[fd], (const char *)buffer, buflen);
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
		ret = PX4_ERROR;
	}
        return ret;
}

int px4_ioctl(int fd, int cmd, unsigned long arg)
{
	int ret = 0;
        if (valid_fd(fd)) {
		VDev *dev = (VDev *)(filemap[fd]->vdev);
		PX4_DEBUG("px4_ioctl fd = %d\n", fd);
		ret = dev->ioctl(filemap[fd], cmd, arg);
	}
	else {
                ret = -EINVAL;
        }
	if (ret < 0) {
		px4_errno = -ret;
	}

        return (ret == 0) ? PX4_OK : PX4_ERROR;
}

int px4_poll(px4_pollfd_struct_t *fds, nfds_t nfds, int timeout)
{
	sem_t sem;
	int count = 0;
	int ret;
	unsigned int i;
	struct timespec ts;

	PX4_DEBUG("Called px4_poll timeout = %d\n", timeout);
	sem_init(&sem, 0, 0);

	// For each fd
	for (i=0; i<nfds; ++i)
	{
		fds[i].sem     = &sem;
		fds[i].revents = 0;
		fds[i].priv    = NULL;

		// If fd is valid
		if (valid_fd(fds[i].fd))
		{
			VDev *dev = (VDev *)(filemap[fds[i].fd]->vdev);;
			PX4_DEBUG("px4_poll: VDev->poll(setup) %d\n", fds[i].fd);
			ret = dev->poll(filemap[fds[i].fd], &fds[i], true);

			if (ret < 0)
				break;
		}
	}

	if (ret >= 0)
	{
		if (timeout >= 0)
		{
			pthread_t pt;
			void *res;

			ts.tv_sec = timeout/1000;
			ts.tv_nsec = (timeout % 1000)*1000;

			// Create a timer to unblock
			struct timerData td(sem, ts);
			int rv = pthread_create(&pt, NULL, timer_handler, (void *)&td);
			if (rv != 0) {
				count = -1;
				goto cleanup;
			}
			sem_wait(&sem);

			// Make sure timer thread is killed before sem goes
			// out of scope
			(void)pthread_cancel(pt);
			(void)pthread_join(pt, &res);
        	}
		else
		{
			sem_wait(&sem);
		}

		// For each fd
		for (i=0; i<nfds; ++i)
		{
			// If fd is valid
			if (valid_fd(fds[i].fd))
			{
				VDev *dev = (VDev *)(filemap[fds[i].fd]->vdev);;
				PX4_DEBUG("px4_poll: VDev->poll(teardown) %d\n", fds[i].fd);
				ret = dev->poll(filemap[fds[i].fd], &fds[i], false);

				if (ret < 0)
					break;

				if (fds[i].revents)
				count += 1;
			}
		}
	}

cleanup:
	sem_destroy(&sem);

	return count;
}

int px4_fsync(int fd)
{
	return 0;
}

void px4_show_devices()
{
	VDev::showDevices();
}

void px4_show_topics()
{
	VDev::showTopics();
}

void px4_show_files()
{
	VDev::showFiles();
}

const char * px4_get_device_names(unsigned int *handle)
{
	return VDev::devList(handle);
}

const char * px4_get_topic_names(unsigned int *handle)
{
	return VDev::topicList(handle);
}

}

<|endoftext|>


<commit_before>/*++
Copyright (c) 2006 Microsoft Corporation

Module Name:

    elim_bounds.cpp

Abstract:

    <abstract>

Author:

    Leonardo de Moura (leonardo) 2008-06-28.

Revision History:

--*/
#include"elim_bounds.h"
#include"used_vars.h"
#include"obj_hashtable.h"
#include"var_subst.h"
#include"ast_pp.h"

elim_bounds::elim_bounds(ast_manager & m):
    m_manager(m),
    m_util(m) {
}

/**
   \brief Find bounds of the form

   (<= x k)
   (<= (+ x (* -1 y)) k)
   (<= (+ x (* -1 t)) k)
   (<= (+ t (* -1 x)) k)

   x and y are a bound variables, t is a ground term and k is a numeral

   It also detects >=, and the atom can be negated.
*/
bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) {
    upper    = 0;
    lower    = 0;
    bool neg = false;
    if (m_manager.is_not(n)) {
        n   = to_app(n)->get_arg(0);
        neg = true;
    }

    bool le  = false;
    if (m_util.is_le(n)) {
        SASSERT(m_util.is_numeral(to_app(n)->get_arg(1)));
        n  = to_app(n)->get_arg(0);
        le = true;
    }
    else if (m_util.is_ge(n)) {
        SASSERT(m_util.is_numeral(to_app(n)->get_arg(1)));
        n  = to_app(n)->get_arg(0);
        le = false;
    }
    else {
        return false;
    }

    if (neg)
        le = !le;

    if (is_var(n)) {
        upper = to_var(n);
    }
    else if (m_util.is_add(n) && to_app(n)->get_num_args() == 2) {
        expr * arg1 = to_app(n)->get_arg(0);
        expr * arg2 = to_app(n)->get_arg(1);
        if (is_var(arg1))
            upper   = to_var(arg1);
        else if (!is_ground(arg1))
            return false;
        rational k;
        bool is_int;
        if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) {
            arg2    = to_app(arg2)->get_arg(1);
            if (is_var(arg2))
                lower = to_var(arg2);
            else if (!is_ground(arg2))
                return false; // not supported
        }
        else {
            return false; // not supported
        }
    }
    else {
        return false;
    }

    if (!le)
        std::swap(upper, lower);

    return true;
}

bool elim_bounds::is_bound(expr * n) {
    var * lower, * upper;
    return is_bound(n, lower, upper);
}

void elim_bounds::operator()(quantifier * q, expr_ref & r) {
    if (!q->is_forall()) {
        r = q;
        return;
    }
    expr * n = q->get_expr();
    ptr_buffer<expr> atoms;
    if (m_manager.is_or(n))
        atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
    else
        atoms.push_back(n);
    used_vars          m_used_vars;
    // collect non-candidates
    unsigned sz = atoms.size();
    for (unsigned i = 0; i < sz; i++) {
        expr * a = atoms[i];
        if (!is_bound(a))
            m_used_vars.process(a);
    }
    if (m_used_vars.uses_all_vars(q->get_num_decls())) {
        r = q;
        return;
    }
    // collect candidates
    obj_hashtable<var> m_lowers;
    obj_hashtable<var> m_uppers;
    obj_hashtable<var> m_candidate_set;
    ptr_buffer<var>    m_candidates;
#define ADD_CANDIDATE(V) if (!m_lowers.contains(V) && !m_uppers.contains(V)) { m_candidate_set.insert(V); m_candidates.push_back(V); }
    for (unsigned i = 0; i < sz; i++) {
        expr * a    = atoms[i];
        var * lower = 0;
        var * upper = 0;
        if (is_bound(a, lower, upper)) {
            if (lower != 0 && !m_used_vars.contains(lower->get_idx())) {
                ADD_CANDIDATE(lower);
                m_lowers.insert(lower);
            }
            if (upper != 0 && !m_used_vars.contains(upper->get_idx())) {
                ADD_CANDIDATE(upper);
                m_uppers.insert(upper);
            }
        }
    }
    TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";);
    // remove candidates that have lower and upper bounds
    for (unsigned i = 0; i < m_candidates.size(); i++) {
        var * v = m_candidates[i];
        if (m_lowers.contains(v) && m_uppers.contains(v))
            m_candidate_set.erase(v);
    }
    TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";);
    if (m_candidate_set.empty()) {
        r = q;
        return;
    }
    // remove bounds that contain variables in m_candidate_set
    unsigned j = 0;
    for (unsigned i = 0; i < sz; i++) {
        expr * a    = atoms[i];
        var * lower = 0;
        var * upper = 0;
        if (is_bound(a, lower, upper) && ((lower != 0 && m_candidate_set.contains(lower)) || (upper != 0 && m_candidate_set.contains(upper))))
            continue;
        atoms[j] = a;
        j++;
    }
    atoms.resize(j);
    expr * new_body = 0;
    switch (atoms.size()) {
    case 0:
        r = m_manager.mk_false();
        return;
    case 1:
        new_body = atoms[0];
        break;
    default:
        new_body = m_manager.mk_or(atoms.size(), atoms.c_ptr());
        break;
    }
    quantifier_ref new_q(m_manager);
    new_q = m_manager.update_quantifier(q, new_body);
    elim_unused_vars(m_manager, new_q, r);
    TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
}

bool elim_bounds_star::visit_quantifier(quantifier * q) {
    if (!q->is_forall() || q->get_num_patterns() != 0)
        return true;
    bool visited         = true;
    visit(q->get_expr(), visited);
    return visited;
}

void elim_bounds_star::reduce1_quantifier(quantifier * q) {
    if (!q->is_forall() || q->get_num_patterns() != 0) {
        cache_result(q, q, 0);
        return;
    }
    quantifier_ref new_q(m);
    expr * new_body = 0;
    proof * new_pr;
    get_cached(q->get_expr(), new_body, new_pr);
    new_q = m.update_quantifier(q, new_body);
    expr_ref r(m);
    m_elim(new_q, r);
    if (q == r.get()) {
        cache_result(q, q, 0);
        return;
    }
    proof_ref pr(m);
    if (m.fine_grain_proofs())
        pr = m.mk_rewrite(q, r); // TODO: improve justification
    cache_result(q, r, pr);
}

<commit_msg>fix bounds elimination bug for nested quantifiers. Codeplex post z3: A formula and its negation are unsatisfiable<commit_after>/*++
Copyright (c) 2006 Microsoft Corporation

Module Name:

    elim_bounds.cpp

Abstract:

    <abstract>

Author:

    Leonardo de Moura (leonardo) 2008-06-28.

Revision History:

--*/
#include"elim_bounds.h"
#include"used_vars.h"
#include"obj_hashtable.h"
#include"var_subst.h"
#include"ast_pp.h"

elim_bounds::elim_bounds(ast_manager & m):
    m_manager(m),
    m_util(m) {
}

/**
   \brief Find bounds of the form

   (<= x k)
   (<= (+ x (* -1 y)) k)
   (<= (+ x (* -1 t)) k)
   (<= (+ t (* -1 x)) k)

   x and y are a bound variables, t is a ground term and k is a numeral

   It also detects >=, and the atom can be negated.
*/
bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) {
    upper    = 0;
    lower    = 0;
    bool neg = false;
    if (m_manager.is_not(n)) {
        n   = to_app(n)->get_arg(0);
        neg = true;
    }

    bool le  = false;
    if (m_util.is_le(n)) {
        SASSERT(m_util.is_numeral(to_app(n)->get_arg(1)));
        n  = to_app(n)->get_arg(0);
        le = true;
    }
    else if (m_util.is_ge(n)) {
        SASSERT(m_util.is_numeral(to_app(n)->get_arg(1)));
        n  = to_app(n)->get_arg(0);
        le = false;
    }
    else {
        return false;
    }

    if (neg)
        le = !le;

    if (is_var(n)) {
        upper = to_var(n);
    }
    else if (m_util.is_add(n) && to_app(n)->get_num_args() == 2) {
        expr * arg1 = to_app(n)->get_arg(0);
        expr * arg2 = to_app(n)->get_arg(1);
        if (is_var(arg1))
            upper   = to_var(arg1);
        else if (!is_ground(arg1))
            return false;
        rational k;
        bool is_int;
        if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) {
            arg2    = to_app(arg2)->get_arg(1);
            if (is_var(arg2))
                lower = to_var(arg2);
            else if (!is_ground(arg2))
                return false; // not supported
        }
        else {
            return false; // not supported
        }
    }
    else {
        return false;
    }

    if (!le)
        std::swap(upper, lower);

    return true;
}

bool elim_bounds::is_bound(expr * n) {
    var * lower, * upper;
    return is_bound(n, lower, upper);
}

void elim_bounds::operator()(quantifier * q, expr_ref & r) {
    if (!q->is_forall()) {
        r = q;
        return;
    }
    expr * n = q->get_expr();
    unsigned num_vars = q->get_num_decls();
    ptr_buffer<expr> atoms;
    if (m_manager.is_or(n))
        atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
    else
        atoms.push_back(n);
    used_vars          m_used_vars;
    // collect non-candidates
    unsigned sz = atoms.size();
    for (unsigned i = 0; i < sz; i++) {
        expr * a = atoms[i];
        if (!is_bound(a))
            m_used_vars.process(a);
    }
    if (m_used_vars.uses_all_vars(q->get_num_decls())) {
        r = q;
        return;
    }
    // collect candidates
    obj_hashtable<var> m_lowers;
    obj_hashtable<var> m_uppers;
    obj_hashtable<var> m_candidate_set;
    ptr_buffer<var>    m_candidates;
#define ADD_CANDIDATE(V) if (!m_lowers.contains(V) && !m_uppers.contains(V)) { m_candidate_set.insert(V); m_candidates.push_back(V); }
    for (unsigned i = 0; i < sz; i++) {
        expr * a    = atoms[i];
        var * lower = 0;
        var * upper = 0;
        if (is_bound(a, lower, upper)) {
            if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) {
                ADD_CANDIDATE(lower);
                m_lowers.insert(lower);
            }
            if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) {
                ADD_CANDIDATE(upper);
                m_uppers.insert(upper);
            }
        }
    }
    TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";);
    // remove candidates that have lower and upper bounds
    for (unsigned i = 0; i < m_candidates.size(); i++) {
        var * v = m_candidates[i];
        if (m_lowers.contains(v) && m_uppers.contains(v))
            m_candidate_set.erase(v);
    }
    TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";);
    if (m_candidate_set.empty()) {
        r = q;
        return;
    }
    // remove bounds that contain variables in m_candidate_set
    unsigned j = 0;
    for (unsigned i = 0; i < sz; i++) {
        expr * a    = atoms[i];
        var * lower = 0;
        var * upper = 0;
        if (is_bound(a, lower, upper) && ((lower != 0 && m_candidate_set.contains(lower)) || (upper != 0 && m_candidate_set.contains(upper))))
            continue;
        atoms[j] = a;
        j++;
    }
    atoms.resize(j);
    expr * new_body = 0;
    switch (atoms.size()) {
    case 0:
        r = m_manager.mk_false();
        TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
        return;
    case 1:
        new_body = atoms[0];
        break;
    default:
        new_body = m_manager.mk_or(atoms.size(), atoms.c_ptr());
        break;
    }
    quantifier_ref new_q(m_manager);
    new_q = m_manager.update_quantifier(q, new_body);
    elim_unused_vars(m_manager, new_q, r);
    TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
}

bool elim_bounds_star::visit_quantifier(quantifier * q) {
    if (!q->is_forall() || q->get_num_patterns() != 0)
        return true;
    bool visited         = true;
    visit(q->get_expr(), visited);
    return visited;
}

void elim_bounds_star::reduce1_quantifier(quantifier * q) {
    if (!q->is_forall() || q->get_num_patterns() != 0) {
        cache_result(q, q, 0);
        return;
    }
    quantifier_ref new_q(m);
    expr * new_body = 0;
    proof * new_pr;
    get_cached(q->get_expr(), new_body, new_pr);
    new_q = m.update_quantifier(q, new_body);
    expr_ref r(m);
    m_elim(new_q, r);
    if (q == r.get()) {
        cache_result(q, q, 0);
        return;
    }
    proof_ref pr(m);
    if (m.fine_grain_proofs())
        pr = m.mk_rewrite(q, r); // TODO: improve justification
    cache_result(q, r, pr);
}

<|endoftext|>