<commit_before>#include <vector>
#include <string>
#include <iostream>
#include <queso/Environment.h>
#include <queso/GslVector.h>
#include <queso/GslMatrix.h>
#include <queso/VectorSpace.h>

int main(int argc, char **argv) {
  MPI_Init(&argc, &argv);

  QUESO::EnvOptionsValues options;
  options.m_numSubEnvironments = 1;
  options.m_subDisplayFileName = "debug_output";
  options.m_seed = 1.0;
  options.m_checkingLevel = 1;
  options.m_displayVerbosity = 20;

  QUESO::FullEnvironment *env = new QUESO::FullEnvironment(MPI_COMM_WORLD, "",
      "", &options);

  std::vector<std::string> names(1);
  names[0] = "my_name";
  QUESO::VectorSpace<QUESO::GslVector, QUESO::GslMatrix> vec_space(*env,
      "vec_prefix", 1, &names);

  // 1x1 diagonal matrix containing the value 3.0 on the diagonal
  QUESO::GslMatrix * diag_matrix = vec_space.newDiagMatrix(3.0);

  if ((*diag_matrix)(0,0) != 3.0) {
    std::cerr << "newDiagMatrix test failed" << std::endl;
    return 1;
  }

  if (vec_space.globalIdOfFirstComponent() != 0) {
    std::cerr << "failed globalIdOfFirstComponent test" << std::endl;
    return 1;
  }

  const QUESO::DistArray<std::string> *names_array = vec_space.componentsNamesArray();

  std::cout << "Test print: componentsNamesArray: "
            << *names_array
            << std::endl;

  std::cout << "Test print: localComponentName: "
            << vec_space.localComponentName(0)
            << std::endl;

  std::cout << "Test print: printComponentsNames horizontally: ";
  vec_space.printComponentsNames(std::cout, true);
  std::cout << std::endl;

  std::cout << "Test print: printComponentsNames vertically: ";
  vec_space.printComponentsNames(std::cout, false);
  std::cout << std::endl;

  std::cout << "Test print: print: ";
  vec_space.print(std::cout);
  std::cout << std::endl;

  delete diag_matrix;
  delete env;
  MPI_Finalize();

  return 0;
}
<commit_msg>Adding verbosity options to pump out some coverage<commit_after>#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <queso/Environment.h>
#include <queso/GslVector.h>
#include <queso/GslMatrix.h>
#include <queso/VectorSpace.h>

