<commit_before>//===-- TargetAsmInfo.cpp - Asm Info ---------------------------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines target asm properties related what form asm statements
// should take.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Dwarf.h"
#include <cctype>
#include <cstring>

using namespace llvm;

TargetAsmInfo::TargetAsmInfo() :
  TextSection("\t.text"),
  DataSection("\t.data"),
  BSSSection("\t.bss"),
  TLSDataSection("\t.section .tdata,\"awT\",@progbits"),
  TLSBSSSection("\t.section .tbss,\"awT\",@nobits"),
  ZeroFillDirective(0),
  NonexecutableStackDirective(0),
  NeedsSet(false),
  MaxInstLength(4),
  PCSymbol("$"),
  SeparatorChar(';'),
  CommentString("#"),
  GlobalPrefix(""),
  PrivateGlobalPrefix("."),
  JumpTableSpecialLabelPrefix(0),
  GlobalVarAddrPrefix(""),
  GlobalVarAddrSuffix(""),
  FunctionAddrPrefix(""),
  FunctionAddrSuffix(""),
  PersonalityPrefix(""),
  PersonalitySuffix(""),
  NeedsIndirectEncoding(false),
  InlineAsmStart("#APP"),
  InlineAsmEnd("#NO_APP"),
  AssemblerDialect(0),
  StringConstantPrefix(".str"),
  ZeroDirective("\t.zero\t"),
  ZeroDirectiveSuffix(0),
  AsciiDirective("\t.ascii\t"),
  AscizDirective("\t.asciz\t"),
  Data8bitsDirective("\t.byte\t"),
  Data16bitsDirective("\t.short\t"),
  Data32bitsDirective("\t.long\t"),
  Data64bitsDirective("\t.quad\t"),
  AlignDirective("\t.align\t"),
  AlignmentIsInBytes(true),
  TextAlignFillValue(0),
  SwitchToSectionDirective("\t.section\t"),
  TextSectionStartSuffix(""),
  DataSectionStartSuffix(""),
  SectionEndDirectiveSuffix(0),
  ConstantPoolSection("\t.section .rodata"),
  JumpTableDataSection("\t.section .rodata"),
  JumpTableDirective(0),
  CStringSection(0),
  StaticCtorsSection("\t.section .ctors,\"aw\",@progbits"),
  StaticDtorsSection("\t.section .dtors,\"aw\",@progbits"),
  FourByteConstantSection(0),
  EightByteConstantSection(0),
  SixteenByteConstantSection(0),
  ReadOnlySection(0),
  GlobalDirective("\t.globl\t"),
  SetDirective(0),
  LCOMMDirective(0),
  COMMDirective("\t.comm\t"),
  COMMDirectiveTakesAlignment(true),
  HasDotTypeDotSizeDirective(true),
  UsedDirective(0),
  WeakRefDirective(0),
  WeakDefDirective(0),
  HiddenDirective("\t.hidden\t"),
  ProtectedDirective("\t.protected\t"),
  AbsoluteDebugSectionOffsets(false),
  AbsoluteEHSectionOffsets(false),
  HasLEB128(false),
  HasDotLocAndDotFile(false),
  SupportsDebugInformation(false),
  SupportsExceptionHandling(false),
  DwarfRequiresFrameSection(true),
  GlobalEHDirective(0),
  SupportsWeakOmittedEHFrame(true),
  DwarfSectionOffsetDirective(0),
  DwarfAbbrevSection(".debug_abbrev"),
  DwarfInfoSection(".debug_info"),
  DwarfLineSection(".debug_line"),
  DwarfFrameSection(".debug_frame"),
  DwarfPubNamesSection(".debug_pubnames"),
  DwarfPubTypesSection(".debug_pubtypes"),
  DwarfStrSection(".debug_str"),
  DwarfLocSection(".debug_loc"),
  DwarfARangesSection(".debug_aranges"),
  DwarfRangesSection(".debug_ranges"),
  DwarfMacInfoSection(".debug_macinfo"),
  DwarfEHFrameSection(".eh_frame"),
  DwarfExceptionSection(".gcc_except_table"),
  AsmTransCBE(0) {
}

TargetAsmInfo::~TargetAsmInfo() {
}

/// Measure the specified inline asm to determine an approximation of its
/// length.
/// Comments (which run till the next SeparatorChar or newline) do not
/// count as an instruction.
/// Any other non-whitespace text is considered an instruction, with
/// multiple instructions separated by SeparatorChar or newlines.
/// Variable-length instructions are not handled here; this function
/// may be overloaded in the target code to do that.
unsigned TargetAsmInfo::getInlineAsmLength(const char *Str) const {
  // Count the number of instructions in the asm.
  bool atInsnStart = true;
  unsigned Length = 0;
  for (; *Str; ++Str) {
    if (*Str == '\n' || *Str == SeparatorChar)
      atInsnStart = true;
    if (atInsnStart && !isspace(*Str)) {
      Length += MaxInstLength;
      atInsnStart = false;
    }
    if (atInsnStart && strncmp(Str, CommentString, strlen(CommentString))==0)
      atInsnStart = false;
  }

  return Length;
}

unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
                                              bool Global) const {
  return dwarf::DW_EH_PE_absptr;
}

static bool isSuitableForBSS(const GlobalVariable *GV) {
  if (!GV->hasInitializer())
    return true;

  // Leave constant zeros in readonly constant sections, so they can be shared
  Constant *C = GV->getInitializer();
  return (C->isNullValue() && !GV->isConstant() && !NoZerosInBSS);
}

SectionKind::Kind
TargetAsmInfo::SectionKindForGlobal(const GlobalValue *GV) const {
  // Early exit - functions should be always in text sections.
  if (isa<Function>(GV))
    return SectionKind::Text;

  const GlobalVariable* GVar = dyn_cast<GlobalVariable>(GV);
  bool isThreadLocal = GVar->isThreadLocal();
  assert(GVar && "Invalid global value for section selection");

  SectionKind::Kind kind;
  if (isSuitableForBSS(GVar)) {
    // Variable can be easily put to BSS section.
    return (isThreadLocal ? SectionKind::ThreadBSS : SectionKind::BSS);
  } else if (GVar->isConstant() && !isThreadLocal) {
    // Now we know, that varible has initializer and it is constant. We need to
    // check its initializer to decide, which section to output it into. Also
    // note, there is no thread-local r/o section.
    Constant *C = GVar->getInitializer();
    if (C->ContainsRelocations())
      kind = SectionKind::ROData;
    else {
      const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
      // Check, if initializer is a null-terminated string
      if (CVA && CVA->isCString())
        kind = SectionKind::RODataMergeStr;
      else
        kind = SectionKind::RODataMergeConst;
    }
  }

  // Variable is not constant or thread-local - emit to generic data section.
  return (isThreadLocal ? SectionKind::ThreadData : SectionKind::Data);
}

unsigned
TargetAsmInfo::SectionFlagsForGlobal(const GlobalValue *GV,
                                     const char* name) const {
  unsigned flags = SectionFlags::None;

  // Decode flags from global itself.
  if (GV) {
    SectionKind::Kind kind = SectionKindForGlobal(GV);
    switch (kind) {
     case SectionKind::Text:
      flags |= SectionFlags::Code;
      break;
     case SectionKind::ThreadData:
      flags |= SectionFlags::TLS;
      // FALLS THROUGH
     case SectionKind::Data:
      flags |= SectionFlags::Writeable;
      break;
     case SectionKind::ThreadBSS:
      flags |= SectionFlags::TLS;
      // FALLS THROUGH
     case SectionKind::BSS:
      flags |= SectionFlags::BSS;
      break;
     case SectionKind::ROData:
      // No additional flags here
      break;
     case SectionKind::RODataMergeStr:
      flags |= SectionFlags::Strings;
      // FALLS THROUGH
     case SectionKind::RODataMergeConst:
      flags |= SectionFlags::Mergeable;
      break;
     default:
      assert(0 && "Unexpected section kind!");
    }

    if (GV->hasLinkOnceLinkage() ||
        GV->hasWeakLinkage() ||
        GV->hasCommonLinkage())
      flags |= SectionFlags::Linkonce;
  }

  // Add flags from sections, if any.
  if (name) {
    // Some lame default implementation
    if (strcmp(name, ".bss") == 0 ||
        strncmp(name, ".bss.", 5) == 0 ||
        strncmp(name, ".gnu.linkonce.b.", 16) == 0)
      flags |= SectionFlags::BSS;
    else if (strcmp(name, ".tdata") == 0 ||
             strncmp(name, ".tdata.", 7) == 0 ||
             strncmp(name, ".gnu.linkonce.td.", 17) == 0)
      flags |= SectionFlags::TLS;
    else if (strcmp(name, ".tbss") == 0 ||
             strncmp(name, ".tbss.", 6) == 0 ||
             strncmp(name, ".gnu.linkonce.tb.", 17) == 0)
      flags |= SectionFlags::BSS | SectionFlags::TLS;
  }

  return flags;
}

const char*
TargetAsmInfo::SectionForGlobal(const GlobalValue *GV) const {
  SectionKind::Kind kind = SectionKindForGlobal(GV);

  if (kind == SectionKind::Text)
    return getTextSection();
  else if (kind == SectionKind::BSS && getBSSSection())
    return getBSSSection();

  return getDataSection();
}
<commit_msg>Use 'llvm-linkonce' consistently<commit_after>//===-- TargetAsmInfo.cpp - Asm Info ---------------------------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines target asm properties related what form asm statements
// should take.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Dwarf.h"
#include <cctype>
#include <cstring>

using namespace llvm;

TargetAsmInfo::TargetAsmInfo() :
  TextSection("\t.text"),
  DataSection("\t.data"),
  BSSSection("\t.bss"),
  TLSDataSection("\t.section .tdata,\"awT\",@progbits"),
  TLSBSSSection("\t.section .tbss,\"awT\",@nobits"),
  ZeroFillDirective(0),
  NonexecutableStackDirective(0),
  NeedsSet(false),
  MaxInstLength(4),
  PCSymbol("$"),
  SeparatorChar(';'),
  CommentString("#"),
  GlobalPrefix(""),
  PrivateGlobalPrefix("."),
  JumpTableSpecialLabelPrefix(0),
  GlobalVarAddrPrefix(""),
  GlobalVarAddrSuffix(""),
  FunctionAddrPrefix(""),
  FunctionAddrSuffix(""),
  PersonalityPrefix(""),
  PersonalitySuffix(""),
  NeedsIndirectEncoding(false),
  InlineAsmStart("#APP"),
  InlineAsmEnd("#NO_APP"),
  AssemblerDialect(0),
  StringConstantPrefix(".str"),
  ZeroDirective("\t.zero\t"),
  ZeroDirectiveSuffix(0),
  AsciiDirective("\t.ascii\t"),
  AscizDirective("\t.asciz\t"),
  Data8bitsDirective("\t.byte\t"),
  Data16bitsDirective("\t.short\t"),
  Data32bitsDirective("\t.long\t"),
  Data64bitsDirective("\t.quad\t"),
  AlignDirective("\t.align\t"),
  AlignmentIsInBytes(true),
  TextAlignFillValue(0),
  SwitchToSectionDirective("\t.section\t"),
  TextSectionStartSuffix(""),
  DataSectionStartSuffix(""),
  SectionEndDirectiveSuffix(0),
  ConstantPoolSection("\t.section .rodata"),
  JumpTableDataSection("\t.section .rodata"),
  JumpTableDirective(0),
  CStringSection(0),
  StaticCtorsSection("\t.section .ctors,\"aw\",@progbits"),
  StaticDtorsSection("\t.section .dtors,\"aw\",@progbits"),
  FourByteConstantSection(0),
  EightByteConstantSection(0),
  SixteenByteConstantSection(0),
  ReadOnlySection(0),
  GlobalDirective("\t.globl\t"),
  SetDirective(0),
  LCOMMDirective(0),
  COMMDirective("\t.comm\t"),
  COMMDirectiveTakesAlignment(true),
  HasDotTypeDotSizeDirective(true),
  UsedDirective(0),
  WeakRefDirective(0),
  WeakDefDirective(0),
  HiddenDirective("\t.hidden\t"),
  ProtectedDirective("\t.protected\t"),
  AbsoluteDebugSectionOffsets(false),
  AbsoluteEHSectionOffsets(false),
  HasLEB128(false),
  HasDotLocAndDotFile(false),
  SupportsDebugInformation(false),
  SupportsExceptionHandling(false),
  DwarfRequiresFrameSection(true),
  GlobalEHDirective(0),
  SupportsWeakOmittedEHFrame(true),
  DwarfSectionOffsetDirective(0),
  DwarfAbbrevSection(".debug_abbrev"),
  DwarfInfoSection(".debug_info"),
  DwarfLineSection(".debug_line"),
  DwarfFrameSection(".debug_frame"),
  DwarfPubNamesSection(".debug_pubnames"),
  DwarfPubTypesSection(".debug_pubtypes"),
  DwarfStrSection(".debug_str"),
  DwarfLocSection(".debug_loc"),
  DwarfARangesSection(".debug_aranges"),
  DwarfRangesSection(".debug_ranges"),
  DwarfMacInfoSection(".debug_macinfo"),
  DwarfEHFrameSection(".eh_frame"),
  DwarfExceptionSection(".gcc_except_table"),
  AsmTransCBE(0) {
}

