<commit_before>//
// The MIT License (MIT)
//
// Copyright 2013-2014 The MilkCat Project Developers
//
// 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.
//
// hmm_part_of_speech_tagger.cc --- Created at 2013-11-10
//

#include "milkcat/hmm_part_of_speech_tagger.h"
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "milkcat/beam.h"
#include "milkcat/hmm_model.h"
#include "milkcat/libmilkcat.h"
#include "milkcat/part_of_speech_tag_instance.h"
#include "milkcat/term_instance.h"
#include "utils/utils.h"

namespace milkcat {

struct HMMPartOfSpeechTagger::Node {
  int tag;
  double cost;
  const HMMPartOfSpeechTagger::Node *prevoius_node;
};

HMMPartOfSpeechTagger::HMMPartOfSpeechTagger(): model_(nullptr),
                                                node_pool_(nullptr),
                                                index_(nullptr),
                                                PU_emit_(nullptr),
                                                DT_emit_(nullptr),
                                                term_instance_(nullptr) {
  for (int i = 0; i < kMaxBeams; ++i) {
    beams_[i] = nullptr;
  }
}

HMMPartOfSpeechTagger::~HMMPartOfSpeechTagger() {
  delete node_pool_;
  node_pool_ = nullptr;

  delete PU_emit_;
  PU_emit_ = nullptr;

  delete DT_emit_;
  DT_emit_ = nullptr;

  for (int i = 0; i < kMaxBeams; ++i) {
    if (beams_[i] != nullptr)
      delete beams_[i];
    beams_[i] = nullptr;
  }
}

namespace {

// Compare two node potiners by its cost value
bool HmmNodePtrCmp(HMMPartOfSpeechTagger::Node *n1,
                   HMMPartOfSpeechTagger::Node *n2) {
  return n1->cost < n2->cost;
}

// New an emit node for tag specified by tag_str. If tag_str not exist in model
// return a nullptr and status indicates an corruption error.
HMMModel::Emit *NewEmitFromTag(const char *tag_str,
                               const HMMModel *model,
                               Status *status) {
  int tagid = model->tag_id(tag_str);
  if (tagid < 0) *status = Status::Corruption("Invalid HMM model.");

  HMMModel::Emit *emit = nullptr;
  if (status->ok()) {
    emit = new HMMModel::Emit(tagid, 0.0, nullptr);
  }

  return emit;
}

}  // namespace

HMMPartOfSpeechTagger *HMMPartOfSpeechTagger::New(
    ModelFactory *model_factory,
    Status *status) {
  HMMPartOfSpeechTagger *self = new HMMPartOfSpeechTagger();
  self->node_pool_ = new NodePool<Node>();

  for (int i = 0; i < kMaxBeams; ++i) {
    self->beams_[i] = new Beam<Node>(kBeamSize,
                                     self->node_pool_,
                                     i,
                                     HmmNodePtrCmp);
  }

  self->model_ = model_factory->HMMPosModel(status);

  if (status->ok()) self->PU_emit_ = NewEmitFromTag("PU", self->model_, status);
  if (status->ok()) self->DT_emit_ = NewEmitFromTag("DT", self->model_, status);

  if (status->ok()) {
    self->BOS_tagid_ = self->model_->tag_id("BOS");
    if (self->BOS_tagid_ < 0)
      *status = Status::Corruption("Invalid HMM model.");
  }

  if (status->ok()) {
    self->NN_tagid_ = self->model_->tag_id("NN");
    if (self->NN_tagid_ < 0)
      *status = Status::Corruption("Invalid HMM model.");
  }

  if (status->ok()) self->index_ = model_factory->Index(status);

  if (status->ok()) {
    return self;
  } else {
    delete self;
    return NULL;
  }
}

HMMModel::Emit *HMMPartOfSpeechTagger::GetEmitAtPosition(int position) {
  int term_id;
  HMMModel::Emit *emit;

  term_id = term_instance_->term_id_at(position);
  if (term_id == TermInstance::kTermIdNone) {
    term_id = index_->Search(term_instance_->term_text_at(position));
  }

  emit = model_->emit(term_id);
  if (emit == nullptr) {
    int term_type = term_instance_->term_type_at(position);
    switch (term_type) {
      case TermInstance::kPunction:
      case TermInstance::kSymbol:
      case TermInstance::kOther:
        emit = PU_emit_;
        break;
      case TermInstance::kNumber:
        emit = DT_emit_;
        break;
    }
  }

  return emit;
}

inline void HMMPartOfSpeechTagger::AddBOSNodeToBeam() {
  Node *bos_node = node_pool_->Alloc();
  bos_node->tag = BOS_tagid_;
  bos_node->cost = 0;
  bos_node->prevoius_node = nullptr;
  beams_[0]->Clear();
  beams_[0]->Add(bos_node);

  Node *bos_node_2 = node_pool_->Alloc();
  bos_node_2->tag = BOS_tagid_;
  bos_node_2->cost = 0;
  bos_node_2->prevoius_node = bos_node;
  beams_[1]->Clear();
  beams_[1]->Add(bos_node_2);
}

inline void HMMPartOfSpeechTagger::GetBestPOSTagFromBeam(
    PartOfSpeechTagInstance *part_of_speech_tag_instance) {
  int position = term_instance_->size() - 1;
  const Node *node = beams_[position + 2]->MinimalNode();

  while (node->tag != BOS_tagid_) {
    part_of_speech_tag_instance->set_value_at(position,
                                              model_->tag_str(node->tag));
    position--;
    node = node->prevoius_node;
  }

  part_of_speech_tag_instance->set_size(term_instance_->size());
}

void HMMPartOfSpeechTagger::Tag(
    PartOfSpeechTagInstance *part_of_speech_tag_instance,
    TermInstance *term_instance) {
  term_instance_ = term_instance;

  AddBOSNodeToBeam();

  // Viterbi algorithm
  for (int i = 0; i < term_instance->size(); ++i)
    BuildBeam(i);

  // Find the best result
  GetBestPOSTagFromBeam(part_of_speech_tag_instance);

  node_pool_->ReleaseAll();
}

void HMMPartOfSpeechTagger::GuessTag(const Node *leftleft_node,
                                     const Node *left_node,
                                     Beam<Node> *beam) {
  int leftleft_tag = leftleft_node->tag,
      left_tag = left_node->tag;
  Node *node = nullptr;

  node = node_pool_->Alloc();
  node->tag = NN_tagid_;
  node->cost = left_node->cost;
  node->prevoius_node = left_node;
  beam->Add(node);

}

void HMMPartOfSpeechTagger::BuildBeam(int position) {
  // Beam has two BOS node at 0 and 1
  int beam_position = position + 2;

  HMMModel::Emit *emit = GetEmitAtPosition(position), *emit_node;
  const Node *leftleft_node, *left_node, *node;
  int leftleft_tag, left_tag, tag;

  Beam<Node> *previous_beam = beams_[beam_position - 1];
  Beam<Node> *beam = beams_[beam_position];

  previous_beam->Shrink();
  beam->Clear();

  for (int i = 0; i < previous_beam->size(); ++i) {
    left_node = previous_beam->node_at(i);
    leftleft_node = left_node->prevoius_node;

    leftleft_tag = leftleft_node->tag;
    left_tag = left_node->tag;

    // If current word has emit information or current word is punction or
    // symbol
    emit_node = emit;
    if (emit_node) {
      while (emit_node) {
        tag = emit_node->tag;
        double trans_cost = model_->trans_cost(leftleft_tag, left_tag, tag);
        double emit_cost = emit_node->cost;
        Node *node = node_pool_->Alloc();
        node->tag = tag;
        node->cost = left_node->cost + trans_cost + emit_cost;
        node->prevoius_node = left_node;
        beam->Add(node);

#ifdef LOG
        printf("node added %s %s cost = %lf trans_cost = %lf emit_cost = %lf\n",
               term_instance_->term_text_at(position),
               model_->tag_str(tag),
               trans_cost + emit_cost,
               trans_cost,
               emit_cost);
#endif

        emit_node = emit_node->next;
      }
    } else {
      GuessTag(leftleft_node, left_node, beam);
    }
  }
}

}  // namespace milkcat
<commit_msg>change decoder method in hmm_part_of_speech_tagger<commit_after>//
// The MIT License (MIT)
//
// Copyright 2013-2014 The MilkCat Project Developers
//
// 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.
//
// hmm_part_of_speech_tagger.cc --- Created at 2013-11-10
//

#include "milkcat/hmm_part_of_speech_tagger.h"
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "milkcat/beam.h"
#include "milkcat/hmm_model.h"
#include "milkcat/libmilkcat.h"
#include "milkcat/part_of_speech_tag_instance.h"
#include "milkcat/term_instance.h"
#include "utils/utils.h"

#define LOG

namespace milkcat {

struct HMMPartOfSpeechTagger::Node {
  int tag;
  double cost;
  const HMMPartOfSpeechTagger::Node *prevoius_node;