int main(int argc, char **argv) {
  MPI_Init(&argc, &argv);

  QUESO::EnvOptionsValues options;
  options.m_numSubEnvironments = 1;
  options.m_subDisplayFileName = "outputData/debug_output";
  options.m_subDisplayAllowAll = 0;
  options.m_subDisplayAllowedSet.insert(0);
  options.m_seed = 1.0;
  options.m_checkingLevel = 1;
  options.m_displayVerbosity = 20;

  QUESO::FullEnvironment *env = new QUESO::FullEnvironment(MPI_COMM_WORLD, "",
      "", &options);

  std::vector<std::string> names(1);
  names[0] = "my_name";
  QUESO::VectorSpace<QUESO::GslVector, QUESO::GslMatrix> vec_space(*env,
      "vec_prefix", 1, &names);

  // 1x1 diagonal matrix containing the value 3.0 on the diagonal
  QUESO::GslMatrix * diag_matrix = vec_space.newDiagMatrix(3.0);

  if ((*diag_matrix)(0,0) != 3.0) {
    std::cerr << "newDiagMatrix test failed" << std::endl;
    return 1;
  }

  if (vec_space.globalIdOfFirstComponent() != 0) {
    std::cerr << "failed globalIdOfFirstComponent test" << std::endl;
    return 1;
  }

  const QUESO::DistArray<std::string> *names_array = vec_space.componentsNamesArray();

  std::cout << "Test print: componentsNamesArray: "
            << *names_array
            << std::endl;

  std::cout << "Test print: localComponentName: "
            << vec_space.localComponentName(0)
            << std::endl;

  std::cout << "Test print: printComponentsNames horizontally: ";
  vec_space.printComponentsNames(std::cout, true);
  std::cout << std::endl;

  std::cout << "Test print: printComponentsNames vertically: ";
  vec_space.printComponentsNames(std::cout, false);
  std::cout << std::endl;

  std::cout << "Test print: print: ";
  vec_space.print(std::cout);
  std::cout << std::endl;

  delete diag_matrix;
  MPI_Finalize();

  return 0;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "LocalDce.h"

#include <iostream>
#include <array>
#include <unordered_set>
#include <vector>

#include <boost/dynamic_bitset.hpp>

#include "ControlFlow.h"
#include "DexClass.h"
#include "IRInstruction.h"
#include "DexUtil.h"
#include "Transform.h"
#include "Walkers.h"

namespace {

constexpr const char* METRIC_DEAD_INSTRUCTIONS = "num_dead_instructions";
constexpr const char* METRIC_UNREACHABLE_INSTRUCTIONS =
    "num_unreachable_instructions";

/*
 * These instructions have observable side effects so must always be considered
 * live, regardless of whether their output is consumed by another instruction.
 */
static bool has_side_effects(DexOpcode opc) {
  switch (opc) {
  case OPCODE_RETURN_VOID:
  case OPCODE_RETURN:
  case OPCODE_RETURN_WIDE:
  case OPCODE_RETURN_OBJECT:
  case OPCODE_MONITOR_ENTER:
  case OPCODE_MONITOR_EXIT:
  case OPCODE_CHECK_CAST:
  case OPCODE_FILL_ARRAY_DATA:
  case OPCODE_THROW:
  case OPCODE_GOTO:
  case OPCODE_GOTO_16:
  case OPCODE_GOTO_32:
  case OPCODE_PACKED_SWITCH:
  case OPCODE_SPARSE_SWITCH:
  case OPCODE_IF_EQ:
  case OPCODE_IF_NE:
  case OPCODE_IF_LT:
  case OPCODE_IF_GE:
  case OPCODE_IF_GT:
  case OPCODE_IF_LE:
  case OPCODE_IF_EQZ:
  case OPCODE_IF_NEZ:
  case OPCODE_IF_LTZ:
  case OPCODE_IF_GEZ:
  case OPCODE_IF_GTZ:
  case OPCODE_IF_LEZ:
  case OPCODE_APUT:
  case OPCODE_APUT_WIDE:
  case OPCODE_APUT_OBJECT:
  case OPCODE_APUT_BOOLEAN:
  case OPCODE_APUT_BYTE:
  case OPCODE_APUT_CHAR:
  case OPCODE_APUT_SHORT:
  case OPCODE_IPUT:
  case OPCODE_IPUT_WIDE:
  case OPCODE_IPUT_OBJECT:
  case OPCODE_IPUT_BOOLEAN:
  case OPCODE_IPUT_BYTE:
  case OPCODE_IPUT_CHAR:
  case OPCODE_IPUT_SHORT:
  case OPCODE_SPUT:
  case OPCODE_SPUT_WIDE:
  case OPCODE_SPUT_OBJECT:
  case OPCODE_SPUT_BOOLEAN:
  case OPCODE_SPUT_BYTE:
  case OPCODE_SPUT_CHAR:
  case OPCODE_SPUT_SHORT:
  case OPCODE_INVOKE_VIRTUAL:
  case OPCODE_INVOKE_SUPER:
  case OPCODE_INVOKE_DIRECT:
  case OPCODE_INVOKE_STATIC:
  case OPCODE_INVOKE_INTERFACE:
  case OPCODE_INVOKE_VIRTUAL_RANGE:
  case OPCODE_INVOKE_SUPER_RANGE:
  case OPCODE_INVOKE_DIRECT_RANGE:
  case OPCODE_INVOKE_STATIC_RANGE:
  case OPCODE_INVOKE_INTERFACE_RANGE:
  case FOPCODE_PACKED_SWITCH:
  case FOPCODE_SPARSE_SWITCH:
  case FOPCODE_FILLED_ARRAY:
  case IOPCODE_LOAD_PARAM:
  case IOPCODE_LOAD_PARAM_OBJECT:
  case IOPCODE_LOAD_PARAM_WIDE:
    return true;
  default:
    return false;
  }
  not_reached();
}

template <typename... T>
std::string show(const boost::dynamic_bitset<T...>& bits) {
  std::string ret;
  to_string(bits, ret);
  return ret;
}

////////////////////////////////////////////////////////////////////////////////

class LocalDce {
 public:
  struct Stats {
    size_t dead_instruction_count{0};
    size_t unreachable_instruction_count{0};
  };

  /*
   * Eliminate dead code using a standard backward dataflow analysis for
   * liveness.  The algorithm is as follows:
   *
   * - Maintain a bitvector for each block representing the liveness for each
   *   register.  Function call results are represented by bit #num_regs.
   *
   * - Walk the blocks in postorder. Compute each block's output state by
   *   OR-ing the liveness of its successors
   *
   * - Walk each block's instructions in reverse to determine its input state.
   *   An instruction's input registers are live if (a) it has side effects, or
   *   (b) its output registers are live.
   *
   * - If the liveness of any block changes during a pass, repeat it.  Since
   *   anything live in one pass is guaranteed to be live in the next, this is
   *   guaranteed to reach a fixed point and terminate.  Visiting blocks in
   *   postorder guarantees a minimum number of passes.
   *
   * - Catch blocks are handled slightly differently; since any instruction
   *   inside a `try` region can jump to a catch block, we assume that any
   *   registers that are live-in to a catch block must be kept live throughout
   *   the `try` region.  (This is actually conservative, since only
   *   potentially-excepting instructions can jump to a catch.)
   */
 public:
  LocalDce() {
    /*
     * Pure methods have no observable side effects, so they can be removed
     * if their outputs are not used.
     *
     * TODO: Derive this list with static analysis rather than hard-coding
     * it.
     */
    m_pure_methods.emplace(DexMethod::make_method( "Ljava/lang/Class;",
          "getSimpleName", "Ljava/lang/String;", {}));
  }

  void dce(DexMethod* method) {
    auto code = method->get_code();
    code->build_cfg();
    auto& cfg = code->cfg();
    auto blocks = postorder_sort(cfg.blocks());
    auto regs = method->get_code()->get_registers_size();
    std::vector<boost::dynamic_bitset<>> liveness(
        cfg.blocks().size(), boost::dynamic_bitset<>(regs + 1));
    bool changed;
    std::vector<FatMethod::iterator> dead_instructions;

    TRACE(DCE, 5, "%s\n", SHOW(method));
    TRACE(DCE, 5, "%s", SHOW(cfg));

    // Iterate liveness analysis to a fixed point.
    do {
      changed = false;
      dead_instructions.clear();
      for (auto& b : blocks) {
        auto prev_liveness = liveness.at(b->id());
        auto& bliveness = liveness.at(b->id());
        bliveness.reset();
        TRACE(DCE, 5, "B%lu: %s\n", b->id(), show(bliveness).c_str());

        // Compute live-out for this block from its successors.
        for (auto& s : b->succs()) {
          if(s->id() == b->id()) {
            bliveness |= prev_liveness;
          }
          TRACE(DCE,
                5,
                "  S%lu: %s\n",
                s->id(),
                show(liveness[s->id()]).c_str());
          bliveness |= liveness[s->id()];
        }

        // Compute live-in for this block by walking its instruction list in
        // reverse and applying the liveness rules.
        for (auto it = b->rbegin(); it != b->rend(); ++it) {
          if (it->type != MFLOW_OPCODE) {
            continue;
          }
          bool required = is_required(it->insn, bliveness);
          if (required) {
            update_liveness(it->insn, bliveness);
          } else {
            dead_instructions.push_back(std::prev(it.base()));
          }
          TRACE(CFG,
                5,
                "%s\n%s\n",
                show(it->insn).c_str(),
                show(bliveness).c_str());
        }
        if (bliveness != prev_liveness) {
          changed = true;
        }
      }
    } while (changed);

    // Remove dead instructions.
    TRACE(DCE, 2, "%s\n", SHOW(method));
    for (auto dead : dead_instructions) {
      TRACE(DCE, 2, "DEAD: %s\n", SHOW(dead->insn));
      code->remove_opcode(dead);
    }
    m_stats.dead_instruction_count += dead_instructions.size();

    // if we deleted an instruction that may throw, we'll need to remove any
    // EDGE_THROW edges in the CFG... ideally we would just prune that edge,
    // but we can do a conservative and inefficient hack for now and just
    // rebuild the entire graph
    if (dead_instructions.size() > 0) {
      code->build_cfg();
    }

    remove_unreachable_blocks(method, &*code);

    TRACE(DCE, 5, "=== Post-DCE CFG ===\n");
    TRACE(DCE, 5, "%s", SHOW(code->cfg()));
  }

  const Stats& get_stats() const {
    return m_stats;
  }

 private:
  void remove_block(IRCode* code, Block* b) {
    for (auto& mei : InstructionIterable(b)) {
      code->remove_opcode(mei.insn);
      ++m_stats.unreachable_instruction_count;
    }
  }

  void remove_unreachable_blocks(DexMethod* method, IRCode* code) {
    auto& cfg = code->cfg();
    auto& blocks = cfg.blocks();
    // Remove edges to catch blocks that no longer exist.
    std::vector<std::pair<Block*, Block*>> remove_edges;
    for (auto& b : blocks) {
      if (!is_catch(b)) {
        continue;
      }
      for (auto& p : b->preds()) {
        if (!ends_with_may_throw(p)) {
          // We removed whatever instruction could throw to this catch.
          remove_edges.emplace_back(p, b);
        }
      }
    }
    for (auto& e : remove_edges) {
      cfg.remove_edge(e.first, e.second, EDGE_THROW);
    }
    remove_edges.clear();

    // remove unreachable blocks
    std::unordered_set<Block*> visited;
    std::function<void (Block*)> visit = [&](Block* b) {
      if (visited.find(b) != visited.end()) {
        return;
      }
      visited.emplace(b);
      for (auto& s : b->succs()) {
        visit(s);
      }
    };
    visit(blocks.at(0));
    for (size_t i = 1; i < blocks.size(); ++i) {
      auto& b = blocks.at(i);
      if (visited.find(b) != visited.end()) {
        continue;
      }
      for (auto& s : b->succs()) {
        remove_edges.emplace_back(b, s);
      }
      for (auto& p : remove_edges) {
        cfg.remove_all_edges(p.first, p.second);
      }
      remove_block(code, b);
    }

    // comb the method looking for superfluous try sections that do not enclose
    // throwing opcodes; remove them. note that try sections should never be
    // nested, otherwise this won't produce the right result.
    bool encloses_throw {false};
    MethodItemEntry* try_start {nullptr};
    for (auto& mie : *code) {
      if (mie.type == MFLOW_TRY) {
        auto tentry = mie.tentry;
        if (tentry->type == TRY_START) {
          encloses_throw = false;
          try_start = &mie;
        } else if (!encloses_throw /* && tentry->type == TRY_END */) {
          try_start->type = MFLOW_FALLTHROUGH;
          try_start->throwing_mie = nullptr;
          try_start = nullptr;
          mie.type = MFLOW_FALLTHROUGH;
          mie.throwing_mie = nullptr;
        }
      } else if (mie.type == MFLOW_OPCODE) {
        auto op = mie.insn->opcode();
        encloses_throw =
            encloses_throw || opcode::may_throw(op) || op == OPCODE_THROW;
      }
    }
  }

  /*
   * An instruction is required (i.e., live) if it has side effects or if its
   * destination register is live.
   */
  bool is_required(IRInstruction* inst, const boost::dynamic_bitset<>& bliveness) {
    if (has_side_effects(inst->opcode())) {
      if (is_invoke(inst->opcode())) {
        if (!is_pure(inst->get_method())) {
          return true;
        }
        return bliveness.test(bliveness.size() - 1);
      }
      return true;
    } else if (inst->dests_size()) {
      bool result = bliveness.test(inst->dest());
      if (inst->dest_is_wide()) {
        result |= bliveness.test(inst->dest() + 1);
      }
      return result;
    } else if (is_filled_new_array(inst->opcode())) {
      // filled-new-array passes its dest via the return-value slot, but isn't
      // inherently live like the invoke-* instructions.
      return bliveness.test(bliveness.size() - 1);
    }
    return false;
  }

  bool is_pure(DexMethod* method) {
    if (assumenosideeffects(method)) {
      return true;
    }
    return m_pure_methods.find(method) != m_pure_methods.end();
  }

  /*
   * Update the liveness vector given that `inst` is live.
   */
  void update_liveness(const IRInstruction* inst,
                       boost::dynamic_bitset<>& bliveness) {
    // The destination register is killed, so it isn't live before this.
    if (inst->dests_size()) {
      bliveness.reset(inst->dest());
      if (inst->dest_is_wide()) {
        bliveness.reset(inst->dest() + 1);
      }
    }
    // The destination of an `invoke` is its return value, which is encoded as
    // the max position in the bitvector.
    if (is_invoke(inst->opcode()) || is_filled_new_array(inst->opcode())) {
      bliveness.reset(bliveness.size() - 1);
    }
    // Source registers are live.
    for (size_t i = 0; i < inst->srcs_size(); i++) {
      bliveness.set(inst->src(i));
    }
    // `invoke-range` instructions need special handling since their sources
    // are encoded as a range.
    if (opcode::has_range(inst->opcode())) {
      for (size_t i = 0; i < inst->range_size(); i++) {
        bliveness.set(inst->range_base() + i);
      }
    }
    // The source of a `move-result` is the return value of the prior call,
    // which is encoded as the max position in the bitvector.
    if (is_move_result(inst->opcode())) {
      bliveness.set(bliveness.size() - 1);
    }
  }

 public:
  void run(const Scope& scope) {
    walk_methods(scope,
                 [&](DexMethod* m) {
                   if (!m->get_code()) {
                     return;
                   }
                   dce(m);
                 });
    TRACE(DCE, 1, "Dead instructions: %lu\n", m_stats.dead_instruction_count);
    TRACE(DCE, 1, "Unreachable instructions: %lu\n",
          m_stats.unreachable_instruction_count);
  }

 private:
  std::unordered_set<DexMethod*> m_pure_methods;
  Stats m_stats;
};

} // namespace

void LocalDcePass::run(DexMethod* m) {
  LocalDce().dce(m);
}

void LocalDcePass::run_pass(DexStoresVector& stores,
                            ConfigFiles& cfg,
                            PassManager& mgr) {
  if (mgr.no_proguard_rules()) {
    TRACE(DCE, 1,
        "LocalDcePass not run because no ProGuard configuration was provided.");
    return;
  }
  auto scope = build_class_scope(stores);
  LocalDce ldce;
  ldce.run(scope);
  const auto& stats = ldce.get_stats();
  mgr.incr_metric(METRIC_DEAD_INSTRUCTIONS, stats.dead_instruction_count);
  mgr.incr_metric(METRIC_UNREACHABLE_INSTRUCTIONS,
                  stats.unreachable_instruction_count);
}

static LocalDcePass s_pass;
<commit_msg>dce: No need to prune CFG edges before removing unreachable blocks<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "LocalDce.h"

#include <iostream>
#include <array>
#include <unordered_set>
#include <vector>

#include <boost/dynamic_bitset.hpp>

#include "ControlFlow.h"
#include "DexClass.h"
#include "IRInstruction.h"
#include "DexUtil.h"
#include "Transform.h"
#include "Walkers.h"

namespace {

constexpr const char* METRIC_DEAD_INSTRUCTIONS = "num_dead_instructions";
constexpr const char* METRIC_UNREACHABLE_INSTRUCTIONS =
    "num_unreachable_instructions";

/*
 * These instructions have observable side effects so must always be considered
 * live, regardless of whether their output is consumed by another instruction.
 */
static bool has_side_effects(DexOpcode opc) {
  switch (opc) {
  case OPCODE_RETURN_VOID:
  case OPCODE_RETURN:
  case OPCODE_RETURN_WIDE:
  case OPCODE_RETURN_OBJECT:
  case OPCODE_MONITOR_ENTER:
  case OPCODE_MONITOR_EXIT:
  case OPCODE_CHECK_CAST:
  case OPCODE_FILL_ARRAY_DATA:
  case OPCODE_THROW:
  case OPCODE_GOTO:
  case OPCODE_GOTO_16:
  case OPCODE_GOTO_32:
  case OPCODE_PACKED_SWITCH:
  case OPCODE_SPARSE_SWITCH:
  case OPCODE_IF_EQ:
  case OPCODE_IF_NE:
  case OPCODE_IF_LT:
  case OPCODE_IF_GE:
  case OPCODE_IF_GT:
  case OPCODE_IF_LE:
  case OPCODE_IF_EQZ:
  case OPCODE_IF_NEZ:
  case OPCODE_IF_LTZ:
  case OPCODE_IF_GEZ:
  case OPCODE_IF_GTZ:
  case OPCODE_IF_LEZ:
  case OPCODE_APUT:
  case OPCODE_APUT_WIDE:
  case OPCODE_APUT_OBJECT:
  case OPCODE_APUT_BOOLEAN:
  case OPCODE_APUT_BYTE:
  case OPCODE_APUT_CHAR:
  case OPCODE_APUT_SHORT:
  case OPCODE_IPUT:
  case OPCODE_IPUT_WIDE:
  case OPCODE_IPUT_OBJECT:
  case OPCODE_IPUT_BOOLEAN:
  case OPCODE_IPUT_BYTE:
  case OPCODE_IPUT_CHAR:
  case OPCODE_IPUT_SHORT:
  case OPCODE_SPUT:
  case OPCODE_SPUT_WIDE:
  case OPCODE_SPUT_OBJECT:
  case OPCODE_SPUT_BOOLEAN:
  case OPCODE_SPUT_BYTE:
  case OPCODE_SPUT_CHAR:
  case OPCODE_SPUT_SHORT:
  case OPCODE_INVOKE_VIRTUAL:
  case OPCODE_INVOKE_SUPER:
  case OPCODE_INVOKE_DIRECT:
  case OPCODE_INVOKE_STATIC:
  case OPCODE_INVOKE_INTERFACE:
  case OPCODE_INVOKE_VIRTUAL_RANGE:
  case OPCODE_INVOKE_SUPER_RANGE:
  case OPCODE_INVOKE_DIRECT_RANGE:
  case OPCODE_INVOKE_STATIC_RANGE:
  case OPCODE_INVOKE_INTERFACE_RANGE:
  case FOPCODE_PACKED_SWITCH:
  case FOPCODE_SPARSE_SWITCH:
  case FOPCODE_FILLED_ARRAY:
  case IOPCODE_LOAD_PARAM:
  case IOPCODE_LOAD_PARAM_OBJECT:
  case IOPCODE_LOAD_PARAM_WIDE:
    return true;
  default:
    return false;
  }
  not_reached();
}

template <typename... T>
std::string show(const boost::dynamic_bitset<T...>& bits) {
  std::string ret;
  to_string(bits, ret);
  return ret;
}

////////////////////////////////////////////////////////////////////////////////

class LocalDce {
 public:
  struct Stats {
    size_t dead_instruction_count{0};
    size_t unreachable_instruction_count{0};
  };

  /*
   * Eliminate dead code using a standard backward dataflow analysis for
   * liveness.  The algorithm is as follows:
   *
   * - Maintain a bitvector for each block representing the liveness for each
   *   register.  Function call results are represented by bit #num_regs.
   *
   * - Walk the blocks in postorder. Compute each block's output state by
   *   OR-ing the liveness of its successors
   *
   * - Walk each block's instructions in reverse to determine its input state.
   *   An instruction's input registers are live if (a) it has side effects, or
   *   (b) its output registers are live.
   *
   * - If the liveness of any block changes during a pass, repeat it.  Since
   *   anything live in one pass is guaranteed to be live in the next, this is
   *   guaranteed to reach a fixed point and terminate.  Visiting blocks in
   *   postorder guarantees a minimum number of passes.
   *
   * - Catch blocks are handled slightly differently; since any instruction
   *   inside a `try` region can jump to a catch block, we assume that any
   *   registers that are live-in to a catch block must be kept live throughout
   *   the `try` region.  (This is actually conservative, since only
   *   potentially-excepting instructions can jump to a catch.)
   */
 public:
  LocalDce() {
    /*
     * Pure methods have no observable side effects, so they can be removed
     * if their outputs are not used.
     *
     * TODO: Derive this list with static analysis rather than hard-coding
     * it.
     */
    m_pure_methods.emplace(DexMethod::make_method( "Ljava/lang/Class;",
          "getSimpleName", "Ljava/lang/String;", {}));
  }

  void dce(DexMethod* method) {
    auto code = method->get_code();
    code->build_cfg();
    auto& cfg = code->cfg();
    auto blocks = postorder_sort(cfg.blocks());
    auto regs = method->get_code()->get_registers_size();
    std::vector<boost::dynamic_bitset<>> liveness(
        cfg.blocks().size(), boost::dynamic_bitset<>(regs + 1));
    bool changed;
    std::vector<FatMethod::iterator> dead_instructions;

    TRACE(DCE, 5, "%s\n", SHOW(method));
    TRACE(DCE, 5, "%s", SHOW(cfg));

    // Iterate liveness analysis to a fixed point.
    do {
      changed = false;
      dead_instructions.clear();
      for (auto& b : blocks) {
        auto prev_liveness = liveness.at(b->id());
        auto& bliveness = liveness.at(b->id());
        bliveness.reset();
        TRACE(DCE, 5, "B%lu: %s\n", b->id(), show(bliveness).c_str());

        // Compute live-out for this block from its successors.
        for (auto& s : b->succs()) {
          if(s->id() == b->id()) {
            bliveness |= prev_liveness;
          }
          TRACE(DCE,
                5,
                "  S%lu: %s\n",
                s->id(),
                show(liveness[s->id()]).c_str());
          bliveness |= liveness[s->id()];
        }

        // Compute live-in for this block by walking its instruction list in
        // reverse and applying the liveness rules.
        for (auto it = b->rbegin(); it != b->rend(); ++it) {
          if (it->type != MFLOW_OPCODE) {
            continue;
          }
          bool required = is_required(it->insn, bliveness);
          if (required) {
            update_liveness(it->insn, bliveness);
          } else {
            dead_instructions.push_back(std::prev(it.base()));
          }
          TRACE(CFG,
                5,
                "%s\n%s\n",
                show(it->insn).c_str(),
                show(bliveness).c_str());
        }
        if (bliveness != prev_liveness) {
          changed = true;
        }
      }
    } while (changed);

    // Remove dead instructions.
    TRACE(DCE, 2, "%s\n", SHOW(method));
    for (auto dead : dead_instructions) {
      TRACE(DCE, 2, "DEAD: %s\n", SHOW(dead->insn));
      code->remove_opcode(dead);
    }
    m_stats.dead_instruction_count += dead_instructions.size();

    // if we deleted an instruction that may throw, we'll need to remove any
    // EDGE_THROW edges in the CFG... ideally we would just prune that edge,
    // but we can do a conservative and inefficient hack for now and just
    // rebuild the entire graph
    if (dead_instructions.size() > 0) {
      code->build_cfg();
    }

    remove_unreachable_blocks(method, &*code);

    TRACE(DCE, 5, "=== Post-DCE CFG ===\n");
    TRACE(DCE, 5, "%s", SHOW(code->cfg()));
  }

  const Stats& get_stats() const {
    return m_stats;
  }

 private:
  void remove_block(IRCode* code, Block* b) {
    for (auto& mei : InstructionIterable(b)) {
      code->remove_opcode(mei.insn);
      ++m_stats.unreachable_instruction_count;
    }
  }

  void remove_unreachable_blocks(DexMethod* method, IRCode* code) {
    auto& cfg = code->cfg();
    auto& blocks = cfg.blocks();

    // remove unreachable blocks
    std::unordered_set<Block*> visited;
    std::function<void (Block*)> visit = [&](Block* b) {
      if (visited.find(b) != visited.end()) {
        return;
      }
      visited.emplace(b);
      for (auto& s : b->succs()) {
        visit(s);
      }
    };
    visit(blocks.at(0));
    for (size_t i = 1; i < blocks.size(); ++i) {
      auto& b = blocks.at(i);
      if (visited.find(b) != visited.end()) {
        continue;
      }
      std::vector<std::pair<Block*, Block*>> remove_edges;
      for (auto& s : b->succs()) {
        remove_edges.emplace_back(b, s);
      }
      for (auto& p : remove_edges) {
        cfg.remove_all_edges(p.first, p.second);
      }
      remove_block(code, b);
    }

    // comb the method looking for superfluous try sections that do not enclose
    // throwing opcodes; remove them. note that try sections should never be
    // nested, otherwise this won't produce the right result.
    bool encloses_throw {false};
    MethodItemEntry* try_start {nullptr};
    for (auto& mie : *code) {
      if (mie.type == MFLOW_TRY) {
        auto tentry = mie.tentry;
        if (tentry->type == TRY_START) {
          encloses_throw = false;
          try_start = &mie;
        } else if (!encloses_throw /* && tentry->type == TRY_END */) {
          try_start->type = MFLOW_FALLTHROUGH;
          try_start->throwing_mie = nullptr;
          try_start = nullptr;
          mie.type = MFLOW_FALLTHROUGH;
          mie.throwing_mie = nullptr;
        }
      } else if (mie.type == MFLOW_OPCODE) {
        auto op = mie.insn->opcode();
        encloses_throw =
            encloses_throw || opcode::may_throw(op) || op == OPCODE_THROW;
      }
    }
  }

  /*
   * An instruction is required (i.e., live) if it has side effects or if its
   * destination register is live.
   */
  bool is_required(IRInstruction* inst, const boost::dynamic_bitset<>& bliveness) {
    if (has_side_effects(inst->opcode())) {
      if (is_invoke(inst->opcode())) {
        if (!is_pure(inst->get_method())) {
          return true;
        }
        return bliveness.test(bliveness.size() - 1);
      }
      return true;
    } else if (inst->dests_size()) {
      bool result = bliveness.test(inst->dest());
      if (inst->dest_is_wide()) {
        result |= bliveness.test(inst->dest() + 1);
      }
      return result;
    } else if (is_filled_new_array(inst->opcode())) {
      // filled-new-array passes its dest via the return-value slot, but isn't
      // inherently live like the invoke-* instructions.
      return bliveness.test(bliveness.size() - 1);
    }
    return false;
  }

  bool is_pure(DexMethod* method) {
    if (assumenosideeffects(method)) {
      return true;
    }
    return m_pure_methods.find(method) != m_pure_methods.end();
  }

  /*
   * Update the liveness vector given that `inst` is live.
   */
  void update_liveness(const IRInstruction* inst,
                       boost::dynamic_bitset<>& bliveness) {
    // The destination register is killed, so it isn't live before this.
    if (inst->dests_size()) {
      bliveness.reset(inst->dest());
      if (inst->dest_is_wide()) {
        bliveness.reset(inst->dest() + 1);
      }
    }
    // The destination of an `invoke` is its return value, which is encoded as
    // the max position in the bitvector.
    if (is_invoke(inst->opcode()) || is_filled_new_array(inst->opcode())) {
      bliveness.reset(bliveness.size() - 1);
    }
    // Source registers are live.
    for (size_t i = 0; i < inst->srcs_size(); i++) {
      bliveness.set(inst->src(i));
    }
    // `invoke-range` instructions need special handling since their sources
    // are encoded as a range.
    if (opcode::has_range(inst->opcode())) {
      for (size_t i = 0; i < inst->range_size(); i++) {
        bliveness.set(inst->range_base() + i);
      }
    }
    // The source of a `move-result` is the return value of the prior call,
    // which is encoded as the max position in the bitvector.
    if (is_move_result(inst->opcode())) {
      bliveness.set(bliveness.size() - 1);
    }
  }

 public:
  void run(const Scope& scope) {
    walk_methods(scope,
                 [&](DexMethod* m) {
                   if (!m->get_code()) {
                     return;
                   }
                   dce(m);
                 });
    TRACE(DCE, 1, "Dead instructions: %lu\n", m_stats.dead_instruction_count);
    TRACE(DCE, 1, "Unreachable instructions: %lu\n",
          m_stats.unreachable_instruction_count);
  }

 private:
  std::unordered_set<DexMethod*> m_pure_methods;
  Stats m_stats;
};

} // namespace

void LocalDcePass::run(DexMethod* m) {
  LocalDce().dce(m);
}

void LocalDcePass::run_pass(DexStoresVector& stores,
                            ConfigFiles& cfg,
                            PassManager& mgr) {
  if (mgr.no_proguard_rules()) {
    TRACE(DCE, 1,
        "LocalDcePass not run because no ProGuard configuration was provided.");
    return;
  }
  auto scope = build_class_scope(stores);
  LocalDce ldce;
  ldce.run(scope);
  const auto& stats = ldce.get_stats();
  mgr.incr_metric(METRIC_DEAD_INSTRUCTIONS, stats.dead_instruction_count);
  mgr.incr_metric(METRIC_UNREACHABLE_INSTRUCTIONS,
                  stats.unreachable_instruction_count);
}

static LocalDcePass s_pass;
<|endoftext|>


<commit_before><commit_msg>add test for calculate CRC-7/ROHC<commit_after><|endoftext|>


<commit_before>//
// Copyright 2013 Jeff Bush
//
// 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 "Debug.h"
#include "Spinlock.h"
#include "utils.h"

extern "C"  {
	unsigned int __udivsi3(unsigned int, unsigned int);
	int __divsi3(int, int);
	unsigned int __umodsi3(unsigned int, unsigned int);
	int __modsi3(int, int);
}

void *__dso_handle;
static volatile unsigned int gNextAlloc = 0x240000;

void memcpy(void *dest, const void *src, unsigned int length)
{
	for (unsigned int i = 0; i < length; i++)
		((char*) dest)[i] = ((const char *) src)[i];
}

void memset(void *_dest, int value, unsigned int length)
{
	char *dest = (char*) _dest;
	value &= 0xff;

	if ((((unsigned int) dest) & 63) == 0)
	{
		// Write 64 bytes at a time.
		veci16 reallyWideValue = splati(value | (value << 8) | (value << 16)
			| (value << 24));
		while (length > 64)
		{
			*((veci16*) dest) = reallyWideValue;
			length -= 64;
			dest += 64;
		}
	}

	if ((((unsigned int) dest) & 3) == 0)
	{
		// Write 4 bytes at a time.
		unsigned wideVal = value | (value << 8) | (value << 16) | (value << 24);
		while (length > 4)
		{
			*((unsigned int*) dest) = wideVal;
			dest += 4;
			length -= 4;
		}
	}

	// Write one byte at a time
	while (length > 0)
	{
		*dest++ = value;
		length--;
	}
}

void *allocMem(unsigned int size)
{
	return (void*) __sync_fetch_and_add(&gNextAlloc, (size + 63) & ~63);
}

void operator delete(void *) throw()
{
	// Unimplemented
}

extern "C" void __cxa_atexit(void (*)(void *), void *, void *)
{
}

extern "C" void __cxa_pure_virtual()
{
	Debug::debug << "pure virtual\n";
	__halt();
}

//
// We don't support integer division in hardware, so emulate those functions
// here.
//
unsigned int __udivsi3(unsigned int dividend, unsigned int divisor)
{
	if (dividend < divisor)
		return 0;

	int quotientBits = __builtin_clz(divisor) - __builtin_clz(dividend);

	divisor <<= quotientBits;
	unsigned int quotient = 0;
	do
	{
		quotient <<= 1;
		if (dividend >= divisor)
		{
			dividend -= divisor;
			quotient |= 1;
		}

		divisor >>= 1;
	}
	while (--quotientBits >= 0);

	return quotient;
}

int __divsi3(int value1, int value2)
{
	int sign1 = value1 >> 31;
	int sign2 = value2 >> 31;

	// Take absolute values
	unsigned int u_value1 = (value1 ^ sign1) - sign1;
	unsigned int u_value2 = (value2 ^ sign2) - sign2;

	// Compute result sign
	sign1 ^= sign2;

	// Perform division, then convert back to 2's complement
	return (__udivsi3(u_value1, u_value2) ^ sign1) - sign1;
}

unsigned int __umodsi3(unsigned int value1, unsigned int value2)
{
	return value1 - __udivsi3(value1, value2) * value2;
}

int __modsi3(int value1, int value2)
{
	return value1 - __divsi3(value1, value2) * value2;
}

//
// Math functions
//

float fmod(float val1, float val2)
{
	int whole = val1 / val2;
	return val1 - (whole * val2);
}

//
// Use taylor series to approximate sine
//   x**3/3! + x**5/5! - x**7/7! ...
//

const int kNumTerms = 7;

const float denominators[] = {
	0.166666666666667f, 	// 1 / 3!
	0.008333333333333f,		// 1 / 5!
	0.000198412698413f,		// 1 / 7!
	0.000002755731922f,		// 1 / 9!
	2.50521084e-8f,			// 1 / 11!
	1.6059044e-10f,			// 1 / 13!
	7.6471637e-13f			// 1 / 15!
};

float sin(float angle)
{
	// More accurate if the angle is smaller. Constrain to 0-M_PI*2
	angle = fmod(angle, M_PI * 2.0f);

	float angleSquared = angle * angle;
	float numerator = angle;
	float result = angle;

	for (int i = 0; i < kNumTerms; i++)
	{
		numerator *= angleSquared;
		float term = numerator * denominators[i];
		if (i & 1)
			result += term;
		else
			result -= term;
	}

	return result;
}

float cos(float angle)
{
	return sin(angle + M_PI * 0.5f);
}

float sqrt(float value)
{
	float guess = value;
	for (int iteration = 0; iteration < 10; iteration++)
		guess = ((value / guess) + guess) / 2.0f;

	return guess;
}
<commit_msg>Fix missing header file.<commit_after>//
// Copyright 2013 Jeff Bush
//
// 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 "Debug.h"
#include "utils.h"

extern "C"  {
	unsigned int __udivsi3(unsigned int, unsigned int);
	int __divsi3(int, int);
	unsigned int __umodsi3(unsigned int, unsigned int);
	int __modsi3(int, int);
}

void *__dso_handle;
static volatile unsigned int gNextAlloc = 0x240000;

void memcpy(void *dest, const void *src, unsigned int length)
{
	for (unsigned int i = 0; i < length; i++)
		((char*) dest)[i] = ((const char *) src)[i];
}

void memset(void *_dest, int value, unsigned int length)
{
	char *dest = (char*) _dest;
	value &= 0xff;

	if ((((unsigned int) dest) & 63) == 0)
	{
		// Write 64 bytes at a time.
		veci16 reallyWideValue = splati(value | (value << 8) | (value << 16)
			| (value << 24));
		while (length > 64)
		{
			*((veci16*) dest) = reallyWideValue;
			length -= 64;
			dest += 64;
		}
	}

	if ((((unsigned int) dest) & 3) == 0)
	{
		// Write 4 bytes at a time.
		unsigned wideVal = value | (value << 8) | (value << 16) | (value << 24);
		while (length > 4)
		{
			*((unsigned int*) dest) = wideVal;
			dest += 4;
			length -= 4;
		}
	}

	// Write one byte at a time
	while (length > 0)
	{
		*dest++ = value;
		length--;
	}
}

void *allocMem(unsigned int size)
{
	return (void*) __sync_fetch_and_add(&gNextAlloc, (size + 63) & ~63);
}

void operator delete(void *) throw()
{
	// Unimplemented
}

extern "C" void __cxa_atexit(void (*)(void *), void *, void *)
{
}

extern "C" void __cxa_pure_virtual()
{
	Debug::debug << "pure virtual\n";
	__halt();
}

//
// We don't support integer division in hardware, so emulate those functions
// here.
//
unsigned int __udivsi3(unsigned int dividend, unsigned int divisor)
{
	if (dividend < divisor)
		return 0;

	int quotientBits = __builtin_clz(divisor) - __builtin_clz(dividend);

	divisor <<= quotientBits;
	unsigned int quotient = 0;
	do
	{
		quotient <<= 1;
		if (dividend >= divisor)
		{
			dividend -= divisor;
			quotient |= 1;
		}

		divisor >>= 1;
	}
	while (--quotientBits >= 0);

	return quotient;
}

int __divsi3(int value1, int value2)
{
	int sign1 = value1 >> 31;
	int sign2 = value2 >> 31;

	// Take absolute values
	unsigned int u_value1 = (value1 ^ sign1) - sign1;
	unsigned int u_value2 = (value2 ^ sign2) - sign2;

	// Compute result sign
	sign1 ^= sign2;

	// Perform division, then convert back to 2's complement
	return (__udivsi3(u_value1, u_value2) ^ sign1) - sign1;
}

unsigned int __umodsi3(unsigned int value1, unsigned int value2)
{
	return value1 - __udivsi3(value1, value2) * value2;
}

int __modsi3(int value1, int value2)
{
	return value1 - __divsi3(value1, value2) * value2;
}

//
// Math functions
//

float fmod(float val1, float val2)
{
	int whole = val1 / val2;
	return val1 - (whole * val2);
}

//
// Use taylor series to approximate sine
//   x**3/3! + x**5/5! - x**7/7! ...
//

const int kNumTerms = 7;

const float denominators[] = {
	0.166666666666667f, 	// 1 / 3!
	0.008333333333333f,		// 1 / 5!
	0.000198412698413f,		// 1 / 7!
	0.000002755731922f,		// 1 / 9!
	2.50521084e-8f,			// 1 / 11!
	1.6059044e-10f,			// 1 / 13!
	7.6471637e-13f			// 1 / 15!
};

float sin(float angle)
{
	// More accurate if the angle is smaller. Constrain to 0-M_PI*2
	angle = fmod(angle, M_PI * 2.0f);

	float angleSquared = angle * angle;
	float numerator = angle;
	float result = angle;

	for (int i = 0; i < kNumTerms; i++)
	{
		numerator *= angleSquared;
		float term = numerator * denominators[i];
		if (i & 1)
			result += term;
		else
			result -= term;
	}

	return result;
}

float cos(float angle)
{
	return sin(angle + M_PI * 0.5f);
}

float sqrt(float value)
{
	float guess = value;
	for (int iteration = 0; iteration < 10; iteration++)
		guess = ((value / guess) + guess) / 2.0f;

	return guess;
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkPALinearSpectralUnmixingFilter.h"

// Includes for AddEnmemberMatrix
#include "mitkPAPropertyCalculator.h"
#include <eigen3/Eigen/Dense>

// Testing algorithms
#include <eigen3\Eigen\src\SVD\JacobiSVD.h>

// ImageAccessor
#include <mitkImageReadAccessor.h>
#include <mitkImageWriteAccessor.h>

mitk::pa::LinearSpectralUnmixingFilter::LinearSpectralUnmixingFilter()
{

}

mitk::pa::LinearSpectralUnmixingFilter::~LinearSpectralUnmixingFilter()
{

}

void mitk::pa::LinearSpectralUnmixingFilter::SetAlgorithm(int SetAlgorithmIndex)
{
  algorithmIndex = static_cast<mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType>(SetAlgorithmIndex);
}

Eigen::VectorXf mitk::pa::LinearSpectralUnmixingFilter::SpectralUnmixingAlgorithm(
  Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> EndmemberMatrix, Eigen::VectorXf inputVector)
{

  //test other solvers https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html

  Eigen::Vector2f resultVector;

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::colPivHouseholderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.colPivHouseholderQr().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::llt == algorithmIndex)
  {
    resultVector = EndmemberMatrix.llt().solve(inputVector); //works with negativ values (no correct unmixing)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::householderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.householderQr().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::ldlt == algorithmIndex)
  {
    mitkThrow() << "not working";
    resultVector = EndmemberMatrix.ldlt().solve(inputVector); //not working because matrix not quadratic(?)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::jacobiSvd == algorithmIndex)
  {
    mitkThrow() << "not working";
    resultVector = EndmemberMatrix.jacobiSvd().solve(inputVector); //not working
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::fullPivLu == algorithmIndex)
  {
    resultVector = EndmemberMatrix.fullPivLu().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::householderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.householderQr().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::fullPivHouseholderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.fullPivHouseholderQr().solve(inputVector);//works :)
  }

  //testing new algorithms:
  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::test == algorithmIndex)
  {
    mitkThrow() << "nothing implemented";
  }

  double relativeError = (EndmemberMatrix*resultVector - inputVector).norm() / inputVector.norm(); // norm() is L2 norm
  //MITK_INFO << "relativ error: " << relativeError;
  float accuracyLevel = .1;
  bool resultIsApprox = inputVector.isApprox(EndmemberMatrix*resultVector, accuracyLevel);
  //MITK_INFO << "IS APPROX RESULT: " << resultIsApprox;
  return resultVector;
}
<commit_msg>EIGEN jacobiSvd solver works now.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkPALinearSpectralUnmixingFilter.h"

// Includes for AddEnmemberMatrix
#include "mitkPAPropertyCalculator.h"
#include <eigen3/Eigen/Dense>

// Testing algorithms
#include <eigen3\Eigen\src\SVD\JacobiSVD.h>

// ImageAccessor
#include <mitkImageReadAccessor.h>
#include <mitkImageWriteAccessor.h>

mitk::pa::LinearSpectralUnmixingFilter::LinearSpectralUnmixingFilter()
{

}

mitk::pa::LinearSpectralUnmixingFilter::~LinearSpectralUnmixingFilter()
{

}

void mitk::pa::LinearSpectralUnmixingFilter::SetAlgorithm(int SetAlgorithmIndex)
{
  algorithmIndex = static_cast<mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType>(SetAlgorithmIndex);
}

Eigen::VectorXf mitk::pa::LinearSpectralUnmixingFilter::SpectralUnmixingAlgorithm(
  Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> EndmemberMatrix, Eigen::VectorXf inputVector)
{

  //test other solvers https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html

  Eigen::Vector2f resultVector;

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::colPivHouseholderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.colPivHouseholderQr().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::llt == algorithmIndex)
  {
    resultVector = EndmemberMatrix.llt().solve(inputVector); //works with negativ values (no correct unmixing)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::householderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.householderQr().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::ldlt == algorithmIndex)
  {
    mitkThrow() << "not working";
    resultVector = EndmemberMatrix.ldlt().solve(inputVector); //not working because matrix not quadratic(?)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::jacobiSvd == algorithmIndex)
  {
    resultVector = EndmemberMatrix.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV).solve(inputVector); //not working
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::fullPivLu == algorithmIndex)
  {
    resultVector = EndmemberMatrix.fullPivLu().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::householderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.householderQr().solve(inputVector); //works :)
  }

  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::fullPivHouseholderQr == algorithmIndex)
  {
    resultVector = EndmemberMatrix.fullPivHouseholderQr().solve(inputVector);//works :)
  }

  //testing new algorithms:
  if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::test == algorithmIndex)
  {
    mitkThrow() << "nothing implemented";
  }

  double relativeError = (EndmemberMatrix*resultVector - inputVector).norm() / inputVector.norm(); // norm() is L2 norm
  MITK_INFO << "relativ error: " << relativeError;
  float accuracyLevel = .1;
  bool resultIsApprox = inputVector.isApprox(EndmemberMatrix*resultVector, accuracyLevel);
  MITK_INFO << "IS APPROX RESULT: " << resultIsApprox;
  return resultVector;
}
<|endoftext|>


