<commit_before>/**
 * This file is part of node-kdtree, a node.js Addon for working with kd-trees.
 * Copyright (C) 2011 Justin Ethier <justinethier@github>
 *
 * Please use github to submit patches and bug reports:
 * https://github.com/justinethier/node-kdtree
 */

#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <kdtree.h>

using namespace v8;
using namespace node;

/**
 * Free memory allocated to the 'data' portion of a node...
 */
void freeNodeData(void *data){
  if (data != NULL) {
    // Release this persistent handle's storage cell
    Persistent<Value> hData = Persistent<Value>::Persistent((Value *)data);
    hData.Dispose();
  }
}

/**
 * The KDTree add-on
 */
class KDTree : public ObjectWrap {
  public:
    static void
    Initialize (v8::Handle<v8::Object> target){
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(String::NewSymbol("KDTree"));

        NODE_SET_PROTOTYPE_METHOD(t, "dimensions", Dimensions);
        NODE_SET_PROTOTYPE_METHOD(t, "insert", Insert);
        NODE_SET_PROTOTYPE_METHOD(t, "nearest", Nearest);
        NODE_SET_PROTOTYPE_METHOD(t, "nearestPoint", NearestPoint);
        NODE_SET_PROTOTYPE_METHOD(t, "nearestValue", NearestValue);
        NODE_SET_PROTOTYPE_METHOD(t, "nearestRange", NearestRange);

        target->Set(String::NewSymbol("KDTree"), t->GetFunction());
    }

    /**
     * Getter for tree's dimensions.
     *
     * @return Dimensions of the tree's points.
     */
    int Dimensions(){
      return dim_;
    }

    /**
     * Insert a set of points into the tree.
     *
     * An optional data argument is present as well;
     * if len == dim_, then the data param will be ignored.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     * @param data  Optional data argument
     *
     * @return true if the point was inserted successfully, false otherwise
     */
    bool Insert(const double *pos, int len, Handle<Value> data){
      if (len != dim_ && len != dim_ + 1){
        ThrowException(Exception::Error(String::New("Insert(): Wrong number of parameters.")));
        // FUTURE: Passed: " + len + " Expected: " + dim_)));
      }

      if (len == dim_)
        return (kd_insert(kd_, pos, NULL) == 0);
      return (kd_insert(kd_, pos, *data) == 0);
    }

    /**
     * Find the point nearest to the given point.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     *
     * @return An array containing the nearest point, or an empty array if no point is found.
     *         If a data element was provided for the nearest point, it will be the last
     *         member of the returned array.
     */
    Handle<Value>
    Nearest(const double *pos, int len){
      HandleScope scope;
      int rpos;
      void *pdata;
      kdres *results = kd_nearest(kd_, pos);
      Local<Array> rv = Array::New(dim_ + 1);

      if (len != dim_){
        ThrowException(Exception::Error(String::New("Nearest(): Wrong number of parameters.")));
        // FUTURE: Passed: " + len + " Expected: " + dim_)));
      }

      if (results != NULL) {
        double *respos = (double *)(malloc(sizeof(double) * dim_));
        pdata = (void *)kd_res_item(results, respos);

        for(rpos = 0; rpos < dim_; rpos++){
          rv->Set(rpos, Number::New(respos[rpos]));
        }

        // Append data element, if present
        if (pdata != NULL) {
          Persistent<Value> hdata = Persistent<Value>::Persistent((Value *)pdata);
          rv->Set(dim_, hdata);
        }

        free(respos);
        kd_res_free(results);
      }
      return scope.Close(rv);
    }

    /**
     * Find the points nearest to the given point, within a given range.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     * @param range Range in which to search for points
     *
     * @return An array containing the nearest points, or an empty array if no point is found.
     *         If a data element was provided for any point, it will be the last
     *         member of that point's returned array.
     */
    Handle<Value>
    NearestRange(const double *pos, int len, double range){
      HandleScope scope;
      int rpos, i = 0;
      void *pdata;
      kdres *results = kd_nearest_range(kd_, pos, range);
      Local<Array> rv = Array::New();

      if (len != dim_){
        ThrowException(Exception::Error(String::New("Nearest(): Wrong number of parameters.")));
        // FUTURE: Passed: " + len + " Expected: " + dim_)));
      }

      while (!kd_res_end( results )){
        Local<Array> rvItem = Array::New(dim_ + 1);
        double *respos = (double *)(malloc(sizeof(double) * dim_));
        pdata = (void *)kd_res_item(results, respos);

        for(rpos = 0; rpos < dim_; rpos++){
          rvItem->Set(rpos, Number::New(respos[rpos]));
        }

        // Append data element, if present
        if (pdata != NULL) {
          Persistent<Value> hdata = Persistent<Value>::Persistent((Value *)pdata);
          rvItem->Set(dim_, hdata);
        }

        rv->Set(i++, rvItem);
        free(respos);

        // Move to next result entry
        kd_res_next( results );
      }

      kd_res_free(results);
      return scope.Close(rv);
    }

  protected:

    static Handle<Value>
    Dimensions (const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
        HandleScope scope;

        return scope.Close(Number::New(kd->Dimensions()));
    }

    /**
     * Wrapper for Insert()
     */
    static Handle<Value>
    Insert(const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
        HandleScope scope;

// TODO: range checking

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      Handle<Value> result = Boolean::New( kd->Insert(pos, args.Length(),
          Persistent<Value>::New(args[ args.Length() - 1])));
      free(pos);
      return scope.Close(result);
    }

    /**
     * Wrapper for Nearest()
     */
    static Handle<Value>
    Nearest(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;

// TODO: range checking

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      Handle<Value> result = kd->Nearest(pos, args.Length());

      free(pos);
      return scope.Close(result);
    }

    /**
     * A shortcut method for Nearest, that returns an array containing only point data.
     * If a value is present, it will NOT be returned in the result array.
     */
    static Handle<Value>
    NearestPoint(const Arguments& args){
      HandleScope scope;
      Handle<Array> nearest = ((KDTree::Nearest(args))).As<Array>();
      int dim = KDTree::Dimensions(args).As<Number>()->Value();

      Local<Array> result = Array::New(dim);
      if (nearest->Length() > 0 &&    // Data present
          nearest->Length() >= dim) { // Points present
         for (int i = 0; i < dim; i++) {
           result->Set(i, nearest->Get(i));
         }
      }

      return scope.Close(result);
    }

    // TODO: Return as a scalar instead of an array
    /**
     * A shortcut method for Nearest, that returns an array containing only the point's value.
     * If a value is not present or no point was found, the returned array will be empty.
     */
    static Handle<Value>
    NearestValue(const Arguments& args){
      HandleScope scope;
      Handle<Array> nearest = ((KDTree::Nearest(args))).As<Array>();
      int dim = KDTree::Dimensions(args).As<Number>()->Value();

      Local<Array> result = Array::New(1);
      if (nearest->Length() > 0 &&       // Data present
          nearest->Length() == (dim + 1)){ // Value present
        result->Set(0, nearest->Get(nearest->Length() - 1));
      }

      return scope.Close(result);
    }

    static Handle<Value>
    NearestRange(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;

// TODO: range checking here

      double *pos = (double *)(malloc(sizeof(double) * args.Length() - 1));
      for (int i = 0; i < args.Length() - 1; i++){
        pos[i] = args[i]->NumberValue();
      }

      Handle<Value> result = kd->NearestRange(pos, args.Length() - 1, args[args.Length() - 1]->NumberValue());

      free(pos);
      return scope.Close(result);
    }

    /**
     * "External" constructor called by the Addon framework
     */
    static Handle<Value>
    New (const Arguments& args){
        HandleScope scope;

        int dimension = 3; // Default
        if (args.Length() > 0){
          dimension = args[0]->Int32Value();
        }

        KDTree *kd = new KDTree(dimension);
        kd->Wrap(args.This());

        return scope.Close(args.This());
    }

    /**
     * Constructor
     *
     * @param dim   Dimensions of each point in the tree
     */
    KDTree (int dim) : ObjectWrap (){
        kd_ = kd_create(dim);
        dim_ = dim;
        kd_data_destructor(kd_, freeNodeData);
    }

    /**
     * Destructor
     */
    ~KDTree(){
        if (kd_ != NULL){
            kd_free(kd_);
        }
    }

  private:
    /**
     * Pointer to the tree itself
     */
    kdtree* kd_;

    /**
     * Dimension of each point in the tree
     */
    int dim_;
};

/**
 * Entry point required by node.js framework
 */
extern "C" void
init (Handle<Object> target)
{
    HandleScope scope;
    KDTree::Initialize(target);
}

<commit_msg>Fixed crashes when no parameters are passed to nearestRange()<commit_after>/**
 * This file is part of node-kdtree, a node.js Addon for working with kd-trees.
 * Copyright (C) 2011 Justin Ethier <justinethier@github>
 *
 * Please use github to submit patches and bug reports:
 * https://github.com/justinethier/node-kdtree
 */

#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <kdtree.h>

using namespace v8;
using namespace node;

/**
 * Free memory allocated to the 'data' portion of a node...
 */
void freeNodeData(void *data){
  if (data != NULL) {
    // Release this persistent handle's storage cell
    Persistent<Value> hData = Persistent<Value>::Persistent((Value *)data);
    hData.Dispose();
  }
}

/**
 * The KDTree add-on
 */
class KDTree : public ObjectWrap {
  public:
    static void
    Initialize (v8::Handle<v8::Object> target){
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(String::NewSymbol("KDTree"));

        NODE_SET_PROTOTYPE_METHOD(t, "dimensions", Dimensions);
        NODE_SET_PROTOTYPE_METHOD(t, "insert", Insert);
        NODE_SET_PROTOTYPE_METHOD(t, "nearest", Nearest);
        NODE_SET_PROTOTYPE_METHOD(t, "nearestPoint", NearestPoint);
        NODE_SET_PROTOTYPE_METHOD(t, "nearestValue", NearestValue);
        NODE_SET_PROTOTYPE_METHOD(t, "nearestRange", NearestRange);

        target->Set(String::NewSymbol("KDTree"), t->GetFunction());
    }

    /**
     * Getter for tree's dimensions.
     *
     * @return Dimensions of the tree's points.
     */
    int Dimensions(){
      return dim_;
    }