  inline void set_value(int tag, int cost, const Node *prevoius_node) {
    this->tag = tag;
    this->cost = cost;
    this->prevoius_node = prevoius_node;
  }
};

HMMPartOfSpeechTagger::HMMPartOfSpeechTagger(): model_(nullptr),
                                                node_pool_(nullptr),
                                                index_(nullptr),
                                                PU_emit_(nullptr),
                                                DT_emit_(nullptr),
                                                term_instance_(nullptr) {
  for (int i = 0; i < kMaxBeams; ++i) {
    beams_[i] = nullptr;
  }
}

HMMPartOfSpeechTagger::~HMMPartOfSpeechTagger() {
  delete node_pool_;
  node_pool_ = nullptr;

  delete PU_emit_;
  PU_emit_ = nullptr;

  delete DT_emit_;
  DT_emit_ = nullptr;

  for (int i = 0; i < kMaxBeams; ++i) {
    if (beams_[i] != nullptr)
      delete beams_[i];
    beams_[i] = nullptr;
  }
}

namespace {

// Compare two node potiners by its cost value
bool HmmNodePtrCmp(HMMPartOfSpeechTagger::Node *n1,
                   HMMPartOfSpeechTagger::Node *n2) {
  return n1->cost < n2->cost;
}

// New an emit node for tag specified by tag_str. If tag_str not exist in model
// return a nullptr and status indicates an corruption error.
HMMModel::Emit *NewEmitFromTag(const char *tag_str,
                               const HMMModel *model,
                               Status *status) {
  int tagid = model->tag_id(tag_str);
  if (tagid < 0) *status = Status::Corruption("Invalid HMM model.");

  HMMModel::Emit *emit = nullptr;
  if (status->ok()) {
    emit = new HMMModel::Emit(tagid, 0.0, nullptr);
  }

  return emit;
}

}  // namespace

HMMPartOfSpeechTagger *HMMPartOfSpeechTagger::New(
    ModelFactory *model_factory,
    Status *status) {
  HMMPartOfSpeechTagger *self = new HMMPartOfSpeechTagger();
  self->node_pool_ = new NodePool<Node>();

  for (int i = 0; i < kMaxBeams; ++i) {
    self->beams_[i] = new Beam<Node>(kBeamSize,
                                     self->node_pool_,
                                     i,
                                     HmmNodePtrCmp);
  }

  self->model_ = model_factory->HMMPosModel(status);

  if (status->ok()) self->PU_emit_ = NewEmitFromTag("PU", self->model_, status);
  if (status->ok()) self->DT_emit_ = NewEmitFromTag("DT", self->model_, status);

  if (status->ok()) {
    self->BOS_tagid_ = self->model_->tag_id("BOS");
    if (self->BOS_tagid_ < 0)
      *status = Status::Corruption("Invalid HMM model.");
  }

  if (status->ok()) {
    self->NN_tagid_ = self->model_->tag_id("NN");
    if (self->NN_tagid_ < 0)
      *status = Status::Corruption("Invalid HMM model.");
  }

  if (status->ok()) self->index_ = model_factory->Index(status);

  if (status->ok()) {
    return self;
  } else {
    delete self;
    return NULL;
  }
}

HMMModel::Emit *HMMPartOfSpeechTagger::GetEmitAtPosition(int position) {
  int term_id;
  HMMModel::Emit *emit;

  term_id = term_instance_->term_id_at(position);
  if (term_id == TermInstance::kTermIdNone) {
    term_id = index_->Search(term_instance_->term_text_at(position));
  }

  emit = model_->emit(term_id);
  if (emit == nullptr) {
    int term_type = term_instance_->term_type_at(position);
    switch (term_type) {
      case TermInstance::kPunction:
      case TermInstance::kSymbol:
      case TermInstance::kOther:
        emit = PU_emit_;
        break;
      case TermInstance::kNumber:
        emit = DT_emit_;
        break;
    }
  }

  if (emit == nullptr) emit = PU_emit_;

  return emit;
}

inline void HMMPartOfSpeechTagger::AddBOSNodeToBeam() {
  Node *bos_node = node_pool_->Alloc();
  bos_node->tag = BOS_tagid_;
  bos_node->cost = 0;
  bos_node->prevoius_node = nullptr;
  beams_[0]->Clear();
  beams_[0]->Add(bos_node);

  Node *bos_node_2 = node_pool_->Alloc();
  bos_node_2->tag = BOS_tagid_;
  bos_node_2->cost = 0;
  bos_node_2->prevoius_node = bos_node;
  beams_[1]->Clear();
  beams_[1]->Add(bos_node_2);
}

inline void HMMPartOfSpeechTagger::GetBestPOSTagFromBeam(
    PartOfSpeechTagInstance *part_of_speech_tag_instance) {
  int position = term_instance_->size() - 1;
  const Node *node = beams_[position + 2]->MinimalNode();

  while (node->tag != BOS_tagid_) {
    part_of_speech_tag_instance->set_value_at(position,
                                              model_->tag_str(node->tag));
    position--;
    node = node->prevoius_node;
  }

  part_of_speech_tag_instance->set_size(term_instance_->size());
}

void HMMPartOfSpeechTagger::Tag(
    PartOfSpeechTagInstance *part_of_speech_tag_instance,
    TermInstance *term_instance) {
  term_instance_ = term_instance;

  AddBOSNodeToBeam();

  // Viterbi algorithm
  for (int i = 0; i < term_instance->size(); ++i)
    BuildBeam(i);

  // Find the best result
  GetBestPOSTagFromBeam(part_of_speech_tag_instance);

  node_pool_->ReleaseAll();
}

void HMMPartOfSpeechTagger::GuessTag(const Node *leftleft_node,
                                     const Node *left_node,
                                     Beam<Node> *beam) {
  int leftleft_tag = leftleft_node->tag,
      left_tag = left_node->tag;
  Node *node = nullptr;

  node = node_pool_->Alloc();
  node->tag = NN_tagid_;
  node->cost = left_node->cost;
  node->prevoius_node = left_node;
  beam->Add(node);

}

void HMMPartOfSpeechTagger::BuildBeam(int position) {
  // Beam has two BOS node at 0 and 1
  int beam_position = position + 2;

  HMMModel::Emit *emit = GetEmitAtPosition(position);
  const Node *leftleft_node, *left_node;
  int leftleft_tag, left_tag, tag;

  Beam<Node> *previous_beam = beams_[beam_position - 1];
  Beam<Node> *beam = beams_[beam_position];

  previous_beam->Shrink();
  beam->Clear();

  while (emit) {
    double min_cost = 1e38;
    const Node *min_left_node;
    for (int i = 0; i < previous_beam->size(); ++i) {
      left_node = previous_beam->node_at(i);
      leftleft_node = left_node->prevoius_node;

      leftleft_tag = leftleft_node->tag;
      left_tag = left_node->tag;

      // If current word has emit information or current word is punction or
      // symbol

      double trans_cost = model_->trans_cost(leftleft_tag,
                                             left_tag,
                                             emit->tag);
      double emit_cost = emit->cost;
      double cost = left_node->cost + trans_cost + emit_cost;
      if (cost < min_cost) {
        printf("find min cost %lf\n", cost);
        min_cost = cost;
        min_left_node = left_node;
      }

#ifdef LOG
      printf("%s %s %s %s"
             "total_cost = %lf cost = %lf trans_cost = %lf emit_cost = %lf\n",
             term_instance_->term_text_at(position),
             model_->tag_str(leftleft_tag),
             model_->tag_str(left_tag),
             model_->tag_str(emit->tag),
             cost,
             trans_cost + emit_cost,
             trans_cost,
             emit_cost);
#endif
    }

    Node *node = node_pool_->Alloc();
    node->set_value(emit->tag, min_cost, min_left_node);
    beam->Add(node);

    emit = emit->next;
  }

}

}  // namespace milkcat
<|endoftext|>


<commit_before>/* NOTE: In this document, for a type to "act like a data type" means that it
is default-constructible, copy-constructible, copy-assignable, and destructible.
If it allocates heap memory, it must manage it on its own. */

namespace clustering {

/* `namespace_interface_t` is the main entry point that protocol parsers use to
perform reads and writes on a namespace. `protocol_t` is a config struct that
holds all the types specific to that protocol. */
template<class protocol_t>
class namespace_interface_t {

    /* This document doesn't deal with the details of how to find namespaces.
    Tim's plan is that each protocol will keep its own directory of namespaces
    organized in a protocol-specific way. Riak could have a map from strings
    to namespaces, along with a way to synchronize the creation of namespaces.
    Memcached could have a set of (namespace, port) pairs. Redis could...
    do whatever makes sense for Redis. */
    namespace_interface_t(
        mailbox_cluster_t *cluster,
        metadata_view_t<namespace_metadata_t<protocol_t> > *namespace_metadata
        );
    ~namespace_interface_t();

    /* Performs the given read query on the namespace. [May block] */
    protocol_t::read_response_t read(protocol_t::read_t query);

    /* Performs the given write query on the namespace. [May block] */
    protocol_t::write_response_t write(protocol_t::write_t query);

    /* Reads and writes configuration information for the namespace, such as the
    replication factor. */
    ... configure(...);

private:
    ...
};

}   /* namespace clustering */