<commit_before>/**********************************************************************
* Felix Winterstein, Imperial College London
*
* File: main.cpp
*
* Revision 1.01
* Additional Comments: distributed under a BSD license, see LICENSE.txt
*
**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
//#include <stdbool.h>
#include <time.h>
#include <time.h>
#include <unistd.h>
#include "my_util.h"
#include "lloyds.h"
#include "filter_it.h"
#include "clustering.h"

int main(int argc, char** argv)
{
    uint k = 128;
    uint n = 16384;
    const double std_dev = 0.20;
    const uint fidx = 1;

    // works for linux!
    char path[FILENAME_MAX];
    if (!getcwd(path, sizeof(path))){
        printf("ERROR: getcwd failed\n");
        return EXIT_SUCCESS;
    }
    printf("Working directory is: %s\n",path);

    // allocate input arrays
    data_type_short *data_points = new data_type_short[NMAX];
    centre_type *initial_centres = new centre_type[KMAX];
    uint *centr_idx = new uint[KMAX];

    // read data points file
    if (read_data_points(data_points, n, k, std_dev, fidx) == false) {
        printf("ERROR: Could not find data points file\n");
        return EXIT_SUCCESS;
    }

    // read initial centres file
    if (read_initial_centres(initial_centres, centr_idx, n, k, std_dev, fidx) == false) {
        printf("ERROR: Could not find data points file\n");
        return EXIT_SUCCESS;
    }

    // allocate output arrays
    data_type_short *data_output= new data_type_short[NMAX];
    centre_type *centre_output = new centre_type[KMAX];
    kdTree_type *tree_memory = new kdTree_type[2*NMAX];

    // build kd-tree and run clustering
    uint root;
    #ifdef FILTERING_ALGO
    buildTree(n, k, data_points, &root, tree_memory);
    #endif
    clustering(n, k, initial_centres, data_points, tree_memory, root, data_output, centre_output);

    #ifdef VERBOSE
    // Clustering result
    printf("New centres after clustering\n");
    for (uint i=0; i<k; i++) {
        printf("%d: ",i);
        for (uint d=0; d<D-1; d++) {
            printf("%d ",centre_output[i].position_short.value[d]);
        }
        printf("%d\n",centre_output[i].position_short.value[D-1]);
    }
    #endif

    //write_data_set_info(tree_memory_lo_lo, tree_memory_lo_hi, tree_memory_hi_lo, tree_memory_hi_hi, fidx);

    // free allocated memory
    delete data_points;
    delete data_output;
    delete centre_output;
    delete tree_memory;
    delete initial_centres;
    delete centr_idx;

    return (EXIT_SUCCESS);
}

<commit_msg>fix dispose-bug<commit_after>/**********************************************************************
* Felix Winterstein, Imperial College London
*
* File: main.cpp
*
* Revision 1.01
* Additional Comments: distributed under a BSD license, see LICENSE.txt
*
**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
//#include <stdbool.h>
#include <time.h>
#include <time.h>
#include <unistd.h>
#include "my_util.h"
#include "lloyds.h"
#include "filter_it.h"
#include "clustering.h"

int main(int argc, char** argv)
{
    uint k = 128;
    uint n = 16384;
    const double std_dev = 0.20;
    const uint fidx = 1;

    // works for linux!
    char path[FILENAME_MAX];
    if (!getcwd(path, sizeof(path))){
        printf("ERROR: getcwd failed\n");
        return EXIT_SUCCESS;
    }
    printf("Working directory is: %s\n",path);

    // allocate input arrays
    data_type_short *data_points = new data_type_short[NMAX];
    centre_type *initial_centres = new centre_type[KMAX];
    uint *centr_idx = new uint[KMAX];

    // read data points file
    if (read_data_points(data_points, n, k, std_dev, fidx) == false) {
        printf("ERROR: Could not find data points file\n");
        return EXIT_SUCCESS;
    }

    // read initial centres file
    if (read_initial_centres(initial_centres, centr_idx, n, k, std_dev, fidx) == false) {
        printf("ERROR: Could not find data points file\n");
        return EXIT_SUCCESS;
    }

    // allocate output arrays
    data_type_short *data_output= new data_type_short[NMAX];
    centre_type *centre_output = new centre_type[KMAX];
    kdTree_type *tree_memory = new kdTree_type[2*NMAX];

    // build kd-tree and run clustering
    uint root;
    #ifdef FILTERING_ALGO
    buildTree(n, k, data_points, &root, tree_memory);
    #endif
    clustering(n, k, initial_centres, data_points, tree_memory, root, data_output, centre_output);

    #ifdef VERBOSE
    // Clustering result
    printf("New centres after clustering\n");
    for (uint i=0; i<k; i++) {
        printf("%d: ",i);
        for (uint d=0; d<D-1; d++) {
            printf("%d ",centre_output[i].position_short.value[d]);
        }
        printf("%d\n",centre_output[i].position_short.value[D-1]);
    }
    #endif

    //write_data_set_info(tree_memory_lo_lo, tree_memory_lo_hi, tree_memory_hi_lo, tree_memory_hi_hi, fidx);

    // free allocated memory
    delete[] data_points;
    delete[] data_output;
    delete[] centre_output;
    delete[] tree_memory;
    delete[] initial_centres;
    delete[] centr_idx;

    return (EXIT_SUCCESS);
}

<|endoftext|>


<commit_before>#ifdef NMC_HAVE_MPI

#include "../gtest.h"

#include <cstring>
#include <vector>

#include <communication/mpi_global_policy.hpp>
#include <communication/mpi.hpp>
#include <util/rangeutil.hpp>

using namespace nest::mc;
using namespace nest::mc::communication;

struct big_thing {
    big_thing() {}
    big_thing(int i): value_(i) {}

    bool operator==(const big_thing& other) const {
        return value_==other.value_ && !std::memcmp(salt_, other.salt_, sizeof(salt_));
    }

    bool operator!=(const big_thing& other) const {
        return !(*this==other);
    }

private:
    int value_;
    char salt_[32] = "it's a lovely day for a picnic";
};

TEST(mpi, gather_all) {
    using policy = mpi_global_policy;

    int id = policy::id();

    std::vector<big_thing> data;
    // odd ranks: three items; even ranks: one item.
    if (id%2) {
        data = { id, id+7, id+8 };
    }
    else {
        data = { id };
    }

    std::vector<big_thing> expected;
    for (int i = 0; i<policy::size(); ++i) {
        if (i%2) {
            int rank_data[] = { i, i+7, i+8 };
            util::append(expected, rank_data);
        }
        else {
            int rank_data[] = { i };
            util::append(expected, rank_data);
        }
    }

    auto gathered = mpi::gather_all(data);

    EXPECT_EQ(expected, gathered);
}

TEST(mpi, gather_all_with_partition) {
    using policy = mpi_global_policy;

    int id = policy::id();

    std::vector<big_thing> data;
    // odd ranks: three items; even ranks: one item.
    if (id%2) {
        data = { id, id+7, id+8 };
    }
    else {
        data = { id };
    }

    std::vector<big_thing> expected_values;
    std::vector<unsigned> expected_divisions;

    expected_divisions.push_back(0);
    for (int i = 0; i<policy::size(); ++i) {
        if (i%2) {
            int rank_data[] = { i, i+7, i+8 };
            util::append(expected_values, rank_data);
            expected_divisions.push_back(expected_divisions.back()+util::size(rank_data));
        }
        else {
            int rank_data[] = { i };
            util::append(expected_values, rank_data);
            expected_divisions.push_back(expected_divisions.back()+util::size(rank_data));
        }
    }

    auto gathered = mpi::gather_all_with_partition(data);

    EXPECT_EQ(expected_values, gathered.values());
    EXPECT_EQ(expected_divisions, gathered.partition());
}

#endif // NMC_HAVE_MPI
<commit_msg>fix bug introduced when global policy was refactored<commit_after>#ifdef NMC_HAVE_MPI

#include "../gtest.h"

#include <cstring>
#include <vector>

#include <communication/global_policy.hpp>
#include <communication/mpi.hpp>
#include <util/rangeutil.hpp>

using namespace nest::mc;
using namespace nest::mc::communication;

struct big_thing {
    big_thing() {}
    big_thing(int i): value_(i) {}

    bool operator==(const big_thing& other) const {
        return value_==other.value_ && !std::memcmp(salt_, other.salt_, sizeof(salt_));
    }

    bool operator!=(const big_thing& other) const {
        return !(*this==other);
    }

private:
    int value_;
    char salt_[32] = "it's a lovely day for a picnic";
};

TEST(mpi, gather_all) {
    using policy = mpi_global_policy;

    int id = policy::id();

    std::vector<big_thing> data;
    // odd ranks: three items; even ranks: one item.
    if (id%2) {
        data = { id, id+7, id+8 };
    }
    else {
        data = { id };
    }

    std::vector<big_thing> expected;
    for (int i = 0; i<policy::size(); ++i) {
        if (i%2) {
            int rank_data[] = { i, i+7, i+8 };
            util::append(expected, rank_data);
        }
        else {
            int rank_data[] = { i };
            util::append(expected, rank_data);
        }
    }

    auto gathered = mpi::gather_all(data);

    EXPECT_EQ(expected, gathered);
}

TEST(mpi, gather_all_with_partition) {
    using policy = mpi_global_policy;

    int id = policy::id();

    std::vector<big_thing> data;
    // odd ranks: three items; even ranks: one item.
    if (id%2) {
        data = { id, id+7, id+8 };
    }
    else {
        data = { id };
    }

    std::vector<big_thing> expected_values;
    std::vector<unsigned> expected_divisions;

    expected_divisions.push_back(0);
    for (int i = 0; i<policy::size(); ++i) {
        if (i%2) {
            int rank_data[] = { i, i+7, i+8 };
            util::append(expected_values, rank_data);
            expected_divisions.push_back(expected_divisions.back()+util::size(rank_data));
        }
        else {
            int rank_data[] = { i };
            util::append(expected_values, rank_data);
            expected_divisions.push_back(expected_divisions.back()+util::size(rank_data));
        }
    }

    auto gathered = mpi::gather_all_with_partition(data);

    EXPECT_EQ(expected_values, gathered.values());
    EXPECT_EQ(expected_divisions, gathered.partition());
}

#endif // NMC_HAVE_MPI
<|endoftext|>


<commit_before>#ifndef __PROCESS_COLLECT_HPP__
#define __PROCESS_COLLECT_HPP__

#include <assert.h>

#include <set>

#include <process/defer.hpp>
#include <process/future.hpp>
#include <process/process.hpp>

namespace process {

// Transforms a set of futures of type T into a set of T's.
template <typename T>
Future<std::set<T> > collect(std::set<Future<T> >& futures);

namespace internal {

template <typename T>
class CollectProcess : public Process<CollectProcess<T> >
{
public:
  CollectProcess(
      const std::set<Future<T> >& _futures,
      Promise<std::set<T> >* _promise)
    : futures(_futures), promise(_promise) {}

  virtual ~CollectProcess()
  {
    delete promise;
  }

  virtual void initialize()
  {
    // Stop this nonsense if nobody cares.
    promise->future().onDiscarded(defer(this, &CollectProcess::discarded));

    typename std::set<Future<T> >::iterator iterator;
    for (iterator = futures.begin(); iterator != futures.end(); ++iterator) {
      const Future<T>& future = *iterator;
      future.onAny(defer(this, &CollectProcess::waited, future));
    }
  }

private:
  void discarded()
  {
    terminate(this);
  }

  void waited(const Future<T>& future)
  {
    if (future.isFailed()) {
      promise->fail(future.failure());
    } else if (future.isDiscarded()) {
      promise->future().discard();
    } else {
      assert(future.isReady());
      values.insert(future.get());
      if (futures.size() == values.size()) {
        promise->set(values);
        terminate(this);
      }
    }
  }

  std::set<Future<T> > futures;
  Promise<std::set<T> >* promise;
  std::set<T> values;
};

} // namespace internal {

template <typename T>
inline Future<std::set<T> > collect(std::set<Future<T> >& futures)
{
  Promise<std::set<T> >* promise = new Promise<std::set<T> >();
  spawn(new internal::CollectProcess<T>(futures, promise), true);
  return promise->future();
}

} // namespace process {

#endif // __PROCESS_COLLECT_HPP__
<commit_msg>Updated semantics of collect (on futures) and updated documentation appropriately.<commit_after>#ifndef __PROCESS_COLLECT_HPP__
#define __PROCESS_COLLECT_HPP__

#include <assert.h>

#include <set>

#include <process/defer.hpp>
#include <process/future.hpp>
#include <process/process.hpp>

namespace process {

// Waits on each future in the specified set and returns the set of
// resulting values. If any future is discarded then the result will
// be a failure. Likewise, if any future fails than the result future
// will be a failure.
template <typename T>
Future<std::set<T> > collect(std::set<Future<T> >& futures);

namespace internal {

template <typename T>
class CollectProcess : public Process<CollectProcess<T> >
{
public:
  CollectProcess(
      const std::set<Future<T> >& _futures,
      Promise<std::set<T> >* _promise)
    : futures(_futures), promise(_promise) {}

  virtual ~CollectProcess()
  {
    delete promise;
  }

  virtual void initialize()
  {
    // Stop this nonsense if nobody cares.
    promise->future().onDiscarded(defer(this, &CollectProcess::discarded));

    typename std::set<Future<T> >::iterator iterator;
    for (iterator = futures.begin(); iterator != futures.end(); ++iterator) {
      const Future<T>& future = *iterator;
      future.onAny(defer(this, &CollectProcess::waited, future));
    }
  }

private:
  void discarded()
  {
    terminate(this);
  }

  void waited(const Future<T>& future)
  {
    if (future.isFailed()) {
      promise->fail("Collect failed: " + future.failure());
    } else if (future.isDiscarded()) {
      promise->fail("Collect failed: future discarded");
    } else {
      assert(future.isReady());
      values.insert(future.get());
      if (futures.size() == values.size()) {
        promise->set(values);
        terminate(this);
      }
    }
  }

  std::set<Future<T> > futures;
  Promise<std::set<T> >* promise;
  std::set<T> values;
};

} // namespace internal {

template <typename T>
inline Future<std::set<T> > collect(std::set<Future<T> >& futures)
{
  Promise<std::set<T> >* promise = new Promise<std::set<T> >();
  spawn(new internal::CollectProcess<T>(futures, promise), true);
  return promise->future();
}

} // namespace process {

#endif // __PROCESS_COLLECT_HPP__
<|endoftext|>


<commit_before>#ifndef BFC_AST_SEQ_HPP
#define BFC_AST_SEQ_HPP

#include "ast/base.hpp"
#include "ast/visitor.hpp"
#include <deque>

namespace bfc {
namespace ast {

class seq : public base {

  using container = std::deque<node>;

public:

  using size_type = typename container::size_type;
  using iterator = typename container::iterator;
  using const_iterator = typename container::const_iterator;

  seq(void);

  template <class InputIt>
  seq(InputIt begin, InputIt end);

  void swap(seq &other) noexcept;

  iterator begin(void) noexcept;
  const_iterator begin(void) const noexcept;
  const_iterator cbegin(void) const noexcept;

  iterator end(void) noexcept;
  const_iterator end(void) const noexcept;
  const_iterator cend(void) const noexcept;

  node &front(void) noexcept;
  const node &front(void) const noexcept;
  node &back(void) noexcept;
  const node &back(void) const noexcept;
  bool empty(void) const noexcept;
  size_type size(void) const noexcept;

  void clear(void) noexcept;
  iterator insert(const_iterator it, node elem);
  template <class InputIt>
  iterator insert(const_iterator it, InputIt first, InputIt last);
  template <class ...Args>
  iterator emplace(const_iterator it, Args &&...args);
  iterator remove(const_iterator it) noexcept;
  iterator remove(const_iterator first, const_iterator last) noexcept;

  void push_front(node node);
  void push_back(node node);
  void pop_front(void) noexcept;
  void pop_back(void) noexcept;

  template <class ...Args>
  void emplace_front(Args &&...args);

  template <class ...Args>
  void emplace_back(Args &&...args);

  visitor::status accept(visitor &visitor) override;
  visitor::status accept(visitor &visitor) const override;
  base *clone(void) const override;

private:

  container elems;

};

template <class InputIt>
seq::seq(InputIt first, InputIt last) : elems(first, last) {}

template <class InputIt>
seq::iterator
seq::insert(const_iterator it, InputIt first, InputIt last)
{
  return elems.insert(first, last);
}

template <class ...Args>
seq::iterator
seq::emplace(const_iterator it, Args &&...args)
{
  return elems.emplace(it, std::forward<Args>(args)...);
}

template <class ...Args>
void
seq::emplace_front(Args &&...args)
{
  elems.emplace_front(std::forward<Args>(args)...);
}

template <class ...Args>
void
seq::emplace_back(Args &&...args)
{
  elems.emplace_back(std::forward<Args>(args)...);
}

}
}

#endif /* !BFC_AST_SEQ_HPP */
<commit_msg>Fix bug in seq::insert definition.<commit_after>#ifndef BFC_AST_SEQ_HPP
#define BFC_AST_SEQ_HPP