TargetAsmInfo::~TargetAsmInfo() {
}

/// Measure the specified inline asm to determine an approximation of its
/// length.
/// Comments (which run till the next SeparatorChar or newline) do not
/// count as an instruction.
/// Any other non-whitespace text is considered an instruction, with
/// multiple instructions separated by SeparatorChar or newlines.
/// Variable-length instructions are not handled here; this function
/// may be overloaded in the target code to do that.
unsigned TargetAsmInfo::getInlineAsmLength(const char *Str) const {
  // Count the number of instructions in the asm.
  bool atInsnStart = true;
  unsigned Length = 0;
  for (; *Str; ++Str) {
    if (*Str == '\n' || *Str == SeparatorChar)
      atInsnStart = true;
    if (atInsnStart && !isspace(*Str)) {
      Length += MaxInstLength;
      atInsnStart = false;
    }
    if (atInsnStart && strncmp(Str, CommentString, strlen(CommentString))==0)
      atInsnStart = false;
  }

  return Length;
}

unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
                                              bool Global) const {
  return dwarf::DW_EH_PE_absptr;
}

static bool isSuitableForBSS(const GlobalVariable *GV) {
  if (!GV->hasInitializer())
    return true;

  // Leave constant zeros in readonly constant sections, so they can be shared
  Constant *C = GV->getInitializer();
  return (C->isNullValue() && !GV->isConstant() && !NoZerosInBSS);
}

SectionKind::Kind
TargetAsmInfo::SectionKindForGlobal(const GlobalValue *GV) const {
  // Early exit - functions should be always in text sections.
  if (isa<Function>(GV))
    return SectionKind::Text;

  const GlobalVariable* GVar = dyn_cast<GlobalVariable>(GV);
  bool isThreadLocal = GVar->isThreadLocal();
  assert(GVar && "Invalid global value for section selection");

  SectionKind::Kind kind;
  if (isSuitableForBSS(GVar)) {
    // Variable can be easily put to BSS section.
    return (isThreadLocal ? SectionKind::ThreadBSS : SectionKind::BSS);
  } else if (GVar->isConstant() && !isThreadLocal) {
    // Now we know, that varible has initializer and it is constant. We need to
    // check its initializer to decide, which section to output it into. Also
    // note, there is no thread-local r/o section.
    Constant *C = GVar->getInitializer();
    if (C->ContainsRelocations())
      kind = SectionKind::ROData;
    else {
      const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
      // Check, if initializer is a null-terminated string
      if (CVA && CVA->isCString())
        kind = SectionKind::RODataMergeStr;
      else
        kind = SectionKind::RODataMergeConst;
    }
  }

  // Variable is not constant or thread-local - emit to generic data section.
  return (isThreadLocal ? SectionKind::ThreadData : SectionKind::Data);
}

unsigned
TargetAsmInfo::SectionFlagsForGlobal(const GlobalValue *GV,
                                     const char* name) const {
  unsigned flags = SectionFlags::None;

  // Decode flags from global itself.
  if (GV) {
    SectionKind::Kind kind = SectionKindForGlobal(GV);
    switch (kind) {
     case SectionKind::Text:
      flags |= SectionFlags::Code;
      break;
     case SectionKind::ThreadData:
      flags |= SectionFlags::TLS;
      // FALLS THROUGH
     case SectionKind::Data:
      flags |= SectionFlags::Writeable;
      break;
     case SectionKind::ThreadBSS:
      flags |= SectionFlags::TLS;
      // FALLS THROUGH
     case SectionKind::BSS:
      flags |= SectionFlags::BSS;
      break;
     case SectionKind::ROData:
      // No additional flags here
      break;
     case SectionKind::RODataMergeStr:
      flags |= SectionFlags::Strings;
      // FALLS THROUGH
     case SectionKind::RODataMergeConst:
      flags |= SectionFlags::Mergeable;
      break;
     default:
      assert(0 && "Unexpected section kind!");
    }

    if (GV->hasLinkOnceLinkage() ||
        GV->hasWeakLinkage() ||
        GV->hasCommonLinkage())
      flags |= SectionFlags::Linkonce;
  }

  // Add flags from sections, if any.
  if (name) {
    // Some lame default implementation
    if (strcmp(name, ".bss") == 0 ||
        strncmp(name, ".bss.", 5) == 0 ||
        strncmp(name, ".llvm.linkonce.b.", 17) == 0)
      flags |= SectionFlags::BSS;
    else if (strcmp(name, ".tdata") == 0 ||
             strncmp(name, ".tdata.", 7) == 0 ||
             strncmp(name, ".llvm.linkonce.td.", 18) == 0)
      flags |= SectionFlags::TLS;
    else if (strcmp(name, ".tbss") == 0 ||
             strncmp(name, ".tbss.", 6) == 0 ||
             strncmp(name, ".llvm.linkonce.tb.", 18) == 0)
      flags |= SectionFlags::BSS | SectionFlags::TLS;
  }

  return flags;
}

const char*
TargetAsmInfo::SectionForGlobal(const GlobalValue *GV) const {
  SectionKind::Kind kind = SectionKindForGlobal(GV);

  if (kind == SectionKind::Text)
    return getTextSection();
  else if (kind == SectionKind::BSS && getBSSSection())
    return getBSSSection();

  return getDataSection();
}
<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
#ifndef LIGHTGBM_BOOSTING_GOSS_H_
#define LIGHTGBM_BOOSTING_GOSS_H_

#include <LightGBM/boosting.h>
#include <LightGBM/utils/array_args.h>
#include <LightGBM/utils/log.h>

#include <string>
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <fstream>
#include <vector>

#include "gbdt.h"
#include "score_updater.hpp"

namespace LightGBM {

class GOSS: public GBDT {
 public:
  /*!
  * \brief Constructor
  */
  GOSS() : GBDT() {
  }

  ~GOSS() {
  }

  void Init(const Config* config, const Dataset* train_data, const ObjectiveFunction* objective_function,
            const std::vector<const Metric*>& training_metrics) override {
    GBDT::Init(config, train_data, objective_function, training_metrics);
    ResetGoss();
  }

  void ResetTrainingData(const Dataset* train_data, const ObjectiveFunction* objective_function,
                         const std::vector<const Metric*>& training_metrics) override {
    GBDT::ResetTrainingData(train_data, objective_function, training_metrics);
    ResetGoss();
  }

  void ResetConfig(const Config* config) override {
    GBDT::ResetConfig(config);
    ResetGoss();
  }

  void ResetGoss() {
    CHECK_LE(config_->top_rate + config_->other_rate, 1.0f);
    CHECK(config_->top_rate > 0.0f && config_->other_rate > 0.0f);
    if (config_->bagging_freq > 0 && config_->bagging_fraction != 1.0f) {
      Log::Fatal("Cannot use bagging in GOSS");
    }
    Log::Info("Using GOSS");
    balanced_bagging_ = false;
    bag_data_indices_.resize(num_data_);
    bagging_runner_.ReSize(num_data_);

    is_use_subset_ = false;
    if (config_->top_rate + config_->other_rate <= 0.5) {
      auto bag_data_cnt = static_cast<data_size_t>((config_->top_rate + config_->other_rate) * num_data_);
      bag_data_cnt = std::max(1, bag_data_cnt);
      tmp_subset_.reset(new Dataset(bag_data_cnt));
      tmp_subset_->CopyFeatureMapperFrom(train_data_);
      is_use_subset_ = true;
    }
    // flag to not bagging first
    bag_data_cnt_ = num_data_;
  }

  data_size_t BaggingHelper(data_size_t start, data_size_t cnt, data_size_t* buffer) override {
    if (cnt <= 0) {
      return 0;
    }
    std::vector<score_t> tmp_gradients(cnt, 0.0f);
    for (data_size_t i = 0; i < cnt; ++i) {
      for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
        size_t idx = static_cast<size_t>(cur_tree_id) * num_data_ + start + i;
        tmp_gradients[i] += std::fabs(gradients_[idx] * hessians_[idx]);
      }
    }
    data_size_t top_k = static_cast<data_size_t>(cnt * config_->top_rate);
    data_size_t other_k = static_cast<data_size_t>(cnt * config_->other_rate);
    top_k = std::max(1, top_k);
    ArrayArgs<score_t>::ArgMaxAtK(&tmp_gradients, 0, static_cast<int>(tmp_gradients.size()), top_k - 1);
    score_t threshold = tmp_gradients[top_k - 1];