/* `?` indicates that something is protocol-specific. Each protocol will define
a `?_protocol_t` for itself and all the members therein. That `?_protocol_t`
will be passed as a template parameter to the clustering code so it knows how
to work with that protocol. */

namespace ? {

struct ?_protocol_t {

    /* `region_t` is like a set (in the mathematical sense) of keys, although
    not all sets can be expressed as `region_t`s. Protocols will probably be
    implemented as a range of keys, although it could be something weirder, like
    the set of all keys whose hashes fall into a certain range.

    In this document, we talk about regions using set notation.
    `union(regions)` refers to the union of multiple regions. And so on. */

    struct region_t {
        /* Returns true if this `region_t` is a superset of `x`. */
        bool contains(region_t x);

        /* Returns true if this `region_t` overlaps `x`. */
        bool overlaps(region_t x);

        /* Returns the `region_t` containing all keys both in this `region_t`
        and `x`. */
        region_t intersection(region_t x);

        /* Other requirements: `region_t` must be serializable. The "==" and
        "!=" operators must work on `region_t`. `region_t` must act like a data
        type. */

    private:
        ?
    };

    /* `read_t`, `read_response_t`, `write_t`, `write_response_t`, and
    `backfill_chunk_t` must all be serializable. */

    struct read_t {

        /* Indicates which keys the read depends on. */
        region_t get_region();

        /* Breaks the read into several sub-reads for individual regions.
        [Precondition] union(regions) == read.get_region()
        [Precondition] forall x,y in regions, x does not overlap y
        [Postcondition] read.shard(regions).size() == regions.size()
        [Postcondition] read.shard(regions)[i].get_region() IsSubsetOf regions[i]
        */
        std::vector<read_t> shard(std::vector<region_t> regions);

        /* Breaks the read into several sub-reads that will be run in parallel
        on different machines. `read_t` may choose how many sub-reads to create,
        but creating more than `optimal_factor` sub-reads won't help performance
        and may hurt it.
        [Postcondition] read.parallelize()[i].get_region() IsSubsetOf read.get_region()
        */
        std::vector<read_t> parallelize(int optimal_factor);

        /* Other requirements: `read_t` must be serializable. `read_t` must act
        like a data type. */

    private:
        ?
    };

    struct read_response_t {

        /* Recombines the responses to a group of reads created by
        `read_t::shard()`. */
        static read_response_t unshard(std::vector<read_response_t> responses);

        /* Recombines the responses to a group of reads created by
        `read_t::parallelize()`. */
        static read_response_t unparallelize(std::vector<read_response_t> responses);

        /* Other requirements: `read_response_t` must be serializable.
        `read_response_t` must act like a data type. */

    private:
        ?
    };

    struct write_t {

        /* Indicates which keys the write depends on or will modify. */
        region_t get_region();

        /* Breaks the write into several sub-writes for individual regions.
        Preconditions and postconditions are the same as for `read_t::shard()`.
        */
        std::vector<write_t> shard(std::vector<region_t> regions);

        /* Other requirements: `write_t` must be serializable. `write_t` must
        act like a data type. */

    private:
        ?
    };

    struct write_response_t {

        /* Recombines the responses to a group of writes created by
        `write_t::shard()`. */
        static write_response_t unshard(std::vector<write_response_t> responses);

        /* Other requirements: `write_response_t` must be serializable.
        `write_response_t` must act like a data type. */

    private:
        ?
    };

    /* `store_t` is the object that performs actual operations on stored data.
    It is responsible for constructing its own cache and btree.

    Although operations may be run on the `store_t` concurrently, it should
    behave as though every operation's effect was instantaneous. For example, if
    the store receives a write and then immediately receives a read before the
    write is done, the read should see the effects of the write. */

    struct store_t {

        /* Returns the same region that was passed to the constructor. */
        region_t get_region();

        /* A store can be either coherent or incoherent. Roughly, "incoherent"
        means you're in the middle of a backfill. The coherence of a store must
        be persisted to disk.
        [Precondition] !store.is_backfilling() */
        bool is_coherent();

        /* Returns the store's current timestamp.
        [Precondition] !store.is_backfilling() */
        repli_timestamp_t get_timestamp();

        /* Performs a read operation on the store. May not modify the store's
        state in any way.
        [Precondition] read.get_region() IsSubsetOf store.get_region()
        [Precondition] store.is_coherent()
        [Precondition] !store.is_backfilling()
        [May block]
        */
        read_response_t read(read_t read, order_token_t otok);

        /* Performs a write operation on the store. The effect on the stored
        state must be deterministic; if I have two `store_t`s in the same state
        and I call `write()` on both with the same parameters, then they must
        both transition to the same state.
        [Precondition] write.get_region() IsSubsetOf store.get_region()
        [Precondition] store.is_coherent()
        [Precondition] !store.is_backfilling()
        [Precondition] timestamp >= store.get_timestamp()
        [Postcondition] store.get_timestamp() == timestamp
        [May block]
        */
        write_response_t write(write_t write, repli_timestamp_t timestamp, order_token_t otok);

        /* Returns `true` if the store is in the middle of a backfill. */
        bool is_backfilling();

        struct backfill_request_t {

            /* You don't have to actually implement `get_region()` and
            `get_timestamp()`; they're only here to make it easier to describe
            preconditions and postconditions. */

            /* Returns the same value as the backfillee's `get_region()` method.
            */
            region_t get_region();

            /* Returns the same value as the backfillee's `get_timestamp()`
            method. */
            repli_timestamp_t get_timestamp();

            /* Other requirements: `backfill_request_t` must be serializable.
            `backfill_request_t` must act like a data type. */

        private:
            ?
        };

        struct backfill_chunk_t {

            /* Other requirements: `backfill_chunk_t` must be serializable.
            `backfill_chunk_t` must act like a data type. */

        private:
            ?
        };

        struct backfill_end_t {

            /* Other requirements: `backfill_end_t` must be serializable.
            `backfill_end_t` must act like a data type. */

        private:
            ?
        };

        /* Prepares the store for a backfill. Returns a `backfill_request_t`
        which expresses what information the store needs backfilled.
        [Precondition] !store.is_backfilling()
        [Postcondition] store.is_backfilling()
        [Postcondition] store.backfillee_begin().get_region() == store.get_region()
        [Postcondition] store.get_timestamp() == store.backfillee_begin().get_timestamp()
        [May block] */
        backfill_request_t backfillee_begin();

        /* Delivers a chunk of a running backfill.
        [Precondition] store.is_backfilling()
        [May block] */
        void backfillee_chunk(backfill_chunk_t);

        /* Notifies that the backfill is over.
        [Precondition] store.is_backfilling()
        [Postcondition] !store.is_backfilling()
        [Postcondition] store.is_coherent()
        [May block] */
        void backfillee_end(backfill_end_t);

        /* Notifies that the backfill won't be finished because something went
        wrong.
        [Precondition] store.is_backfilling()
        [Postcondition] !store.is_backfilling()
        [Postcondition] !store.is_coherent()
        [May block] */
        void backfillee_cancel();

        /* Sends a backfill to another store. `request` should be the return
        value of the backfillee's `backfillee_begin()` method. `backfiller()`
        should call `chunk_fun` with `backfill_chunk_t`s to be passed to the
        backfillee's `backfillee_chunk()` method. `backfiller()` should block
        until the backfill is done, and then return a `backfill_end_t` to be
        passed to the backfillee's `backfillee_end()` method. If `interruptor`
        is pulsed before the backfill is over, then `backfiller()` should stop
        the backfill and throw an `interrupted_exc_t` as soon as possible.
        [Precondition] request.get_region() == store.get_region()
        [Precondition] request.get_timestamp() <= store.get_timestamp()
        [Precondition] !store.is_backfilling()
        [Precondition] store.is_coherent()
        [May block] */
        backfill_end_t backfiller(
            backfill_request_t request,
            boost::function<void(backfill_chunk_t)> chunk_fun,
            signal_t *interruptor);

        /* Here's an example of how to use the backfill API. `backfill()` will
        copy data from `backfiller` to `backfillee` unless `interruptor` is
        pulsed, in which case it will throw `interrupted_exc_t`.

        void backfill(store_t *backfillee, store_t *backfiller, signal_t *interruptor) {
            backfill_request_t req = backfillee->backfillee_begin();
            backfill_end_t end;
            try {
                end = backfiller->backfiller(
                    req,
                    boost::bind(&store_t::backfillee_chunk, backfillee),
                    interruptor);
            } catch (interrupted_exc_t) {
                backfillee->backfillee_cancel();
                throw;
            }
            backfillee->backfillee_end(end);
        }
        */

    private:
        ?
    };

    /* Stores will be created and destroyed via some yet-unspecified mechanism.
    I don't know exactly what it will be yet. */