#include "ast/base.hpp"
#include "ast/visitor.hpp"
#include <deque>

namespace bfc {
namespace ast {

class seq : public base {

  using container = std::deque<node>;

public:

  using size_type = typename container::size_type;
  using iterator = typename container::iterator;
  using const_iterator = typename container::const_iterator;

  seq(void);

  template <class InputIt>
  seq(InputIt begin, InputIt end);

  void swap(seq &other) noexcept;

  iterator begin(void) noexcept;
  const_iterator begin(void) const noexcept;
  const_iterator cbegin(void) const noexcept;

  iterator end(void) noexcept;
  const_iterator end(void) const noexcept;
  const_iterator cend(void) const noexcept;

  node &front(void) noexcept;
  const node &front(void) const noexcept;
  node &back(void) noexcept;
  const node &back(void) const noexcept;
  bool empty(void) const noexcept;
  size_type size(void) const noexcept;

  void clear(void) noexcept;
  iterator insert(const_iterator it, node elem);
  template <class InputIt>
  iterator insert(const_iterator it, InputIt first, InputIt last);
  template <class ...Args>
  iterator emplace(const_iterator it, Args &&...args);
  iterator remove(const_iterator it) noexcept;
  iterator remove(const_iterator first, const_iterator last) noexcept;

  void push_front(node node);
  void push_back(node node);
  void pop_front(void) noexcept;
  void pop_back(void) noexcept;