    /**
     * Insert a set of points into the tree.
     *
     * An optional data argument is present as well;
     * if len == dim_, then the data param will be ignored.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     * @param data  Optional data argument
     *
     * @return true if the point was inserted successfully, false otherwise
     */
    bool Insert(const double *pos, int len, Handle<Value> data){
      if (len != dim_ && len != dim_ + 1){
        ThrowException(Exception::Error(String::New("Insert(): Wrong number of parameters.")));
        // FUTURE: Passed: " + len + " Expected: " + dim_)));
      }

      if (len == dim_)
        return (kd_insert(kd_, pos, NULL) == 0);
      return (kd_insert(kd_, pos, *data) == 0);
    }

    /**
     * Find the point nearest to the given point.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     *
     * @return An array containing the nearest point, or an empty array if no point is found.
     *         If a data element was provided for the nearest point, it will be the last
     *         member of the returned array.
     */
    Handle<Value>
    Nearest(const double *pos, int len){
      HandleScope scope;
      int rpos;
      void *pdata;

      if (len != dim_){
        ThrowException(Exception::Error(String::New("Nearest(): Wrong number of parameters.")));
        // FUTURE: Passed: " + len + " Expected: " + dim_)));
      }

      kdres *results = kd_nearest(kd_, pos);
      Local<Array> rv = Array::New(dim_ + 1);

      if (results != NULL) {
        double *respos = (double *)(malloc(sizeof(double) * dim_));
        pdata = (void *)kd_res_item(results, respos);

        for(rpos = 0; rpos < dim_; rpos++){
          rv->Set(rpos, Number::New(respos[rpos]));
        }

        // Append data element, if present
        if (pdata != NULL) {
          Persistent<Value> hdata = Persistent<Value>::Persistent((Value *)pdata);
          rv->Set(dim_, hdata);
        }

        free(respos);
        kd_res_free(results);
      }
      return scope.Close(rv);
    }

    /**
     * Find the points nearest to the given point, within a given range.
     *
     * @param pos   An array of points
     * @param len   Number of points in the array
     * @param range Range in which to search for points
     *
     * @return An array containing the nearest points, or an empty array if no point is found.
     *         If a data element was provided for any point, it will be the last
     *         member of that point's returned array.
     */
    Handle<Value>
    NearestRange(const double *pos, int len, double range){
      HandleScope scope;
      int rpos, i = 0;
      void *pdata;
      kdres *results = NULL;
      Local<Array> rv = Array::New();

      if (len != dim_){
        ThrowException(Exception::Error(String::New("Nearest(): Wrong number of parameters.")));
        // FUTURE: Passed: " + len + " Expected: " + dim_)));
      }

      results = kd_nearest_range(kd_, pos, range);
      while (!kd_res_end( results )){
        Local<Array> rvItem = Array::New(dim_ + 1);
        double *respos = (double *)(malloc(sizeof(double) * dim_));
        pdata = (void *)kd_res_item(results, respos);

        for(rpos = 0; rpos < dim_; rpos++){
          rvItem->Set(rpos, Number::New(respos[rpos]));
        }

        // Append data element, if present
        if (pdata != NULL) {
          Persistent<Value> hdata = Persistent<Value>::Persistent((Value *)pdata);
          rvItem->Set(dim_, hdata);
        }

        rv->Set(i++, rvItem);
        free(respos);

        // Move to next result entry
        kd_res_next( results );
      }

      kd_res_free(results);
      return scope.Close(rv);
    }

  protected:

    static Handle<Value>
    Dimensions (const Arguments& args){
        KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
        HandleScope scope;

        return scope.Close(Number::New(kd->Dimensions()));
    }

    /**
     * Wrapper for Insert()
     */
    static Handle<Value>
    Insert(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      Handle<Value> result = Boolean::New( kd->Insert(pos, args.Length(),
          Persistent<Value>::New(args[ args.Length() - 1])));
      free(pos);
      return scope.Close(result);
    }

    /**
     * Wrapper for Nearest()
     */
    static Handle<Value>
    Nearest(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;

      double *pos = (double *)(malloc(sizeof(double) * args.Length()));
      for (int i = 0; i < args.Length(); i++){
        pos[i] = args[i]->NumberValue();
      }

      Handle<Value> result = kd->Nearest(pos, args.Length());

      free(pos);
      return scope.Close(result);
    }

    /**
     * A shortcut method for Nearest, that returns an array containing only point data.
     * If a value is present, it will NOT be returned in the result array.
     */
    static Handle<Value>
    NearestPoint(const Arguments& args){
      HandleScope scope;
      Handle<Array> nearest = ((KDTree::Nearest(args))).As<Array>();
      int dim = KDTree::Dimensions(args).As<Number>()->Value();

      Local<Array> result = Array::New(dim);
      if (nearest->Length() > 0 &&    // Data present
          nearest->Length() >= dim) { // Points present
         for (int i = 0; i < dim; i++) {
           result->Set(i, nearest->Get(i));
         }
      }

      return scope.Close(result);
    }

    // TODO: Return as a scalar instead of an array
    /**
     * A shortcut method for Nearest, that returns an array containing only the point's value.
     * If a value is not present or no point was found, the returned array will be empty.
     */
    static Handle<Value>
    NearestValue(const Arguments& args){
      HandleScope scope;
      Handle<Array> nearest = ((KDTree::Nearest(args))).As<Array>();
      int dim = KDTree::Dimensions(args).As<Number>()->Value();

      Local<Array> result = Array::New(1);
      if (nearest->Length() > 0 &&       // Data present
          nearest->Length() == (dim + 1)){ // Value present
        result->Set(0, nearest->Get(nearest->Length() - 1));
      }

      return scope.Close(result);
    }

    static Handle<Value>
    NearestRange(const Arguments& args){
      KDTree *kd = ObjectWrap::Unwrap<KDTree>(args.This());
      HandleScope scope;
      Handle<Value> result;

      if (args.Length() == 0) {
        ThrowException(Exception::Error(String::New("NearestRange(): No parameters were provided.")));
      }
      else {
        double *pos = (double *)(malloc(sizeof(double) * args.Length() - 1));
        for (int i = 0; i < args.Length() - 1; i++){
          pos[i] = args[i]->NumberValue();
        }

        result = kd->NearestRange(pos, args.Length() - 1, args[args.Length() - 1]->NumberValue());
        free(pos);
      }

      return scope.Close(result);
    }

    /**
     * "External" constructor called by the Addon framework
     */
    static Handle<Value>
    New (const Arguments& args){
        HandleScope scope;

        int dimension = 3; // Default
        if (args.Length() > 0){
          dimension = args[0]->Int32Value();
        }

        KDTree *kd = new KDTree(dimension);
        kd->Wrap(args.This());

        return scope.Close(args.This());
    }

    /**
     * Constructor
     *
     * @param dim   Dimensions of each point in the tree
     */
    KDTree (int dim) : ObjectWrap (){
        kd_ = kd_create(dim);
        dim_ = dim;
        kd_data_destructor(kd_, freeNodeData);
    }

    /**
     * Destructor
     */
    ~KDTree(){
        if (kd_ != NULL){
            kd_free(kd_);
        }
    }

  private:
    /**
     * Pointer to the tree itself
     */
    kdtree* kd_;

    /**
     * Dimension of each point in the tree
     */
    int dim_;
};

/**
 * Entry point required by node.js framework
 */