    /* NOTE: I don't know what form the `rebalance()` function will take in the
    finished product. I'm including it here because I know something like it
    will eventually be necessary. But it probably won't be a stand-alone
    function, and its type signature might be different.

    Creates a set of stores which contain the same data as `recyclees`, but
    whose regions are `goals`. Each store in `recyclees` must either be
    destroyed or re-used as part of the return value.
    [Precondition] The regions of the stores in `recyclees` must not overlap.
    [Precondition] The regions in `goals` must not overlap.
    [Precondition] The union of the regions in `recyclees` must be the same
        as the union of the regions in `goals`.
    [Postcondition] store_manager.rebalance(recyclees, goals)[i].get_region() == goals[i]
    [Postcondition] store_manager.rebalance(recyclees, goals).size() == goals.size()
    [May block] */
    static std::vector<store_t *> rebalance(
        std::vector<store_t *> recyclees,
        std::vector<region_t> goals);
};

}   /* namespace ? */

/* Notes on ordering guarantees:

1.  All the replicas of each individual key will see writes in the same order.

    Example: Suppose K = "x". You send (append "a" to K) and (append "b" to K)
    concurrently from different nodes. Either every copy of K will become "xab",
    or every copy of K will become "xba", but the different copies of K will
    never disagree.

2.  Queries from the same origin will be performed in same order they are sent.

    Example: Suppose K = "a". You send (set K to "b") and (read K) from the same
    thread on the same node, in that order. The read will return "b".

3.  Arbitrary atomic single-key operations can be performed, as long as the
    `protocol_t::store_t` supports them.

4.  There are no other atomicity or ordering guarantees.

    Example: Suppose K1 = "x" and K2 = "x". You send (append "a" to every key)
    and (append "b" to every key) concurrently. Every copy of K1 will agree with
    every other copy of K1, and every copy of K2 will agree with every other
    copy of K2, but K1 and K2 may disagree.

    Example: Suppose K = "a". You send (set K to "b"). As soon as it's sent, you
    send (set K to "c") from a different node. K may end up being either "b" or
    "c".

    Example: Suppose K1 = "a" and K2 = "a". You send (set K1 to "b") and (set K2
    to "b") from the same node, in that order. Then you send (read K1 and K2)
    from a different node. The read may return (K1 = "a", K2 = "b").

5.  There is no simple way to perform an atomic multikey transaction. You might
    be able to fake it by using a key as a "lock".
*/
<commit_msg>Add another insight to clustering doc. (Joe is annoying tim even more)<commit_after>/* NOTE: In this document, for a type to "act like a data type" means that it
is default-constructible, copy-constructible, copy-assignable, and destructible.
If it allocates heap memory, it must manage it on its own. */

namespace clustering {

/* `namespace_interface_t` is the main entry point that protocol parsers use to
perform reads and writes on a namespace. `protocol_t` is a config struct that
holds all the types specific to that protocol. */
template<class protocol_t>
class namespace_interface_t {

    /* This document doesn't deal with the details of how to find namespaces.
    Tim's plan is that each protocol will keep its own directory of namespaces
    organized in a protocol-specific way. Riak could have a map from strings
    to namespaces, along with a way to synchronize the creation of namespaces.
    Memcached could have a set of (namespace, port) pairs. Redis could...
    do whatever makes sense for Redis. */
    namespace_interface_t(
        mailbox_cluster_t *cluster,
        metadata_view_t<namespace_metadata_t<protocol_t> > *namespace_metadata
        );
    ~namespace_interface_t();

    /* Performs the given read query on the namespace. [May block] */
    protocol_t::read_response_t read(protocol_t::read_t query);

    /* Performs the given write query on the namespace. [May block] */
    protocol_t::write_response_t write(protocol_t::write_t query);

    /* Reads and writes configuration information for the namespace, such as the
    replication factor. */
    ... configure(...);

private:
    ...
};

}   /* namespace clustering */

/* `?` indicates that something is protocol-specific. Each protocol will define
a `?_protocol_t` for itself and all the members therein. That `?_protocol_t`
will be passed as a template parameter to the clustering code so it knows how
to work with that protocol. */

namespace ? {

struct ?_protocol_t {

    /* `region_t` is like a set (in the mathematical sense) of keys, although
    not all sets can be expressed as `region_t`s. Protocols will probably be
    implemented as a range of keys, although it could be something weirder, like
    the set of all keys whose hashes fall into a certain range.

    In this document, we talk about regions using set notation.
    `union(regions)` refers to the union of multiple regions. And so on. */

    struct region_t {
        /* Returns true if this `region_t` is a superset of `x`. */
        bool contains(region_t x);

        /* Returns true if this `region_t` overlaps `x`. */
        bool overlaps(region_t x);

        /* Returns the `region_t` containing all keys both in this `region_t`
        and `x`. */
        region_t intersection(region_t x);

        /* Other requirements: `region_t` must be serializable. The "==" and
        "!=" operators must work on `region_t`. `region_t` must act like a data
        type. */

    private:
        ?
    };

    /* `read_t`, `read_response_t`, `write_t`, `write_response_t`, and
    `backfill_chunk_t` must all be serializable. */

    struct read_t {

        /* Indicates which keys the read depends on. */
        region_t get_region();

        /* Breaks the read into several sub-reads for individual regions.
        [Precondition] union(regions) == read.get_region()
        [Precondition] forall x,y in regions, x does not overlap y
        [Postcondition] read.shard(regions).size() == regions.size()
        [Postcondition] read.shard(regions)[i].get_region() IsSubsetOf regions[i]
        */
        std::vector<read_t> shard(std::vector<region_t> regions);

        /* Breaks the read into several sub-reads that will be run in parallel
        on different machines. `read_t` may choose how many sub-reads to create,
        but creating more than `optimal_factor` sub-reads won't help performance
        and may hurt it.
        [Postcondition] read.parallelize()[i].get_region() IsSubsetOf read.get_region()

        Notice that parallelize need not return reads with disjoint regions, in fact in
        many reasonable cases the regions will not be disjoint. Such as in the case of
        a riak bucket dump.
        */
        std::vector<read_t> parallelize(int optimal_factor);

        /* Other requirements: `read_t` must be serializable. `read_t` must act
        like a data type. */

    private:
        ?
    };

    struct read_response_t {

        /* Recombines the responses to a group of reads created by
        `read_t::shard()`. */
        static read_response_t unshard(std::vector<read_response_t> responses);

        /* Recombines the responses to a group of reads created by
        `read_t::parallelize()`. */
        static read_response_t unparallelize(std::vector<read_response_t> responses);

        /* Other requirements: `read_response_t` must be serializable.
        `read_response_t` must act like a data type. */

    private:
        ?
    };

    struct write_t {

        /* Indicates which keys the write depends on or will modify. */
        region_t get_region();

        /* Breaks the write into several sub-writes for individual regions.
        Preconditions and postconditions are the same as for `read_t::shard()`.
        */
        std::vector<write_t> shard(std::vector<region_t> regions);

        /* Other requirements: `write_t` must be serializable. `write_t` must
        act like a data type. */

    private:
        ?
    };

    struct write_response_t {

        /* Recombines the responses to a group of writes created by
        `write_t::shard()`. */
        static write_response_t unshard(std::vector<write_response_t> responses);

        /* Other requirements: `write_response_t` must be serializable.
        `write_response_t` must act like a data type. */

    private:
        ?
    };

    /* `store_t` is the object that performs actual operations on stored data.
    It is responsible for constructing its own cache and btree.

    Although operations may be run on the `store_t` concurrently, it should
    behave as though every operation's effect was instantaneous. For example, if
    the store receives a write and then immediately receives a read before the
    write is done, the read should see the effects of the write. */

    struct store_t {

        /* Returns the same region that was passed to the constructor. */
        region_t get_region();

        /* A store can be either coherent or incoherent. Roughly, "incoherent"
        means you're in the middle of a backfill. The coherence of a store must
        be persisted to disk.
        [Precondition] !store.is_backfilling() */
        bool is_coherent();

        /* Returns the store's current timestamp.
        [Precondition] !store.is_backfilling() */
        repli_timestamp_t get_timestamp();

        /* Performs a read operation on the store. May not modify the store's
        state in any way.
        [Precondition] read.get_region() IsSubsetOf store.get_region()
        [Precondition] store.is_coherent()
        [Precondition] !store.is_backfilling()
        [May block]
        */
        read_response_t read(read_t read, order_token_t otok);

        /* Performs a write operation on the store. The effect on the stored
        state must be deterministic; if I have two `store_t`s in the same state
        and I call `write()` on both with the same parameters, then they must
        both transition to the same state.
        [Precondition] write.get_region() IsSubsetOf store.get_region()
        [Precondition] store.is_coherent()
        [Precondition] !store.is_backfilling()
        [Precondition] timestamp >= store.get_timestamp()
        [Postcondition] store.get_timestamp() == timestamp
        [May block]
        */
        write_response_t write(write_t write, repli_timestamp_t timestamp, order_token_t otok);

        /* Returns `true` if the store is in the middle of a backfill. */
        bool is_backfilling();

        struct backfill_request_t {

            /* You don't have to actually implement `get_region()` and
            `get_timestamp()`; they're only here to make it easier to describe
            preconditions and postconditions. */

            /* Returns the same value as the backfillee's `get_region()` method.
            */
            region_t get_region();

            /* Returns the same value as the backfillee's `get_timestamp()`
            method. */
            repli_timestamp_t get_timestamp();