    score_t multiply = static_cast<score_t>(cnt - top_k) / other_k;
    data_size_t cur_left_cnt = 0;
    data_size_t cur_right_pos = cnt;
    data_size_t big_weight_cnt = 0;
    for (data_size_t i = 0; i < cnt; ++i) {
      auto cur_idx = start + i;
      score_t grad = 0.0f;
      for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
        size_t idx = static_cast<size_t>(cur_tree_id) * num_data_ + cur_idx;
        grad += std::fabs(gradients_[idx] * hessians_[idx]);
      }
      if (grad >= threshold) {
        buffer[cur_left_cnt++] = cur_idx;
        ++big_weight_cnt;
      } else {
        data_size_t sampled = cur_left_cnt - big_weight_cnt;
        data_size_t rest_need = other_k - sampled;
        data_size_t rest_all = (cnt - i) - (top_k - big_weight_cnt);
        double prob = (rest_need) / static_cast<double>(rest_all);
        if (bagging_rands_[cur_idx / bagging_rand_block_].NextFloat() < prob) {
          buffer[cur_left_cnt++] = cur_idx;
          for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
            size_t idx = static_cast<size_t>(cur_tree_id) * num_data_ + cur_idx;
            gradients_[idx] *= multiply;
            hessians_[idx] *= multiply;
          }
        } else {
          buffer[--cur_right_pos] = cur_idx;
        }
      }
    }
    return cur_left_cnt;
  }

  void Bagging(int iter) override {
    bag_data_cnt_ = num_data_;
    // not subsample for first iterations
    if (iter < static_cast<int>(1.0f / config_->learning_rate)) { return; }
    GBDT::Bagging(iter);
  }
};

}  // namespace LightGBM
#endif   // LIGHTGBM_BOOSTING_GOSS_H_
<commit_msg>fix goss bug (#3063)<commit_after>/*!
 * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
#ifndef LIGHTGBM_BOOSTING_GOSS_H_
#define LIGHTGBM_BOOSTING_GOSS_H_

#include <LightGBM/boosting.h>
#include <LightGBM/utils/array_args.h>
#include <LightGBM/utils/log.h>

#include <string>
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <fstream>
#include <vector>

#include "gbdt.h"
#include "score_updater.hpp"

namespace LightGBM {

class GOSS: public GBDT {
 public:
  /*!
  * \brief Constructor
  */
  GOSS() : GBDT() {
  }

  ~GOSS() {
  }

  void Init(const Config* config, const Dataset* train_data, const ObjectiveFunction* objective_function,
            const std::vector<const Metric*>& training_metrics) override {
    GBDT::Init(config, train_data, objective_function, training_metrics);
    ResetGoss();
  }

  void ResetTrainingData(const Dataset* train_data, const ObjectiveFunction* objective_function,
                         const std::vector<const Metric*>& training_metrics) override {
    GBDT::ResetTrainingData(train_data, objective_function, training_metrics);
    ResetGoss();
  }

  void ResetConfig(const Config* config) override {
    GBDT::ResetConfig(config);
    ResetGoss();
  }

  void ResetGoss() {
    CHECK_LE(config_->top_rate + config_->other_rate, 1.0f);
    CHECK(config_->top_rate > 0.0f && config_->other_rate > 0.0f);
    if (config_->bagging_freq > 0 && config_->bagging_fraction != 1.0f) {
      Log::Fatal("Cannot use bagging in GOSS");
    }
    Log::Info("Using GOSS");
    balanced_bagging_ = false;
    bag_data_indices_.resize(num_data_);
    bagging_runner_.ReSize(num_data_);

    is_use_subset_ = false;
    if (config_->top_rate + config_->other_rate <= 0.5) {
      auto bag_data_cnt = static_cast<data_size_t>((config_->top_rate + config_->other_rate) * num_data_);
      bag_data_cnt = std::max(1, bag_data_cnt);
      tmp_subset_.reset(new Dataset(bag_data_cnt));
      tmp_subset_->CopyFeatureMapperFrom(train_data_);
      is_use_subset_ = true;
    }
    // flag to not bagging first
    bag_data_cnt_ = num_data_;
  }

  data_size_t BaggingHelper(data_size_t start, data_size_t cnt, data_size_t* buffer) override {
    if (cnt <= 0) {
      return 0;
    }
    std::vector<score_t> tmp_gradients(cnt, 0.0f);
    for (data_size_t i = 0; i < cnt; ++i) {
      for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
        size_t idx = static_cast<size_t>(cur_tree_id) * num_data_ + start + i;
        tmp_gradients[i] += std::fabs(gradients_[idx] * hessians_[idx]);
      }
    }
    data_size_t top_k = static_cast<data_size_t>(cnt * config_->top_rate);
    data_size_t other_k = static_cast<data_size_t>(cnt * config_->other_rate);
    top_k = std::max(1, top_k);
    ArrayArgs<score_t>::ArgMaxAtK(&tmp_gradients, 0, static_cast<int>(tmp_gradients.size()), top_k - 1);
    score_t threshold = tmp_gradients[top_k - 1];

    score_t multiply = static_cast<score_t>(cnt - top_k) / other_k;
    data_size_t cur_left_cnt = 0;
    data_size_t cur_right_pos = cnt;
    data_size_t big_weight_cnt = 0;
    for (data_size_t i = 0; i < cnt; ++i) {
      auto cur_idx = start + i;
      score_t grad = 0.0f;
      for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
        size_t idx = static_cast<size_t>(cur_tree_id) * num_data_ + cur_idx;
        grad += std::fabs(gradients_[idx] * hessians_[idx]);
      }
      if (grad >= threshold) {
        buffer[cur_left_cnt++] = cur_idx;
        ++big_weight_cnt;
      } else {
        data_size_t sampled = cur_left_cnt - big_weight_cnt;
        data_size_t rest_need = other_k - sampled;
        data_size_t rest_all = (cnt - i) - (top_k - big_weight_cnt);
        double prob = (rest_need) / static_cast<double>(rest_all);
        if (bagging_rands_[cur_idx / bagging_rand_block_].NextFloat() < prob) {
          buffer[cur_left_cnt++] = cur_idx;
          for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
            size_t idx = static_cast<size_t>(cur_tree_id) * num_data_ + cur_idx;
            gradients_[idx] *= multiply;
            hessians_[idx] *= multiply;
          }
        } else {
          buffer[--cur_right_pos] = cur_idx;
        }
      }
    }
    return cur_left_cnt;
  }

  void Bagging(int iter) override {
    bag_data_cnt_ = num_data_;
    // not subsample for first iterations
    if (iter < static_cast<int>(1.0f / config_->learning_rate)) { return; }
    auto left_cnt = bagging_runner_.Run<true>(
        num_data_,
        [=](int, data_size_t cur_start, data_size_t cur_cnt, data_size_t* left,
            data_size_t*) {
          data_size_t cur_left_count = 0;
          cur_left_count = BaggingHelper(cur_start, cur_cnt, left);
          return cur_left_count;
        },
        bag_data_indices_.data());
    bag_data_cnt_ = left_cnt;
    // set bagging data to tree learner
    if (!is_use_subset_) {
      tree_learner_->SetBaggingData(nullptr, bag_data_indices_.data(), bag_data_cnt_);
    } else {
      // get subset
      tmp_subset_->ReSize(bag_data_cnt_);
      tmp_subset_->CopySubrow(train_data_, bag_data_indices_.data(),
                              bag_data_cnt_, false);
      tree_learner_->SetBaggingData(tmp_subset_.get(), bag_data_indices_.data(),
                                    bag_data_cnt_);
    }
  }
};

}  // namespace LightGBM
#endif   // LIGHTGBM_BOOSTING_GOSS_H_
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2009 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

// interface header
#include "Mumble.h"

// system headers
#ifdef WIN32
#  include <windows.h>
#else
#  include <unistd.h>
#  include <fcntl.h>
#  include <sys/mman.h>
#  include <sys/stat.h>
#  include <sys/types.h>
#  include <sys/time.h>
#endif

// common headers
#include "vectors.h"
#include "bzfio.h"
#include "StateDatabase.h"

//
// NOTE:  http://mumble.sourceforge.net/Link
//        (Linking a game to Mumble)
//

//============================================================================//
//
//  the shared memory data structure
//

#ifndef WIN32
struct LinkedMem {
  uint32_t uiVersion;
  uint32_t uiTick;
  float    fPosition[3];
  float    fFront[3];
  float    fTop[3];
  wchar_t  name[256];
};
#else
struct LinkedMem {
  UINT32  uiVersion;
  DWORD   uiTick;
  float   fPosition[3];
  float   fFront[3];
  float   fTop[3];
  wchar_t name[256];
};
#endif

static LinkedMem* linkedMem = NULL;

//============================================================================//
//
//  init() and kill()
//

/////////////
#ifndef WIN32
/////////////

static int shmfd = -1;

bool Mumble::init()
{
  if (!BZDB.isTrue("mumblePosition")) {
    return false;
  }

  char memname[256];
  snprintf(memname, 256, "/MumbleLink.%d", getuid());

  // note the lack of O_CREAT
  shmfd = shm_open(memname, O_RDWR, S_IRUSR | S_IWUSR);
  if (shmfd < 0) {
    logDebugMessage(0, "MUMBLE: failed to open %s\n", memname);
    return false;
  }

  linkedMem = (LinkedMem*) mmap(NULL, sizeof(struct LinkedMem),
                                PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
  if (linkedMem == MAP_FAILED) { // (void*)-1
    linkedMem = NULL;
    close(shmfd);
    shmfd = -1;
    logDebugMessage(0, "MUMBLE: failed to map %s\n", memname);
    return false;
  }

  logDebugMessage(0, "MUMBLE: linked using %s\n", memname);

  return true;
}

void Mumble::kill()
{
  if (linkedMem == NULL) {
    return;
  }

  munmap(linkedMem, sizeof(struct LinkedMem));
  linkedMem = NULL;

  // NOTE: shm_unlink() is not used

  close(shmfd);
  shmfd = -1;
}

/////
#else
/////

static HANDLE hMapObject = NULL;

bool Mumble::init()
{
  if (!BZDB.isTrue("mumblePosition")) {
    return false;
  }

  hMapObject = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
  if (hMapObject == NULL) {
    logDebugMessage(0, "MUMBLE: failed to open MumbleLink\n");
    return false;
  }

  linkedMem = (LinkedMem*)
    MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
  if (linkedMem == NULL) {
    CloseHandle(hMapObject);
    hMapObject = NULL;
    logDebugMessage(0, "MUMBLE: failed to map MumbleLink\n");
    return false;
  }

  wcscpy_s(linkedMem->name, 256, L"BZFlag");

  logDebugMessage(0, "MUMBLE: linked using MumbleLink\n");

  return true;
}

void Mumble::kill()
{
  if (linkedMem == NULL) {
    return;
  }

  UnmapViewOfFile(linkedMem);
  linkedMem = NULL;

  CloseHandle(hMapObject);
  hMapObject = NULL;
}

//////
#endif
//////

//============================================================================//
//
//  active()
//

bool Mumble::active()
{
  return (linkedMem != NULL);
}

//============================================================================//
//
//  update()
//

#ifndef WIN32
static uint32_t GetTickCount()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);

  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
#endif

bool Mumble::update(const fvec3& pos, const fvec3& front, const fvec3& top)
{
  if (linkedMem == NULL) {
    return false;
  }

  //  mumble uses a left-handed coordinate system
  //    +x: right
  //    +y: above
  //    +z: forward
  //
  //  mumble  bzflag
  //  ------  ------
  //    +x      -y
  //    +y      +z
  //    +z      +x

  linkedMem->fPosition[0] = -pos.y;
  linkedMem->fPosition[1] = +pos.z;
  linkedMem->fPosition[2] = +pos.x;
  linkedMem->fFront[0] = -front.y;
  linkedMem->fFront[1] = +front.z;
  linkedMem->fFront[2] = +front.x;
  linkedMem->fTop[0] = -top.y;
  linkedMem->fTop[1] = +top.z;
  linkedMem->fTop[2] = +top.x;

  linkedMem->uiVersion = 1;
  linkedMem->uiTick = GetTickCount();

  return true;
}