extern "C" void
init (Handle<Object> target)
{
    HandleScope scope;
    KDTree::Initialize(target);
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file object/UVar.cc
 ** \brief Creation of the URBI object UVar.
 */

# include <kernel/userver.hh>
# include <kernel/uvalue-cast.hh>

# include <object/symbols.hh>
# include <object/urbi-exception.hh>
# include <object/uvar.hh>

# include <urbi/object/global.hh>
# include <urbi/object/list.hh>
# include <urbi/object/lobby.hh>

# include <runner/runner.hh>
# include <runner/interpreter.hh>

namespace urbi
{
  namespace object
  {
    static inline void
    show_exception_message(runner::Runner& r, rObject self, const char* m1,
                           const char* m2)
    {
      r.lobby_get()->call(SYMBOL(send),
                          new object::String(
                            m1
                            + libport::format(
                              "%s.%s",
                              self->slot_get(SYMBOL(ownerName))->as<String>()->value_get(),
                              self->slot_get(SYMBOL(initialName))->as<String>()->value_get()
                              )
                            + m2),
                          new object::String("error"));
    }

    static inline void callNotify(runner::Runner& r, rObject self,
                                  libport::Symbol notifyList)
    {
      rList l =
        self->slot_get(notifyList)->slot_get(SYMBOL(values))->as<List>();
      objects_type args;
      args.push_back(self);
      List::value_type& callbacks = l->value_get();
      for (List::value_type::iterator i = callbacks.begin();
           i != callbacks.end(); )
      {
        bool failed = true;
        try
        {
          r.apply(*i, SYMBOL(NOTIFY), args);
          failed = false;
        }
        catch(UrbiException& e)
        {
          show_exception_message(r, self,
                                 "!!! Exception caught while processing notify on ", " :");
          runner::Interpreter& in = dynamic_cast<runner::Interpreter&>(r);
          in.show_exception(e);

        }
        catch(sched::exception& e)
        {
          throw;
        }
        catch(...)
        {
          show_exception_message(r, self,
                                 "!!! Unknown exception called while processing notify on ", "");
        }
        if (failed && self->slot_get(SYMBOL(eraseThrowingCallbacks))->as_bool())
        {
          // 'value' is just a cache, not the actual storage location.
          self->slot_get(notifyList)->call(SYMBOL(remove), *i);
          i = callbacks.erase(i);
        }
        else
          ++i;
      }
    }

    static rObject
    update_bounce(objects_type args)
    {
      //called with self slotname slotval
      check_arg_count(args.size() - 1, 2);
      libport::intrusive_ptr<UVar> rvar =
        args.front()
        ->slot_get(libport::Symbol(args[1]->as<String>()->value_get())).value()
        .unsafe_cast<UVar>();
      if (!rvar)
        RAISE("UVar updatehook called on non-uvar slot");
      rvar->update_(args[2]);
      return void_class;
    }

    UVar::UVar()
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    UVar::UVar(libport::intrusive_ptr<UVar>)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    void
    UVar::loopCheck()
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      // Prepare a call to System.period.  Keep its computation in the
      // loop, so that we can change it at run time.
      CAPTURE_GLOBAL(System);
      objects_type args;
      args << System;

      // Loop if we have both notifychange and notifyaccess callbacs.
      // Listeners on the changed event counts as notifychange
      if (!looping_
          &&
          (!slot_get(SYMBOL(change))->call(SYMBOL(empty))->as_bool()
           || slot_get(SYMBOL(changed))->call(SYMBOL(hasSubscribers))->as_bool()
           )
          && !slot_get(SYMBOL(access))->call(SYMBOL(empty))->as_bool())
      {
        looping_ = true;
        while (true)
        {
          accessor();
          rObject period = args[0]->call_with_this(SYMBOL(period), args);
          r.yield_until(libport::utime() +
                        libport::utime_t(period->as<Float>()->value_get()
                                         * 1000000.0));
        }
      }
    }

    void
    UVar::checkBypassCopy()
    {
      // If there are blocked reads, call extract to force caching of the
      // temporary value, and unblock them.
      if (waiterCount_)
      {
        rUValue val = slot_get(slot_get(SYMBOL(owned))->as_bool()
                               ? SYMBOL(valsensor)
                               : SYMBOL(val))
                      ->as<UValue>();
        if (val)
          val->extract();
        slot_get(SYMBOL(waiterTag))->call(SYMBOL(stop));
      }
    }

    rObject
    UVar::update_(rObject val)
    {
      // Do not bother with object::UValue for numeric types.
      if (rUValue uval = val->as<object::UValue>())
       if (uval->value_get().type == urbi::DATA_DOUBLE)
         val = uval->extract();
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(val), val);
      if (slot_get(SYMBOL(owned))->as_bool())
        callNotify(r, rObject(this), SYMBOL(changeOwned));
      else
      {
        checkBypassCopy();
        std::set<void*>::iterator i = inChange_.find(&r);
        if (i == inChange_.end())
        {
          // callNotify does not throw, this is safe.
          i = inChange_.insert(&r).first;
          callNotify(r, rObject(this), SYMBOL(change));
          inChange_.erase(i);
        }
        slot_get(SYMBOL(changed))->call("emit");
      }
      return val;
    }

    rObject
    UVar::accessor()
    {
      return getter(false);
    }

    rObject
    UVar::getter(bool fromCXX)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();

      if (this == proto.get())
        return this;
      if (!inAccess_)
      {
        inAccess_ = true;
        callNotify(r, rObject(this), SYMBOL(access));
        inAccess_ = false;
      }
      rObject res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                             ? SYMBOL(valsensor)
                             : SYMBOL(val));
      if (!fromCXX)
      {
        if (object::rUValue bv = res->as<object::UValue>())
        {
          if (bv->bypassMode_ && bv->extract() == nil_class)
          {
            // This is a read on a bypass-mode UVar, from outside any
            // notifychange: the value is not available.
            // So we mark that we wait by inc-ing waiterCount, and wait
            // on waiterTag until we timeout, or someone writes to the UVar
            // and unlock us.

            // free the shared ptrs
            res.reset();
            bv.reset();
            ++waiterCount_;
            slot_get(SYMBOL(waiterTag))->call(SYMBOL(waitUntilStopped),
                                              new Float(0.5));
            --waiterCount_;
            // The val slot likely changed, fetch it again.
            res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                           ? SYMBOL(valsensor)
                           : SYMBOL(val));
            if (object::rUValue bv = res->as<object::UValue>())
              return bv->extract();
            else
              return res;
          }
          return bv->extract();
        }
      }
      return res;
    }

    rObject
    UVar::writeOwned(rObject newval)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(valsensor), newval);
      checkBypassCopy();
      callNotify(r, rObject(this), SYMBOL(change));
      slot_get(SYMBOL(changed))->call("emit");
      return newval;
    }

    void
    UVar::initialize(CxxObject::Binder<UVar>& bind)
    {
      bind(SYMBOL(writeOwned), &UVar::writeOwned);
      bind(SYMBOL(update_), &UVar::update_);
      bind(SYMBOL(loopCheck), &UVar::loopCheck);
      bind(SYMBOL(accessor), &UVar::accessor);
      proto->slot_set(SYMBOL(update_bounce), new Primitive(&update_bounce));
    }

    URBI_CXX_OBJECT_REGISTER(UVar)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
    {}

    UValue::UValue()
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(libport::intrusive_ptr<UValue>)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(const urbi::UValue& v, bool bypass)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
      put(v, bypass);
    }

    UValue::~UValue()
    {}

    rObject
    UValue::extract()
    {
      if (cache_)
        return cache_;
      if (value_.type == urbi::DATA_VOID)
        return nil_class;
      if (!cache_)
        cache_ = object_cast(value_);
      return cache_;
    }

    std::string
    UValue::extractAsToplevelPrintable()
    {
      if (value_.type == urbi::DATA_VOID && cache_)
      { // Someone used put, cache_ is more recent
        return cache_->call("asToplevelPrintable")->as<String>()->value_get();
      }
      std::stringstream s;
      value_.print(s);
      return s.str();
    }

    const urbi::UValue&
    UValue::value_get()
    {
      static urbi::UValue dummy;
      if (value_.type != urbi::DATA_VOID)
        return value_;
      if (!cache_ || cache_ == nil_class)
        return dummy;
      value_ = ::uvalue_cast(cache_);
      alocated_ = true;
      return value_;
    }

    void
    UValue::invalidate()
    {
      if (!alocated_)
        value_ = urbi::UValue();
    }

    void
    UValue::put(const urbi::UValue& v,  bool bypass)
    {
      bypassMode_ = bypass;
      alocated_ = !bypass;
      value_.set(v, !bypass);
      cache_ = 0;
    }

    void
    UValue::put(rObject r)
    {
      value_ = urbi::UValue();
      cache_ = r;
    }

    void
    UValue::initialize(CxxObject::Binder<UValue>& bind)
    {
      bind(SYMBOL(extract), &UValue::extract);
      bind(SYMBOL(extractAsToplevelPrintable),
           &UValue::extractAsToplevelPrintable);
      bind(SYMBOL(invalidate), &UValue::invalidate);
      bind(SYMBOL(put), (void (UValue::*)(rObject))&UValue::put);
    }

    URBI_CXX_OBJECT_REGISTER(UValue)
    {}
  }
}
<commit_msg>Fix UBinary printing.<commit_after>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file object/UVar.cc
 ** \brief Creation of the URBI object UVar.
 */

# include <kernel/userver.hh>
# include <kernel/uvalue-cast.hh>

# include <object/symbols.hh>
# include <object/urbi-exception.hh>
# include <object/uvar.hh>

# include <urbi/object/global.hh>
# include <urbi/object/list.hh>
# include <urbi/object/lobby.hh>

# include <runner/runner.hh>
# include <runner/interpreter.hh>

namespace urbi
{
  namespace object
  {
    static inline void
    show_exception_message(runner::Runner& r, rObject self, const char* m1,
                           const char* m2)
    {
      r.lobby_get()->call(SYMBOL(send),
                          new object::String(
                            m1
                            + libport::format(
                              "%s.%s",
                              self->slot_get(SYMBOL(ownerName))->as<String>()->value_get(),
                              self->slot_get(SYMBOL(initialName))->as<String>()->value_get()
                              )
                            + m2),
                          new object::String("error"));
    }

    static inline void callNotify(runner::Runner& r, rObject self,
                                  libport::Symbol notifyList)
    {
      rList l =
        self->slot_get(notifyList)->slot_get(SYMBOL(values))->as<List>();
      objects_type args;
      args.push_back(self);
      List::value_type& callbacks = l->value_get();
      for (List::value_type::iterator i = callbacks.begin();
           i != callbacks.end(); )
      {
        bool failed = true;
        try
        {
          r.apply(*i, SYMBOL(NOTIFY), args);
          failed = false;
        }
        catch(UrbiException& e)
        {
          show_exception_message(r, self,
                                 "!!! Exception caught while processing notify on ", " :");
          runner::Interpreter& in = dynamic_cast<runner::Interpreter&>(r);
          in.show_exception(e);

        }
        catch(sched::exception& e)
        {
          throw;
        }
        catch(...)
        {
          show_exception_message(r, self,
                                 "!!! Unknown exception called while processing notify on ", "");
        }
        if (failed && self->slot_get(SYMBOL(eraseThrowingCallbacks))->as_bool())
        {
          // 'value' is just a cache, not the actual storage location.
          self->slot_get(notifyList)->call(SYMBOL(remove), *i);
          i = callbacks.erase(i);
        }
        else
          ++i;
      }
    }

    static rObject
    update_bounce(objects_type args)
    {
      //called with self slotname slotval
      check_arg_count(args.size() - 1, 2);
      libport::intrusive_ptr<UVar> rvar =
        args.front()
        ->slot_get(libport::Symbol(args[1]->as<String>()->value_get())).value()
        .unsafe_cast<UVar>();
      if (!rvar)
        RAISE("UVar updatehook called on non-uvar slot");
      rvar->update_(args[2]);
      return void_class;
    }

    UVar::UVar()
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    UVar::UVar(libport::intrusive_ptr<UVar>)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    void
    UVar::loopCheck()
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      // Prepare a call to System.period.  Keep its computation in the
      // loop, so that we can change it at run time.
      CAPTURE_GLOBAL(System);
      objects_type args;
      args << System;

      // Loop if we have both notifychange and notifyaccess callbacs.
      // Listeners on the changed event counts as notifychange
      if (!looping_
          &&
          (!slot_get(SYMBOL(change))->call(SYMBOL(empty))->as_bool()
           || slot_get(SYMBOL(changed))->call(SYMBOL(hasSubscribers))->as_bool()
           )
          && !slot_get(SYMBOL(access))->call(SYMBOL(empty))->as_bool())
      {
        looping_ = true;
        while (true)
        {
          accessor();
          rObject period = args[0]->call_with_this(SYMBOL(period), args);
          r.yield_until(libport::utime() +
                        libport::utime_t(period->as<Float>()->value_get()
                                         * 1000000.0));
        }
      }
    }

    void
    UVar::checkBypassCopy()
    {
      // If there are blocked reads, call extract to force caching of the
      // temporary value, and unblock them.
      if (waiterCount_)
      {
        rUValue val = slot_get(slot_get(SYMBOL(owned))->as_bool()
                               ? SYMBOL(valsensor)
                               : SYMBOL(val))
                      ->as<UValue>();
        if (val)
          val->extract();
        slot_get(SYMBOL(waiterTag))->call(SYMBOL(stop));
      }
    }