  template <class ...Args>
  void emplace_front(Args &&...args);

  template <class ...Args>
  void emplace_back(Args &&...args);

  visitor::status accept(visitor &visitor) override;
  visitor::status accept(visitor &visitor) const override;

private:

  base *clone(void) const override;
  container elems;

};

template <class InputIt>
seq::seq(InputIt first, InputIt last) : elems(first, last) {}

template <class InputIt>
seq::iterator
seq::insert(const_iterator it, InputIt first, InputIt last)
{
  return elems.insert(it, first, last);
}

template <class ...Args>
seq::iterator
seq::emplace(const_iterator it, Args &&...args)
{
  return elems.emplace(it, std::forward<Args>(args)...);
}

template <class ...Args>
void
seq::emplace_front(Args &&...args)
{
  elems.emplace_front(std::forward<Args>(args)...);
}

template <class ...Args>
void
seq::emplace_back(Args &&...args)
{
  elems.emplace_back(std::forward<Args>(args)...);
}

}
}

#endif /* !BFC_AST_SEQ_HPP */
<|endoftext|>


<commit_before>/*
 * Author: Dino Wernli
 */

#include "scene_parser.h"

#include <glog/logging.h>

#include "parser/mesh_parser.h"
#include "proto/scene/scene_data.pb.h"
#include "proto/util/color_data.pb.h"
#include "scene/camera.h"
#include "scene/element.h"
#include "scene/geometry/circle_plane.h"
#include "scene/geometry/plane.h"
#include "scene/geometry/sphere.h"
#include "scene/geometry/triangle.h"
#include "scene/material.h"
#include "scene/mesh.h"
#include "scene/point_light.h"
#include "scene/scene.h"
#include "util/color3.h"
#include "util/point3.h"
#include "util/vector3.h"