//============================================================================//

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>* set the position to (0,0,0) in Mumble::kill()  (disable positional sound)<commit_after>/* bzflag
 * Copyright (c) 1993 - 2009 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

// interface header
#include "Mumble.h"

// system headers
#ifdef WIN32
#  include <windows.h>
#else
#  include <unistd.h>
#  include <fcntl.h>
#  include <sys/mman.h>
#  include <sys/stat.h>
#  include <sys/types.h>
#  include <sys/time.h>
#endif

// common headers
#include "vectors.h"
#include "bzfio.h"
#include "StateDatabase.h"

//
// NOTE:  http://mumble.sourceforge.net/Link
//        (Linking a game to Mumble)
//

//============================================================================//
//
//  the shared memory data structure
//

#ifndef WIN32
struct LinkedMem {
  uint32_t uiVersion;
  uint32_t uiTick;
  float    fPosition[3];
  float    fFront[3];
  float    fTop[3];
  wchar_t  name[256];
};
#else
struct LinkedMem {
  UINT32  uiVersion;
  DWORD   uiTick;
  float   fPosition[3];
  float   fFront[3];
  float   fTop[3];
  wchar_t name[256];
};
#endif

static LinkedMem* linkedMem = NULL;

//============================================================================//
//
//  init() and kill()
//

/////////////
#ifndef WIN32
/////////////

static int shmfd = -1;

bool Mumble::init()
{
  if (!BZDB.isTrue("mumblePosition")) {
    return false;
  }

  char memname[256];
  snprintf(memname, 256, "/MumbleLink.%d", getuid());

  // note the lack of O_CREAT
  shmfd = shm_open(memname, O_RDWR, S_IRUSR | S_IWUSR);
  if (shmfd < 0) {
    logDebugMessage(0, "MUMBLE: failed to open %s\n", memname);
    return false;
  }

  linkedMem = (LinkedMem*) mmap(NULL, sizeof(struct LinkedMem),
                                PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
  if (linkedMem == MAP_FAILED) { // (void*)-1
    linkedMem = NULL;
    close(shmfd);
    shmfd = -1;
    logDebugMessage(0, "MUMBLE: failed to map %s\n", memname);
    return false;
  }

  logDebugMessage(0, "MUMBLE: linked using %s\n", memname);

  return true;
}

void Mumble::kill()
{
  if (linkedMem == NULL) {
    return;
  }

  update(fvec3(0.0f, 0.0f, 0.0f),
         fvec3(1.0f, 0.0f, 0.0f),
         fvec3(0.0f, 0.0f, 1.0f));

  munmap(linkedMem, sizeof(struct LinkedMem));
  linkedMem = NULL;

  // NOTE: shm_unlink() is not used

  close(shmfd);
  shmfd = -1;
}

/////
#else
/////

static HANDLE hMapObject = NULL;

bool Mumble::init()
{
  if (!BZDB.isTrue("mumblePosition")) {
    return false;
  }

  hMapObject = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
  if (hMapObject == NULL) {
    logDebugMessage(0, "MUMBLE: failed to open MumbleLink\n");
    return false;
  }

  linkedMem = (LinkedMem*)
    MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
  if (linkedMem == NULL) {
    CloseHandle(hMapObject);
    hMapObject = NULL;
    logDebugMessage(0, "MUMBLE: failed to map MumbleLink\n");
    return false;
  }

  wcscpy_s(linkedMem->name, 256, L"BZFlag");

  logDebugMessage(0, "MUMBLE: linked using MumbleLink\n");

  return true;
}

void Mumble::kill()
{
  if (linkedMem == NULL) {
    return;
  }

  update(fvec3(0.0f, 0.0f, 0.0f),
         fvec3(1.0f, 0.0f, 0.0f),
         fvec3(0.0f, 0.0f, 1.0f));

  UnmapViewOfFile(linkedMem);
  linkedMem = NULL;

  CloseHandle(hMapObject);
  hMapObject = NULL;
}

//////
#endif
//////

//============================================================================//
//
//  active()
//

bool Mumble::active()
{
  return (linkedMem != NULL);
}

//============================================================================//
//
//  update()
//

#ifndef WIN32
static uint32_t GetTickCount()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);

  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
#endif

bool Mumble::update(const fvec3& pos, const fvec3& front, const fvec3& top)
{
  if (linkedMem == NULL) {
    return false;
  }

  //  mumble uses a left-handed coordinate system
  //    +x: right
  //    +y: above
  //    +z: forward
  //
  //  mumble  bzflag
  //  ------  ------
  //    +x      -y
  //    +y      +z
  //    +z      +x

  linkedMem->fPosition[0] = -pos.y;
  linkedMem->fPosition[1] = +pos.z;
  linkedMem->fPosition[2] = +pos.x;
  linkedMem->fFront[0] = -front.y;
  linkedMem->fFront[1] = +front.z;
  linkedMem->fFront[2] = +front.x;
  linkedMem->fTop[0] = -top.y;
  linkedMem->fTop[1] = +top.z;
  linkedMem->fTop[2] = +top.x;

  linkedMem->uiVersion = 1;
  linkedMem->uiTick = GetTickCount();

  return true;
}

//============================================================================//

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>// Copyright 2014 BVLC and contributors.

#include <stdint.h>
#include <fcntl.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>

#include <algorithm>
#include <string>
#include <vector>
#include <fstream>  // NOLINT(readability/streams)

#include "caffe/common.hpp"
#include "caffe/util/io.hpp"
#include "caffe/proto/caffe.pb.h"

using std::fstream;
using std::ios;
using std::max;
using std::string;
using google::protobuf::io::FileInputStream;
using google::protobuf::io::FileOutputStream;
using google::protobuf::io::ZeroCopyInputStream;
using google::protobuf::io::CodedInputStream;
using google::protobuf::io::ZeroCopyOutputStream;
using google::protobuf::io::CodedOutputStream;
using google::protobuf::Message;

namespace caffe {

bool ReadProtoFromTextFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  FileInputStream* input = new FileInputStream(fd);
  bool success = google::protobuf::TextFormat::Parse(input, proto);
  delete input;
  close(fd);
  return success;
}

void WriteProtoToTextFile(const Message& proto, const char* filename) {
  int fd = open(filename, O_WRONLY);
  FileOutputStream* output = new FileOutputStream(fd);
  CHECK(google::protobuf::TextFormat::Print(proto, output));
  delete output;
  close(fd);
}

bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  ZeroCopyInputStream* raw_input = new FileInputStream(fd);
  CodedInputStream* coded_input = new CodedInputStream(raw_input);
  coded_input->SetTotalBytesLimit(536870912, 268435456);

  bool success = proto->ParseFromCodedStream(coded_input);

  delete coded_input;
  delete raw_input;
  close(fd);
  return success;
}

void WriteProtoToBinaryFile(const Message& proto, const char* filename) {
  fstream output(filename, ios::out | ios::trunc | ios::binary);
  CHECK(proto.SerializeToOstream(&output));
}

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, Datum* datum) {
  cv::Mat cv_img;
  if (height > 0 && width > 0) {
    cv::Mat cv_img_origin = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
    cv::resize(cv_img_origin, cv_img, cv::Size(height, width));
  } else {
    cv_img = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
  }
  if (!cv_img.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return false;
  }
  datum->set_channels(3);
  datum->set_height(cv_img.rows);
  datum->set_width(cv_img.cols);
  datum->set_label(label);
  datum->clear_data();
  datum->clear_float_data();
  string* datum_string = datum->mutable_data();
  for (int c = 0; c < 3; ++c) {
    for (int h = 0; h < cv_img.rows; ++h) {
      for (int w = 0; w < cv_img.cols; ++w) {
        datum_string->push_back(
            static_cast<char>(cv_img.at<cv::Vec3b>(h, w)[c]));
      }
    }
  }
  return true;
}

// Verifies format of data stored in HDF5 file and reshapes blob accordingly.
template <typename Dtype>
void hdf5_load_nd_dataset_helper(
    hid_t file_id, const char* dataset_name_, int min_dim, int max_dim,
    Blob<Dtype>* blob) {
  // Verify that the number of dimensions is in the accepted range.
  herr_t status;
  int ndims;
  status = H5LTget_dataset_ndims(file_id, dataset_name_, &ndims);
  CHECK_GE(ndims, min_dim);
  CHECK_LE(ndims, max_dim);

  // Verify that the data format is what we expect: float or double.
  std::vector<hsize_t> dims(ndims);
  H5T_class_t class_;
  status = H5LTget_dataset_info(
      file_id, dataset_name_, dims.data(), &class_, NULL);
  CHECK_EQ(class_, H5T_FLOAT) << "Expected float or double data";

  blob->Reshape(
    dims[0],
    (dims.size() > 1) ? dims[1] : 1,
    (dims.size() > 2) ? dims[2] : 1,
    (dims.size() > 3) ? dims[3] : 1);
}

template <>
void hdf5_load_nd_dataset<float>(hid_t file_id, const char* dataset_name_,
        int min_dim, int max_dim, Blob<float>* blob) {
  hdf5_load_nd_dataset_helper(file_id, dataset_name_, min_dim, max_dim, blob);
  herr_t status = H5LTread_dataset_float(
    file_id, dataset_name_, blob->mutable_cpu_data());
}

template <>
void hdf5_load_nd_dataset<double>(hid_t file_id, const char* dataset_name_,
        int min_dim, int max_dim, Blob<double>* blob) {
  hdf5_load_nd_dataset_helper(file_id, dataset_name_, min_dim, max_dim, blob);
  herr_t status = H5LTread_dataset_double(
    file_id, dataset_name_, blob->mutable_cpu_data());
}

template <>
void hdf5_save_nd_dataset<float>(
    const hid_t file_id, const string dataset_name, const Blob<float>& blob) {
  hsize_t dims[HDF5_NUM_DIMS];
  dims[0] = blob.num();
  dims[1] = blob.channels();
  dims[2] = blob.height();
  dims[3] = blob.width();
  herr_t status = H5LTmake_dataset_float(
      file_id, dataset_name.c_str(), HDF5_NUM_DIMS, dims, blob.cpu_data());
  CHECK_GE(status, 0) << "Failed to make float dataset " << dataset_name;
}

template <>
void hdf5_save_nd_dataset<double>(
    const hid_t file_id, const string dataset_name, const Blob<double>& blob) {
  hsize_t dims[HDF5_NUM_DIMS];
  dims[0] = blob.num();
  dims[1] = blob.channels();
  dims[2] = blob.height();
  dims[3] = blob.width();
  herr_t status = H5LTmake_dataset_double(
      file_id, dataset_name.c_str(), HDF5_NUM_DIMS, dims, blob.cpu_data());
  CHECK_GE(status, 0) << "Failed to make double dataset " << dataset_name;
}

}  // namespace caffe
<commit_msg>Doubled protobuf Bytes Limit<commit_after>// Copyright 2014 BVLC and contributors.

#include <stdint.h>
#include <fcntl.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>

#include <algorithm>
#include <string>
#include <vector>
#include <fstream>  // NOLINT(readability/streams)

#include "caffe/common.hpp"
#include "caffe/util/io.hpp"
#include "caffe/proto/caffe.pb.h"

using std::fstream;
using std::ios;
using std::max;
using std::string;
using google::protobuf::io::FileInputStream;
using google::protobuf::io::FileOutputStream;
using google::protobuf::io::ZeroCopyInputStream;
using google::protobuf::io::CodedInputStream;
using google::protobuf::io::ZeroCopyOutputStream;
using google::protobuf::io::CodedOutputStream;
using google::protobuf::Message;

namespace caffe {

bool ReadProtoFromTextFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  FileInputStream* input = new FileInputStream(fd);
  bool success = google::protobuf::TextFormat::Parse(input, proto);
  delete input;
  close(fd);
  return success;
}

void WriteProtoToTextFile(const Message& proto, const char* filename) {
  int fd = open(filename, O_WRONLY);
  FileOutputStream* output = new FileOutputStream(fd);
  CHECK(google::protobuf::TextFormat::Print(proto, output));
  delete output;
  close(fd);
}

bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
  int fd = open(filename, O_RDONLY);
  CHECK_NE(fd, -1) << "File not found: " << filename;
  ZeroCopyInputStream* raw_input = new FileInputStream(fd);
  CodedInputStream* coded_input = new CodedInputStream(raw_input);
  coded_input->SetTotalBytesLimit(1073741824, 536870912);

  bool success = proto->ParseFromCodedStream(coded_input);

  delete coded_input;
  delete raw_input;
  close(fd);
  return success;
}

void WriteProtoToBinaryFile(const Message& proto, const char* filename) {
  fstream output(filename, ios::out | ios::trunc | ios::binary);
  CHECK(proto.SerializeToOstream(&output));
}

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, Datum* datum) {
  cv::Mat cv_img;
  if (height > 0 && width > 0) {
    cv::Mat cv_img_origin = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
    cv::resize(cv_img_origin, cv_img, cv::Size(height, width));
  } else {
    cv_img = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
  }
  if (!cv_img.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return false;
  }
  datum->set_channels(3);
  datum->set_height(cv_img.rows);
  datum->set_width(cv_img.cols);
  datum->set_label(label);
  datum->clear_data();
  datum->clear_float_data();
  string* datum_string = datum->mutable_data();
  for (int c = 0; c < 3; ++c) {
    for (int h = 0; h < cv_img.rows; ++h) {
      for (int w = 0; w < cv_img.cols; ++w) {
        datum_string->push_back(
            static_cast<char>(cv_img.at<cv::Vec3b>(h, w)[c]));
      }
    }
  }
  return true;
}

// Verifies format of data stored in HDF5 file and reshapes blob accordingly.
template <typename Dtype>
void hdf5_load_nd_dataset_helper(
    hid_t file_id, const char* dataset_name_, int min_dim, int max_dim,
    Blob<Dtype>* blob) {
  // Verify that the number of dimensions is in the accepted range.
  herr_t status;
  int ndims;
  status = H5LTget_dataset_ndims(file_id, dataset_name_, &ndims);
  CHECK_GE(ndims, min_dim);
  CHECK_LE(ndims, max_dim);

  // Verify that the data format is what we expect: float or double.
  std::vector<hsize_t> dims(ndims);
  H5T_class_t class_;
  status = H5LTget_dataset_info(
      file_id, dataset_name_, dims.data(), &class_, NULL);
  CHECK_EQ(class_, H5T_FLOAT) << "Expected float or double data";

  blob->Reshape(
    dims[0],
    (dims.size() > 1) ? dims[1] : 1,
    (dims.size() > 2) ? dims[2] : 1,
    (dims.size() > 3) ? dims[3] : 1);
}

template <>
void hdf5_load_nd_dataset<float>(hid_t file_id, const char* dataset_name_,
        int min_dim, int max_dim, Blob<float>* blob) {
  hdf5_load_nd_dataset_helper(file_id, dataset_name_, min_dim, max_dim, blob);
  herr_t status = H5LTread_dataset_float(
    file_id, dataset_name_, blob->mutable_cpu_data());
}

template <>
void hdf5_load_nd_dataset<double>(hid_t file_id, const char* dataset_name_,
        int min_dim, int max_dim, Blob<double>* blob) {
  hdf5_load_nd_dataset_helper(file_id, dataset_name_, min_dim, max_dim, blob);
  herr_t status = H5LTread_dataset_double(
    file_id, dataset_name_, blob->mutable_cpu_data());
}

template <>
void hdf5_save_nd_dataset<float>(
    const hid_t file_id, const string dataset_name, const Blob<float>& blob) {
  hsize_t dims[HDF5_NUM_DIMS];
  dims[0] = blob.num();
  dims[1] = blob.channels();
  dims[2] = blob.height();
  dims[3] = blob.width();
  herr_t status = H5LTmake_dataset_float(
      file_id, dataset_name.c_str(), HDF5_NUM_DIMS, dims, blob.cpu_data());
  CHECK_GE(status, 0) << "Failed to make float dataset " << dataset_name;
}

template <>
void hdf5_save_nd_dataset<double>(
    const hid_t file_id, const string dataset_name, const Blob<double>& blob) {
  hsize_t dims[HDF5_NUM_DIMS];
  dims[0] = blob.num();
  dims[1] = blob.channels();
  dims[2] = blob.height();
  dims[3] = blob.width();
  herr_t status = H5LTmake_dataset_double(
      file_id, dataset_name.c_str(), HDF5_NUM_DIMS, dims, blob.cpu_data());
  CHECK_GE(status, 0) << "Failed to make double dataset " << dataset_name;
}

}  // namespace caffe
<|endoftext|>


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

#include <openspace/camera/camera.h>

#include <sstream>

namespace openspace {

const glm::dvec3 Camera::ViewDirectionCameraSpace = glm::dvec3(0.0, 0.0, -1.0);
const glm::dvec3 Camera::UpDirectionCameraSpace = glm::dvec3(0.0, 1.0, 0.0);

Camera::Camera(const Camera& o)
    : sgctInternal(o.sgctInternal)
    , _position(o._position)
    , _rotation(o._rotation)
    , _scaling(o._scaling)
    , _maxFov(o._maxFov)
    , _cachedViewDirection(o._cachedViewDirection)
    , _cachedLookupVector(o._cachedLookupVector)
{}

void Camera::setPositionVec3(glm::dvec3 pos) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _position = std::move(pos);

    _cachedCombinedViewMatrix.isDirty = true;
}

void Camera::setRotation(glm::dquat rotation) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _rotation = std::move(rotation);
    _cachedViewDirection.isDirty = true;
    _cachedLookupVector.isDirty = true;
    _cachedViewRotationMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
}

void Camera::setScaling(float scaling) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _scaling = scaling;
    _cachedViewScaleMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
}

void Camera::setMaxFov(float fov) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _maxFov = fov;
    _cachedSinMaxFov.isDirty = true;
}

void Camera::setParent(SceneGraphNode* parent) {
    _parent = parent;
}

void Camera::rotate(glm::dquat rotation) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _rotation = std::move(rotation) * static_cast<glm::dquat>(_rotation);

    _cachedViewDirection.isDirty = true;
    _cachedLookupVector.isDirty = true;
    _cachedViewRotationMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
}

const glm::dvec3& Camera::positionVec3() const {
    return _position;
}

glm::dvec3 Camera::eyePositionVec3() const {
    glm::dvec4 eyeInEyeSpace(0.0, 0.0, 0.0, 1.0);

    glm::dmat4 invViewMatrix = glm::inverse(sgctInternal.viewMatrix());
    glm::dmat4 invRotationMatrix = glm::mat4_cast(static_cast<glm::dquat>(_rotation));
    glm::dmat4 invTranslationMatrix = glm::translate(
        glm::dmat4(1.0),
        static_cast<glm::dvec3>(_position)
    );

    glm::dmat4 invViewScale = glm::inverse(viewScaleMatrix());

    glm::dvec4 eyeInWorldSpace = invTranslationMatrix * invRotationMatrix *
        invViewScale * invViewMatrix * eyeInEyeSpace;

    return glm::dvec3(eyeInWorldSpace.x, eyeInWorldSpace.y, eyeInWorldSpace.z);
}

const glm::dvec3& Camera::unsynchedPositionVec3() const {
    return _position;
}

const glm::dvec3& Camera::viewDirectionWorldSpace() const {
    if (_cachedViewDirection.isDirty) {
        _cachedViewDirection.datum = glm::normalize(
            static_cast<glm::dquat>(_rotation) * ViewDirectionCameraSpace
        );
        _cachedViewDirection.isDirty = false;
    }
    return _cachedViewDirection.datum;
}

const glm::dvec3& Camera::lookUpVectorCameraSpace() const {
    return UpDirectionCameraSpace;
}

const glm::dvec3& Camera::lookUpVectorWorldSpace() const {
    if (_cachedLookupVector.isDirty) {
        _cachedLookupVector.datum = glm::normalize(
            static_cast<glm::dquat>(_rotation) * UpDirectionCameraSpace
        );
        _cachedLookupVector.isDirty = false;
    }

    return _cachedLookupVector.datum;
}

float Camera::maxFov() const {
    return _maxFov;
}

float Camera::sinMaxFov() const {
    if (_cachedSinMaxFov.isDirty) {
        _cachedSinMaxFov.datum = sin(_maxFov);
        _cachedSinMaxFov.isDirty = true;
    }
    return _cachedSinMaxFov.datum;
}

SceneGraphNode* Camera::parent() const {
    return _parent;
}

float Camera::scaling() const {
    return _scaling;
}

const glm::dmat4& Camera::viewRotationMatrix() const {
    //if (_cachedViewRotationMatrix.isDirty) {
        _cachedViewRotationMatrix.datum = glm::mat4_cast(
            glm::inverse(static_cast<glm::dquat>(_rotation))
        );
        _cachedViewRotationMatrix.isDirty = false;
    //}
    return _cachedViewRotationMatrix.datum;
}

const glm::dmat4& Camera::viewScaleMatrix() const {
    //if (_cachedViewScaleMatrix.isDirty) {
        _cachedViewScaleMatrix.datum = glm::scale(glm::mat4(1.f), glm::vec3(_scaling));
        _cachedViewScaleMatrix.isDirty = false;
    //}
    return _cachedViewScaleMatrix.datum;
}

const glm::dquat& Camera::rotationQuaternion() const {
    return _rotation;
}

const glm::dmat4& Camera::combinedViewMatrix() const {
    //if (_cachedCombinedViewMatrix.isDirty) {
        const glm::dmat4 cameraTranslation = glm::inverse(
            glm::translate(glm::dmat4(1.0), static_cast<glm::dvec3>(_position))
        );
        _cachedCombinedViewMatrix.datum =
            glm::dmat4(sgctInternal.viewMatrix()) *
            glm::dmat4(viewScaleMatrix()) *
            glm::dmat4(viewRotationMatrix()) *
            cameraTranslation;
        _cachedCombinedViewMatrix.isDirty = false;
    //}
    return _cachedCombinedViewMatrix.datum;
}

void Camera::invalidateCache() {
    _cachedViewDirection.isDirty = true;
    _cachedLookupVector.isDirty = true;
    _cachedViewRotationMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
    _cachedViewScaleMatrix.isDirty = true;
    _cachedSinMaxFov.isDirty = true;
}

void Camera::serialize(std::ostream& os) const {
    const glm::dvec3 p = positionVec3();
    const glm::dquat q = rotationQuaternion();
    os << p.x << " " << p.y << " " << p.z << std::endl;
    os << q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
}

void Camera::deserialize(std::istream& is) {
    glm::dvec3 p;
    is >> p.x >> p.y >> p.z;
    glm::dquat q;
    is >> q.x >> q.y >> q.z >> q.w;
    setPositionVec3(p);
    setRotation(q);
}

Camera::SgctInternal::SgctInternal(const SgctInternal& o)
    : _viewMatrix(o._viewMatrix)
    , _projectionMatrix(o._projectionMatrix)
    , _cachedViewProjectionMatrix(o._cachedViewProjectionMatrix)
{}

void Camera::SgctInternal::setSceneMatrix(glm::mat4 sceneMatrix) {
    std::lock_guard<std::mutex> _lock(_mutex);

    _sceneMatrix = std::move(sceneMatrix);
}

void Camera::SgctInternal::setViewMatrix(glm::mat4 viewMatrix) {
    std::lock_guard<std::mutex> _lock(_mutex);

    _viewMatrix = std::move(viewMatrix);
    _cachedViewProjectionMatrix.isDirty = true;
}

void Camera::SgctInternal::setProjectionMatrix(glm::mat4 projectionMatrix) {
    std::lock_guard<std::mutex> _lock(_mutex);

    _projectionMatrix = std::move(projectionMatrix);
    _cachedViewProjectionMatrix.isDirty = true;
}

const glm::mat4& Camera::SgctInternal::sceneMatrix() const {
    return _sceneMatrix;
}

const glm::mat4& Camera::SgctInternal::viewMatrix() const {
    return _viewMatrix;
}

const glm::mat4& Camera::SgctInternal::projectionMatrix() const {
    return _projectionMatrix;
}

const glm::mat4& Camera::SgctInternal::viewProjectionMatrix() const {
    //if (_cachedViewProjectionMatrix.isDirty) {
        std::lock_guard<std::mutex> _lock(_mutex);
        _cachedViewProjectionMatrix.datum = _projectionMatrix * _viewMatrix;
        _cachedViewProjectionMatrix.isDirty = false;
    //}
    return _cachedViewProjectionMatrix.datum;
}

const glm::mat4& Camera::viewMatrix() const {
    return sgctInternal.viewMatrix();
}

const glm::mat4& Camera::projectionMatrix() const {
    return sgctInternal.projectionMatrix();
}

const glm::mat4& Camera::viewProjectionMatrix() const {
    return sgctInternal.viewProjectionMatrix();
}

std::vector<Syncable*> Camera::getSyncables() {
    return { &_position, &_rotation, &_scaling };
}

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

#include <openspace/camera/camera.h>

#include <sstream>

namespace openspace {

// (2021-07-16, emmbr) Note that this hard coded vector for the view direction is also
// used in a qauternion -> view direction helper function in ghoul/glm.h
const glm::dvec3 Camera::ViewDirectionCameraSpace = glm::dvec3(0.0, 0.0, -1.0);
const glm::dvec3 Camera::UpDirectionCameraSpace = glm::dvec3(0.0, 1.0, 0.0);

Camera::Camera(const Camera& o)
    : sgctInternal(o.sgctInternal)
    , _position(o._position)
    , _rotation(o._rotation)
    , _scaling(o._scaling)
    , _maxFov(o._maxFov)
    , _cachedViewDirection(o._cachedViewDirection)
    , _cachedLookupVector(o._cachedLookupVector)
{}

void Camera::setPositionVec3(glm::dvec3 pos) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _position = std::move(pos);

    _cachedCombinedViewMatrix.isDirty = true;
}

void Camera::setRotation(glm::dquat rotation) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _rotation = std::move(rotation);
    _cachedViewDirection.isDirty = true;
    _cachedLookupVector.isDirty = true;
    _cachedViewRotationMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
}

void Camera::setScaling(float scaling) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _scaling = scaling;
    _cachedViewScaleMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
}

void Camera::setMaxFov(float fov) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _maxFov = fov;
    _cachedSinMaxFov.isDirty = true;
}

void Camera::setParent(SceneGraphNode* parent) {
    _parent = parent;
}

void Camera::rotate(glm::dquat rotation) {
    std::lock_guard<std::mutex> _lock(_mutex);
    _rotation = std::move(rotation) * static_cast<glm::dquat>(_rotation);

    _cachedViewDirection.isDirty = true;
    _cachedLookupVector.isDirty = true;
    _cachedViewRotationMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
}

const glm::dvec3& Camera::positionVec3() const {
    return _position;
}

glm::dvec3 Camera::eyePositionVec3() const {
    glm::dvec4 eyeInEyeSpace(0.0, 0.0, 0.0, 1.0);

    glm::dmat4 invViewMatrix = glm::inverse(sgctInternal.viewMatrix());
    glm::dmat4 invRotationMatrix = glm::mat4_cast(static_cast<glm::dquat>(_rotation));
    glm::dmat4 invTranslationMatrix = glm::translate(
        glm::dmat4(1.0),
        static_cast<glm::dvec3>(_position)
    );

    glm::dmat4 invViewScale = glm::inverse(viewScaleMatrix());

    glm::dvec4 eyeInWorldSpace = invTranslationMatrix * invRotationMatrix *
        invViewScale * invViewMatrix * eyeInEyeSpace;

    return glm::dvec3(eyeInWorldSpace.x, eyeInWorldSpace.y, eyeInWorldSpace.z);
}

const glm::dvec3& Camera::unsynchedPositionVec3() const {
    return _position;
}

const glm::dvec3& Camera::viewDirectionWorldSpace() const {
    if (_cachedViewDirection.isDirty) {
        _cachedViewDirection.datum = glm::normalize(
            static_cast<glm::dquat>(_rotation) * ViewDirectionCameraSpace
        );
        _cachedViewDirection.isDirty = false;
    }
    return _cachedViewDirection.datum;
}

const glm::dvec3& Camera::lookUpVectorCameraSpace() const {
    return UpDirectionCameraSpace;
}

const glm::dvec3& Camera::lookUpVectorWorldSpace() const {
    if (_cachedLookupVector.isDirty) {
        _cachedLookupVector.datum = glm::normalize(
            static_cast<glm::dquat>(_rotation) * UpDirectionCameraSpace
        );
        _cachedLookupVector.isDirty = false;
    }

    return _cachedLookupVector.datum;
}

float Camera::maxFov() const {
    return _maxFov;
}

float Camera::sinMaxFov() const {
    if (_cachedSinMaxFov.isDirty) {
        _cachedSinMaxFov.datum = sin(_maxFov);
        _cachedSinMaxFov.isDirty = true;
    }
    return _cachedSinMaxFov.datum;
}

SceneGraphNode* Camera::parent() const {
    return _parent;
}

float Camera::scaling() const {
    return _scaling;
}

const glm::dmat4& Camera::viewRotationMatrix() const {
    //if (_cachedViewRotationMatrix.isDirty) {
        _cachedViewRotationMatrix.datum = glm::mat4_cast(
            glm::inverse(static_cast<glm::dquat>(_rotation))
        );
        _cachedViewRotationMatrix.isDirty = false;
    //}
    return _cachedViewRotationMatrix.datum;
}

const glm::dmat4& Camera::viewScaleMatrix() const {
    //if (_cachedViewScaleMatrix.isDirty) {
        _cachedViewScaleMatrix.datum = glm::scale(glm::mat4(1.f), glm::vec3(_scaling));
        _cachedViewScaleMatrix.isDirty = false;
    //}
    return _cachedViewScaleMatrix.datum;
}

const glm::dquat& Camera::rotationQuaternion() const {
    return _rotation;
}

const glm::dmat4& Camera::combinedViewMatrix() const {
    //if (_cachedCombinedViewMatrix.isDirty) {
        const glm::dmat4 cameraTranslation = glm::inverse(
            glm::translate(glm::dmat4(1.0), static_cast<glm::dvec3>(_position))
        );
        _cachedCombinedViewMatrix.datum =
            glm::dmat4(sgctInternal.viewMatrix()) *
            glm::dmat4(viewScaleMatrix()) *
            glm::dmat4(viewRotationMatrix()) *
            cameraTranslation;
        _cachedCombinedViewMatrix.isDirty = false;
    //}
    return _cachedCombinedViewMatrix.datum;
}

void Camera::invalidateCache() {
    _cachedViewDirection.isDirty = true;
    _cachedLookupVector.isDirty = true;
    _cachedViewRotationMatrix.isDirty = true;
    _cachedCombinedViewMatrix.isDirty = true;
    _cachedViewScaleMatrix.isDirty = true;
    _cachedSinMaxFov.isDirty = true;
}

void Camera::serialize(std::ostream& os) const {
    const glm::dvec3 p = positionVec3();
    const glm::dquat q = rotationQuaternion();
    os << p.x << " " << p.y << " " << p.z << std::endl;
    os << q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
}

void Camera::deserialize(std::istream& is) {
    glm::dvec3 p;
    is >> p.x >> p.y >> p.z;
    glm::dquat q;
    is >> q.x >> q.y >> q.z >> q.w;
    setPositionVec3(p);
    setRotation(q);
}

Camera::SgctInternal::SgctInternal(const SgctInternal& o)
    : _viewMatrix(o._viewMatrix)
    , _projectionMatrix(o._projectionMatrix)
    , _cachedViewProjectionMatrix(o._cachedViewProjectionMatrix)
{}

void Camera::SgctInternal::setSceneMatrix(glm::mat4 sceneMatrix) {
    std::lock_guard<std::mutex> _lock(_mutex);

    _sceneMatrix = std::move(sceneMatrix);
}

void Camera::SgctInternal::setViewMatrix(glm::mat4 viewMatrix) {
    std::lock_guard<std::mutex> _lock(_mutex);

    _viewMatrix = std::move(viewMatrix);
    _cachedViewProjectionMatrix.isDirty = true;
}

void Camera::SgctInternal::setProjectionMatrix(glm::mat4 projectionMatrix) {
    std::lock_guard<std::mutex> _lock(_mutex);

    _projectionMatrix = std::move(projectionMatrix);
    _cachedViewProjectionMatrix.isDirty = true;
}

const glm::mat4& Camera::SgctInternal::sceneMatrix() const {
    return _sceneMatrix;
}

const glm::mat4& Camera::SgctInternal::viewMatrix() const {
    return _viewMatrix;
}

const glm::mat4& Camera::SgctInternal::projectionMatrix() const {
    return _projectionMatrix;
}

const glm::mat4& Camera::SgctInternal::viewProjectionMatrix() const {
    //if (_cachedViewProjectionMatrix.isDirty) {
        std::lock_guard<std::mutex> _lock(_mutex);
        _cachedViewProjectionMatrix.datum = _projectionMatrix * _viewMatrix;
        _cachedViewProjectionMatrix.isDirty = false;
    //}
    return _cachedViewProjectionMatrix.datum;
}

const glm::mat4& Camera::viewMatrix() const {
    return sgctInternal.viewMatrix();
}

const glm::mat4& Camera::projectionMatrix() const {
    return sgctInternal.projectionMatrix();
}

const glm::mat4& Camera::viewProjectionMatrix() const {
    return sgctInternal.viewProjectionMatrix();
}

std::vector<Syncable*> Camera::getSyncables() {
    return { &_position, &_rotation, &_scaling };
}

} // namespace openspace
<|endoftext|>


<commit_before>#ifndef CAN_EMULATOR

#include "interface/usb.h"
#include "can/canread.h"
#include "interface/uart.h"
#include "interface/network.h"
#include "signals.h"
#include "util/log.h"
#include "cJSON.h"
#include "pipeline.h"
#include "util/timer.h"
#include "lights.h"
#include "power.h"
#include "bluetooth.h"
#include "platform/platform.h"
#include <stdint.h>
#include <stdlib.h>

namespace uart = openxc::interface::uart;
namespace network = openxc::interface::network;
namespace usb = openxc::interface::usb;
namespace lights = openxc::lights;
namespace can = openxc::can;
namespace platform = openxc::platform;
namespace time = openxc::util::time;
namespace signals = openxc::signals;

using openxc::can::lookupCommand;
using openxc::can::lookupSignal;
using openxc::signals::initialize;
using openxc::signals::getCanBuses;
using openxc::signals::getCanBusCount;
using openxc::signals::getCommands;
using openxc::signals::getCommandCount;
using openxc::signals::getSignals;
using openxc::signals::getSignalCount;
using openxc::signals::decodeCanMessage;

extern Pipeline pipeline;

/* Forward declarations */