    rObject
    UVar::update_(rObject val)
    {
      // Do not bother with object::UValue for numeric types.
      if (rUValue uval = val->as<object::UValue>())
       if (uval->value_get().type == urbi::DATA_DOUBLE)
         val = uval->extract();
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(val), val);
      if (slot_get(SYMBOL(owned))->as_bool())
        callNotify(r, rObject(this), SYMBOL(changeOwned));
      else
      {
        checkBypassCopy();
        std::set<void*>::iterator i = inChange_.find(&r);
        if (i == inChange_.end())
        {
          // callNotify does not throw, this is safe.
          i = inChange_.insert(&r).first;
          callNotify(r, rObject(this), SYMBOL(change));
          inChange_.erase(i);
        }
        slot_get(SYMBOL(changed))->call("emit");
      }
      return val;
    }

    rObject
    UVar::accessor()
    {
      return getter(false);
    }

    rObject
    UVar::getter(bool fromCXX)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();

      if (this == proto.get())
        return this;
      if (!inAccess_)
      {
        inAccess_ = true;
        callNotify(r, rObject(this), SYMBOL(access));
        inAccess_ = false;
      }
      rObject res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                             ? SYMBOL(valsensor)
                             : SYMBOL(val));
      if (!fromCXX)
      {
        if (object::rUValue bv = res->as<object::UValue>())
        {
          if (bv->bypassMode_ && bv->extract() == nil_class)
          {
            // This is a read on a bypass-mode UVar, from outside any
            // notifychange: the value is not available.
            // So we mark that we wait by inc-ing waiterCount, and wait
            // on waiterTag until we timeout, or someone writes to the UVar
            // and unlock us.

            // free the shared ptrs
            res.reset();
            bv.reset();
            ++waiterCount_;
            slot_get(SYMBOL(waiterTag))->call(SYMBOL(waitUntilStopped),
                                              new Float(0.5));
            --waiterCount_;
            // The val slot likely changed, fetch it again.
            res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                           ? SYMBOL(valsensor)
                           : SYMBOL(val));
            if (object::rUValue bv = res->as<object::UValue>())
              return bv->extract();
            else
              return res;
          }
          return bv->extract();
        }
      }
      return res;
    }

    rObject
    UVar::writeOwned(rObject newval)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(valsensor), newval);
      checkBypassCopy();
      callNotify(r, rObject(this), SYMBOL(change));
      slot_get(SYMBOL(changed))->call("emit");
      return newval;
    }

    void
    UVar::initialize(CxxObject::Binder<UVar>& bind)
    {
      bind(SYMBOL(writeOwned), &UVar::writeOwned);
      bind(SYMBOL(update_), &UVar::update_);
      bind(SYMBOL(loopCheck), &UVar::loopCheck);
      bind(SYMBOL(accessor), &UVar::accessor);
      proto->slot_set(SYMBOL(update_bounce), new Primitive(&update_bounce));
    }

    URBI_CXX_OBJECT_REGISTER(UVar)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
    {}

    UValue::UValue()
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(libport::intrusive_ptr<UValue>)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(const urbi::UValue& v, bool bypass)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
      put(v, bypass);
    }

    UValue::~UValue()
    {}

    rObject
    UValue::extract()
    {
      if (cache_)
        return cache_;
      if (value_.type == urbi::DATA_VOID)
        return nil_class;
      if (!cache_)
        cache_ = object_cast(value_);
      return cache_;
    }

    std::string
    UValue::extractAsToplevelPrintable()
    {
      if (value_.type == urbi::DATA_VOID && cache_)
      { // Someone used put, cache_ is more recent
        return cache_->call("asToplevelPrintable")->as<String>()->value_get();
      }
      std::stringstream s;
      value_.print(s);
      std::string res = s.str();
      if (value_.type == urbi::DATA_BINARY)
      {
        /** Problem:  the Binary was printed with ';' as a separator, and we
        *  need '\n'. The clean thing would be to convert the UBinary to
        * its rObject version and call asPrintable, but it implies an extra
        * copy.
        */
        size_t pos = res.find_first_of(";");
        if (pos != res.npos)
          res[pos] = '\n';
      }
      return res;
    }

    const urbi::UValue&
    UValue::value_get()
    {
      static urbi::UValue dummy;
      if (value_.type != urbi::DATA_VOID)
        return value_;
      if (!cache_ || cache_ == nil_class)
        return dummy;
      value_ = ::uvalue_cast(cache_);
      alocated_ = true;
      return value_;
    }

    void
    UValue::invalidate()
    {
      if (!alocated_)
        value_ = urbi::UValue();
    }

    void
    UValue::put(const urbi::UValue& v,  bool bypass)
    {
      bypassMode_ = bypass;
      alocated_ = !bypass;
      value_.set(v, !bypass);
      cache_ = 0;
    }

    void
    UValue::put(rObject r)
    {
      value_ = urbi::UValue();
      cache_ = r;
    }

    void
    UValue::initialize(CxxObject::Binder<UValue>& bind)
    {
      bind(SYMBOL(extract), &UValue::extract);
      bind(SYMBOL(extractAsToplevelPrintable),
           &UValue::extractAsToplevelPrintable);
      bind(SYMBOL(invalidate), &UValue::invalidate);
      bind(SYMBOL(put), (void (UValue::*)(rObject))&UValue::put);
    }

    URBI_CXX_OBJECT_REGISTER(UValue)
    {}
  }
}
<|endoftext|>


<commit_before>/* Copyright (C) 2016-2018 INRA
 *
 * 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.
 */

#ifndef ORG_VLEPROJECT_BARYONYX_LIB_PRIVATE_RESULT_HPP
#define ORG_VLEPROJECT_BARYONYX_LIB_PRIVATE_RESULT_HPP

#include <baryonyx/core>

#include "itm-common.hpp"

#include <iosfwd>

namespace baryonyx {
namespace detail {

template<typename Mode>
inline bool
store_one_solution(const context_ptr& ctx,
                   result& res,
                   const std::vector<bool>& solution,
                   double value)
{
    if (itm::is_better_solution(value, res.solutions.back().value, Mode())) {
        res.solutions.back() = { solution, value };
        return true;
    }

    return false;
}

template<typename Mode>
inline bool
store_bound_solutions(const context_ptr& ctx,
                      result& res,
                      const std::vector<bool>& solution,
                      double value)
{
    if (res.solutions.size() == static_cast<size_t>(1)) {
        if (itm::is_better_solution(
              value, res.solutions.back().value, Mode())) {
            res.solutions.emplace_back(solution, value);
        } else {
            res.solutions.emplace(res.solutions.begin(), solution, value);
        }
    }

    if (itm::is_better_solution(value, res.solutions.back().value, Mode())) {
        res.solutions.back() = { solution, value };
    } else if (itm::is_better_solution(
                 res.solutions.front().value, value, Mode())) {
        res.solutions.front() = { solution, value };
    }

    return res.solutions.back().value == value;
}

template<typename Mode>
inline bool
store_five_solutions(const context_ptr& ctx,
                     result& res,
                     const std::vector<bool>& solution,
                     double value)
{
    auto it = res.solutions.rbegin();
    auto et = res.solutions.rend();

    if (res.solutions.size() == static_cast<size_t>(5)) {
        for (; it != et; ++it) {

            // If the current element is better, we need to shift all
            // previous solutions, drop the worst and replace the
            // solution.

            if (itm::is_better_solution(value, it->value, Mode())) {
                auto found = it.base();
                auto first = res.solutions.begin() + 1;

                for (; first != found; ++first)
                    std::iter_swap(first - 1, first);

                *found = { solution, value };
            }
        }
    } else {
        for (; it != et; ++it)
            if (itm::is_better_solution(value, it->value, Mode()))
                res.solutions.emplace(it.base(), solution, value);
    }

    return res.solutions.back().value == value;
}

} // namespace detail

template<typename Mode>
bool
store_solution(const context_ptr& ctx,
               result& res,
               const std::vector<bool>& solution,
               double value)
{
    // If the result solutions vector is empty, the solution and value
    // are pushed into the solution vector. All detail functions are
    // sure to have at lest one solution is the result solutions
    // vector.

    if (res.solutions.empty()) {
        res.solutions.emplace_back(solution, value);
        res.remaining_constraints = 0;
        res.status = result_status::success;
        return true;
    } else {
        switch (ctx->parameters.storage) {
        case solver_parameters::storage_type::one:
            return detail::store_one_solution<Mode>(ctx, res, solution, value);
        case solver_parameters::storage_type::bound:
            return detail::store_bound_solutions<Mode>(
              ctx, res, solution, value);
        case solver_parameters::storage_type::five:
            return detail::store_five_solutions<Mode>(
              ctx, res, solution, value);
        }
    }

    return detail::store_one_solution<Mode>(ctx, res, solution, value);
}

inline bool
store_advance(result& res, int constraint_remaining)
{
    if (res.remaining_constraints > constraint_remaining) {
        res.remaining_constraints = constraint_remaining;
        return true;
    }

    return false;
}

std::istream&
operator>>(std::istream& is, result& r);

struct best_solution_writer
{
    const result& res;

    best_solution_writer(const result& res_)
      : res(res_)
    {}
};

std::ostream&
operator<<(std::ostream& os, const best_solution_writer& writer);

} // namespace baryonyx

#endif
<commit_msg>result: fix unused ctx parameter in three functions<commit_after>/* Copyright (C) 2016-2018 INRA
 *
 * 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.
 */

#ifndef ORG_VLEPROJECT_BARYONYX_LIB_PRIVATE_RESULT_HPP
#define ORG_VLEPROJECT_BARYONYX_LIB_PRIVATE_RESULT_HPP

#include <baryonyx/core>

#include "itm-common.hpp"

#include <iosfwd>