SceneParser::SceneParser() {
}

SceneParser::~SceneParser() {
}

static Color3 Parse(const raytracer::ColorData& data) {
  return Color3(data.r(), data.g(), data.b());
}

static Vector3 Parse(const raytracer::VectorData& data) {
  return Vector3(data.x(), data.y(), data.z());
}

static Point3 Parse(const raytracer::PointData& data) {
  return Point3(data.x(), data.y(), data.z());
}

// Fetches the material pointer from the map, returns none if it is not found.
Material* SceneParser::GetMaterial(const std::string& id) const {
  auto it = material_map_.find(id);
  return ((it == material_map_.end()) ? NULL : it->second);
}

Material* SceneParser::ParseMaterial(const raytracer::MaterialData& data) {
  if (!(data.has_emission() && data.has_ambient()
      && data.has_diffuse() && data.has_specular())) {
    return NULL;
  }

  return new Material(Parse(data.emission()), Parse(data.ambient()),
                      Parse(data.diffuse()), Parse(data.specular()),
                      data.shininess(), data.reflection_percentage(),
                      data.refraction_percentage(), data.refraction_index());
}

// static
void SceneParser::ParseScene(const raytracer::SceneData& data, Scene* scene) {
  material_map_.clear();

  if (data.has_background()) {
    scene->set_background(Parse(data.background()));
  }

  if (data.has_ambient()) {
    scene->set_ambient(Parse(data.ambient()));
  }

  Material* material = NULL;
  for (int i = 0; i < data.materials_size(); ++i) {
    if (!data.materials(i).has_identifier()) {
      LOG(WARNING) << "Skipping material without identifier";
      continue;
    }

    if (!(material = ParseMaterial(data.materials(i)))) {
      LOG(WARNING) << "Skipping incomplete material";
      continue;
    }

    // Ownership taken by scene.
    scene->AddMaterial(material);
    material_map_[data.materials(i).identifier()] = material;
  }

  if (data.has_camera()) {
    const auto& camera = data.camera();
    if (!(camera.has_position() && camera.has_view() && camera.has_up()
        && camera.has_opening_angle() && camera.resolution_x()
        && camera.resolution_y())) {
      LOG(WARNING) << "Skipping incomplete camera";
    } else {
      scene->set_camera(new Camera(Parse(data.camera().position()),
                                   Parse(data.camera().view()),
                                   Parse(data.camera().up()),
                                   data.camera().opening_angle(),
                                   data.camera().resolution_x(),
                                   data.camera().resolution_y()));
    }
  }

  for (int i = 0; i < data.lights_size(); ++i) {
    if (!(data.lights(i).has_position() && data.lights(i).has_color())) {
      LOG(WARNING) << "Skipping incomplete light";
      continue;
    }
    scene->AddLight(new PointLight(Parse(data.lights(i).position()),
                                   Parse(data.lights(i).color())));
  }

  // Parse triangles if any.
  for (int i = 0; i < data.triangles_size(); ++i) {
    const auto& triangle = data.triangles(i);
    std::unique_ptr<Vector3> n1(triangle.has_n1() ?
        new Vector3(Parse(triangle.n1())) : NULL);
    std::unique_ptr<Vector3> n2(triangle.has_n2() ?
        new Vector3(Parse(triangle.n2())) : NULL);
    std::unique_ptr<Vector3> n3(triangle.has_n3() ?
        new Vector3(Parse(triangle.n3())) : NULL);

    if (triangle.has_p1() && triangle.has_p2() && triangle.has_p3()) {
      if (!(material = GetMaterial(triangle.material_id()))) {
        LOG(WARNING) << "Failed to get material, skipping triangle";
        continue;
      }
      scene->AddElement(
          new Triangle(Parse(triangle.p1()), Parse(triangle.p2()),
                       Parse(triangle.p3()), *material,
                       n1.get(), n2.get(), n3.get()));
    } else {
      LOG(WARNING) << "Skipping incomplete triangle";
    }
  }

  // Parse planes if any.
  for (int i = 0; i < data.planes_size(); ++i) {
    const auto& plane = data.planes(i);
    if (plane.has_point() && plane.has_normal()) {
      if (!(material = GetMaterial(plane.material_id()))) {
        LOG(WARNING) << "Failed to get material, skipping plane";
        continue;
      }

      scene->AddElement(
          new Plane(Parse(plane.point()), Parse(plane.normal()), *material));
    } else {
      LOG(WARNING) << "Skipping incomplete plane";
    }
  }

  // Parse circle planes if any.
  for (int i = 0; i < data.circle_planes_size(); ++i) {
    const auto& cplane = data.circle_planes(i);
    if (!(cplane.has_plane_data() && cplane.plane_data().has_point()
          && cplane.plane_data().has_normal())) {
      LOG(WARNING) << "Skipping incomplete circle plane";
      continue;
    }

    const Material* main_material;
    if (!(main_material = GetMaterial(cplane.plane_data().material_id()))) {
      LOG(WARNING) << "Failed to get main material, skipping circle plane";
      continue;
    }

    const Material* ring_material;
    if (!(ring_material = GetMaterial(cplane.ring_material_id()))) {
      LOG(WARNING) << "Failed to get ring material, skipping circle plane";
      continue;
    }

    scene->AddElement(new CirclePlane(
        Parse(cplane.plane_data().point()), Parse(cplane.plane_data().normal()),
        cplane.radius(), *main_material, *ring_material));
  }

  // Parse spheres if any.
  for (int i = 0; i < data.spheres_size(); ++i) {
    const auto& sphere = data.spheres(i);
    if (!(material = GetMaterial(sphere.material_id()))) {
      LOG(WARNING) << "Failed to get material, skipping sphere";
      continue;
    }

    if (sphere.has_center() && sphere.has_radius()) {
      scene->AddElement(new Sphere(Parse(sphere.center()), sphere.radius(),
                                   *material));
    } else {
      LOG(WARNING) << "Skipping incomplete sphere";
    }
  }

  // Load meshes if any.
  MeshParser parser;
  for (int i = 0; i < data.meshes_size(); ++i) {
    const auto& mesh_data = data.meshes(i);
    if (mesh_data.has_obj_file()) {
      const std::string& path = mesh_data.obj_file();
      Mesh* mesh = parser.LoadFile(path);
      if (mesh != NULL) {
        if (!(material = GetMaterial(mesh_data.material_id()))) {
          LOG(WARNING) << "Failed to get main material, skipping mesh";
          continue;
        }

        mesh->set_material(material);
        if (mesh_data.has_translation() || mesh_data.has_radius()) {
          Vector3 translation;
          if (mesh_data.has_translation()) {
            translation = Parse(mesh_data.translation());
          }
          mesh->Transform(mesh_data.has_radius() ? mesh_data.radius() : 1,
                          translation);
        }
        mesh->InferNormals();
        scene->AddMesh(mesh);
      } else {
        LOG(WARNING) << "Unable to load mesh from: " << path;
      }
    } else {
      LOG(WARNING) << "Skipping incomplete mesh";
    }
  }
}
<commit_msg>Remove misleading comment.<commit_after>/*
 * Author: Dino Wernli
 */