void receiveCan(Pipeline*, CanBus*);
void initializeAllCan();
bool receiveWriteRequest(uint8_t*);
void updateDataLights();

void setup() {
    initializeAllCan();
    signals::initialize();
}

void loop() {
    for(int i = 0; i < getCanBusCount(); i++) {
        receiveCan(&pipeline, &getCanBuses()[i]);
    }

    usb::read(pipeline.usb, receiveWriteRequest);
    uart::read(pipeline.uart, receiveWriteRequest);
    network::read(pipeline.network, receiveWriteRequest);

    for(int i = 0; i < getCanBusCount(); i++) {
        can::write::processWriteQueue(&getCanBuses()[i]);
    }

    updateDataLights();
    openxc::signals::loop();
}

/* Public: Update the color and status of a board's light that shows the status
 * of the CAN bus. This function is intended to be called each time through the
 * main program loop.
 */
void updateDataLights() {
    static unsigned long startupTime = time::systemTimeMs();
    static bool busWasActive;
    bool busActive = false;
    for(int i = 0; i < getCanBusCount(); i++) {
        busActive = busActive || can::busActive(&getCanBuses()[i]);
    }

    if(!busWasActive && busActive) {
        debug("CAN woke up - enabling LED");
        lights::enable(lights::LIGHT_A, lights::COLORS.blue);
        busWasActive = true;
    } else if(!busActive && (busWasActive || time::systemTimeMs() - startupTime >
            (unsigned long)openxc::can::CAN_ACTIVE_TIMEOUT_S * 1000)) {
        // stay awake at least CAN_ACTIVE_TIMEOUT_S after power on
#ifndef TRANSMITTER
        busWasActive = false;
        platform::suspend(&pipeline);
#endif
    }
}