namespace baryonyx {
namespace detail {

template<typename Mode>
inline bool
store_one_solution(const context_ptr& /*ctx*/,
                   result& res,
                   const std::vector<bool>& solution,
                   double value)
{
    if (itm::is_better_solution(value, res.solutions.back().value, Mode())) {
        res.solutions.back() = { solution, value };
        return true;
    }

    return false;
}

template<typename Mode>
inline bool
store_bound_solutions(const context_ptr& /*ctx*/,
                      result& res,
                      const std::vector<bool>& solution,
                      double value)
{
    if (res.solutions.size() == static_cast<size_t>(1)) {
        if (itm::is_better_solution(
              value, res.solutions.back().value, Mode())) {
            res.solutions.emplace_back(solution, value);
        } else {
            res.solutions.emplace(res.solutions.begin(), solution, value);
        }
    }

    if (itm::is_better_solution(value, res.solutions.back().value, Mode())) {
        res.solutions.back() = { solution, value };
    } else if (itm::is_better_solution(
                 res.solutions.front().value, value, Mode())) {
        res.solutions.front() = { solution, value };
    }

    return res.solutions.back().value == value;
}

template<typename Mode>
inline bool
store_five_solutions(const context_ptr& /*ctx*/,
                     result& res,
                     const std::vector<bool>& solution,
                     double value)
{
    auto it = res.solutions.rbegin();
    auto et = res.solutions.rend();

    if (res.solutions.size() == static_cast<size_t>(5)) {
        for (; it != et; ++it) {

            // If the current element is better, we need to shift all
            // previous solutions, drop the worst and replace the
            // solution.

            if (itm::is_better_solution(value, it->value, Mode())) {
                auto found = it.base();
                auto first = res.solutions.begin() + 1;

                for (; first != found; ++first)
                    std::iter_swap(first - 1, first);

                *found = { solution, value };
            }
        }
    } else {
        for (; it != et; ++it)
            if (itm::is_better_solution(value, it->value, Mode()))
                res.solutions.emplace(it.base(), solution, value);
    }

    return res.solutions.back().value == value;
}

} // namespace detail

template<typename Mode>
bool
store_solution(const context_ptr& ctx,
               result& res,
               const std::vector<bool>& solution,
               double value)
{
    // If the result solutions vector is empty, the solution and value
    // are pushed into the solution vector. All detail functions are
    // sure to have at lest one solution is the result solutions
    // vector.

    if (res.solutions.empty()) {
        res.solutions.emplace_back(solution, value);
        res.remaining_constraints = 0;
        res.status = result_status::success;
        return true;
    } else {
        switch (ctx->parameters.storage) {
        case solver_parameters::storage_type::one:
            return detail::store_one_solution<Mode>(ctx, res, solution, value);
        case solver_parameters::storage_type::bound:
            return detail::store_bound_solutions<Mode>(
              ctx, res, solution, value);
        case solver_parameters::storage_type::five:
            return detail::store_five_solutions<Mode>(
              ctx, res, solution, value);
        }
    }

    return detail::store_one_solution<Mode>(ctx, res, solution, value);
}

inline bool
store_advance(result& res, int constraint_remaining)
{
    if (res.remaining_constraints > constraint_remaining) {
        res.remaining_constraints = constraint_remaining;
        return true;
    }

    return false;
}

std::istream&
operator>>(std::istream& is, result& r);

struct best_solution_writer
{
    const result& res;

    best_solution_writer(const result& res_)
      : res(res_)
    {}
};

std::ostream&
operator<<(std::ostream& os, const best_solution_writer& writer);

} // namespace baryonyx

#endif
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * 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 <../driver/tensor_driver.hpp>
#include <miopen/rnn.hpp>
#include <miopen/env.hpp>
#include <miopen/util.hpp>
#include <miopen/float_equal.hpp>
#include <vector>
#include <numeric>

#include <miopengemm/gemm.hpp>

namespace miopen {

MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEBUG_CONV_DIRECT)

struct AutoEnableProfiling
{
    AutoEnableProfiling(Handle& x) : h(x)
    {
        prev_state = h.IsProfilingEnabled();
        h.EnableProfiling();
    }

    ~AutoEnableProfiling()
    {
        h.EnableProfiling(prev_state);
        h.ResetKernelTime();
    }

    private:
    Handle& h;
    bool prev_state;
};

void RNNDescriptor::RNNForwardTraining(Handle& handle,
	const int seqLen,
//	const TensorDescriptor& xDesc,
	ConstData_t x,
//	const TensorDescriptor& hxDesc,
	ConstData_t hx,
//	const TensorDescriptor& cxDesc,
	ConstData_t cx,
//	const TensorDescriptor& wDesc,
	ConstData_t w,
//	const TensorDescriptor& yDesc,
	Data_t y,
//	const TensorDescriptor& hyDesc,
	Data_t hy,
//	const TensorDescriptor& cyDesc,
	Data_t cy,
	Data_t workSpace,
	size_t workSpaceSize,
	Data_t reserveSpace,
	size_t reserveSpaceSize,
	const std::vector<int> &in_n,
	const int in_h,
	const int hy_d,
	const int hy_n,
	const int hy_h,
	const int out_h) const
{/*
	if (x == nullptr || w == nullptr || y == nullptr)
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (xDesc.GetSize() != yDesc.GetSize() || xDesc.GetSize() != wDesc.GetSize())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (xDesc.GetType() != yDesc.GetType() || xDesc.GetType() != wDesc.GetType())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
*/
//	int in_n, in_c, in_h, in_w;
	//		std::tie(in_n, in_c, in_h, in_w) = tie4(xDesc.GetLengths());

//	int out_h, out_w;
	//		std::tie(std::ignore, std::ignore, out_h, out_w) = tie4(yDesc.GetLengths());
/*
	if (workSpace == nullptr ||
		workSpaceSize < ForwardGetWorkSpaceSize(handle, wDesc, xDesc, yDesc) || reserveSpaceSize < ForwardGetReserveSpaceSize(handle, wDesc, xDesc, yDesc))
	{
		MIOPEN_THROW("Workspace is required");
	}
	*/

//	miopenRNNMode_t mode;
//	int seqLength;
//	int layer;
//	int bidir;
//	int bias;

	int batch_n = std::accumulate(in_n.begin(), in_n.end(), 0);

	bool bidirection = (bidir != 0);
	bool biased = (bias != 0);
	int numlayer = layer;
	int bacc, baccbi;
	int bi = bidirection ? 2 : 1;

	int wei_len = (bi * (in_h + hy_h + out_h) + (numlayer - 1) * bi * (bi + 1) * hy_h) * hy_h;
	if (biased)
	{
		wei_len += (bi * 2 + (numlayer - 1) * bi * (bi + 1)) * hy_h + bi * out_h;
	}

	int wei_shift_bias =
		((in_h + hy_h + out_h) * bi + (bi * hy_h + hy_h) * bi * (numlayer - 1)) * hy_h;
	int in_stride = in_h;
	int hy_stride = hy_h * bi;
	int h_stride = hy_h * bi;
	int out_stride = out_h;
	int wei_stride = hy_h * bi;

	if (mode == miopenRNNRELU || mode == miopenRNNTANH)
	{
#if MIOPEN_USE_MIOPENGEMM

		printf("rnn gpu \n");
		cl_command_queue Q = (cl_command_queue)handle.GetStream();

		for (int li = 0; li < numlayer; li++)
		{
			int hid_shift = li * batch_n * hy_h * bi;
			int hx_shift = li * bi * in_n[0] * hy_h;

			// from input
			if (li == 0)
			{
				MIOpenGEMM::gemm0<float>(false,
					false,
					false,
					batch_n,
					hy_h * bi,
					in_h,
					1,
					x,
					0,
					in_stride,
					w,
					0,
					wei_stride,
					1,
					reserveSpace,
					hid_shift,
					hy_stride,
					&Q,
					0,
					nullptr,
					nullptr);
			}
			else
			{
				int wei_shift = bi * (in_h + hy_h) * hy_h + (li - 1) * bi * (bi * hy_h + hy_h) * hy_h;
				int prelayer_shift = (li - 1) * batch_n * hy_h * bi;

				MIOpenGEMM::gemm0<float>(false,
					false,
					false,
					batch_n,
					hy_h * bi,
					hy_h * bi,
					1,
					workSpace,
					prelayer_shift,
					hy_stride,
					w,
					wei_shift,
					wei_stride,
					1,
					reserveSpace,
					hid_shift,
					hy_stride,
					&Q,
					0,
					nullptr,
					nullptr);
			}

			// from hidden state
			bacc = 0;
			baccbi = batch_n;
			for (int ti = 0; ti < seqLen; ti++)
			{
				baccbi -= in_n[seqLen - 1 - ti];

				int wei_shift =
					li == 0 ? (in_h * hy_h * bi)
					: (bi * (in_h + hy_h) * hy_h + (li - 1) * bi * (bi * hy_h + hy_h) * hy_h +
						bi * hy_h * hy_stride);

				if (ti == 0)
				{
					MIOpenGEMM::gemm0<float>(false,
						false,
						false,
						in_n[ti],
						hy_h,
						hy_h,
						1,
						hx,
						hx_shift,
						h_stride,
						w,
						wei_shift,
						wei_stride,
						1,
						reserveSpace,
						hid_shift + bacc * hy_stride,
						hy_stride,
						&Q,
						0,
						nullptr,
						nullptr);

					if (bidirection)
					{
						MIOpenGEMM::gemm0<float>(false,
							false,
							false,
							in_n[seqLen - 1 - ti],
							hy_h,
							hy_h,
							1,
							hx,
							hx_shift + hy_h,
							h_stride,
							w,
							wei_shift + hy_h,
							wei_stride,
							1,
							reserveSpace,
							hid_shift + baccbi * hy_stride + hy_h,
							hy_stride,
							&Q,
							0,
							nullptr,
							nullptr);
					}
				}
				else
				{
					MIOpenGEMM::gemm0<float>(false,
						false,
						false,
						in_n[ti],
						hy_h,
						hy_h,
						1,
						hy,
						hx_shift,
						h_stride,
						w,
						wei_shift,
						wei_stride,
						1,
						reserveSpace,
						hid_shift + bacc * hy_stride,
						hy_stride,
						&Q,
						0,
						nullptr,
						nullptr);

					if (bidirection)
					{
						MIOpenGEMM::gemm0<float>(false,
							false,
							false,
							in_n[seqLen - 1 - ti],
							hy_h,
							hy_h,
							1,
							hy,
							hx_shift + hy_h,
							h_stride,
							w,
							wei_shift + hy_h,
							wei_stride,
							1,
							reserveSpace,
							hid_shift + baccbi * hy_stride + hy_h,
							hy_stride,
							&Q,
							0,
							nullptr,
							nullptr);
					}
				}

				int rsv_sz = batch_n * hy_d * hy_h;
				std::vector<int> rsv_size(3, 1);
				rsv_size.push_back(rsv_sz);

				miopenTensorDescriptor_t rsvTensor;
				miopenCreateTensorDescriptor(&rsvTensor);
				SetTensor4d(rsvTensor, rsv_size);

				miopenActivationDescriptor_t activDesc;
				miopenCreateActivationDescriptor(&activDesc);

				miopenActivationMode_t amode;
				amode = (mode == miopenRNNRELU) ? miopenActivationRELU : miopenActivationLOGISTIC;
				miopenSetActivationDescriptor(activDesc, amode, 1, 0, 1);

				miopenActivationForward(handle,
					activDesc,
					1,
					rsvTensor,
					reserveSpace,
					0,
					rsvTensor,
					workSpace);

				bacc += in_n[ti];
			}

		}

		int prelayer_shift = (numlayer - 1) * batch_n * hy_h * bi;
		int wei_shift = bi * (in_h + hy_h) * hy_h + (numlayer - 1) * bi * (bi * hy_h + hy_h) * hy_h;

		MIOpenGEMM::gemm0<float>(false,
			false,
			true,
			batch_n,
			out_h,
			hy_h * bi,
			1,
			workSpace,
			prelayer_shift,
			hy_stride,
			w,
			wei_shift,
			wei_stride,
			1,
			y,
			0,
			out_stride,
			&Q,
			0,
			nullptr,
			nullptr);

		clFinish(Q);
#else
		MIOPEN_THROW("GEMM is not supported");
#endif
	}
	else if (mode == miopenLSTM)
	{
		printf("lstm gpu \n");
	}
	else if (mode == miopenGRU)
	{
		printf("gru gpu \n");
	}

};