#include "scene_parser.h"

#include <glog/logging.h>

#include "parser/mesh_parser.h"
#include "proto/scene/scene_data.pb.h"
#include "proto/util/color_data.pb.h"
#include "scene/camera.h"
#include "scene/element.h"
#include "scene/geometry/circle_plane.h"
#include "scene/geometry/plane.h"
#include "scene/geometry/sphere.h"
#include "scene/geometry/triangle.h"
#include "scene/material.h"
#include "scene/mesh.h"
#include "scene/point_light.h"
#include "scene/scene.h"
#include "util/color3.h"
#include "util/point3.h"
#include "util/vector3.h"

SceneParser::SceneParser() {
}

SceneParser::~SceneParser() {
}

static Color3 Parse(const raytracer::ColorData& data) {
  return Color3(data.r(), data.g(), data.b());
}

static Vector3 Parse(const raytracer::VectorData& data) {
  return Vector3(data.x(), data.y(), data.z());
}

static Point3 Parse(const raytracer::PointData& data) {
  return Point3(data.x(), data.y(), data.z());
}

// Fetches the material pointer from the map, returns none if it is not found.
Material* SceneParser::GetMaterial(const std::string& id) const {
  auto it = material_map_.find(id);
  return ((it == material_map_.end()) ? NULL : it->second);
}