void initializeAllCan() {
    for(int i = 0; i < getCanBusCount(); i++) {
        can::initialize(&(getCanBuses()[i]));
    }
}

void receiveRawWriteRequest(cJSON* idObject, cJSON* root) {
    uint32_t id = idObject->valueint;
    cJSON* dataObject = cJSON_GetObjectItem(root, "data");
    if(dataObject == NULL) {
        debug("Raw write request missing data", id);
        return;
    }

    char* dataString = dataObject->valuestring;
    char* end;
    // TODO hard coding bus 0 right now, but it should support sending on either
    CanMessage message = {&getCanBuses()[0], id};
    can::write::enqueueMessage(&message, strtoull(dataString, &end, 16));
}

void receiveTranslatedWriteRequest(cJSON* nameObject, cJSON* root) {
    char* name = nameObject->valuestring;
    cJSON* value = cJSON_GetObjectItem(root, "value");

    // Optional, may be NULL
    cJSON* event = cJSON_GetObjectItem(root, "event");

    CanSignal* signal = lookupSignal(name, getSignals(), getSignalCount(),
            true);
    if(signal != NULL) {
        if(value == NULL) {
            debug("Write request for %s missing value", name);
            return;
        }
        can::write::sendSignal(signal, value, getSignals(), getSignalCount());
    } else {
        CanCommand* command = lookupCommand(name, getCommands(),
                getCommandCount());
        if(command != NULL) {
            command->handler(name, value, event, getSignals(),
                    getSignalCount());
        } else {
            debug("Writing not allowed for signal with name %s", name);
        }
    }
}

bool receiveWriteRequest(uint8_t* message) {
    cJSON *root = cJSON_Parse((char*)message);
    bool foundMessage = false;
    if(root != NULL) {
        foundMessage = true;
        cJSON* nameObject = cJSON_GetObjectItem(root, "name");
        if(nameObject == NULL) {
            cJSON* idObject = cJSON_GetObjectItem(root, "id");
            if(idObject == NULL) {
                debug("Write request is malformed, "
                        "missing name or id: %s", message);
            } else {
                receiveRawWriteRequest(idObject, root);
            }
        } else {
            receiveTranslatedWriteRequest(nameObject, root);
        }
        cJSON_Delete(root);
    } else {
        debug("No valid JSON in incoming buffer yet -- "
                "if it's valid, may be out of memory");
    }
    return foundMessage;
}