            /* Other requirements: `backfill_request_t` must be serializable.
            `backfill_request_t` must act like a data type. */

        private:
            ?
        };

        struct backfill_chunk_t {

            /* Other requirements: `backfill_chunk_t` must be serializable.
            `backfill_chunk_t` must act like a data type. */

        private:
            ?
        };

        struct backfill_end_t {

            /* Other requirements: `backfill_end_t` must be serializable.
            `backfill_end_t` must act like a data type. */

        private:
            ?
        };

        /* Prepares the store for a backfill. Returns a `backfill_request_t`
        which expresses what information the store needs backfilled.
        [Precondition] !store.is_backfilling()
        [Postcondition] store.is_backfilling()
        [Postcondition] store.backfillee_begin().get_region() == store.get_region()
        [Postcondition] store.get_timestamp() == store.backfillee_begin().get_timestamp()
        [May block] */
        backfill_request_t backfillee_begin();

        /* Delivers a chunk of a running backfill.
        [Precondition] store.is_backfilling()
        [May block] */
        void backfillee_chunk(backfill_chunk_t);

        /* Notifies that the backfill is over.
        [Precondition] store.is_backfilling()
        [Postcondition] !store.is_backfilling()
        [Postcondition] store.is_coherent()
        [May block] */
        void backfillee_end(backfill_end_t);

        /* Notifies that the backfill won't be finished because something went
        wrong.
        [Precondition] store.is_backfilling()
        [Postcondition] !store.is_backfilling()
        [Postcondition] !store.is_coherent()
        [May block] */
        void backfillee_cancel();

        /* Sends a backfill to another store. `request` should be the return
        value of the backfillee's `backfillee_begin()` method. `backfiller()`
        should call `chunk_fun` with `backfill_chunk_t`s to be passed to the
        backfillee's `backfillee_chunk()` method. `backfiller()` should block
        until the backfill is done, and then return a `backfill_end_t` to be
        passed to the backfillee's `backfillee_end()` method. If `interruptor`
        is pulsed before the backfill is over, then `backfiller()` should stop
        the backfill and throw an `interrupted_exc_t` as soon as possible.
        [Precondition] request.get_region() == store.get_region()
        [Precondition] request.get_timestamp() <= store.get_timestamp()
        [Precondition] !store.is_backfilling()
        [Precondition] store.is_coherent()
        [May block] */
        backfill_end_t backfiller(
            backfill_request_t request,
            boost::function<void(backfill_chunk_t)> chunk_fun,
            signal_t *interruptor);

        /* Here's an example of how to use the backfill API. `backfill()` will
        copy data from `backfiller` to `backfillee` unless `interruptor` is
        pulsed, in which case it will throw `interrupted_exc_t`.

        void backfill(store_t *backfillee, store_t *backfiller, signal_t *interruptor) {
            backfill_request_t req = backfillee->backfillee_begin();
            backfill_end_t end;
            try {
                end = backfiller->backfiller(
                    req,
                    boost::bind(&store_t::backfillee_chunk, backfillee),
                    interruptor);
            } catch (interrupted_exc_t) {
                backfillee->backfillee_cancel();
                throw;
            }
            backfillee->backfillee_end(end);
        }
        */

    private:
        ?
    };

    /* Stores will be created and destroyed via some yet-unspecified mechanism.
    I don't know exactly what it will be yet. */

    /* NOTE: I don't know what form the `rebalance()` function will take in the
    finished product. I'm including it here because I know something like it
    will eventually be necessary. But it probably won't be a stand-alone
    function, and its type signature might be different.

    Creates a set of stores which contain the same data as `recyclees`, but
    whose regions are `goals`. Each store in `recyclees` must either be
    destroyed or re-used as part of the return value.
    [Precondition] The regions of the stores in `recyclees` must not overlap.
    [Precondition] The regions in `goals` must not overlap.
    [Precondition] The union of the regions in `recyclees` must be the same
        as the union of the regions in `goals`.
    [Postcondition] store_manager.rebalance(recyclees, goals)[i].get_region() == goals[i]
    [Postcondition] store_manager.rebalance(recyclees, goals).size() == goals.size()
    [May block] */
    static std::vector<store_t *> rebalance(
        std::vector<store_t *> recyclees,
        std::vector<region_t> goals);
};

}   /* namespace ? */

/* Notes on ordering guarantees:

1.  All the replicas of each individual key will see writes in the same order.

    Example: Suppose K = "x". You send (append "a" to K) and (append "b" to K)
    concurrently from different nodes. Either every copy of K will become "xab",
    or every copy of K will become "xba", but the different copies of K will
    never disagree.

2.  Queries from the same origin will be performed in same order they are sent.

    Example: Suppose K = "a". You send (set K to "b") and (read K) from the same
    thread on the same node, in that order. The read will return "b".

3.  Arbitrary atomic single-key operations can be performed, as long as the
    `protocol_t::store_t` supports them.

4.  There are no other atomicity or ordering guarantees.

    Example: Suppose K1 = "x" and K2 = "x". You send (append "a" to every key)
    and (append "b" to every key) concurrently. Every copy of K1 will agree with
    every other copy of K1, and every copy of K2 will agree with every other
    copy of K2, but K1 and K2 may disagree.

    Example: Suppose K = "a". You send (set K to "b"). As soon as it's sent, you
    send (set K to "c") from a different node. K may end up being either "b" or
    "c".

    Example: Suppose K1 = "a" and K2 = "a". You send (set K1 to "b") and (set K2
    to "b") from the same node, in that order. Then you send (read K1 and K2)
    from a different node. The read may return (K1 = "a", K2 = "b").

5.  There is no simple way to perform an atomic multikey transaction. You might
    be able to fake it by using a key as a "lock".
*/
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#ifndef ALTITUDE_HPP
#define ALTITUDE_HPP

#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/wind_estimate.h>

class MavlinkStreamAltitude : public MavlinkStream
{
public:
	static MavlinkStream *new_instance(Mavlink *mavlink) { return new MavlinkStreamAltitude(mavlink); }

	static constexpr const char *get_name_static() { return "ALTITUDE"; }
	static constexpr uint16_t get_id_static() { return MAVLINK_MSG_ID_ALTITUDE; }

	const char *get_name() const override { return get_name_static(); }
	uint16_t get_id() override { return get_id_static(); }

	unsigned get_size() override
	{
		return _local_pos_sub.advertised() ? MAVLINK_MSG_ID_ALTITUDE_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
	}

private:
	explicit MavlinkStreamAltitude(Mavlink *mavlink) : MavlinkStream(mavlink) {}

	uORB::Subscription _local_pos_sub{ORB_ID(vehicle_local_position)};
	uORB::Subscription _home_sub{ORB_ID(home_position)};
	uORB::Subscription _air_data_sub{ORB_ID(vehicle_air_data)};

	bool send() override
	{
		mavlink_altitude_t msg{};

		msg.altitude_monotonic = NAN;
		msg.altitude_amsl = NAN;
		msg.altitude_local = NAN;
		msg.altitude_relative = NAN;
		msg.altitude_terrain = NAN;
		msg.bottom_clearance = NAN;

		// always update monotonic altitude
		bool air_data_updated = false;
		vehicle_air_data_s air_data{};
		_air_data_sub.copy(&air_data);

		if (air_data.timestamp > 0) {
			msg.altitude_monotonic = air_data.baro_alt_meter;

			air_data_updated = true;
		}

		bool lpos_updated = false;

		vehicle_local_position_s local_pos;

		if (_local_pos_sub.copy(&local_pos)) {

			if (local_pos.z_valid) {
				if (local_pos.z_global) {
					msg.altitude_amsl = -local_pos.z + local_pos.ref_alt;

				} else {
					msg.altitude_amsl = msg.altitude_monotonic;
				}

				msg.altitude_local = -local_pos.z;

				home_position_s home{};
				_home_sub.copy(&home);

				if (home.valid_alt) {
					msg.altitude_relative = -(local_pos.z - home.z);

				} else {
					msg.altitude_relative = -local_pos.z;
				}

				if (local_pos.dist_bottom_valid) {
					msg.altitude_terrain = -local_pos.z - local_pos.dist_bottom;
					msg.bottom_clearance = local_pos.dist_bottom;
				}
			}

			lpos_updated = true;
		}

		// local position timeout after 10 ms
		// avoid publishing only baro altitude_monotonic if possible
		bool lpos_timeout = (hrt_elapsed_time(&local_pos.timestamp) > 10_ms);

		if (lpos_updated || (air_data_updated && lpos_timeout)) {
			msg.time_usec = hrt_absolute_time();
			mavlink_msg_altitude_send_struct(_mavlink->get_channel(), &msg);

			return true;
		}

		return false;
	}
};

#endif // ALTITUDE_HPP
<commit_msg>mavlink: ALTITUDE stream initialize local_pos<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#ifndef ALTITUDE_HPP
#define ALTITUDE_HPP

#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/wind_estimate.h>

class MavlinkStreamAltitude : public MavlinkStream
{
public:
	static MavlinkStream *new_instance(Mavlink *mavlink) { return new MavlinkStreamAltitude(mavlink); }