void RNNDescriptor::RNNBackwardData(Handle& handle,
	const int seqLen,
	const TensorDescriptor& yDesc,
	ConstData_t y,
	const TensorDescriptor& dyDesc,
	ConstData_t dy,
	const TensorDescriptor& dhyDesc,
	ConstData_t dhy,
	const TensorDescriptor& dcyDesc,
	ConstData_t dcy,
	const TensorDescriptor& wDesc,
	ConstData_t w,
	const TensorDescriptor& hxDesc,
	ConstData_t hx,
	const TensorDescriptor& cxDesc,
	ConstData_t cx,
	const TensorDescriptor& dxDesc,
	Data_t dx,
	const TensorDescriptor& dhxDesc,
	Data_t dhx,
	const TensorDescriptor& dcxDesc,
	Data_t dcx,
	Data_t workSpace,
	size_t workSpaceSize,
	ConstData_t reserveSpace,
	size_t reserveSpaceSize) const
{
	/*
	if (dx == nullptr || w == nullptr || dy == nullptr)
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (dyDesc.GetSize() != dxDesc.GetSize() || dyDesc.GetSize() != wDesc.GetSize())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (dyDesc.GetType() != dxDesc.GetType() || dyDesc.GetType() != wDesc.GetType())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}

	*/

        int in_n, in_c, in_h, in_w;
	//		std::tie(in_n, in_c, in_h, in_w) = tie4(xDesc.GetLengths());

	int wei_n, wei_h, wei_w;
	//		std::tie(wei_n, std::ignore, wei_h, wei_w) = tie4(wDesc.GetLengths());

	int out_h, out_w;
	//		std::tie(std::ignore, std::ignore, out_h, out_w) = tie4(yDesc.GetLengths());
};

void RNNDescriptor::RNNBackwardWeights(Handle& handle,
	const int seqLen,
	const TensorDescriptor& xDesc,
	ConstData_t x,
	const TensorDescriptor& hxDesc,
	ConstData_t hx,
	const TensorDescriptor& dyDesc,
	ConstData_t dy,
	ConstData_t workSpace,
	size_t workSpaceSize,
	const TensorDescriptor& dwDesc,
	Data_t dw,
	ConstData_t reserveSpace,
	size_t reserveSpaceSize) const
{

        int in_n, in_c, in_h, in_w;
	//		std::tie(in_n, in_c, in_h, in_w) = tie4(xDesc.GetLengths());

	int wei_n, wei_h, wei_w;
	//		std::tie(wei_n, std::ignore, wei_h, wei_w) = tie4(wDesc.GetLengths());

	int out_h, out_w;
	//		std::tie(std::ignore, std::ignore, out_h, out_w) = tie4(yDesc.GetLengths());
};

} // namespace miopen
<commit_msg>activ.....<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * 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 <../driver/tensor_driver.hpp>
#include <miopen/rnn.hpp>
#include <miopen/env.hpp>
#include <miopen/util.hpp>
#include <miopen/float_equal.hpp>
#include <vector>
#include <numeric>

#include <miopengemm/gemm.hpp>

namespace miopen {

MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEBUG_CONV_DIRECT)

struct AutoEnableProfiling
{
    AutoEnableProfiling(Handle& x) : h(x)
    {
        prev_state = h.IsProfilingEnabled();
        h.EnableProfiling();
    }

    ~AutoEnableProfiling()
    {
        h.EnableProfiling(prev_state);
        h.ResetKernelTime();
    }

    private:
    Handle& h;
    bool prev_state;
};

void RNNDescriptor::RNNForwardTraining(Handle& handle,
	const int seqLen,
//	const TensorDescriptor& xDesc,
	ConstData_t x,
//	const TensorDescriptor& hxDesc,
	ConstData_t hx,
//	const TensorDescriptor& cxDesc,
	ConstData_t cx,
//	const TensorDescriptor& wDesc,
	ConstData_t w,
//	const TensorDescriptor& yDesc,
	Data_t y,
//	const TensorDescriptor& hyDesc,
	Data_t hy,
//	const TensorDescriptor& cyDesc,
	Data_t cy,
	Data_t workSpace,
	size_t workSpaceSize,
	Data_t reserveSpace,
	size_t reserveSpaceSize,
	const std::vector<int> &in_n,
	const int in_h,
	const int hy_d,
	const int hy_n,
	const int hy_h,
	const int out_h) const
{/*
	if (x == nullptr || w == nullptr || y == nullptr)
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (xDesc.GetSize() != yDesc.GetSize() || xDesc.GetSize() != wDesc.GetSize())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (xDesc.GetType() != yDesc.GetType() || xDesc.GetType() != wDesc.GetType())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
*/
//	int in_n, in_c, in_h, in_w;
	//		std::tie(in_n, in_c, in_h, in_w) = tie4(xDesc.GetLengths());

//	int out_h, out_w;
	//		std::tie(std::ignore, std::ignore, out_h, out_w) = tie4(yDesc.GetLengths());
/*
	if (workSpace == nullptr ||
		workSpaceSize < ForwardGetWorkSpaceSize(handle, wDesc, xDesc, yDesc) || reserveSpaceSize < ForwardGetReserveSpaceSize(handle, wDesc, xDesc, yDesc))
	{
		MIOPEN_THROW("Workspace is required");
	}
	*/

//	miopenRNNMode_t mode;
//	int seqLength;
//	int layer;
//	int bidir;
//	int bias;

	int batch_n = std::accumulate(in_n.begin(), in_n.end(), 0);

	bool bidirection = (bidir != 0);
	bool biased = (bias != 0);
	int numlayer = layer;
	int bacc, baccbi;
	int bi = bidirection ? 2 : 1;

	int wei_len = (bi * (in_h + hy_h + out_h) + (numlayer - 1) * bi * (bi + 1) * hy_h) * hy_h;
	if (biased)
	{
		wei_len += (bi * 2 + (numlayer - 1) * bi * (bi + 1)) * hy_h + bi * out_h;
	}

	int wei_shift_bias =
		((in_h + hy_h + out_h) * bi + (bi * hy_h + hy_h) * bi * (numlayer - 1)) * hy_h;
	int in_stride = in_h;
	int hy_stride = hy_h * bi;
	int h_stride = hy_h * bi;
	int out_stride = out_h;
	int wei_stride = hy_h * bi;

	if (mode == miopenRNNRELU || mode == miopenRNNTANH)
	{
#if MIOPEN_USE_MIOPENGEMM

		printf("rnn gpu \n");
		cl_command_queue Q = (cl_command_queue)handle.GetStream();

		for (int li = 0; li < numlayer; li++)
		{
			int hid_shift = li * batch_n * hy_h * bi;
			int hx_shift = li * bi * in_n[0] * hy_h;

			// from input
			if (li == 0)
			{
				MIOpenGEMM::gemm0<float>(false,
					false,
					false,
					batch_n,
					hy_h * bi,
					in_h,
					1,
					x,
					0,
					in_stride,
					w,
					0,
					wei_stride,
					1,
					reserveSpace,
					hid_shift,
					hy_stride,
					&Q,
					0,
					nullptr,
					nullptr);
			}
			else
			{
				int wei_shift = bi * (in_h + hy_h) * hy_h + (li - 1) * bi * (bi * hy_h + hy_h) * hy_h;
				int prelayer_shift = (li - 1) * batch_n * hy_h * bi;

				MIOpenGEMM::gemm0<float>(false,
					false,
					false,
					batch_n,
					hy_h * bi,
					hy_h * bi,
					1,
					workSpace,
					prelayer_shift,
					hy_stride,
					w,
					wei_shift,
					wei_stride,
					1,
					reserveSpace,
					hid_shift,
					hy_stride,
					&Q,
					0,
					nullptr,
					nullptr);
			}

			// from hidden state
			bacc = 0;
			baccbi = batch_n;
			for (int ti = 0; ti < seqLen; ti++)
			{
				baccbi -= in_n[seqLen - 1 - ti];

				int wei_shift =
					li == 0 ? (in_h * hy_h * bi)
					: (bi * (in_h + hy_h) * hy_h + (li - 1) * bi * (bi * hy_h + hy_h) * hy_h +
						bi * hy_h * hy_stride);

				if (ti == 0)
				{
					MIOpenGEMM::gemm0<float>(false,
						false,
						false,
						in_n[ti],
						hy_h,
						hy_h,
						1,
						hx,
						hx_shift,
						h_stride,
						w,
						wei_shift,
						wei_stride,
						1,
						reserveSpace,
						hid_shift + bacc * hy_stride,
						hy_stride,
						&Q,
						0,
						nullptr,
						nullptr);

					if (bidirection)
					{
						MIOpenGEMM::gemm0<float>(false,
							false,
							false,
							in_n[seqLen - 1 - ti],
							hy_h,
							hy_h,
							1,
							hx,
							hx_shift + hy_h,
							h_stride,
							w,
							wei_shift + hy_h,
							wei_stride,
							1,
							reserveSpace,
							hid_shift + baccbi * hy_stride + hy_h,
							hy_stride,
							&Q,
							0,
							nullptr,
							nullptr);
					}
				}
				else
				{
					MIOpenGEMM::gemm0<float>(false,
						false,
						false,
						in_n[ti],
						hy_h,
						hy_h,
						1,
						hy,
						hx_shift,
						h_stride,
						w,
						wei_shift,
						wei_stride,
						1,
						reserveSpace,
						hid_shift + bacc * hy_stride,
						hy_stride,
						&Q,
						0,
						nullptr,
						nullptr);

					if (bidirection)
					{
						MIOpenGEMM::gemm0<float>(false,
							false,
							false,
							in_n[seqLen - 1 - ti],
							hy_h,
							hy_h,
							1,
							hy,
							hx_shift + hy_h,
							h_stride,
							w,
							wei_shift + hy_h,
							wei_stride,
							1,
							reserveSpace,
							hid_shift + baccbi * hy_stride + hy_h,
							hy_stride,
							&Q,
							0,
							nullptr,
							nullptr);
					}
				}

				int rsv_sz = batch_n * hy_d * hy_h;
				std::vector<int> rsv_size(3, 1);
				rsv_size.push_back(rsv_sz);

				miopenTensorDescriptor_t rsvTensor;
				miopenCreateTensorDescriptor(&rsvTensor);
				SetTensor4d(rsvTensor, rsv_size);

				miopenActivationDescriptor_t activDesc;
				miopenCreateActivationDescriptor(&activDesc);

				miopenActivationMode_t amode;
				amode = (mode == miopenRNNRELU) ? miopenActivationRELU : miopenActivationLOGISTIC;
				miopenSetActivationDescriptor(activDesc, amode, 1, 0, 1);

				miopenActivationForward(GetHandle(),
					activDesc,
					1,
					rsvTensor,
					reserveSpace,
					0,
					rsvTensor,
					workSpace);

				bacc += in_n[ti];
			}

		}

		int prelayer_shift = (numlayer - 1) * batch_n * hy_h * bi;
		int wei_shift = bi * (in_h + hy_h) * hy_h + (numlayer - 1) * bi * (bi * hy_h + hy_h) * hy_h;

		MIOpenGEMM::gemm0<float>(false,
			false,
			true,
			batch_n,
			out_h,
			hy_h * bi,
			1,
			workSpace,
			prelayer_shift,
			hy_stride,
			w,
			wei_shift,
			wei_stride,
			1,
			y,
			0,
			out_stride,
			&Q,
			0,
			nullptr,
			nullptr);

		clFinish(Q);
#else
		MIOPEN_THROW("GEMM is not supported");
#endif
	}
	else if (mode == miopenLSTM)
	{
		printf("lstm gpu \n");
	}
	else if (mode == miopenGRU)
	{
		printf("gru gpu \n");
	}

};