/*
 * Check to see if a packet has been received. If so, read the packet and print
 * the packet payload to the uart monitor.
 */
void receiveCan(Pipeline* pipeline, CanBus* bus) {
    // TODO what happens if we process until the queue is empty?
    if(!QUEUE_EMPTY(CanMessage, &bus->receiveQueue)) {
        CanMessage message = QUEUE_POP(CanMessage, &bus->receiveQueue);
        decodeCanMessage(pipeline, bus, message.id, message.data);
        bus->lastMessageReceived = time::systemTimeMs();
    }
}

void reset() {
    initializeAllCan();
}

#endif // CAN_EMULATOR
<commit_msg>Don't go into low power mode if we are debugging.<commit_after>#ifndef CAN_EMULATOR

#include "interface/usb.h"
#include "can/canread.h"
#include "interface/uart.h"
#include "interface/network.h"
#include "signals.h"
#include "util/log.h"
#include "cJSON.h"
#include "pipeline.h"
#include "util/timer.h"
#include "lights.h"
#include "power.h"
#include "bluetooth.h"
#include "platform/platform.h"
#include <stdint.h>
#include <stdlib.h>

namespace uart = openxc::interface::uart;
namespace network = openxc::interface::network;
namespace usb = openxc::interface::usb;
namespace lights = openxc::lights;
namespace can = openxc::can;
namespace platform = openxc::platform;
namespace time = openxc::util::time;
namespace signals = openxc::signals;

using openxc::can::lookupCommand;
using openxc::can::lookupSignal;
using openxc::signals::initialize;
using openxc::signals::getCanBuses;
using openxc::signals::getCanBusCount;
using openxc::signals::getCommands;
using openxc::signals::getCommandCount;
using openxc::signals::getSignals;
using openxc::signals::getSignalCount;
using openxc::signals::decodeCanMessage;

extern Pipeline pipeline;

/* Forward declarations */

void receiveCan(Pipeline*, CanBus*);
void initializeAllCan();
bool receiveWriteRequest(uint8_t*);
void updateDataLights();

void setup() {
    initializeAllCan();
    signals::initialize();
}

void loop() {
    for(int i = 0; i < getCanBusCount(); i++) {
        receiveCan(&pipeline, &getCanBuses()[i]);
    }

    usb::read(pipeline.usb, receiveWriteRequest);
    uart::read(pipeline.uart, receiveWriteRequest);
    network::read(pipeline.network, receiveWriteRequest);

    for(int i = 0; i < getCanBusCount(); i++) {
        can::write::processWriteQueue(&getCanBuses()[i]);
    }

    updateDataLights();
    openxc::signals::loop();
}

/* Public: Update the color and status of a board's light that shows the status
 * of the CAN bus. This function is intended to be called each time through the
 * main program loop.
 */
void updateDataLights() {
    static unsigned long startupTime = time::systemTimeMs();
    static bool busWasActive;
    bool busActive = false;
    for(int i = 0; i < getCanBusCount(); i++) {
        busActive = busActive || can::busActive(&getCanBuses()[i]);
    }

    if(!busWasActive && busActive) {
        debug("CAN woke up - enabling LED");
        lights::enable(lights::LIGHT_A, lights::COLORS.blue);
        busWasActive = true;
    } else if(!busActive && (busWasActive || time::systemTimeMs() - startupTime >
            (unsigned long)openxc::can::CAN_ACTIVE_TIMEOUT_S * 1000)) {
        // stay awake at least CAN_ACTIVE_TIMEOUT_S after power on
#ifndef TRANSMITTER
#ifndef __DEBUG__
        busWasActive = false;
        platform::suspend(&pipeline);
#endif
#endif
    }
}

void initializeAllCan() {
    for(int i = 0; i < getCanBusCount(); i++) {
        can::initialize(&(getCanBuses()[i]));
    }
}

void receiveRawWriteRequest(cJSON* idObject, cJSON* root) {
    uint32_t id = idObject->valueint;
    cJSON* dataObject = cJSON_GetObjectItem(root, "data");
    if(dataObject == NULL) {
        debug("Raw write request missing data", id);
        return;
    }

    char* dataString = dataObject->valuestring;
    char* end;
    // TODO hard coding bus 0 right now, but it should support sending on either
    CanMessage message = {&getCanBuses()[0], id};
    can::write::enqueueMessage(&message, strtoull(dataString, &end, 16));
}

void receiveTranslatedWriteRequest(cJSON* nameObject, cJSON* root) {
    char* name = nameObject->valuestring;
    cJSON* value = cJSON_GetObjectItem(root, "value");

    // Optional, may be NULL
    cJSON* event = cJSON_GetObjectItem(root, "event");

    CanSignal* signal = lookupSignal(name, getSignals(), getSignalCount(),
            true);
    if(signal != NULL) {
        if(value == NULL) {
            debug("Write request for %s missing value", name);
            return;
        }
        can::write::sendSignal(signal, value, getSignals(), getSignalCount());
    } else {
        CanCommand* command = lookupCommand(name, getCommands(),
                getCommandCount());
        if(command != NULL) {
            command->handler(name, value, event, getSignals(),
                    getSignalCount());
        } else {
            debug("Writing not allowed for signal with name %s", name);
        }
    }
}

bool receiveWriteRequest(uint8_t* message) {
    cJSON *root = cJSON_Parse((char*)message);
    bool foundMessage = false;
    if(root != NULL) {
        foundMessage = true;
        cJSON* nameObject = cJSON_GetObjectItem(root, "name");
        if(nameObject == NULL) {
            cJSON* idObject = cJSON_GetObjectItem(root, "id");
            if(idObject == NULL) {
                debug("Write request is malformed, "
                        "missing name or id: %s", message);
            } else {
                receiveRawWriteRequest(idObject, root);
            }
        } else {
            receiveTranslatedWriteRequest(nameObject, root);
        }
        cJSON_Delete(root);
    } else {
        debug("No valid JSON in incoming buffer yet -- "
                "if it's valid, may be out of memory");
    }
    return foundMessage;
}

/*
 * Check to see if a packet has been received. If so, read the packet and print
 * the packet payload to the uart monitor.
 */
void receiveCan(Pipeline* pipeline, CanBus* bus) {
    // TODO what happens if we process until the queue is empty?
    if(!QUEUE_EMPTY(CanMessage, &bus->receiveQueue)) {
        CanMessage message = QUEUE_POP(CanMessage, &bus->receiveQueue);
        decodeCanMessage(pipeline, bus, message.id, message.data);
        bus->lastMessageReceived = time::systemTimeMs();
    }
}

void reset() {
    initializeAllCan();
}

#endif // CAN_EMULATOR
<|endoftext|>


<commit_before>#ifndef _SDD_ORDER_ORDER_HH_
#define _SDD_ORDER_ORDER_HH_

#include <algorithm> // find
#include <initializer_list>
#include <iostream>
#include <memory>    // shared_ptr
#include <sstream>
#include <utility>   // pair
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "sdd/order/order_builder.hh"
#include "sdd/order/order_identifier.hh"
#include "sdd/order/order_node.hh"
#include "sdd/util/hash.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @internal
using order_positions_type = std::vector<order_position_type>;

/// @internal
using order_positions_iterator = typename order_positions_type::const_iterator;

/*------------------------------------------------------------------------------------------------*/

/// @brief Represent an order of identifiers, possibly with some hierarchy.
/// @todo Manage artificial identifiers.
///
/// It helps associate a variable (generated by the library) in an SDD to an identifiers
/// (provided to the user). An identifier should appear only once by order.
template <typename C>
class order final
{
public:

  /// @brief A user's identifier type.
  using identifier_type = typename C::Identifier;

  /// @brief A library's variable type.
  using variable_type = typename C::variable_type;

private:

  /// @brief A path, following hierarchies, to a node.
  using path_type = typename order_node<C>::path_type;

  /// @brief All nodes.
  using nodes_type = std::vector<order_node<C>>;

  /// @brief A shared pointer to nodes.
  using nodes_ptr_type = std::shared_ptr<const nodes_type>;

  /// @brief Define a mapping identifier->node.
  using id_to_node_type = std::unordered_map<order_identifier<C>, const order_node<C>*>;

  /// @brief The concrete order.
  nodes_ptr_type nodes_ptr_;

  /// @brief Maps identifiers to nodes.
  std::shared_ptr<id_to_node_type> id_to_node_ptr_;

  /// @brief The first node in the order.
  const order_node<C>* head_;

public:

  order(const order&) = default;
  order& operator=(const order&) = default;
  order(order&&) = default;
  order& operator=(order&&) = default;

  /// @brief Constructor.
  order(const order_builder<C>& builder)
    : nodes_ptr_(mk_nodes_ptr(builder))
    , id_to_node_ptr_(mk_identifier_to_node(nodes_ptr_))
    , head_(nodes_ptr_ ? &(nodes_ptr_->front()) : nullptr)
  {}

  /// @internal
  /// @brief Tell if upper contains nested in its possibly contained hierarchy.
  /// @param uppper Must belong to the current order.
  /// @param nested Must belong to the current order.
  bool
  contains(order_position_type upper, order_position_type nested)
  const noexcept
  {
    const auto& path = (*nodes_ptr_)[nested].path();
    return std::find(path.begin(), path.end(), upper) != path.end();
  }

  /// @brief Tell if upper contains nested in its possibly contained hierarchy.
  /// @param uppper Must belong to the current order.
  /// @param nested Must belong to the current order.
  bool
  contains(const identifier_type& upper, const identifier_type& nested)
  const noexcept
  {
    return contains(node(upper).position(), node(nested).position());
  }

  /// @brief
  const nodes_type&
  identifiers()
  const noexcept
  {
    return *nodes_ptr_;
  }

  /// @brief Get the variable of this order's head.
  variable_type
  variable()
  const noexcept
  {
    return head_->variable();
  }

  /// @brief Get the identifier of this order's head.
  const order_identifier<C>&
  identifier()
  const noexcept
  {
    return head_->identifier();
  }

  /// @brief Get the position of this order's head.
  order_position_type
  position()
  const noexcept
  {
    return head_->position();
  }

  /// @brief Get the next order of this order's head.
  order
  next()
  const noexcept
  {
    return order(nodes_ptr_, id_to_node_ptr_, head_->next());
  }

  /// @brief Get the nested order of this order's head.
  order
  nested()
  const noexcept
  {
    return order(nodes_ptr_, id_to_node_ptr_, head_->nested());
  }

  /// @brief Tell if this order is empty.
  bool
  empty()
  const noexcept
  {
    return head_ == nullptr;
  }

  /// @internal
  const order_node<C>&
  node(const identifier_type& id)
  const
  {
    return *id_to_node_ptr_->at(order_identifier<C>(id));
  }

  /// @internal
  std::size_t
  hash()
  const noexcept
  {
    std::size_t seed = 0;
    util::hash_combine(seed, nodes_ptr_.get());
    util::hash_combine(seed, head_);
    return seed;
  }

  /// @internal
  bool
  operator==(const order& other)
  const noexcept
  {
    if (empty())
    {
      return other.empty() ? true : false;
    }
    else if (other.empty())
    {
      return false;
    }
    return position() == other.position() and identifier() == other.identifier()
       and nested() == other.nested() and next() == other.next();
  }

private:

  /// @brief Construct with a shallow copy an already existing order.
  order( const nodes_ptr_type& nodes_ptr, const std::shared_ptr<id_to_node_type>& id_to_node
       , const order_node<C>* head)
    : nodes_ptr_(nodes_ptr), id_to_node_ptr_(id_to_node), head_(head)
  {}