	static constexpr const char *get_name_static() { return "ALTITUDE"; }
	static constexpr uint16_t get_id_static() { return MAVLINK_MSG_ID_ALTITUDE; }

	const char *get_name() const override { return get_name_static(); }
	uint16_t get_id() override { return get_id_static(); }

	unsigned get_size() override
	{
		return _local_pos_sub.advertised() ? MAVLINK_MSG_ID_ALTITUDE_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES : 0;
	}

private:
	explicit MavlinkStreamAltitude(Mavlink *mavlink) : MavlinkStream(mavlink) {}

	uORB::Subscription _local_pos_sub{ORB_ID(vehicle_local_position)};
	uORB::Subscription _home_sub{ORB_ID(home_position)};
	uORB::Subscription _air_data_sub{ORB_ID(vehicle_air_data)};

	bool send() override
	{
		mavlink_altitude_t msg{};

		msg.altitude_monotonic = NAN;
		msg.altitude_amsl = NAN;
		msg.altitude_local = NAN;
		msg.altitude_relative = NAN;
		msg.altitude_terrain = NAN;
		msg.bottom_clearance = NAN;

		// always update monotonic altitude
		bool air_data_updated = false;
		vehicle_air_data_s air_data{};
		_air_data_sub.copy(&air_data);

		if (air_data.timestamp > 0) {
			msg.altitude_monotonic = air_data.baro_alt_meter;

			air_data_updated = true;
		}

		bool lpos_updated = false;

		vehicle_local_position_s local_pos{};

		if (_local_pos_sub.copy(&local_pos)) {

			if (local_pos.z_valid) {
				if (local_pos.z_global) {
					msg.altitude_amsl = -local_pos.z + local_pos.ref_alt;

				} else {
					msg.altitude_amsl = msg.altitude_monotonic;
				}

				msg.altitude_local = -local_pos.z;

				home_position_s home{};
				_home_sub.copy(&home);

				if (home.valid_alt) {
					msg.altitude_relative = -(local_pos.z - home.z);

				} else {
					msg.altitude_relative = -local_pos.z;
				}

				if (local_pos.dist_bottom_valid) {
					msg.altitude_terrain = -local_pos.z - local_pos.dist_bottom;
					msg.bottom_clearance = local_pos.dist_bottom;
				}
			}

			lpos_updated = true;
		}

		// local position timeout after 10 ms
		// avoid publishing only baro altitude_monotonic if possible
		bool lpos_timeout = (hrt_elapsed_time(&local_pos.timestamp) > 10_ms);

		if (lpos_updated || (air_data_updated && lpos_timeout)) {
			msg.time_usec = hrt_absolute_time();
			mavlink_msg_altitude_send_struct(_mavlink->get_channel(), &msg);

			return true;
		}

		return false;
	}
};

#endif // ALTITUDE_HPP
<|endoftext|>


<commit_before>#include "platform/i_platform.h"
#include "network/ctf_client_datas_message.h"
#include "core/ctf_program_state.h"

namespace network {
namespace ctf {

ClientDatasMessageSenderSystem::ClientDatasMessageSenderSystem()
    : MessageSenderSystem()
{
        //This one is not used yet you should wire it before use
}

void ClientDatasMessageSenderSystem::Init()
{
    MessageSenderSystem::Init();
        //This one is not used yet you should wire it before use
    mOnCtfClientDatasChangedEvent = EventServer<CtfClientDatasChangedEvent>::Get().Subscribe( boost::bind( &ClientDatasMessageSenderSystem::OnCtfClientDatasChangedEvent, this, _1) );
}

void ClientDatasMessageSenderSystem::Update(double DeltaTime)
{
    MessageSenderSystem::Update(DeltaTime);
        //This one is not used yet you should wire it before use
}

void ClientDatasMessageSenderSystem::OnCtfClientDatasChangedEvent( CtfClientDatasChangedEvent const & event )
{
    std::auto_ptr<ctf::ClientDatasMessage> message(new ctf::ClientDatasMessage);
    message->mClientDatas = event.mCtfClientDatas;
    mMessageHolder.AddOutgoingMessage(message);
}

ClientDatasMessageHandlerSubSystem::ClientDatasMessageHandlerSubSystem()
    : MessageHandlerSubSystem()
{
}

void ClientDatasMessageHandlerSubSystem::Init()
{
}

void ClientDatasMessageHandlerSubSystem::Execute(Message const& message)
{
    if ( mProgramState.mMode )
    {
    }
    ClientDatasMessage const& msg=static_cast<ClientDatasMessage const&>(message);
    L1("executing ctf::ClientDatasMessageHandlerSubSystem from id: %d \n",msg.mSenderId );
    ::ctf::ProgramState& ctfProgramState=::ctf::ProgramState::Get();
    ctfProgramState.mClientDatas=msg.mClientDatas;
    for (::ctf::ProgramState::ClientDatas_t::iterator i=ctfProgramState.mClientDatas.begin(), e=ctfProgramState.mClientDatas.end();i!=e;++i)
    {
        L1("**** ctf arrived. **** from id: %d \n", i->mClientId );
        L1("   team:%d\n", i->mTeam );
    }
}

} // namespace ctf
} // namespace network

<commit_msg>M: remove unused condition<commit_after>#include "platform/i_platform.h"
#include "network/ctf_client_datas_message.h"
#include "core/ctf_program_state.h"

namespace network {
namespace ctf {

ClientDatasMessageSenderSystem::ClientDatasMessageSenderSystem()
    : MessageSenderSystem()
{
        //This one is not used yet you should wire it before use
}

void ClientDatasMessageSenderSystem::Init()
{
    MessageSenderSystem::Init();
        //This one is not used yet you should wire it before use
    mOnCtfClientDatasChangedEvent = EventServer<CtfClientDatasChangedEvent>::Get().Subscribe( boost::bind( &ClientDatasMessageSenderSystem::OnCtfClientDatasChangedEvent, this, _1) );
}

void ClientDatasMessageSenderSystem::Update(double DeltaTime)
{
    MessageSenderSystem::Update(DeltaTime);
        //This one is not used yet you should wire it before use
}

void ClientDatasMessageSenderSystem::OnCtfClientDatasChangedEvent( CtfClientDatasChangedEvent const & event )
{
    std::auto_ptr<ctf::ClientDatasMessage> message(new ctf::ClientDatasMessage);
    message->mClientDatas = event.mCtfClientDatas;
    mMessageHolder.AddOutgoingMessage(message);
}

ClientDatasMessageHandlerSubSystem::ClientDatasMessageHandlerSubSystem()
    : MessageHandlerSubSystem()
{
}

void ClientDatasMessageHandlerSubSystem::Init()
{
}

void ClientDatasMessageHandlerSubSystem::Execute(Message const& message)
{
    ClientDatasMessage const& msg=static_cast<ClientDatasMessage const&>(message);
    L1("executing ctf::ClientDatasMessageHandlerSubSystem from id: %d \n",msg.mSenderId );
    ::ctf::ProgramState& ctfProgramState=::ctf::ProgramState::Get();
    ctfProgramState.mClientDatas=msg.mClientDatas;
    for (::ctf::ProgramState::ClientDatas_t::iterator i=ctfProgramState.mClientDatas.begin(), e=ctfProgramState.mClientDatas.end();i!=e;++i)
    {
        L1("**** ctf arrived. **** from id: %d \n", i->mClientId );
        L1("   team:%d\n", i->mTeam );
    }
}

} // namespace ctf
} // namespace network

<|endoftext|>


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

#include "ngraph/op/embedding_segments_sum.hpp"
#include "ngraph/op/constant.hpp"

using namespace std;
using namespace ngraph;

constexpr NodeTypeInfo op::v3::EmbeddingSegmentsSum::type_info;

op::v3::EmbeddingSegmentsSum::EmbeddingSegmentsSum(const Output<Node>& emb_table,
                                                   const Output<Node>& indices,
                                                   const Output<Node>& segment_ids,
                                                   const Output<Node>& num_segments,
                                                   const Output<Node>& per_sample_weights,
                                                   const Output<Node>& default_index)
    : Op({emb_table, indices, segment_ids, num_segments, per_sample_weights, default_index})
{
    constructor_validate_and_infer_types();
}

op::v3::EmbeddingSegmentsSum::EmbeddingSegmentsSum(const Output<Node>& emb_table,
                                                   const Output<Node>& indices,
                                                   const Output<Node>& segment_ids,
                                                   const Output<Node>& num_segments,
                                                   const Output<Node>& per_sample_weights)
    : Op({emb_table, indices, segment_ids, num_segments, per_sample_weights})
{
    constructor_validate_and_infer_types();
}

op::v3::EmbeddingSegmentsSum::EmbeddingSegmentsSum(const Output<Node>& emb_table,
                                                   const Output<Node>& indices,
                                                   const Output<Node>& segment_ids,
                                                   const Output<Node>& num_segments)
    : Op({emb_table, indices, segment_ids, num_segments})
{
    constructor_validate_and_infer_types();
}