void RNNDescriptor::RNNBackwardData(Handle& handle,
	const int seqLen,
	const TensorDescriptor& yDesc,
	ConstData_t y,
	const TensorDescriptor& dyDesc,
	ConstData_t dy,
	const TensorDescriptor& dhyDesc,
	ConstData_t dhy,
	const TensorDescriptor& dcyDesc,
	ConstData_t dcy,
	const TensorDescriptor& wDesc,
	ConstData_t w,
	const TensorDescriptor& hxDesc,
	ConstData_t hx,
	const TensorDescriptor& cxDesc,
	ConstData_t cx,
	const TensorDescriptor& dxDesc,
	Data_t dx,
	const TensorDescriptor& dhxDesc,
	Data_t dhx,
	const TensorDescriptor& dcxDesc,
	Data_t dcx,
	Data_t workSpace,
	size_t workSpaceSize,
	ConstData_t reserveSpace,
	size_t reserveSpaceSize) const
{
	/*
	if (dx == nullptr || w == nullptr || dy == nullptr)
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (dyDesc.GetSize() != dxDesc.GetSize() || dyDesc.GetSize() != wDesc.GetSize())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}
	if (dyDesc.GetType() != dxDesc.GetType() || dyDesc.GetType() != wDesc.GetType())
	{
		MIOPEN_THROW(miopenStatusBadParm);
	}

	*/

        int in_n, in_c, in_h, in_w;
	//		std::tie(in_n, in_c, in_h, in_w) = tie4(xDesc.GetLengths());

	int wei_n, wei_h, wei_w;
	//		std::tie(wei_n, std::ignore, wei_h, wei_w) = tie4(wDesc.GetLengths());

	int out_h, out_w;
	//		std::tie(std::ignore, std::ignore, out_h, out_w) = tie4(yDesc.GetLengths());
};

void RNNDescriptor::RNNBackwardWeights(Handle& handle,
	const int seqLen,
	const TensorDescriptor& xDesc,
	ConstData_t x,
	const TensorDescriptor& hxDesc,
	ConstData_t hx,
	const TensorDescriptor& dyDesc,
	ConstData_t dy,
	ConstData_t workSpace,
	size_t workSpaceSize,
	const TensorDescriptor& dwDesc,
	Data_t dw,
	ConstData_t reserveSpace,
	size_t reserveSpaceSize) const
{

        int in_n, in_c, in_h, in_w;
	//		std::tie(in_n, in_c, in_h, in_w) = tie4(xDesc.GetLengths());

	int wei_n, wei_h, wei_w;
	//		std::tie(wei_n, std::ignore, wei_h, wei_w) = tie4(wDesc.GetLengths());

	int out_h, out_w;
	//		std::tie(std::ignore, std::ignore, out_h, out_w) = tie4(yDesc.GetLengths());
};

} // namespace miopen
<|endoftext|>


<commit_before>
#include "ofxCvImage.h"
#include "ofxCvGrayscaleImage.h"
#include "ofxCvColorImage.h"
#include "ofxCvFloatImage.h"

//--------------------------------------------------------------------------------
ofxCvImage::ofxCvImage() {
    width			= 0;
    height			= 0;
    bUseTexture		= true;
	bAllocated		= false;
	pixels			= NULL;
}

//--------------------------------------------------------------------------------
ofxCvImage::~ofxCvImage() {
    clear();
}