  /// @brief Create the concrete order using an order_builder.
  static
  nodes_ptr_type
  mk_nodes_ptr(const order_builder<C>& builder)
  {
    if (builder.empty())
    {
      return nullptr;
    }

    auto nodes_ptr = std::make_shared<nodes_type>(builder.size());
    auto& nodes = *nodes_ptr;

    // Ensure that identifiers appear only once.
    std::unordered_set<identifier_type> unicity;

    // Counter for identifiers' positions.
    unsigned int pos = 0;

    // To enable recursion in the lambda.
    std::function<
      std::pair<order_node<C>*, variable_type>
      (const order_builder<C>&, const std::shared_ptr<path_type>&)
    > helper;

    helper = [&helper, &pos, &nodes, &unicity]
    (const order_builder<C>& ob, const std::shared_ptr<path_type>& path)
    -> std::pair<order_node<C>*, unsigned int>
    {
      const unsigned int current_position = pos++;

      std::pair<order_node<C>*, variable_type> nested(nullptr, 0 /*first variable*/);
      std::pair<order_node<C>*, variable_type> next(nullptr, 0 /* first variable */);

      if (not ob.nested().empty())
      {
        const auto new_path = std::make_shared<path_type>(*path);
        new_path->push_back(current_position);
        new_path->shrink_to_fit();
        nested = helper(ob.nested(), new_path);
      }

      if (not ob.next().empty())
      {
        next = helper(ob.next(), path);
      }

      const auto variable = next.second;
      if (not ob.identifier().artificial() and not unicity.insert(ob.identifier().user()).second)
      {
        // Must stream user identifier to call its operator<<().
        std::stringstream ss;
        ss << "Duplicate order identifier " << ob.identifier().user();
        throw std::runtime_error(ss.str());
      }
      nodes[current_position] =
        order_node<C>(ob.identifier(), variable, current_position, next.first, nested.first, path);
      return std::make_pair(&nodes[current_position], variable + 1);
    };

    // Launch the recursion.
    helper(builder, std::make_shared<path_type>());

    return nodes_ptr;
  }

  /// @brief
  const std::shared_ptr<id_to_node_type>
  mk_identifier_to_node(const nodes_ptr_type& nodes_ptr)
  {
    auto identifier_to_node_ptr = std::make_shared<id_to_node_type>();
    if (nodes_ptr)
    {
      identifier_to_node_ptr->reserve(nodes_ptr->size());
      std::for_each( nodes_ptr->begin(), nodes_ptr_->end()
                   , [&](const order_node<C>& n)
                        {identifier_to_node_ptr->emplace(n.identifier(), &n);}
                   );
    }
    return identifier_to_node_ptr;
  }
};

/*------------------------------------------------------------------------------------------------*/

/// @brief Textual representation of an order.
/// @related order
template <typename C>
std::ostream&
operator<<(std::ostream& os, const order<C>& ord)
{
  const std::function<std::ostream&(const order<C>&, unsigned int)> helper
   = [&helper, &os](const order<C>& o, unsigned int indent)
  -> std::ostream&
  {
    if (not o.empty())
    {
      const std::string spaces(indent, ' ');
      os << spaces << o.identifier() << std::endl;
      if (not o.nested().empty())
      {
        helper(o.nested(), indent + 2);
      }
      if (not o.next().empty())
      {
        helper(o.next(), indent);
      }
    }
    return os;
  };
  return helper(ord, 0);
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Hash specialization for sdd::order.
template <typename C>
struct hash<sdd::order<C>>
{
  std::size_t
  operator()(const sdd::order<C>& o)
  const noexcept
  {
    return o.hash();
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_ORDER_ORDER_HH_
<commit_msg>Get flat identifiers of an order.<commit_after>#ifndef _SDD_ORDER_ORDER_HH_
#define _SDD_ORDER_ORDER_HH_

#include <algorithm>  // find
#include <initializer_list>
#include <iostream>
#include <memory>     // shared_ptr
#include <sstream>
#include <utility>    // pair
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "sdd/order/order_builder.hh"
#include "sdd/order/order_identifier.hh"
#include "sdd/order/order_node.hh"
#include "sdd/util/hash.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @internal
using order_positions_type = std::vector<order_position_type>;

/// @internal
using order_positions_iterator = typename order_positions_type::const_iterator;

/*------------------------------------------------------------------------------------------------*/

/// @brief Represent an order of identifiers, possibly with some hierarchy.
/// @todo Manage artificial identifiers.
///
/// It helps associate a variable (generated by the library) in an SDD to an identifiers
/// (provided to the user). An identifier should appear only once by order.
template <typename C>
class order final
{
public:

  /// @brief A user's identifier type.
  using identifier_type = typename C::Identifier;

  /// @brief A library's variable type.
  using variable_type = typename C::variable_type;

private:

  /// @brief A path, following hierarchies, to a node.
  using path_type = typename order_node<C>::path_type;

  /// @brief All nodes.
  using nodes_type = std::vector<order_node<C>>;

  /// @brief A shared pointer to nodes.
  using nodes_ptr_type = std::shared_ptr<const nodes_type>;

  /// @brief Define a mapping identifier->node.
  using id_to_node_type = std::unordered_map<order_identifier<C>, const order_node<C>*>;

  /// @brief The concrete order.
  nodes_ptr_type nodes_ptr_;

  /// @brief Maps identifiers to nodes.
  std::shared_ptr<id_to_node_type> id_to_node_ptr_;

  /// @brief The first node in the order.
  const order_node<C>* head_;

public:

  order(const order&) = default;
  order& operator=(const order&) = default;
  order(order&&) = default;
  order& operator=(order&&) = default;

  /// @brief Constructor.
  order(const order_builder<C>& builder)
    : nodes_ptr_(mk_nodes_ptr(builder))
    , id_to_node_ptr_(mk_identifier_to_node(nodes_ptr_))
    , head_(nodes_ptr_ ? &(nodes_ptr_->front()) : nullptr)
  {}

  /// @internal
  /// @brief Tell if upper contains nested in its possibly contained hierarchy.
  /// @param uppper Must belong to the current order.
  /// @param nested Must belong to the current order.
  bool
  contains(order_position_type upper, order_position_type nested)
  const noexcept
  {
    const auto& path = (*nodes_ptr_)[nested].path();
    return std::find(path.begin(), path.end(), upper) != path.end();
  }

  /// @brief Tell if upper contains nested in its possibly contained hierarchy.
  /// @param uppper Must belong to the current order.
  /// @param nested Must belong to the current order.
  bool
  contains(const identifier_type& upper, const identifier_type& nested)
  const noexcept
  {
    return contains(node(upper).position(), node(nested).position());
  }

  /// @brief
  const nodes_type&
  identifiers()
  const noexcept
  {
    return *nodes_ptr_;
  }

  /// @brief Get the variable of this order's head.
  variable_type
  variable()
  const noexcept
  {
    return head_->variable();
  }

  /// @brief Get the identifier of this order's head.
  const order_identifier<C>&
  identifier()
  const noexcept
  {
    return head_->identifier();
  }

  /// @brief Get the position of this order's head.
  order_position_type
  position()
  const noexcept
  {
    return head_->position();
  }

  /// @brief Get the next order of this order's head.
  order
  next()
  const noexcept
  {
    return order(nodes_ptr_, id_to_node_ptr_, head_->next());
  }

  /// @brief Get the nested order of this order's head.
  order
  nested()
  const noexcept
  {
    return order(nodes_ptr_, id_to_node_ptr_, head_->nested());
  }

  /// @brief Tell if this order is empty.
  bool
  empty()
  const noexcept
  {
    return head_ == nullptr;
  }

  /// @brief Return flat variables, from top to bottom.
  template <typename OutputIterator>
  void
  flat(OutputIterator it)
  const
  {
    flat_impl(it, head_);
  }

  /// @internal
  const order_node<C>&
  node(const identifier_type& id)
  const
  {
    return *id_to_node_ptr_->at(order_identifier<C>(id));
  }

  /// @internal
  std::size_t
  hash()
  const noexcept
  {
    std::size_t seed = 0;
    util::hash_combine(seed, nodes_ptr_.get());
    util::hash_combine(seed, head_);
    return seed;
  }

  /// @internal
  bool
  operator==(const order& other)
  const noexcept
  {
    if (empty())
    {
      return other.empty() ? true : false;
    }
    else if (other.empty())
    {
      return false;
    }
    return position() == other.position() and identifier() == other.identifier()
       and nested() == other.nested() and next() == other.next();
  }

private:

  /// @brief Recursion on the order to get flat nodes
  template <typename OutputIterator>
  static
  void
  flat_impl(OutputIterator it, const order_node<C>* current)
  {
    if (current != nullptr)
    {
      if (current->nested())
      {
        flat_impl(it, current->nested());
      }
      else
      {
        *it++ = current->identifier().user();
      }
      flat_impl(it, current->next());
    }
  }

  /// @brief Construct with a shallow copy an already existing order.
  order( const nodes_ptr_type& nodes_ptr, const std::shared_ptr<id_to_node_type>& id_to_node
       , const order_node<C>* head)
    : nodes_ptr_(nodes_ptr), id_to_node_ptr_(id_to_node), head_(head)
  {}

  /// @brief Create the concrete order using an order_builder.
  static
  nodes_ptr_type
  mk_nodes_ptr(const order_builder<C>& builder)
  {
    if (builder.empty())
    {
      return nullptr;
    }

    auto nodes_ptr = std::make_shared<nodes_type>(builder.size());
    auto& nodes = *nodes_ptr;

    // Ensure that identifiers appear only once.
    std::unordered_set<identifier_type> unicity;

    // Counter for identifiers' positions.
    unsigned int pos = 0;

    // To enable recursion in the lambda.
    std::function<
      std::pair<order_node<C>*, variable_type>
      (const order_builder<C>&, const std::shared_ptr<path_type>&)
    > helper;

    helper = [&helper, &pos, &nodes, &unicity]
    (const order_builder<C>& ob, const std::shared_ptr<path_type>& path)
    -> std::pair<order_node<C>*, unsigned int>
    {
      const unsigned int current_position = pos++;

      std::pair<order_node<C>*, variable_type> nested(nullptr, 0 /*first variable*/);
      std::pair<order_node<C>*, variable_type> next(nullptr, 0 /* first variable */);

      if (not ob.nested().empty())
      {
        const auto new_path = std::make_shared<path_type>(*path);
        new_path->push_back(current_position);
        new_path->shrink_to_fit();
        nested = helper(ob.nested(), new_path);
      }

      if (not ob.next().empty())
      {
        next = helper(ob.next(), path);
      }

      const auto variable = next.second;
      if (not ob.identifier().artificial() and not unicity.insert(ob.identifier().user()).second)
      {
        // Must stream user identifier to call its operator<<().
        std::stringstream ss;
        ss << "Duplicate order identifier " << ob.identifier().user();
        throw std::runtime_error(ss.str());
      }
      nodes[current_position] =
        order_node<C>(ob.identifier(), variable, current_position, next.first, nested.first, path);
      return std::make_pair(&nodes[current_position], variable + 1);
    };

    // Launch the recursion.
    helper(builder, std::make_shared<path_type>());

    return nodes_ptr;
  }

  /// @brief
  const std::shared_ptr<id_to_node_type>
  mk_identifier_to_node(const nodes_ptr_type& nodes_ptr)
  {
    auto identifier_to_node_ptr = std::make_shared<id_to_node_type>();
    if (nodes_ptr)
    {
      identifier_to_node_ptr->reserve(nodes_ptr->size());
      std::for_each( nodes_ptr->begin(), nodes_ptr_->end()
                   , [&](const order_node<C>& n)
                        {identifier_to_node_ptr->emplace(n.identifier(), &n);}
                   );
    }
    return identifier_to_node_ptr;
  }
};

/*------------------------------------------------------------------------------------------------*/

/// @brief Textual representation of an order.
/// @related order
template <typename C>
std::ostream&
operator<<(std::ostream& os, const order<C>& ord)
{
  const std::function<std::ostream&(const order<C>&, unsigned int)> helper
   = [&helper, &os](const order<C>& o, unsigned int indent)
  -> std::ostream&
  {
    if (not o.empty())
    {
      const std::string spaces(indent, ' ');
      os << spaces << o.identifier() << std::endl;
      if (not o.nested().empty())
      {
        helper(o.nested(), indent + 2);
      }
      if (not o.next().empty())
      {
        helper(o.next(), indent);
      }
    }
    return os;
  };
  return helper(ord, 0);
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Hash specialization for sdd::order.
template <typename C>
struct hash<sdd::order<C>>
{
  std::size_t
  operator()(const sdd::order<C>& o)
  const noexcept
  {
    return o.hash();
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_ORDER_ORDER_HH_
<|endoftext|>