void op::v3::EmbeddingSegmentsSum::validate_and_infer_types()
{
    enum
    {
        EMB_TABLE,
        INDICES,
        SEGMENT_IDS,
        NUM_SEGMENTS,
        PER_SAMPLE_WEIGHTS,
        DEFAULT_INDEX
    };

    NODE_VALIDATION_CHECK(this,
                          get_input_element_type(SEGMENT_IDS) == element::i64 ||
                              get_input_element_type(SEGMENT_IDS) == element::i32,
                          "SEGMENT_IDS type must be i32 or i64");

    NODE_VALIDATION_CHECK(this,
                          get_input_element_type(INDICES) == element::i64 ||
                              get_input_element_type(INDICES) == element::i32,
                          "INDICES type must be i32 or i64");

    NODE_VALIDATION_CHECK(this,
                          get_input_element_type(NUM_SEGMENTS) == element::i64 ||
                              get_input_element_type(NUM_SEGMENTS) == element::i32,
                          "NUM_SEGMENTS type must be i32 or i64");

    NODE_VALIDATION_CHECK(
        this,
        get_input_element_type(INDICES).compatible(get_input_element_type(SEGMENT_IDS)),
        "Segment_ids element type (",
        get_input_element_type(SEGMENT_IDS),
        ") must match indices element type (",
        get_input_element_type(INDICES),
        ")");

    NODE_VALIDATION_CHECK(
        this,
        get_input_element_type(SEGMENT_IDS).compatible(get_input_element_type(NUM_SEGMENTS)),
        "Num_segments element type (",
        get_input_element_type(NUM_SEGMENTS),
        ") must match Segment_ids element type (",
        get_input_element_type(SEGMENT_IDS),
        ")");

    NODE_VALIDATION_CHECK(this,
                          get_input_partial_shape(INDICES).is_dynamic() ||
                              get_input_partial_shape(INDICES).to_shape().size() == 1,
                          "INDICES must be 1D");

    NODE_VALIDATION_CHECK(this,
                          get_input_partial_shape(SEGMENT_IDS).is_dynamic() ||
                              get_input_partial_shape(SEGMENT_IDS).to_shape().size() == 1,
                          "SEGMENT_IDS must be 1D");

    NODE_VALIDATION_CHECK(
        this,
        get_input_partial_shape(INDICES).compatible(get_input_partial_shape(SEGMENT_IDS)),
        "INDICES and SEGMENT_IDS shape must be same");

    NODE_VALIDATION_CHECK(this,
                          get_input_partial_shape(NUM_SEGMENTS).compatible(PartialShape{}),
                          "NUM_SEGMENTS must be a scalar");

    if (get_input_size() >= 5)
    {
        NODE_VALIDATION_CHECK(this,
                              get_input_element_type(EMB_TABLE).compatible(
                                  get_input_element_type(PER_SAMPLE_WEIGHTS)),
                              "Per sample weight element type (",
                              get_input_element_type(PER_SAMPLE_WEIGHTS),
                              ") must match embedding table element type (",
                              get_input_element_type(EMB_TABLE),
                              ")");

        NODE_VALIDATION_CHECK(this,
                              get_input_partial_shape(PER_SAMPLE_WEIGHTS).is_dynamic() ||
                                  get_input_partial_shape(PER_SAMPLE_WEIGHTS).to_shape().size() ==
                                      1,
                              "PER_SAMPLE_WEIGHTS must be 1D");

        NODE_VALIDATION_CHECK(this,
                              get_input_partial_shape(INDICES).compatible(
                                  get_input_partial_shape(PER_SAMPLE_WEIGHTS)),
                              "INDICES and PER_SAMPLE_WEIGHTS shape must be same");
    }

    if (get_input_size() == 6)
    {
        NODE_VALIDATION_CHECK(this,
                              get_input_element_type(DEFAULT_INDEX) == element::i64 ||
                                  get_input_element_type(DEFAULT_INDEX) == element::i32,
                              "DEFAULT_INDEX type must be i32 or i64");

        NODE_VALIDATION_CHECK(
            this,
            get_input_element_type(INDICES).compatible(get_input_element_type(DEFAULT_INDEX)),
            "Default_index element type (",
            get_input_element_type(DEFAULT_INDEX),
            ") must match indices element type (",
            get_input_element_type(INDICES),
            ")");

        NODE_VALIDATION_CHECK(this,
                              get_input_partial_shape(DEFAULT_INDEX).compatible(PartialShape{}),
                              "DEFAULT_INDEX must be a scalar");
    }

    element::Type result_et = get_input_element_type(EMB_TABLE);

    const PartialShape& emb_table_shape = get_input_partial_shape(EMB_TABLE);

    PartialShape result_shape;
    if (emb_table_shape.rank().is_static())
    {
        std::vector<Dimension> result_dims(emb_table_shape.rank().get_length());
        result_dims[0] = Dimension::dynamic();
        for (size_t i = 1; i < emb_table_shape.rank().get_length(); i++)
        {
            result_dims[i] = emb_table_shape[i];
        }

        result_shape = PartialShape(result_dims);
    }
    else
    {
        result_shape = PartialShape::dynamic();
    }

    set_input_is_relevant_to_shape(NUM_SEGMENTS);
    set_output_type(0, result_et, result_shape);
}

shared_ptr<Node>
    op::v3::EmbeddingSegmentsSum::clone_with_new_inputs(const OutputVector& new_args) const
{
    check_new_args_count(this, new_args);
    if (new_args.size() == 4)
    {
        return make_shared<EmbeddingSegmentsSum>(
            new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3));
    }
    else if (new_args.size() == 5)
    {
        return make_shared<EmbeddingSegmentsSum>(
            new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4));
    }
    else
    {
        return make_shared<EmbeddingSegmentsSum>(new_args.at(0),
                                                 new_args.at(1),
                                                 new_args.at(2),
                                                 new_args.at(3),
                                                 new_args.at(4),
                                                 new_args.at(5));
    }
}
<commit_msg>Add more checks<commit_after>//*****************************************************************************
// Copyright 2017-2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#include "ngraph/op/embedding_segments_sum.hpp"
#include "ngraph/op/constant.hpp"

using namespace std;
using namespace ngraph;

constexpr NodeTypeInfo op::v3::EmbeddingSegmentsSum::type_info;

op::v3::EmbeddingSegmentsSum::EmbeddingSegmentsSum(const Output<Node>& emb_table,
                                                   const Output<Node>& indices,
                                                   const Output<Node>& segment_ids,
                                                   const Output<Node>& num_segments,
                                                   const Output<Node>& per_sample_weights,
                                                   const Output<Node>& default_index)
    : Op({emb_table, indices, segment_ids, num_segments, per_sample_weights, default_index})
{
    constructor_validate_and_infer_types();
}

op::v3::EmbeddingSegmentsSum::EmbeddingSegmentsSum(const Output<Node>& emb_table,
                                                   const Output<Node>& indices,
                                                   const Output<Node>& segment_ids,
                                                   const Output<Node>& num_segments,
                                                   const Output<Node>& per_sample_weights)
    : Op({emb_table, indices, segment_ids, num_segments, per_sample_weights})
{
    constructor_validate_and_infer_types();
}

op::v3::EmbeddingSegmentsSum::EmbeddingSegmentsSum(const Output<Node>& emb_table,
                                                   const Output<Node>& indices,
                                                   const Output<Node>& segment_ids,
                                                   const Output<Node>& num_segments)
    : Op({emb_table, indices, segment_ids, num_segments})
{
    constructor_validate_and_infer_types();
}