//--------------------------------------------------------------------------------
void ofxCvImage::convertToRange(float scaleMin, float scaleMax ){
    float range = (scaleMax - scaleMin);
    float scale = 255/range;
    float offset = - (scaleMin * scale);  // ie, 0.5 - 1 = scale by (255*2), subtract 255, 128-255 = scale by 1/2, subtract 128
    cvConvertScale( cvImage, cvImageTemp, scale, offset );
    swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::clear() {

    // ------------------------------ only delete if the
	// ------------------------------ image is really an image.
	// ------------------------------ ie, w > 0, h > 0

	if (bAllocated == true){
		if (width > 0 && height > 0){
			cvReleaseImage( &cvImage );
			cvReleaseImage( &cvImageTemp );
		}
		delete pixels;
		width = 0;
		height = 0;

		if( bUseTexture ) {
			tex.clear();
		}
	}
}

//--------------------------------------------------------------------------------
void ofxCvImage::setUseTexture( bool bUse ) {
	bUseTexture = bUse;
}

//--------------------------------------------------------------------------------
void ofxCvImage::swapTemp() {
	IplImage*  temp;
	temp = cvImage;
	cvImage	= cvImageTemp;
	cvImageTemp	= temp;
}

// Set Pixel Data - Scalars
//--------------------------------------------------------------------------------
void ofxCvImage::set( int value ) {
	cvSet( cvImage, cvScalar(value) );
}

//--------------------------------------------------------------------------------
void ofxCvImage::operator -= ( float scalar ) {
	cvSubS( cvImage, cvScalar(scalar), cvImageTemp );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::operator += ( float scalar ) {
	cvAddS( cvImage, cvScalar(scalar), cvImageTemp );
	swapTemp();
}

// Image Filter Operations
//--------------------------------------------------------------------------------
void ofxCvImage::dilate() {
	cvDilate( cvImage, cvImageTemp, 0, 1 );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::erode() {
	cvErode( cvImage, cvImageTemp, 0, 1 );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::blur( int value ) {
	cvSmooth( cvImage, cvImageTemp, CV_BLUR , value);
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::blurGaussian( int value ) {
	cvSmooth( cvImage, cvImageTemp, CV_GAUSSIAN ,value );
	swapTemp();
}

// Image Transformation Operations

//--------------------------------------------------------------------------------
void ofxCvImage::mirror( bool bFlipVertically, bool bFlipHorizontally ) {
	int flipMode = 0;

	if( bFlipVertically && !bFlipHorizontally ) flipMode = 0;
	else if( !bFlipVertically && bFlipHorizontally ) flipMode = 1;
	else if( bFlipVertically && bFlipHorizontally ) flipMode = -1;
	else return;

	cvFlip( cvImage, cvImageTemp, flipMode );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::translate( float x, float y ) {
    transform( 0, 0,0, 1,1, x,y );
}

//--------------------------------------------------------------------------------
void ofxCvImage::rotate( float angle, float centerX, float centerY ) {
    transform( angle, centerX, centerY, 1,1, 0,0 );
}

//--------------------------------------------------------------------------------
void ofxCvImage::scale( float scaleX, float scaleY ) {
    transform( 0, 0,0, scaleX,scaleY, 0,0 );
}

//--------------------------------------------------------------------------------
void ofxCvImage::transform( float angle, float centerX, float centerY,
                           float scaleX, float scaleY,
                           float moveX, float moveY )
{
    float sina = sin(angle * DEG_TO_RAD);
    float cosa = cos(angle * DEG_TO_RAD);
    CvMat*  transmat = cvCreateMat( 2,3, CV_32F );
    cvmSet( transmat, 0,0, scaleX*cosa );
    cvmSet( transmat, 0,1, scaleY*sina );
    cvmSet( transmat, 0,2, -centerX*scaleX*cosa - centerY*scaleY*sina + moveX + centerX );
    cvmSet( transmat, 1,0, -1.0*scaleX*sina );
    cvmSet( transmat, 1,1, scaleY*cosa );
    cvmSet( transmat, 1,2, -centerY*scaleY*cosa + centerX*scaleX*sina + moveY + centerY);

    cvWarpAffine( cvImage, cvImageTemp, transmat );
	swapTemp();

    cvReleaseMat( &transmat );
}

//--------------------------------------------------------------------------------
void ofxCvImage::undistort( float radialDistX, float radialDistY,
                           float tangentDistX, float tangentDistY,
                           float focalX, float focalY,
                           float centerX, float centerY ){
    float camIntrinsics[] = { focalX, 0, centerX, 0, focalY, centerY, 0, 0, 1 };
    float distortionCoeffs[] = { radialDistX, radialDistY, tangentDistX, tangentDistY };
    cvUnDistortOnce( cvImage, cvImageTemp, camIntrinsics, distortionCoeffs, 1 );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::remap( IplImage* mapX, IplImage* mapY ) {
    cvRemap( cvImage, cvImageTemp, mapX, mapY );
	swapTemp();
}

/**
*    A  +-------------+  B
*      /               \
*     /                 \
*    /                   \
* D +-------------------- +  C
*/

//--------------------------------------------------------------------------------
void ofxCvImage::warpPerspective( const ofPoint& A, const ofPoint& B,
                                  const ofPoint& C, const ofPoint& D )
{
    // compute matrix for perspectival warping (homography)
    CvPoint2D32f cvsrc[4];
    CvPoint2D32f cvdst[4];
    CvMat* translate = cvCreateMat( 3,3, CV_32FC1 );
    cvSetZero( translate );

    cvdst[0].x = 0;
    cvdst[0].y = 0;
    cvdst[1].x = width;
    cvdst[1].y = 0;
    cvdst[2].x = width;
    cvdst[2].y = height;
    cvdst[3].x = 0;
    cvdst[3].y = height;

    cvsrc[0].x = A.x;
    cvsrc[0].y = A.y;
    cvsrc[1].x = B.x;
    cvsrc[1].y = B.y;
    cvsrc[2].x = C.x;
    cvsrc[2].y = C.y;
    cvsrc[3].x = D.x;
    cvsrc[3].y = D.y;

    cvWarpPerspectiveQMatrix( cvsrc, cvdst, translate );  // calculate homography
    cvWarpPerspective( cvImage, cvImageTemp, translate );
    swapTemp();
    cvReleaseMat( &translate );
}

//--------------------------------------------------------------------------------
void ofxCvImage::warpIntoMe( const ofxCvGrayscaleImage& mom,
                            ofPoint src[4], ofPoint dst[4] )
{
	// compute matrix for perspectival warping (homography)
	CvPoint2D32f cvsrc[4];
	CvPoint2D32f cvdst[4];
	CvMat* translate = cvCreateMat( 3, 3, CV_32FC1 );
	cvSetZero( translate );
	for (int i = 0; i < 4; i++ ) {
		cvsrc[i].x = src[i].x;
		cvsrc[i].y = src[i].y;
		cvdst[i].x = dst[i].x;
		cvdst[i].y = dst[i].y;
	}
	cvWarpPerspectiveQMatrix( cvsrc, cvdst, translate );  // calculate homography
	cvWarpPerspective( mom.getCvImage(), cvImage, translate);
	cvReleaseMat( &translate );
}

// Other Image Operations

//--------------------------------------------------------------------------------
int ofxCvImage::countNonZeroInRegion( int x, int y, int w, int h ) const {
	if (w == 0 || h == 0) return 0;
    int count = 0;
	cvSetImageROI( cvImage, cvRect(x,y,w,h) );
	count = cvCountNonZero( cvImage );
	cvResetImageROI( cvImage );
	return count;
}

<commit_msg>BUGFIX: reallocation error (on windows) because ofxCvImage::clear() did not set bAllocated = false<commit_after>
#include "ofxCvImage.h"
#include "ofxCvGrayscaleImage.h"
#include "ofxCvColorImage.h"
#include "ofxCvFloatImage.h"

//--------------------------------------------------------------------------------
ofxCvImage::ofxCvImage() {
    width			= 0;
    height			= 0;
    bUseTexture		= true;
	bAllocated		= false;
	pixels			= NULL;
}

//--------------------------------------------------------------------------------
ofxCvImage::~ofxCvImage() {
    clear();
}

//--------------------------------------------------------------------------------
void ofxCvImage::convertToRange(float scaleMin, float scaleMax ){
    float range = (scaleMax - scaleMin);
    float scale = 255/range;
    float offset = - (scaleMin * scale);  // ie, 0.5 - 1 = scale by (255*2), subtract 255, 128-255 = scale by 1/2, subtract 128
    cvConvertScale( cvImage, cvImageTemp, scale, offset );
    swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::clear() {

    // ------------------------------ only delete if the
	// ------------------------------ image is really an image.
	// ------------------------------ ie, w > 0, h > 0

	if (bAllocated == true){
		if (width > 0 && height > 0){
			cvReleaseImage( &cvImage );
			cvReleaseImage( &cvImageTemp );
		}
		delete pixels;
		width = 0;
		height = 0;

		if( bUseTexture ) {
			tex.clear();
		}

		bAllocated = false;
	}
}

//--------------------------------------------------------------------------------
void ofxCvImage::setUseTexture( bool bUse ) {
	bUseTexture = bUse;
}

//--------------------------------------------------------------------------------
void ofxCvImage::swapTemp() {
	IplImage*  temp;
	temp = cvImage;
	cvImage	= cvImageTemp;
	cvImageTemp	= temp;
}

// Set Pixel Data - Scalars
//--------------------------------------------------------------------------------
void ofxCvImage::set( int value ) {
	cvSet( cvImage, cvScalar(value) );
}

//--------------------------------------------------------------------------------
void ofxCvImage::operator -= ( float scalar ) {
	cvSubS( cvImage, cvScalar(scalar), cvImageTemp );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::operator += ( float scalar ) {
	cvAddS( cvImage, cvScalar(scalar), cvImageTemp );
	swapTemp();
}

// Image Filter Operations
//--------------------------------------------------------------------------------
void ofxCvImage::dilate() {
	cvDilate( cvImage, cvImageTemp, 0, 1 );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::erode() {
	cvErode( cvImage, cvImageTemp, 0, 1 );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::blur( int value ) {
	cvSmooth( cvImage, cvImageTemp, CV_BLUR , value);
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::blurGaussian( int value ) {
	cvSmooth( cvImage, cvImageTemp, CV_GAUSSIAN ,value );
	swapTemp();
}

// Image Transformation Operations

//--------------------------------------------------------------------------------
void ofxCvImage::mirror( bool bFlipVertically, bool bFlipHorizontally ) {
	int flipMode = 0;

	if( bFlipVertically && !bFlipHorizontally ) flipMode = 0;
	else if( !bFlipVertically && bFlipHorizontally ) flipMode = 1;
	else if( bFlipVertically && bFlipHorizontally ) flipMode = -1;
	else return;

	cvFlip( cvImage, cvImageTemp, flipMode );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::translate( float x, float y ) {
    transform( 0, 0,0, 1,1, x,y );
}

//--------------------------------------------------------------------------------
void ofxCvImage::rotate( float angle, float centerX, float centerY ) {
    transform( angle, centerX, centerY, 1,1, 0,0 );
}

//--------------------------------------------------------------------------------
void ofxCvImage::scale( float scaleX, float scaleY ) {
    transform( 0, 0,0, scaleX,scaleY, 0,0 );
}

//--------------------------------------------------------------------------------
void ofxCvImage::transform( float angle, float centerX, float centerY,
                           float scaleX, float scaleY,
                           float moveX, float moveY )
{
    float sina = sin(angle * DEG_TO_RAD);
    float cosa = cos(angle * DEG_TO_RAD);
    CvMat*  transmat = cvCreateMat( 2,3, CV_32F );
    cvmSet( transmat, 0,0, scaleX*cosa );
    cvmSet( transmat, 0,1, scaleY*sina );
    cvmSet( transmat, 0,2, -centerX*scaleX*cosa - centerY*scaleY*sina + moveX + centerX );
    cvmSet( transmat, 1,0, -1.0*scaleX*sina );
    cvmSet( transmat, 1,1, scaleY*cosa );
    cvmSet( transmat, 1,2, -centerY*scaleY*cosa + centerX*scaleX*sina + moveY + centerY);

    cvWarpAffine( cvImage, cvImageTemp, transmat );
	swapTemp();

    cvReleaseMat( &transmat );
}

//--------------------------------------------------------------------------------
void ofxCvImage::undistort( float radialDistX, float radialDistY,
                           float tangentDistX, float tangentDistY,
                           float focalX, float focalY,
                           float centerX, float centerY ){
    float camIntrinsics[] = { focalX, 0, centerX, 0, focalY, centerY, 0, 0, 1 };
    float distortionCoeffs[] = { radialDistX, radialDistY, tangentDistX, tangentDistY };
    cvUnDistortOnce( cvImage, cvImageTemp, camIntrinsics, distortionCoeffs, 1 );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvImage::remap( IplImage* mapX, IplImage* mapY ) {
    cvRemap( cvImage, cvImageTemp, mapX, mapY );
	swapTemp();
}

/**
*    A  +-------------+  B
*      /               \
*     /                 \
*    /                   \
* D +-------------------- +  C
*/

//--------------------------------------------------------------------------------
void ofxCvImage::warpPerspective( const ofPoint& A, const ofPoint& B,
                                  const ofPoint& C, const ofPoint& D )
{
    // compute matrix for perspectival warping (homography)
    CvPoint2D32f cvsrc[4];
    CvPoint2D32f cvdst[4];
    CvMat* translate = cvCreateMat( 3,3, CV_32FC1 );
    cvSetZero( translate );

    cvdst[0].x = 0;
    cvdst[0].y = 0;
    cvdst[1].x = width;
    cvdst[1].y = 0;
    cvdst[2].x = width;
    cvdst[2].y = height;
    cvdst[3].x = 0;
    cvdst[3].y = height;

    cvsrc[0].x = A.x;
    cvsrc[0].y = A.y;
    cvsrc[1].x = B.x;
    cvsrc[1].y = B.y;
    cvsrc[2].x = C.x;
    cvsrc[2].y = C.y;
    cvsrc[3].x = D.x;
    cvsrc[3].y = D.y;

    cvWarpPerspectiveQMatrix( cvsrc, cvdst, translate );  // calculate homography
    cvWarpPerspective( cvImage, cvImageTemp, translate );
    swapTemp();
    cvReleaseMat( &translate );
}

//--------------------------------------------------------------------------------
void ofxCvImage::warpIntoMe( const ofxCvGrayscaleImage& mom,
                            ofPoint src[4], ofPoint dst[4] )
{
	// compute matrix for perspectival warping (homography)
	CvPoint2D32f cvsrc[4];
	CvPoint2D32f cvdst[4];
	CvMat* translate = cvCreateMat( 3, 3, CV_32FC1 );
	cvSetZero( translate );
	for (int i = 0; i < 4; i++ ) {
		cvsrc[i].x = src[i].x;
		cvsrc[i].y = src[i].y;
		cvdst[i].x = dst[i].x;
		cvdst[i].y = dst[i].y;
	}
	cvWarpPerspectiveQMatrix( cvsrc, cvdst, translate );  // calculate homography
	cvWarpPerspective( mom.getCvImage(), cvImage, translate);
	cvReleaseMat( &translate );
}

// Other Image Operations

//--------------------------------------------------------------------------------
int ofxCvImage::countNonZeroInRegion( int x, int y, int w, int h ) const {
	if (w == 0 || h == 0) return 0;
    int count = 0;
	cvSetImageROI( cvImage, cvRect(x,y,w,h) );
	count = cvCountNonZero( cvImage );
	cvResetImageROI( cvImage );
	return count;
}

<|endoftext|>