Material* SceneParser::ParseMaterial(const raytracer::MaterialData& data) {
  if (!(data.has_emission() && data.has_ambient()
      && data.has_diffuse() && data.has_specular())) {
    return NULL;
  }

  return new Material(Parse(data.emission()), Parse(data.ambient()),
                      Parse(data.diffuse()), Parse(data.specular()),
                      data.shininess(), data.reflection_percentage(),
                      data.refraction_percentage(), data.refraction_index());
}

void SceneParser::ParseScene(const raytracer::SceneData& data, Scene* scene) {
  material_map_.clear();

  if (data.has_background()) {
    scene->set_background(Parse(data.background()));
  }

  if (data.has_ambient()) {
    scene->set_ambient(Parse(data.ambient()));
  }

  Material* material = NULL;
  for (int i = 0; i < data.materials_size(); ++i) {
    if (!data.materials(i).has_identifier()) {
      LOG(WARNING) << "Skipping material without identifier";
      continue;
    }

    if (!(material = ParseMaterial(data.materials(i)))) {
      LOG(WARNING) << "Skipping incomplete material";
      continue;
    }

    // Ownership taken by scene.
    scene->AddMaterial(material);
    material_map_[data.materials(i).identifier()] = material;
  }

  if (data.has_camera()) {
    const auto& camera = data.camera();
    if (!(camera.has_position() && camera.has_view() && camera.has_up()
        && camera.has_opening_angle() && camera.resolution_x()
        && camera.resolution_y())) {
      LOG(WARNING) << "Skipping incomplete camera";
    } else {
      scene->set_camera(new Camera(Parse(data.camera().position()),
                                   Parse(data.camera().view()),
                                   Parse(data.camera().up()),
                                   data.camera().opening_angle(),
                                   data.camera().resolution_x(),
                                   data.camera().resolution_y()));
    }
  }

  for (int i = 0; i < data.lights_size(); ++i) {
    if (!(data.lights(i).has_position() && data.lights(i).has_color())) {
      LOG(WARNING) << "Skipping incomplete light";
      continue;
    }
    scene->AddLight(new PointLight(Parse(data.lights(i).position()),
                                   Parse(data.lights(i).color())));
  }

  // Parse triangles if any.
  for (int i = 0; i < data.triangles_size(); ++i) {
    const auto& triangle = data.triangles(i);
    std::unique_ptr<Vector3> n1(triangle.has_n1() ?
        new Vector3(Parse(triangle.n1())) : NULL);
    std::unique_ptr<Vector3> n2(triangle.has_n2() ?
        new Vector3(Parse(triangle.n2())) : NULL);
    std::unique_ptr<Vector3> n3(triangle.has_n3() ?
        new Vector3(Parse(triangle.n3())) : NULL);

    if (triangle.has_p1() && triangle.has_p2() && triangle.has_p3()) {
      if (!(material = GetMaterial(triangle.material_id()))) {
        LOG(WARNING) << "Failed to get material, skipping triangle";
        continue;
      }
      scene->AddElement(
          new Triangle(Parse(triangle.p1()), Parse(triangle.p2()),
                       Parse(triangle.p3()), *material,
                       n1.get(), n2.get(), n3.get()));
    } else {
      LOG(WARNING) << "Skipping incomplete triangle";
    }
  }

  // Parse planes if any.
  for (int i = 0; i < data.planes_size(); ++i) {
    const auto& plane = data.planes(i);
    if (plane.has_point() && plane.has_normal()) {
      if (!(material = GetMaterial(plane.material_id()))) {
        LOG(WARNING) << "Failed to get material, skipping plane";
        continue;
      }

      scene->AddElement(
          new Plane(Parse(plane.point()), Parse(plane.normal()), *material));
    } else {
      LOG(WARNING) << "Skipping incomplete plane";
    }
  }

  // Parse circle planes if any.
  for (int i = 0; i < data.circle_planes_size(); ++i) {
    const auto& cplane = data.circle_planes(i);
    if (!(cplane.has_plane_data() && cplane.plane_data().has_point()
          && cplane.plane_data().has_normal())) {
      LOG(WARNING) << "Skipping incomplete circle plane";
      continue;
    }

    const Material* main_material;
    if (!(main_material = GetMaterial(cplane.plane_data().material_id()))) {
      LOG(WARNING) << "Failed to get main material, skipping circle plane";
      continue;
    }

    const Material* ring_material;
    if (!(ring_material = GetMaterial(cplane.ring_material_id()))) {
      LOG(WARNING) << "Failed to get ring material, skipping circle plane";
      continue;
    }

    scene->AddElement(new CirclePlane(
        Parse(cplane.plane_data().point()), Parse(cplane.plane_data().normal()),
        cplane.radius(), *main_material, *ring_material));
  }

  // Parse spheres if any.
  for (int i = 0; i < data.spheres_size(); ++i) {
    const auto& sphere = data.spheres(i);
    if (!(material = GetMaterial(sphere.material_id()))) {
      LOG(WARNING) << "Failed to get material, skipping sphere";
      continue;
    }

    if (sphere.has_center() && sphere.has_radius()) {
      scene->AddElement(new Sphere(Parse(sphere.center()), sphere.radius(),
                                   *material));
    } else {
      LOG(WARNING) << "Skipping incomplete sphere";
    }
  }

  // Load meshes if any.
  MeshParser parser;
  for (int i = 0; i < data.meshes_size(); ++i) {
    const auto& mesh_data = data.meshes(i);
    if (mesh_data.has_obj_file()) {
      const std::string& path = mesh_data.obj_file();
      Mesh* mesh = parser.LoadFile(path);
      if (mesh != NULL) {
        if (!(material = GetMaterial(mesh_data.material_id()))) {
          LOG(WARNING) << "Failed to get main material, skipping mesh";
          continue;
        }

        mesh->set_material(material);
        if (mesh_data.has_translation() || mesh_data.has_radius()) {
          Vector3 translation;
          if (mesh_data.has_translation()) {
            translation = Parse(mesh_data.translation());
          }
          mesh->Transform(mesh_data.has_radius() ? mesh_data.radius() : 1,
                          translation);
        }
        mesh->InferNormals();
        scene->AddMesh(mesh);
      } else {
        LOG(WARNING) << "Unable to load mesh from: " << path;
      }
    } else {
      LOG(WARNING) << "Skipping incomplete mesh";
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2013 ZNC, see the NOTICE file for details.
 *
 * 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 <znc/FileUtils.h>
#include <znc/Client.h>
#include <znc/Chan.h>
#include <znc/Modules.h>

using std::vector;

class CBacklogMod : public CModule {
public:
	MODCONSTRUCTOR(CBacklogMod) {}

	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		PutModule("I'm being loaded with the arguments: [" + sArgs + "]");
		//AddTimer(new CSampleTimer(this, 300, 0, "Sample", "Sample timer for sample things."));
		//AddTimer(new CSampleTimer(this, 5, 20, "Another", "Another sample timer."));
		//AddTimer(new CSampleTimer(this, 25000, 5, "Third", "A third sample timer."));
		return true;
	}

	virtual ~CBacklogMod() {
		PutModule("I'm being unloaded!");
	}

	virtual bool OnBoot() {
		// This is called when the app starts up (only modules that are loaded in the config will get this event)
		return true;
	}

	virtual void OnModCommand(const CString& sCommand) {
		/*
		if (sCommand.Equals("TIMERS")) {
			ListTimers();
		}
		*/
		// TODO: sanity check on file path, see log.cpp

		CFile LogFile(sCommand);
		CString Line;

		if (LogFile.Open()) {
			while (LogFile.ReadLine(Line)) {
				PutModule(Line);
			}
		} else {
			PutModule("Could not open log file [" + sCommand + "]: " + strerror(errno));
		}

		LogFile.Close();
	}
};

template<> void TModInfo<CBacklogMod>(CModInfo& Info) {
	Info.SetWikiPage("sample");
	Info.SetHasArgs(true);
	Info.SetArgsHelpText("Takes %Channelname% and %number of lines% as arguments");
}

NETWORKMODULEDEFS(CBacklogMod, "Module for getting the last X lines of a channels log.")

<commit_msg>cleanup<commit_after>/*
 * Copyright (C) 2004-2013 ZNC, see the NOTICE file for details.
 *
 * 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 <znc/FileUtils.h>
#include <znc/Client.h>
#include <znc/Chan.h>
#include <znc/Modules.h>

class CBacklogMod : public CModule {
public:
	MODCONSTRUCTOR(CBacklogMod) {}

	virtual bool OnLoad(const CString& sArgs, CString& sMessage);
	virtual ~CBacklogMod();
	virtual void OnModCommand(const CString& sCommand);

private:
	CString			LogPath;
};

bool CBacklogMod::OnLoad(const CString& sArgs, CString& sMessage) {
	PutModule("I'm being loaded with the arguments: [" + sArgs + "]");
	return true;
}

CBacklogMod::~CBacklogMod() {
	PutModule("I'm being unloaded!");
}

void CBacklogMod::OnModCommand(const CString& sCommand) {
	CFile LogFile(sCommand);
	CString Line;

	if (LogFile.Open()) {
		while (LogFile.ReadLine(Line)) {
			PutModule(Line);
		}
	} else {
		PutModule("Could not open log file [" + sCommand + "]: " + strerror(errno));
	}

	LogFile.Close();
}

template<> void TModInfo<CBacklogMod>(CModInfo& Info) {
	Info.AddType(CModInfo::NetworkModule);
	Info.AddType(CModInfo::GlobalModule);
	Info.SetWikiPage("backlog");
	Info.SetArgsHelpText("Takes path to logs as argument, use keywords: $USER, $NETWORK and $WINDOW");
	Info.SetHasArgs(true);
}

NETWORKMODULEDEFS(CBacklogMod, "Module for getting the last X lines of a channels log.")
<|endoftext|>