void op::v3::EmbeddingSegmentsSum::validate_and_infer_types()
{
    enum
    {
        EMB_TABLE,
        INDICES,
        SEGMENT_IDS,
        NUM_SEGMENTS,
        PER_SAMPLE_WEIGHTS,
        DEFAULT_INDEX
    };

    NODE_VALIDATION_CHECK(this,
                          get_input_element_type(SEGMENT_IDS) == element::i64 ||
                              get_input_element_type(SEGMENT_IDS) == element::i32,
                          "SEGMENT_IDS type must be i32 or i64");

    NODE_VALIDATION_CHECK(this,
                          get_input_element_type(INDICES) == element::i64 ||
                              get_input_element_type(INDICES) == element::i32,
                          "INDICES type must be i32 or i64");

    NODE_VALIDATION_CHECK(this,
                          get_input_element_type(NUM_SEGMENTS) == element::i64 ||
                              get_input_element_type(NUM_SEGMENTS) == element::i32,
                          "NUM_SEGMENTS type must be i32 or i64");

    NODE_VALIDATION_CHECK(
        this,
        get_input_element_type(INDICES).compatible(get_input_element_type(SEGMENT_IDS)),
        "Segment_ids element type (",
        get_input_element_type(SEGMENT_IDS),
        ") must match indices element type (",
        get_input_element_type(INDICES),
        ")");

    NODE_VALIDATION_CHECK(
        this,
        get_input_element_type(SEGMENT_IDS).compatible(get_input_element_type(NUM_SEGMENTS)),
        "Num_segments element type (",
        get_input_element_type(NUM_SEGMENTS),
        ") must match Segment_ids element type (",
        get_input_element_type(SEGMENT_IDS),
        ")");

    NODE_VALIDATION_CHECK(this,
                          get_input_partial_shape(INDICES).is_dynamic() ||
                              get_input_partial_shape(INDICES).to_shape().size() == 1,
                          "INDICES must be 1D");

    NODE_VALIDATION_CHECK(this,
                          get_input_partial_shape(SEGMENT_IDS).is_dynamic() ||
                              get_input_partial_shape(SEGMENT_IDS).to_shape().size() == 1,
                          "SEGMENT_IDS must be 1D");

    NODE_VALIDATION_CHECK(
        this,
        get_input_partial_shape(INDICES).compatible(get_input_partial_shape(SEGMENT_IDS)),
        "INDICES and SEGMENT_IDS shape must be same");

    NODE_VALIDATION_CHECK(this,
                          get_input_partial_shape(NUM_SEGMENTS).compatible(PartialShape{}),
                          "NUM_SEGMENTS must be a scalar");

    if (get_input_size() >= 5)
    {
        NODE_VALIDATION_CHECK(this,
                              get_input_element_type(EMB_TABLE).compatible(
                                  get_input_element_type(PER_SAMPLE_WEIGHTS)),
                              "Per sample weight element type (",
                              get_input_element_type(PER_SAMPLE_WEIGHTS),
                              ") must match embedding table element type (",
                              get_input_element_type(EMB_TABLE),
                              ")");

        NODE_VALIDATION_CHECK(this,
                              get_input_partial_shape(PER_SAMPLE_WEIGHTS).is_dynamic() ||
                                  get_input_partial_shape(PER_SAMPLE_WEIGHTS).to_shape().size() ==
                                      1,
                              "PER_SAMPLE_WEIGHTS must be 1D");

        NODE_VALIDATION_CHECK(this,
                              get_input_partial_shape(INDICES).compatible(
                                  get_input_partial_shape(PER_SAMPLE_WEIGHTS)),
                              "INDICES and PER_SAMPLE_WEIGHTS shape must be same");
    }

    if (get_input_size() == 6)
    {
        NODE_VALIDATION_CHECK(this,
                              get_input_element_type(DEFAULT_INDEX) == element::i64 ||
                                  get_input_element_type(DEFAULT_INDEX) == element::i32,
                              "DEFAULT_INDEX type must be i32 or i64");

        NODE_VALIDATION_CHECK(
            this,
            get_input_element_type(INDICES).compatible(get_input_element_type(DEFAULT_INDEX)),
            "Default_index element type (",
            get_input_element_type(DEFAULT_INDEX),
            ") must match indices element type (",
            get_input_element_type(INDICES),
            ")");

        NODE_VALIDATION_CHECK(this,
                              get_input_partial_shape(DEFAULT_INDEX).compatible(PartialShape{}),
                              "DEFAULT_INDEX must be a scalar");
    }

    element::Type result_et = get_input_element_type(EMB_TABLE);

    const PartialShape& emb_table_shape = get_input_partial_shape(EMB_TABLE);

    PartialShape result_shape;
    if (emb_table_shape.rank().is_static())
    {
        std::vector<Dimension> result_dims(emb_table_shape.rank().get_length());
        result_dims[0] = Dimension::dynamic();
        for (size_t i = 1; i < emb_table_shape.rank().get_length(); i++)
        {
            result_dims[i] = emb_table_shape[i];
        }

        result_shape = PartialShape(result_dims);
    }
    else
    {
        result_shape = PartialShape::dynamic();
    }

    set_input_is_relevant_to_shape(NUM_SEGMENTS);
    set_output_type(0, result_et, result_shape);
}

shared_ptr<Node>
    op::v3::EmbeddingSegmentsSum::clone_with_new_inputs(const OutputVector& new_args) const
{
    check_new_args_count(this, new_args);
    if (new_args.size() == 4)
    {
        return make_shared<EmbeddingSegmentsSum>(
            new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3));
    }
    else if (new_args.size() == 5)
    {
        return make_shared<EmbeddingSegmentsSum>(
            new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4));
    }
    else if (new_args.size() == 6)
    {
        return make_shared<EmbeddingSegmentsSum>(new_args.at(0),
                                                 new_args.at(1),
                                                 new_args.at(2),
                                                 new_args.at(3),
                                                 new_args.at(4),
                                                 new_args.at(5));
    }
    else
    {
        throw ngraph_error("Incorrect number of arguments");
    }
}
<|endoftext|>


<commit_before>//===-- tsan_string.cc ----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "tsan_test_util.h"
#include "gtest/gtest.h"
#include <string.h>

namespace __tsan {

TEST(ThreadSanitizer, Memcpy) {
  char data0[7] = {1, 2, 3, 4, 5, 6, 7};
  char data[7] = {42, 42, 42, 42, 42, 42, 42};
  MainThread().Memcpy(data+1, data0+1, 5);
  EXPECT_EQ(data[0], 42);
  EXPECT_EQ(data[1], 2);
  EXPECT_EQ(data[2], 3);
  EXPECT_EQ(data[3], 4);
  EXPECT_EQ(data[4], 5);
  EXPECT_EQ(data[5], 6);
  EXPECT_EQ(data[6], 42);
  MainThread().Memset(data+1, 13, 5);
  EXPECT_EQ(data[0], 42);
  EXPECT_EQ(data[1], 13);
  EXPECT_EQ(data[2], 13);
  EXPECT_EQ(data[3], 13);
  EXPECT_EQ(data[4], 13);
  EXPECT_EQ(data[5], 13);
  EXPECT_EQ(data[6], 42);
}

TEST(ThreadSanitizer, MemcpyRace1) {
  char *data = new char[10];
  char *data1 = new char[10];
  char *data2 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data, data1, 10);
  t2.Memcpy(data, data2, 10, true);
}

TEST(ThreadSanitizer, MemcpyRace2) {
  char *data = new char[10];
  char *data1 = new char[10];
  char *data2 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data+5, data1, 1);
  t2.Memcpy(data+3, data2, 4, true);
}

TEST(ThreadSanitizer, MemcpyRace3) {
  char *data = new char[10];
  char *data1 = new char[10];
  char *data2 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data, data1, 10);
  t2.Memcpy(data1, data2, 10, true);
}

TEST(ThreadSanitizer, MemcpyStack) {
  char *data = new char[10];
  char *data1 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data, data1, 10);
  t2.Memcpy(data, data1, 10, true);
}

TEST(ThreadSanitizer, MemsetRace1) {
  char *data = new char[10];
  ScopedThread t1, t2;
  t1.Memset(data, 1, 10);
  t2.Memset(data, 2, 10, true);
}

}  // namespace __tsan
<commit_msg>tsan: exclude flaky test<commit_after>//===-- tsan_string.cc ----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "tsan_test_util.h"
#include "gtest/gtest.h"
#include <string.h>

namespace __tsan {

TEST(ThreadSanitizer, Memcpy) {
  char data0[7] = {1, 2, 3, 4, 5, 6, 7};
  char data[7] = {42, 42, 42, 42, 42, 42, 42};
  MainThread().Memcpy(data+1, data0+1, 5);
  EXPECT_EQ(data[0], 42);
  EXPECT_EQ(data[1], 2);
  EXPECT_EQ(data[2], 3);
  EXPECT_EQ(data[3], 4);
  EXPECT_EQ(data[4], 5);
  EXPECT_EQ(data[5], 6);
  EXPECT_EQ(data[6], 42);
  MainThread().Memset(data+1, 13, 5);
  EXPECT_EQ(data[0], 42);
  EXPECT_EQ(data[1], 13);
  EXPECT_EQ(data[2], 13);
  EXPECT_EQ(data[3], 13);
  EXPECT_EQ(data[4], 13);
  EXPECT_EQ(data[5], 13);
  EXPECT_EQ(data[6], 42);
}

TEST(ThreadSanitizer, MemcpyRace1) {
  char *data = new char[10];
  char *data1 = new char[10];
  char *data2 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data, data1, 10);
  t2.Memcpy(data, data2, 10, true);
}

// The test fails with TSAN_SHADOW_COUNT=2,
// because the old racy access is evicted.
#if defined(TSAN_SHADOW_COUNT) && TSAN_SHADOW_COUNT >= 4
TEST(ThreadSanitizer, MemcpyRace2) {
  char *data = new char[10];
  char *data1 = new char[10];
  char *data2 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data+5, data1, 1);
  t2.Memcpy(data+3, data2, 4, true);
}
#endif

TEST(ThreadSanitizer, MemcpyRace3) {
  char *data = new char[10];
  char *data1 = new char[10];
  char *data2 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data, data1, 10);
  t2.Memcpy(data1, data2, 10, true);
}

TEST(ThreadSanitizer, MemcpyStack) {
  char *data = new char[10];
  char *data1 = new char[10];
  ScopedThread t1, t2;
  t1.Memcpy(data, data1, 10);
  t2.Memcpy(data, data1, 10, true);
}

TEST(ThreadSanitizer, MemsetRace1) {
  char *data = new char[10];
  ScopedThread t1, t2;
  t1.Memset(data, 1, 10);
  t2.Memset(data, 2, 10, true);
}

}  // namespace __tsan
<|endoftext|>