<commit_before>/* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
 *
 * Quadra, an action puzzle game
 * Copyright (C) 1998-2000  Ludus Design
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef UGS_LINUX_X11

#include <X11/keysym.h>
#include "cursor.h"
#include "main.h"
#include "input_x11.h"
#include "video_x11.h"
#include <X11/Xutil.h>

RCSID("$Id$")

static KeyCode xlate[256];

Input_X11::Input_X11() {
  int i;
  Video_X11* videox11;

  videox11 = dynamic_cast<Video_X11*>(video);

  mouse.dx = mouse.dy = mouse.dz = 0;

  mouse.quel = -1;
  for(i = 0; i < 4; i++)
    mouse.button[i] = RELEASED;

  pause = false;

  clear_key();

  /*
   * Here, I'm just about to go mad. Let's map platform-specific X11 keycodes
   * to PC AT scancodes (yes, this means it can only be right for one
   * platform, you all run the same version of X on Linux/x86, right?). ;-)
   */
  for(i = 0; i < 256; i++)
    xlate[i] = 0;

  for(i = 9; i < 92; i++)
    xlate[i] = i - 8;

  for(i = 94; i < 97; i++)
    xlate[i] = i - 8;

  for(i = 97; i < 101; i++)
    xlate[i] = i + 5;

  for(i = 102; i < 108; i++)
    xlate[i] = i + 4;

  xlate[108] = KEY_PADENTER;
  xlate[109] = KEY_RCTRL;
  xlate[110] = 119; /* SCANCODE_BREAK_ALTERNATIVE */
  xlate[111] = KEY_UPARROW;
  xlate[112] = 98; /* SCANCODE_KEYPADDIVIDE */
  xlate[113] = KEY_LEFTARROW;
  xlate[114] = KEY_RIGHTARROW;
  xlate[115] = 219; /* Win left */
  xlate[116] = KEY_DOWNARROW;
  xlate[117] = 221; /* Win popup */

  im = XOpenIM(videox11->display, NULL, NULL, NULL);
  if(im) {
    ic = XCreateIC(im,
		   XNInputStyle, XIMPreeditNothing|XIMStatusNothing,
		   XNClientWindow, videox11->window,
		   XNFocusWindow, videox11->window,
		   NULL);
    if(!ic) {
      msgbox("Warning: unsupported input method\n");
      XCloseIM(im);
      im = NULL;
    }
  } else {
    msgbox("Warning: error opening X input method\n");
    ic = NULL;
  }

  reraw();
}

Input_X11::~Input_X11() {
  if(ic)
    XDestroyIC(ic);

  if(im)
    XCloseIM(im);
}

void Input_X11::clear_key() {
  int i;

  shift_key = 0;
  quel_key = -1;
  key_pending = 0;

  for(i = 0; i < 256; i++)
    keys[i] = 0;
}

void Input_X11::check() {
  Video_X11* videox11;
  int pending;

  if(!video)
    return;

  videox11 = dynamic_cast<Video_X11*>(video);

  for(pending = XPending(videox11->display);
      pending > 0;
      pending--) {
    XEvent event;

    XNextEvent(videox11->display, &event);

    if(!XFilterEvent(&event, None))
      switch(event.type) {
      case KeyPress:
      case KeyRelease:
        process_key(event);
        break;

      case ButtonPress:
      case ButtonRelease:
      case LeaveNotify:
      case MotionNotify:
        process_mouse(event);
        break;

      case FocusIn:
        videox11->focus_in(event.xfocus.window);
        alt_tab = false;
        break;

      case FocusOut:
        videox11->focus_out(event.xfocus.window);
        alt_tab = true;
        break;

      case ClientMessage:
        if((Atom)event.xclient.data.l[0] == videox11->delete_win)
          quit_game(0);
        break;

      case Expose:
        if(videox11)
          videox11->dirty2(event.xexpose.x,
                           event.xexpose.y,
                           event.xexpose.x+event.xexpose.width,
                           event.xexpose.y+event.xexpose.height);
        break;

      default:
        skelton_msgbox("Unknown XEvent (%i)\n", event.type);
        break;
      }
  }
}

void Input_X11::process_key(XEvent event) {
  KeyCode key = xlate[event.xkey.keycode];
  char buf[20];
  KeySym keysym;
  Status status;
  int num;

  switch(event.type) {
  case KeyPress:
    keys[key] |= PRESSED;

    if(event.xkey.state == Mod1Mask && XLookupKeysym(&event.xkey, 0) == XK_Return) {
      video->toggle_fullscreen();
      return;
    }

    if(!key)
      skelton_msgbox("Unknown KeyCode: %i\n", event.xkey.keycode);

    if(israw) {
      switch(key) {
      case KEY_RSHIFT:
      case KEY_LSHIFT:
        shift_key |= SHIFT;
        break;
      case KEY_RALT:
      case KEY_LALT:
        shift_key |= ALT;
        break;
      case KEY_RCTRL:
      case KEY_LCTRL:
        shift_key |= CONTROL;
        break;
      case 101:
      case 119:
        pause = true;
        break;
      default:
        quel_key = key;
      }
    } else {
      if(ic) {
        num = XmbLookupString(ic, &event.xkey, buf, 20, &keysym, &status);
      } else {
        num = XLookupString(&event.xkey, buf, 20, &keysym, NULL);
      }
      if(num) {
        switch(buf[0]) {
        case 27:
          quel_key = KEY_ESCAPE;
          break;
        case 10:
        case 13:
          quel_key = KEY_ENTER;
          break;
        default:
          if(key_pending < MAXKEY) {
            key_buf[key_pending].c = buf[0];
            key_buf[key_pending].special = false;
            key_pending++;
          }
        }
      }
    }
    break;

  case KeyRelease:
    keys[key] = RELEASED;
    switch(key) {
    case KEY_RSHIFT:
    case KEY_LSHIFT:
      shift_key &= ~SHIFT;
      break;
    case KEY_RALT:
    case KEY_LALT:
      shift_key &= ~ALT;
      break;
    case KEY_RCTRL:
    case KEY_LCTRL:
      shift_key &= ~CONTROL;
      break;
    }
    break;

  default:
    skelton_msgbox("process_key got non-key event\n");
    break;
  }
}

void Input_X11::process_mouse(XEvent event) {
  switch(event.type) {
  case ButtonPress:
    switch(event.xbutton.button) {
    case 1:
      if(mouse.button[0] == RELEASED)
	mouse.quel = 0;
      mouse.button[0] = PRESSED;
      break;
    case 2:
      if(mouse.button[1] == RELEASED)
	mouse.quel = 1;
      mouse.button[1] = PRESSED;
      break;
    case 3:
      if(mouse.button[2] == RELEASED)
	mouse.quel = 2;
      mouse.button[2] = PRESSED;
      break;
    }
    break;

  case ButtonRelease:
    switch(event.xbutton.button) {
    case 1:
      mouse.button[0] = RELEASED;
      break;
    case 2:
      mouse.button[1] = RELEASED;
      break;
    case 3:
      mouse.button[2] = RELEASED;
      break;
    }
    break;

  case LeaveNotify:
    cursor->set_pos(-1, -1);
    break;

  case MotionNotify:
    if(cursor)
      cursor->set_pos(event.xmotion.x, event.xmotion.y);
    break;

  default:
    skelton_msgbox("process_mouse got non-mouse event\n");
    break;
  }
}

void Input_X11::deraw() {
  israw = false;
}

void Input_X11::reraw() {
  israw = true;
}

#endif /* UGS_LINUX_X11 */

<commit_msg>Use mod+keysym for detecting the Pause key (also added a Ctrl-P alternative), instead of the unreliable "translated" keycodes.<commit_after>/* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
 *
 * Quadra, an action puzzle game
 * Copyright (C) 1998-2000  Ludus Design
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef UGS_LINUX_X11

#include <X11/keysym.h>
#include "cursor.h"
#include "main.h"
#include "input_x11.h"
#include "video_x11.h"
#include <X11/Xutil.h>

RCSID("$Id$")

static KeyCode xlate[256];

Input_X11::Input_X11() {
  int i;
  Video_X11* videox11;

  videox11 = dynamic_cast<Video_X11*>(video);

  mouse.dx = mouse.dy = mouse.dz = 0;

  mouse.quel = -1;
  for(i = 0; i < 4; i++)
    mouse.button[i] = RELEASED;

  pause = false;

  clear_key();

  /*
   * Here, I'm just about to go mad. Let's map platform-specific X11 keycodes
   * to PC AT scancodes (yes, this means it can only be right for one
   * platform, you all run the same version of X on Linux/x86, right?). ;-)
   */
  for(i = 0; i < 256; i++)
    xlate[i] = 0;

  for(i = 9; i < 92; i++)
    xlate[i] = i - 8;

  for(i = 94; i < 97; i++)
    xlate[i] = i - 8;

  for(i = 97; i < 101; i++)
    xlate[i] = i + 5;

  for(i = 102; i < 108; i++)
    xlate[i] = i + 4;

  xlate[108] = KEY_PADENTER;
  xlate[109] = KEY_RCTRL;
  xlate[110] = 119; /* SCANCODE_BREAK_ALTERNATIVE */
  xlate[111] = KEY_UPARROW;
  xlate[112] = 98; /* SCANCODE_KEYPADDIVIDE */
  xlate[113] = KEY_LEFTARROW;
  xlate[114] = KEY_RIGHTARROW;
  xlate[115] = 219; /* Win left */
  xlate[116] = KEY_DOWNARROW;
  xlate[117] = 221; /* Win popup */

  im = XOpenIM(videox11->display, NULL, NULL, NULL);
  if(im) {
    ic = XCreateIC(im,
		   XNInputStyle, XIMPreeditNothing|XIMStatusNothing,
		   XNClientWindow, videox11->window,
		   XNFocusWindow, videox11->window,
		   NULL);
    if(!ic) {
      msgbox("Warning: unsupported input method\n");
      XCloseIM(im);
      im = NULL;
    }
  } else {
    msgbox("Warning: error opening X input method\n");
    ic = NULL;
  }

  reraw();
}

Input_X11::~Input_X11() {
  if(ic)
    XDestroyIC(ic);

  if(im)
    XCloseIM(im);
}

void Input_X11::clear_key() {
  int i;

  shift_key = 0;
  quel_key = -1;
  key_pending = 0;

  for(i = 0; i < 256; i++)
    keys[i] = 0;
}

void Input_X11::check() {
  Video_X11* videox11;
  int pending;

  if(!video)
    return;

  videox11 = dynamic_cast<Video_X11*>(video);

  for(pending = XPending(videox11->display);
      pending > 0;
      pending--) {
    XEvent event;

    XNextEvent(videox11->display, &event);

    if(!XFilterEvent(&event, None))
      switch(event.type) {
      case KeyPress:
      case KeyRelease:
        process_key(event);
        break;

      case ButtonPress:
      case ButtonRelease:
      case LeaveNotify:
      case MotionNotify:
        process_mouse(event);
        break;

      case FocusIn:
        videox11->focus_in(event.xfocus.window);
        alt_tab = false;
        break;

      case FocusOut:
        videox11->focus_out(event.xfocus.window);
        alt_tab = true;
        break;

      case ClientMessage:
        if((Atom)event.xclient.data.l[0] == videox11->delete_win)
          quit_game(0);
        break;

      case Expose:
        if(videox11)
          videox11->dirty2(event.xexpose.x,
                           event.xexpose.y,
                           event.xexpose.x+event.xexpose.width,
                           event.xexpose.y+event.xexpose.height);
        break;

      default:
        skelton_msgbox("Unknown XEvent (%i)\n", event.type);
        break;
      }
  }
}

void Input_X11::process_key(XEvent event) {
  KeyCode key = xlate[event.xkey.keycode];
  char buf[20];
  KeySym keysym;
  Status status;
  int num;

  switch(event.type) {
  case KeyPress:
    keys[key] |= PRESSED;
    keysym = XLookupKeysym(&event.xkey, 0);

    if(event.xkey.state == Mod1Mask && keysym == XK_Return) {
      video->toggle_fullscreen();
      return;
    }

    if(!key)
      skelton_msgbox("Unknown KeyCode: %i\n", event.xkey.keycode);

    if(israw) {
      if ((event.xkey.state == 0 && keysym == XK_Pause)
           || (event.xkey.state == ControlMask && keysym == XK_p))
        pause = true;
      else
        switch(key) {
          case KEY_RSHIFT:
          case KEY_LSHIFT:
            shift_key |= SHIFT;
            break;
          case KEY_RALT:
          case KEY_LALT:
            shift_key |= ALT;
            break;
          case KEY_RCTRL:
          case KEY_LCTRL:
            shift_key |= CONTROL;
            break;
          default:
            quel_key = key;
        }
    } else {
      if(ic) {
        num = XmbLookupString(ic, &event.xkey, buf, 20, &keysym, &status);
      } else {
        num = XLookupString(&event.xkey, buf, 20, &keysym, NULL);
      }
      if(num) {
        switch(buf[0]) {
        case 27:
          quel_key = KEY_ESCAPE;
          break;
        case 10:
        case 13:
          quel_key = KEY_ENTER;
          break;
        default:
          if(key_pending < MAXKEY) {
            key_buf[key_pending].c = buf[0];
            key_buf[key_pending].special = false;
            key_pending++;
          }
        }
      }
    }
    break;

  case KeyRelease:
    keys[key] = RELEASED;
    switch(key) {
    case KEY_RSHIFT:
    case KEY_LSHIFT:
      shift_key &= ~SHIFT;
      break;
    case KEY_RALT:
    case KEY_LALT:
      shift_key &= ~ALT;
      break;
    case KEY_RCTRL:
    case KEY_LCTRL:
      shift_key &= ~CONTROL;
      break;
    }
    break;

  default:
    skelton_msgbox("process_key got non-key event\n");
    break;
  }
}

void Input_X11::process_mouse(XEvent event) {
  switch(event.type) {
  case ButtonPress:
    switch(event.xbutton.button) {
    case 1:
      if(mouse.button[0] == RELEASED)
	mouse.quel = 0;
      mouse.button[0] = PRESSED;
      break;
    case 2:
      if(mouse.button[1] == RELEASED)
	mouse.quel = 1;
      mouse.button[1] = PRESSED;
      break;
    case 3:
      if(mouse.button[2] == RELEASED)
	mouse.quel = 2;
      mouse.button[2] = PRESSED;
      break;
    }
    break;

  case ButtonRelease:
    switch(event.xbutton.button) {
    case 1:
      mouse.button[0] = RELEASED;
      break;
    case 2:
      mouse.button[1] = RELEASED;
      break;
    case 3:
      mouse.button[2] = RELEASED;
      break;
    }
    break;

  case LeaveNotify:
    cursor->set_pos(-1, -1);
    break;

  case MotionNotify:
    if(cursor)
      cursor->set_pos(event.xmotion.x, event.xmotion.y);
    break;

  default:
    skelton_msgbox("process_mouse got non-mouse event\n");
    break;
  }
}

void Input_X11::deraw() {
  israw = false;
}

void Input_X11::reraw() {
  israw = true;
}

#endif /* UGS_LINUX_X11 */

<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/io/network/stream.hpp"

#include <algorithm>

#include "caf/logger.hpp"
#include "caf/defaults.hpp"
#include "caf/config_value.hpp"

#include "caf/io/network/default_multiplexer.hpp"

namespace caf {
namespace io {
namespace network {

stream::stream(default_multiplexer& backend_ref, native_socket sockfd)
    : event_handler(backend_ref, sockfd),
      max_consecutive_reads_(
        get_or(backend().system().config(), "middleman.max-consecutive-reads",
               defaults::middleman::max_consecutive_reads)),
      read_threshold_(1),
      collected_(0),
      written_(0) {
  configure_read(receive_policy::at_most(1024));
}

void stream::start(stream_manager* mgr) {
  CAF_ASSERT(mgr != nullptr);
  activate(mgr);
}

void stream::activate(stream_manager* mgr) {
  if (!reader_) {
    reader_.reset(mgr);
    event_handler::activate();
    prepare_next_read();
  }
}

void stream::configure_read(receive_policy::config config) {
  state_.rd_flag = config.first;
  max_ = config.second;
}

void stream::write(const void* buf, size_t num_bytes) {
  CAF_LOG_TRACE(CAF_ARG(num_bytes));
  auto first = reinterpret_cast<const char*>(buf);
  auto last  = first + num_bytes;
  wr_offline_buf_.insert(wr_offline_buf_.end(), first, last);
}

void stream::flush(const manager_ptr& mgr) {
  CAF_ASSERT(mgr != nullptr);
  CAF_LOG_TRACE(CAF_ARG(wr_offline_buf_.size()));
  if (!wr_offline_buf_.empty() && !state_.writing) {
    backend().add(operation::write, fd(), this);
    writer_ = mgr;
    state_.writing = true;
    prepare_next_write();
  }
}

void stream::removed_from_loop(operation op) {
  CAF_LOG_TRACE(CAF_ARG2("fd", fd_) << CAF_ARG(op));
  switch (op) {
    case operation::read:  reader_.reset(); break;
    case operation::write: writer_.reset(); break;
    case operation::propagate_error: ; // nop
  }
}

void stream::graceful_shutdown() {
  CAF_LOG_TRACE(CAF_ARG2("fd", fd_));
  // Ignore repeated calls.
  if (state_.shutting_down)
    return;
  state_.shutting_down = true;
  // Initiate graceful shutdown unless we have still data to send.
  if (!state_.writing)
    send_fin();
  // Otherwise, send_fin() gets called after draining the send buffer.
}

void stream::force_empty_write(const manager_ptr& mgr) {
  if (!state_.writing) {
    backend().add(operation::write, fd(), this);
    writer_ = mgr;
    state_.writing = true;
  }
}

void stream::prepare_next_read() {
  collected_ = 0;
  switch (state_.rd_flag) {
    case receive_policy_flag::exactly:
      if (rd_buf_.size() != max_)
        rd_buf_.resize(max_);
      read_threshold_ = max_;
      break;
    case receive_policy_flag::at_most:
      if (rd_buf_.size() != max_)
        rd_buf_.resize(max_);
      read_threshold_ = 1;
      break;
    case receive_policy_flag::at_least: {
      // read up to 10% more, but at least allow 100 bytes more
      auto max_size = max_ + std::max<size_t>(100, max_ / 10);
      if (rd_buf_.size() != max_size)
        rd_buf_.resize(max_size);
      read_threshold_ = max_;
      break;
    }
  }
}

void stream::prepare_next_write() {
  CAF_LOG_TRACE(CAF_ARG(wr_buf_.size()) << CAF_ARG(wr_offline_buf_.size()));
  written_ = 0;
  wr_buf_.clear();
  if (wr_offline_buf_.empty()) {
    state_.writing = false;
    backend().del(operation::write, fd(), this);
    if (state_.shutting_down)
      send_fin();
  } else {
    wr_buf_.swap(wr_offline_buf_);
  }
}

bool stream::handle_read_result(rw_state read_result, size_t rb) {
  switch (read_result) {
    case rw_state::failure:
      reader_->io_failure(&backend(), operation::read);
      passivate();
      return false;
    case rw_state::indeterminate:
      return false;
    case rw_state::success:
      if (rb == 0)
        return false;
      collected_ += rb;
      if (collected_ >= read_threshold_) {
        auto res = reader_->consume(&backend(), rd_buf_.data(),
                                    collected_);
        prepare_next_read();
        if (!res) {
          passivate();
          return false;
        }
      }
      break;
  }
  return true;
}

void stream::handle_write_result(rw_state write_result, size_t wb) {
  switch (write_result) {
    case rw_state::failure:
      writer_->io_failure(&backend(), operation::write);
      backend().del(operation::write, fd(), this);
      break;
    case rw_state::indeterminate:
      prepare_next_write();
      break;
    case rw_state::success:
      written_ += wb;
      CAF_ASSERT(written_ <= wr_buf_.size());
      auto remaining = wr_buf_.size() - written_;
      if (state_.ack_writes)
        writer_->data_transferred(&backend(), wb,
                                  remaining + wr_offline_buf_.size());
      // prepare next send (or stop sending)
      if (remaining == 0)
        prepare_next_write();
      break;
  }
}

void stream::handle_error_propagation() {
  if (reader_)
    reader_->io_failure(&backend(), operation::read);
  if (writer_)
    writer_->io_failure(&backend(), operation::write);
}

void stream::send_fin() {
  CAF_LOG_TRACE(CAF_ARG2("fd", fd_));
  // Shutting down the write channel will cause TCP to send FIN for the
  // graceful shutdown sequence. The peer then closes its connection as well
  // and we will notice this by getting 0 as return value of recv without error
  // (connection closed).
  shutdown_write(fd_);
}

} // namespace network
} // namespace io
} // namespace caf
<commit_msg>Fix compiler error on GCC <= 4.9<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/io/network/stream.hpp"

#include <algorithm>

#include "caf/logger.hpp"
#include "caf/defaults.hpp"
#include "caf/config_value.hpp"

#include "caf/io/network/default_multiplexer.hpp"

namespace caf {
namespace io {
namespace network {

stream::stream(default_multiplexer& backend_ref, native_socket sockfd)
    : event_handler(backend_ref, sockfd),
      max_consecutive_reads_(
        get_or(backend().system().config(), "middleman.max-consecutive-reads",
               defaults::middleman::max_consecutive_reads)),
      read_threshold_(1),
      collected_(0),
      written_(0) {
  configure_read(receive_policy::at_most(1024));
}

void stream::start(stream_manager* mgr) {
  CAF_ASSERT(mgr != nullptr);
  activate(mgr);
}

void stream::activate(stream_manager* mgr) {
  if (!reader_) {
    reader_.reset(mgr);
    event_handler::activate();
    prepare_next_read();
  }
}

void stream::configure_read(receive_policy::config config) {
  state_.rd_flag = config.first;
  max_ = config.second;
}

void stream::write(const void* buf, size_t num_bytes) {
  CAF_LOG_TRACE(CAF_ARG(num_bytes));
  auto first = reinterpret_cast<const char*>(buf);
  auto last  = first + num_bytes;
  wr_offline_buf_.insert(wr_offline_buf_.end(), first, last);
}

void stream::flush(const manager_ptr& mgr) {
  CAF_ASSERT(mgr != nullptr);
  CAF_LOG_TRACE(CAF_ARG(wr_offline_buf_.size()));
  if (!wr_offline_buf_.empty() && !state_.writing) {
    backend().add(operation::write, fd(), this);
    writer_ = mgr;
    state_.writing = true;
    prepare_next_write();
  }
}

void stream::removed_from_loop(operation op) {
  CAF_LOG_TRACE(CAF_ARG2("fd", fd_) << CAF_ARG(op));
  switch (op) {
    case operation::read:  reader_.reset(); break;
    case operation::write: writer_.reset(); break;
    case operation::propagate_error: ; // nop
  }
}

void stream::graceful_shutdown() {
  CAF_LOG_TRACE(CAF_ARG2("fd", fd_));
  // Ignore repeated calls.
  if (state_.shutting_down)
    return;
  state_.shutting_down = true;
  // Initiate graceful shutdown unless we have still data to send.
  if (!state_.writing)
    send_fin();
  // Otherwise, send_fin() gets called after draining the send buffer.
}

void stream::force_empty_write(const manager_ptr& mgr) {
  if (!state_.writing) {
    backend().add(operation::write, fd(), this);
    writer_ = mgr;
    state_.writing = true;
  }
}

void stream::prepare_next_read() {
  collected_ = 0;
  // This cast does nothing, but prevents a weird compiler error on GCC <= 4.9.
  // TODO: remove cast when dropping support for GCC 4.9.
  switch (static_cast<receive_policy_flag>(state_.rd_flag)) {
    case receive_policy_flag::exactly:
      if (rd_buf_.size() != max_)
        rd_buf_.resize(max_);
      read_threshold_ = max_;
      break;
    case receive_policy_flag::at_most:
      if (rd_buf_.size() != max_)
        rd_buf_.resize(max_);
      read_threshold_ = 1;
      break;
    case receive_policy_flag::at_least: {
      // read up to 10% more, but at least allow 100 bytes more
      auto max_size = max_ + std::max<size_t>(100, max_ / 10);
      if (rd_buf_.size() != max_size)
        rd_buf_.resize(max_size);
      read_threshold_ = max_;
      break;
    }
  }
}

void stream::prepare_next_write() {
  CAF_LOG_TRACE(CAF_ARG(wr_buf_.size()) << CAF_ARG(wr_offline_buf_.size()));
  written_ = 0;
  wr_buf_.clear();
  if (wr_offline_buf_.empty()) {
    state_.writing = false;
    backend().del(operation::write, fd(), this);
    if (state_.shutting_down)
      send_fin();
  } else {
    wr_buf_.swap(wr_offline_buf_);
  }
}

bool stream::handle_read_result(rw_state read_result, size_t rb) {
  switch (read_result) {
    case rw_state::failure:
      reader_->io_failure(&backend(), operation::read);
      passivate();
      return false;
    case rw_state::indeterminate:
      return false;
    case rw_state::success:
      if (rb == 0)
        return false;
      collected_ += rb;
      if (collected_ >= read_threshold_) {
        auto res = reader_->consume(&backend(), rd_buf_.data(),
                                    collected_);
        prepare_next_read();
        if (!res) {
          passivate();
          return false;
        }
      }
      break;
  }
  return true;
}

void stream::handle_write_result(rw_state write_result, size_t wb) {
  switch (write_result) {
    case rw_state::failure:
      writer_->io_failure(&backend(), operation::write);
      backend().del(operation::write, fd(), this);
      break;
    case rw_state::indeterminate:
      prepare_next_write();
      break;
    case rw_state::success:
      written_ += wb;
      CAF_ASSERT(written_ <= wr_buf_.size());
      auto remaining = wr_buf_.size() - written_;
      if (state_.ack_writes)
        writer_->data_transferred(&backend(), wb,
                                  remaining + wr_offline_buf_.size());
      // prepare next send (or stop sending)
      if (remaining == 0)
        prepare_next_write();
      break;
  }
}

void stream::handle_error_propagation() {
  if (reader_)
    reader_->io_failure(&backend(), operation::read);
  if (writer_)
    writer_->io_failure(&backend(), operation::write);
}

void stream::send_fin() {
  CAF_LOG_TRACE(CAF_ARG2("fd", fd_));
  // Shutting down the write channel will cause TCP to send FIN for the
  // graceful shutdown sequence. The peer then closes its connection as well
  // and we will notice this by getting 0 as return value of recv without error
  // (connection closed).
  shutdown_write(fd_);
}

} // namespace network
} // namespace io
} // namespace caf
<|endoftext|>


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

 Program: FEMUS
 Module: NonLinearImplicitSystem
 Authors: Simone Bnà

 Copyright (c) FEMTTU
 All rights reserved.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notice for more information.

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

#include "NonLinearImplicitSystem.hpp"
#include "LinearEquationSolver.hpp"
#include "NumericVector.hpp"
#include "iomanip"

namespace femus {

// ------------------------------------------------------------
// NonLinearImplicitSystem implementation
  NonLinearImplicitSystem::NonLinearImplicitSystem( MultiLevelProblem& ml_probl,
      const std::string& name_in,
      const unsigned int number_in, const MgSmoother& smoother_type ) :
    LinearImplicitSystem( ml_probl, name_in, number_in, smoother_type ),
    _n_max_nonlinear_iterations( 15 ),
    _final_nonlinear_residual( 1.e20 ),
    _max_nonlinear_convergence_tolerance( 1.e-6 ),
    _maxNumberOfResidualUpdateIterations( 1 )
  {

  }

  NonLinearImplicitSystem::~NonLinearImplicitSystem() {
    this->clear();
  }

  void NonLinearImplicitSystem::clear() {
  }

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

  void NonLinearImplicitSystem::init() {
    Parent::init();
  }

  // ************************MG********************

  bool NonLinearImplicitSystem::IsNonLinearConverged( const unsigned igridn, double &nonLinearEps ) {
    bool conv = true;
    double L2normEps, L2normSol, L2normEpsDividedSol;
    std::cout << std::endl;

    nonLinearEps = 0.;
    const double absMinNonlinearEps = 1.e-50;
    const double absMinNormSol = 1.e-15;
    const double mindeltaNormSol = 1.e-50;

    for( unsigned k = 0; k < _SolSystemPdeIndex.size(); k++ ) {
      unsigned indexSol = _SolSystemPdeIndex[k];
      L2normEps    = _solution[igridn]->_Eps[indexSol]->l2_norm();
      L2normSol    = _solution[igridn]->_Sol[indexSol]->l2_norm();
      L2normEpsDividedSol = L2normEps/(L2normSol+mindeltaNormSol);

      std::cout << " ********* Level Max " << igridn + 1 << " Nonlinear Eps_l2norm/Sol_l2norm " << \
        std::scientific << _ml_sol->GetSolutionName( indexSol ) << "= " << L2normEpsDividedSol << \
        "  ** Eps_l2norm= " << L2normEps << "  ** Sol_l2norm= " << L2normSol << std::endl;
      nonLinearEps = ( nonLinearEps > L2normEpsDividedSol ) ? nonLinearEps : L2normEpsDividedSol;

      if( (L2normEpsDividedSol < _max_nonlinear_convergence_tolerance || L2normEps < absMinNonlinearEps || L2normSol < absMinNormSol) && conv == true ) {
        conv = true;
      }
      else {
        conv = false;
      }
    }

    return conv;
  }

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

  void NonLinearImplicitSystem::solve( const MgSmootherType& mgSmootherType ) {

    clock_t start_mg_time = clock();

    unsigned grid0;

    if( _mg_type == F_CYCLE ) {
      std::cout << std::endl << " *** Start Nonlinear " << _solverType << " Full-Cycle ***" << std::endl;
      grid0 = 1;
    }
    else if( _mg_type == V_CYCLE ) {
      std::cout << std::endl << " *** Start Nonlinear  " << _solverType << " V-Cycle ***" << std::endl;
      grid0 = _gridn;
    }
    else if( _mg_type == M_CYCLE ) {
      std::cout << std::endl << " *** Start Nonlinear  " << _solverType << " Mixed-Cycle ***" << std::endl;
      grid0 = _gridr;
    }
    else {
      std::cout << "wrong " << _solverType << " type for this solver " << std::endl;
      abort();
    }

    unsigned AMRCounter = 0;

    for( unsigned igridn = grid0; igridn <= _gridn; igridn++ ) {   //_igridn
      std::cout << std::endl << " ****** Start Level Max " << igridn << " ******" << std::endl;
      clock_t start_nl_time = clock();

      bool ThisIsAMR = ( _mg_type == F_CYCLE && _AMRtest &&  AMRCounter < _maxAMRlevels && igridn == _gridn ) ? 1 : 0;

      if( ThisIsAMR ) _solution[igridn - 1]->InitAMREps();

      for( unsigned nonLinearIterator = 0; nonLinearIterator < _n_max_nonlinear_iterations; nonLinearIterator++ ) {

        std::cout << std::endl << " ********* Nonlinear iteration " << nonLinearIterator + 1 << " *********" << std::endl;

        clock_t start_assembly_time = clock();
        _levelToAssemble = igridn - 1u; //Be carefull!!!! this is needed in the _assemble_function
        _LinSolver[igridn - 1u]->SetResZero();
        _assembleMatrix = _buildSolver;
        _assemble_system_function( _equation_systems );

        if( _buildSolver ){
          _MGmatrixFineReuse = ( 0 == nonLinearIterator ) ? false : true;
          _MGmatrixCoarseReuse = ( igridn - grid0 > 0 ) ?  true : _MGmatrixFineReuse;

          for( unsigned i = igridn - 1u; i > 0; i-- ) {
            if( _RR[i] ) {
              if( i == igridn - 1u )
                _LinSolver[i - 1u]->_KK->matrix_ABC( *_RR[i], *_LinSolver[i]->_KK, *_PP[i], _MGmatrixFineReuse );
              else
                _LinSolver[i - 1u]->_KK->matrix_ABC( *_RR[i], *_LinSolver[i]->_KK, *_PP[i], _MGmatrixCoarseReuse );
            }
            else {
              if( i == igridn - 1u )
                _LinSolver[i - 1u]->_KK->matrix_PtAP( *_PP[i], *_LinSolver[i]->_KK, _MGmatrixFineReuse );
              else
                _LinSolver[i - 1u]->_KK->matrix_PtAP( *_PP[i], *_LinSolver[i]->_KK, _MGmatrixCoarseReuse );
            }
          }
          if( _MGsolver ) {
            _LinSolver[igridn - 1u]->MGInit( mgSmootherType, igridn, _outer_ksp_solver.c_str() );

            for( unsigned i = 0; i < igridn; i++ ) {
              if( _RR[i] )
                _LinSolver[i]->MGSetLevel( _LinSolver[igridn - 1u], i, igridn - 1u, _VariablesToBeSolvedIndex, _PP[i], _RR[i], _npre, _npost );
              else
                _LinSolver[i]->MGSetLevel( _LinSolver[igridn - 1u], i, igridn - 1u, _VariablesToBeSolvedIndex, _PP[i], _PP[i], _npre, _npost );
            }
          }
        }
        std::cout << std::endl << " ********* Level Max " << igridn << " ASSEMBLY TIME:\t" << static_cast<double>( ( clock() - start_assembly_time ) ) / CLOCKS_PER_SEC << std::endl;
        clock_t startUpdateResidualTime = clock();

        for( unsigned updateResidualIterator = 0; updateResidualIterator < _maxNumberOfResidualUpdateIterations; updateResidualIterator++ ) {

          std::cout << std::endl << " ************ Residual Update iteration " << updateResidualIterator + 1 << std::endl;

          bool thisIsConverged;

          if( _MGsolver ) thisIsConverged = MGVcycle( igridn, mgSmootherType );
          else thisIsConverged = MLVcycle( igridn );

          if( thisIsConverged || updateResidualIterator == _maxNumberOfResidualUpdateIterations - 1 ) break;

          _LinSolver[igridn - 1u]->SetResZero();
          _assembleMatrix = false;
          _assemble_system_function( _equation_systems );

        }

        std::cout << "\n ********* Residual Update-Cycle TIME:\t" << std::setw( 11 ) << std::setprecision( 6 ) << std::fixed
                  << static_cast<double>( ( clock() - startUpdateResidualTime ) ) / CLOCKS_PER_SEC << std::endl;

        if( _MGsolver * _buildSolver ) _LinSolver[igridn - 1u]->MGClear();

        double nonLinearEps;
        bool nonLinearIsConverged = IsNonLinearConverged( igridn - 1, nonLinearEps );

        if( nonLinearIsConverged ) break;

      }

      if( ThisIsAMR ) AddAMRLevel( AMRCounter );

      if( igridn < _gridn ) ProlongatorSol( igridn );

      std::cout << std::endl << " ****** Nonlinear-Cycle TIME: " << std::setw( 11 ) << std::setprecision( 6 ) << std::fixed
                << static_cast<double>( ( clock() - start_nl_time ) ) / CLOCKS_PER_SEC << std::endl;

      std::cout << std::endl << " ****** End Level Max " << igridn << " ******" << std::endl;
    }

    std::cout << std::endl << " *** Nonlinear " << _solverType << " TIME: " << std::setw( 11 ) << std::setprecision( 6 ) << std::fixed
              << static_cast<double>( ( clock() - start_mg_time ) ) / CLOCKS_PER_SEC << std::endl;

  }

} //end namespace femus

<commit_msg>added printout<commit_after>/*=========================================================================

 Program: FEMUS
 Module: NonLinearImplicitSystem
 Authors: Simone Bnà

 Copyright (c) FEMTTU
 All rights reserved.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notice for more information.

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

#include "NonLinearImplicitSystem.hpp"
#include "LinearEquationSolver.hpp"
#include "NumericVector.hpp"
#include "iomanip"

namespace femus {

// ------------------------------------------------------------
// NonLinearImplicitSystem implementation
  NonLinearImplicitSystem::NonLinearImplicitSystem( MultiLevelProblem& ml_probl,
      const std::string& name_in,
      const unsigned int number_in, const MgSmoother& smoother_type ) :
    LinearImplicitSystem( ml_probl, name_in, number_in, smoother_type ),
    _n_max_nonlinear_iterations( 15 ),
    _final_nonlinear_residual( 1.e20 ),
    _max_nonlinear_convergence_tolerance( 1.e-6 ),
    _maxNumberOfResidualUpdateIterations( 1 )
  {

  }

  NonLinearImplicitSystem::~NonLinearImplicitSystem() {
    this->clear();
  }

  void NonLinearImplicitSystem::clear() {
  }

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

  void NonLinearImplicitSystem::init() {
    Parent::init();
  }

  // ************************MG********************

  bool NonLinearImplicitSystem::IsNonLinearConverged( const unsigned igridn, double &nonLinearEps ) {
    bool conv = true;
    double L2normEps, L2normSol, L2normEpsDividedSol;
    std::cout << std::endl;

    nonLinearEps = 0.;
    const double absMinNonlinearEps = 1.e-50;
    const double absMinNormSol = 1.e-15;
    const double mindeltaNormSol = 1.e-50;

    for( unsigned k = 0; k < _SolSystemPdeIndex.size(); k++ ) {
      unsigned indexSol = _SolSystemPdeIndex[k];
      L2normEps    = _solution[igridn]->_Eps[indexSol]->l2_norm();
      L2normSol    = _solution[igridn]->_Sol[indexSol]->l2_norm();
      L2normEpsDividedSol = L2normEps/(L2normSol+mindeltaNormSol);

      std::cout << " ********* Level Max " << igridn + 1 << " Nonlinear Eps_l2norm/Sol_l2norm " << \
        std::scientific << _ml_sol->GetSolutionName( indexSol ) << "= " << L2normEpsDividedSol << \
        "  ** Eps_l2norm= " << L2normEps << "  ** Sol_l2norm= " << L2normSol << std::endl;
      nonLinearEps = ( nonLinearEps > L2normEpsDividedSol ) ? nonLinearEps : L2normEpsDividedSol;

      if( (L2normEpsDividedSol < _max_nonlinear_convergence_tolerance || L2normEps < absMinNonlinearEps || L2normSol < absMinNormSol) && conv == true ) {
        conv = true;
      }
      else {
        conv = false;
      }
    }

    return conv;
  }

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

  void NonLinearImplicitSystem::solve( const MgSmootherType& mgSmootherType ) {

    clock_t start_mg_time = clock();

    unsigned grid0;

    if( _mg_type == F_CYCLE ) {
      std::cout << std::endl << " *** Start Nonlinear " << _solverType << " Full-Cycle ***" << std::endl;
      grid0 = 1;
    }
    else if( _mg_type == V_CYCLE ) {
      std::cout << std::endl << " *** Start Nonlinear  " << _solverType << " V-Cycle ***" << std::endl;
      grid0 = _gridn;
    }
    else if( _mg_type == M_CYCLE ) {
      std::cout << std::endl << " *** Start Nonlinear  " << _solverType << " Mixed-Cycle ***" << std::endl;
      grid0 = _gridr;
    }
    else {
      std::cout << "wrong " << _solverType << " type for this solver " << std::endl;
      abort();
    }

    unsigned AMRCounter = 0;

    for( unsigned igridn = grid0; igridn <= _gridn; igridn++ ) {   //_igridn
      std::cout << std::endl << " ****** Start Level Max " << igridn << " ******" << std::endl;
      clock_t start_nl_time = clock();

      bool ThisIsAMR = ( _mg_type == F_CYCLE && _AMRtest &&  AMRCounter < _maxAMRlevels && igridn == _gridn ) ? 1 : 0;

      if( ThisIsAMR ) _solution[igridn - 1]->InitAMREps();

      for( unsigned nonLinearIterator = 0; nonLinearIterator < _n_max_nonlinear_iterations; nonLinearIterator++ ) {

        std::cout << std::endl << " ********* Nonlinear iteration " << nonLinearIterator + 1 << " *********" << std::endl;

        clock_t start_assembly_time = clock();
        _levelToAssemble = igridn - 1u; //Be carefull!!!! this is needed in the _assemble_function
        _LinSolver[igridn - 1u]->SetResZero();
        _assembleMatrix = _buildSolver;
        _assemble_system_function( _equation_systems );

        std::cout << std::endl << " ********* Assembly is finished \n";

        if( _buildSolver ){
          _MGmatrixFineReuse = ( 0 == nonLinearIterator ) ? false : true;
          _MGmatrixCoarseReuse = ( igridn - grid0 > 0 ) ?  true : _MGmatrixFineReuse;

          for( unsigned i = igridn - 1u; i > 0; i-- ) {
            if( _RR[i] ) {
              std::cout << std::endl << " ********* Building sub \n";
              if( i == igridn - 1u )
                _LinSolver[i - 1u]->_KK->matrix_ABC( *_RR[i], *_LinSolver[i]->_KK, *_PP[i], _MGmatrixFineReuse );
              else
                _LinSolver[i - 1u]->_KK->matrix_ABC( *_RR[i], *_LinSolver[i]->_KK, *_PP[i], _MGmatrixCoarseReuse );
            }
            else {
              if( i == igridn - 1u )
                _LinSolver[i - 1u]->_KK->matrix_PtAP( *_PP[i], *_LinSolver[i]->_KK, _MGmatrixFineReuse );
              else
                _LinSolver[i - 1u]->_KK->matrix_PtAP( *_PP[i], *_LinSolver[i]->_KK, _MGmatrixCoarseReuse );
            }
          }
          if( _MGsolver ) {
            std::cout << std::endl << " ********* Building MG \n";
            _LinSolver[igridn - 1u]->MGInit( mgSmootherType, igridn, _outer_ksp_solver.c_str() );

            for( unsigned i = 0; i < igridn; i++ ) {
              if( _RR[i] )
                _LinSolver[i]->MGSetLevel( _LinSolver[igridn - 1u], i, igridn - 1u, _VariablesToBeSolvedIndex, _PP[i], _RR[i], _npre, _npost );
              else
                _LinSolver[i]->MGSetLevel( _LinSolver[igridn - 1u], i, igridn - 1u, _VariablesToBeSolvedIndex, _PP[i], _PP[i], _npre, _npost );
            }
          }
        }
        std::cout << std::endl << " ********* Level Max " << igridn << " ASSEMBLY TIME:\t" << static_cast<double>( ( clock() - start_assembly_time ) ) / CLOCKS_PER_SEC << std::endl;
        clock_t startUpdateResidualTime = clock();

        for( unsigned updateResidualIterator = 0; updateResidualIterator < _maxNumberOfResidualUpdateIterations; updateResidualIterator++ ) {

          std::cout << std::endl << " ************ Residual Update iteration " << updateResidualIterator + 1 << std::endl;

          bool thisIsConverged;

          if( _MGsolver ) thisIsConverged = MGVcycle( igridn, mgSmootherType );
          else thisIsConverged = MLVcycle( igridn );

          if( thisIsConverged || updateResidualIterator == _maxNumberOfResidualUpdateIterations - 1 ) break;

          _LinSolver[igridn - 1u]->SetResZero();
          _assembleMatrix = false;
          _assemble_system_function( _equation_systems );

        }

        std::cout << "\n ********* Residual Update-Cycle TIME:\t" << std::setw( 11 ) << std::setprecision( 6 ) << std::fixed
                  << static_cast<double>( ( clock() - startUpdateResidualTime ) ) / CLOCKS_PER_SEC << std::endl;

        if( _MGsolver * _buildSolver ) _LinSolver[igridn - 1u]->MGClear();

        double nonLinearEps;
        bool nonLinearIsConverged = IsNonLinearConverged( igridn - 1, nonLinearEps );

        if( nonLinearIsConverged ) break;

      }

      if( ThisIsAMR ) AddAMRLevel( AMRCounter );

      if( igridn < _gridn ) ProlongatorSol( igridn );

      std::cout << std::endl << " ****** Nonlinear-Cycle TIME: " << std::setw( 11 ) << std::setprecision( 6 ) << std::fixed
                << static_cast<double>( ( clock() - start_nl_time ) ) / CLOCKS_PER_SEC << std::endl;

      std::cout << std::endl << " ****** End Level Max " << igridn << " ******" << std::endl;
    }

    std::cout << std::endl << " *** Nonlinear " << _solverType << " TIME: " << std::setw( 11 ) << std::setprecision( 6 ) << std::fixed
              << static_cast<double>( ( clock() - start_mg_time ) ) / CLOCKS_PER_SEC << std::endl;

  }

} //end namespace femus

<|endoftext|>


<commit_before>/*  libscratch - Multipurpose objective C++ library.
    Copyright (C) 2012 - 2013  Angelo Geels

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include <cstdio> // for printf
#include <iostream> // for std::cin.get

#include <Scratch.h>

static INDEX _ctFailed = 0;

#define TEST(expr) {                \
  BOOL bSuccess = (expr);           \
  ASSERT(bSuccess);                 \
  printf("  Test: (%s) ", #expr);   \
  if(!bSuccess) {                   \
    _ctFailed++;                    \
    printf("FAILED!\n");            \
  } else {                          \
    printf("OK\n");                 \
  }                                 \
}

/// String testing
void TestString()
{
  printf("Testing strings\n");

  CString strTest;
  strTest += "Lib";
  strTest += "Scratch";
  strTest = strTest.ToLower();
  TEST(strTest == "libscratch");

  strTest += " is great";
  CStackArray<CString> astrParse = strTest.Split(" ");
  TEST(astrParse[2] == "great");
  TEST(astrParse[2][1] == 'r');

  CString strTest2 = strTest.Replace("great", "cool");
  TEST(strTest2 == "libscratch is cool");
}

/// Stack array testing
void TestStackArray()
{
  printf("Testing stack arrays\n");

  CStackArray<INDEX> aiNumbers;
  TEST(aiNumbers.Count() == 0);

  aiNumbers.Push() = 5;
  aiNumbers.Push() = 10;
  aiNumbers.Push() = 15;
  TEST(aiNumbers.Count() == 3);
  TEST(aiNumbers[0] == 5);
  TEST(aiNumbers[1] == 10);
  TEST(aiNumbers[2] + aiNumbers[0] == 20);

  TEST(aiNumbers.Pop() == 15);
  TEST(aiNumbers.Count() == 2);
}

/// Dictionary testing
void TestDictionary()
{
  printf("Testing dictionary\n");

  CDictionary<CString, INDEX> diTest;
  TEST(!diTest.HasKey("Test"));

  diTest["Test"] = 100;
  diTest["Test2"] = 200;
  TEST(diTest.HasKey("Test"));
  TEST(diTest["Test"] == 100);

  diTest.RemoveByKey("Test");
  TEST(diTest.Count() == 1);
  TEST(!diTest.HasKey("Test"));
}

int main()
{
  // perform tests
  TestString();
  TestStackArray();
  TestDictionary();

  // check if all went OK
  if(_ctFailed == 0) {
    // it did! no failures. :)
    printf("\n\nAll OK!\n");
  } else {
    // oops, there's a bug somewhere. please report!
    printf("\n\nSome problems seem to have popped up. Please report a bug.\n");
  }

  std::cin.get();
  return 0;
}
<commit_msg>Updated test results code<commit_after>/*  libscratch - Multipurpose objective C++ library.
    Copyright (C) 2012 - 2013  Angelo Geels

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include <cstdio> // for printf
#include <iostream> // for std::cin.get

#include <Scratch.h>

static INDEX _ctTests = 0;
static INDEX _ctFailed = 0;

#define TEST(expr) {                            \
  BOOL bSuccess = (expr);                       \
  _ctTests++;                                   \
  ASSERT(bSuccess);                             \
  printf("  Test #%d: (%s) ", _ctTests, #expr); \
  if(!bSuccess) {                               \
    _ctFailed++;                                \
    printf("FAILED!\n");                        \
  } else {                                      \
    printf("OK\n");                             \
  }                                             \
}

/// String testing
void TestString()
{
  printf("Testing strings\n");

  CString strTest;
  strTest += "Lib";
  strTest += "Scratch";
  strTest = strTest.ToLower();
  TEST(strTest == "libscratch");

  strTest += " is great";
  CStackArray<CString> astrParse = strTest.Split(" ");
  TEST(astrParse[2] == "great");
  TEST(astrParse[2][1] == 'r');

  CString strTest2 = strTest.Replace("great", "cool");
  TEST(strTest2 == "libscratch is cool");
}

/// Stack array testing
void TestStackArray()
{
  printf("Testing stack arrays\n");

  CStackArray<INDEX> aiNumbers;
  TEST(aiNumbers.Count() == 0);

  aiNumbers.Push() = 5;
  aiNumbers.Push() = 10;
  aiNumbers.Push() = 15;
  TEST(aiNumbers.Count() == 3);
  TEST(aiNumbers[0] == 5);
  TEST(aiNumbers[1] == 10);
  TEST(aiNumbers[2] + aiNumbers[0] == 20);

  TEST(aiNumbers.Pop() == 15);
  TEST(aiNumbers.Count() == 2);
}

/// Dictionary testing
void TestDictionary()
{
  printf("Testing dictionary\n");

  CDictionary<CString, INDEX> diTest;
  TEST(!diTest.HasKey("Test"));

  diTest["Test"] = 100;
  diTest["Test2"] = 200;
  TEST(diTest.HasKey("Test"));
  TEST(diTest["Test"] == 100);

  diTest.RemoveByKey("Test");
  TEST(diTest.Count() == 1);
  TEST(!diTest.HasKey("Test"));
}

int main()
{
  // perform tests
  TestString();
  TestStackArray();
  TestDictionary();

  // report test results
  printf("\n\nResults: %d out of %d went OK.\n\n", _ctTests - _ctFailed, _ctTests);

  // check if all went OK
  if(_ctFailed == 0) {
    // it did! no failures. :)
    printf("All OK!\n");
  } else {
    // oops, there's a bug somewhere. please report!
    printf("Some problems seem to have popped up. Please report a bug.\n");
  }

  std::cin.get();
  return 0;
}
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_tmva
/// \notebook -nodraw
/// This macro provides an example of how to use TMVA for k-folds cross
/// evaluation.
///
/// As input data is used a toy-MC sample consisting of two guassian
/// distributions.
///
/// The output file "TMVA.root" can be analysed with the use of dedicated
/// macros (simply say: root -l <macro.C>), which can be conveniently
/// invoked through a GUI that will appear at the end of the run of this macro.
/// Launch the GUI via the command:
///
/// ```
/// root -l -e 'TMVA::TMVAGui("TMVA.root")'
/// ```
///
/// ## Cross Evaluation
/// Cross evaluation is a special case of k-folds cross validation where the
/// splitting into k folds is computed deterministically. This ensures that the
/// a given event will always end up in the same fold.
///
/// In addition all resulting classifiers are saved and can be applied to new
/// data using `MethodCrossValidation`. One requirement for this to work is a
/// splitting function that is evaluated for each event to determine into what
/// fold it goes (for training/evaluation) or to what classifier (for
/// application).
///
/// ## Split Expression
/// Cross evaluation uses a deterministic split to partition the data into
/// folds called the split expression. The expression can be any valid
/// `TFormula` as long as all parts used are defined.
///
/// For each event the split expression is evaluated to a number and the event
/// is put in the fold corresponding to that number.
///
/// It is recommended to always use `%int([NumFolds])` at the end of the
/// expression.
///
/// The split expression has access to all spectators and variables defined in
/// the dataloader. Additionally, the number of folds in the split can be
/// accessed with `NumFolds` (or `numFolds`).
///
/// ### Example
///  ```
///  "int(fabs([eventID]))%int([NumFolds])"
///  ```
///
/// - Project   : TMVA - a ROOT-integrated toolkit for multivariate data analysis
/// - Package   : TMVA
/// - Root Macro: TMVACrossValidation
///
/// \macro_output
/// \macro_code
/// \author Kim Albertsson (adapted from code originally by Andreas Hoecker)

#include <cstdlib>
#include <iostream>
#include <map>
#include <string>

#include "TChain.h"
#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TObjString.h"
#include "TSystem.h"
#include "TROOT.h"

#include "TMVA/CrossValidation.h"
#include "TMVA/DataLoader.h"
#include "TMVA/Factory.h"
#include "TMVA/Tools.h"
#include "TMVA/TMVAGui.h"

// Helper function to load data into TTrees.
TTree *genTree(Int_t nPoints, Double_t offset, Double_t scale, UInt_t seed = 100)
{
   TRandom3 rng(seed);
   Float_t x = 0;
   Float_t y = 0;
   UInt_t eventID = 0;

   TTree *data = new TTree();
   data->Branch("x", &x, "x/F");
   data->Branch("y", &y, "y/F");
   data->Branch("eventID", &eventID, "eventID/I");

   for (Int_t n = 0; n < nPoints; ++n) {
      x = rng.Gaus(offset, scale);
      y = rng.Gaus(offset, scale);

      // For our simple example it is enough that the id's are uniformly
      // distributed and independent of the data.
      ++eventID;

      data->Fill();
   }

   // Important: Disconnects the tree from the memory locations of x and y.
   data->ResetBranchAddresses();
   return data;
}

int TMVACrossValidation()
{
   // This loads the library
   TMVA::Tools::Instance();

   // --------------------------------------------------------------------------

   // Load the data into TTrees. If you load data from file you can use a
   // variant of
   // ```
   // TString filename = "/path/to/file";
   // TFile * input = TFile::Open( filename );
   // TTree * signalTree = (TTree*)input->Get("TreeName");
   // ```
   TTree *sigTree = genTree(1000, 1.0, 1.0, 100);
   TTree *bkgTree = genTree(1000, -1.0, 1.0, 101);

   // Create a ROOT output file where TMVA will store ntuples, histograms, etc.
   TString outfileName("TMVA.root");
   TFile *outputFile = TFile::Open(outfileName, "RECREATE");

   // DataLoader definitions; We declare variables in the tree so that TMVA can
   // find them. For more information see TMVAClassification tutorial.
   TMVA::DataLoader *dataloader = new TMVA::DataLoader("dataset");

   // Data variables
   dataloader->AddVariable("x", 'F');
   dataloader->AddVariable("y", 'F');

   // Spectator used for split
   dataloader->AddSpectator("eventID", 'I');

   // Attaches the trees so they can be read from
   dataloader->AddSignalTree(sigTree, 1.0);
   dataloader->AddBackgroundTree(bkgTree, 1.0);

   // The CV mechanism of TMVA splits up the training set into several folds.
   // The test set is currently left unused. The `nTest_ClassName=1` assigns
   // one event to the the test set for each class and puts the rest in the
   // training set. A value of 0 is a special value and would split the
   // datasets 50 / 50.
   dataloader->PrepareTrainingAndTestTree("", "",
                                          "nTest_Signal=1"
                                          ":nTest_Background=1"
                                          ":SplitMode=Random"
                                          ":NormMode=NumEvents"
                                          ":!V");

   // --------------------------------------------------------------------------

   //
   // This sets up a CrossValidation class (which wraps a TMVA::Factory
   // internally) for 2-fold cross validation.
   //
   UInt_t numFolds = 2;
   TString analysisType = "Classification";
   TString splitExpr = "";

   //
   // One can also use a custom splitting function for producing the folds.
   // The example uses a dataset spectator `eventID`.
   //
   // The idea here is that eventID should be an event number that is integral,
   // random and independent of the data, generated only once. This last
   // property ensures that if a calibration is changed the same event will
   // still be assigned the same fold.
   //
   // This can be used to use the cross validated classifiers in application,
   // a technique that can simplify statistical analysis.
   //
   // If you want to run TMVACrossValidationApplication, make sure you have
   // run this tutorial with the below line uncommented first.
   //

   // TString splitExpr = "int(fabs([eventID]))%int([NumFolds])";

   TString cvOptions = Form("!V"
                            ":!Silent"
                            ":ModelPersistence"
                            ":AnalysisType=%s"
                            ":NumFolds=%i"
                            ":SplitExpr=%s",
                            analysisType.Data(), numFolds, splitExpr.Data());

   TMVA::CrossValidation cv{"TMVACrossValidation", dataloader, outputFile, cvOptions};

   // --------------------------------------------------------------------------

   //
   // Books a method to use for evaluation
   //
   cv.BookMethod(TMVA::Types::kBDT, "BDTG",
                 "!H:!V:NTrees=100:MinNodeSize=2.5%:BoostType=Grad"
                 ":NegWeightTreatment=Pray:Shrinkage=0.10:nCuts=20"
                 ":MaxDepth=2");

   cv.BookMethod(TMVA::Types::kFisher, "Fisher",
                 "!H:!V:Fisher:VarTransform=None");

   // --------------------------------------------------------------------------

   //
   // Train, test and evaluate the booked methods.
   // Evaluates the booked methods once for each fold and aggregates the result
   // in the specified output file.
   //
   cv.Evaluate();

   // --------------------------------------------------------------------------

   //
   // Process some output programatically, printing the ROC score for each
   // booked method.
   //
   size_t iMethod = 0;
   for (auto && result : cv.GetResults()) {
      std::cout << "Summary for method " << cv.GetMethods()[iMethod++].GetValue<TString>("MethodName")
                << std::endl;
      for (UInt_t iFold = 0; iFold<cv.GetNumFolds(); ++iFold) {
         std::cout << "\tFold " << iFold << ": "
                   << "ROC int: " << result.GetROCValues()[iFold]
                   << ", "
                   << "BkgEff@SigEff=0.3: " << result.GetEff30Values()[iFold]
                   << std::endl;
      }
   }

   // --------------------------------------------------------------------------

   //
   // Save the output
   //
   outputFile->Close();

   std::cout << "==> Wrote root file: " << outputFile->GetName() << std::endl;
   std::cout << "==> TMVACrossValidation is done!" << std::endl;

   // --------------------------------------------------------------------------

   //
   // Launch the GUI for the root macros
   //
   if (!gROOT->IsBatch()) {
      TMVA::TMVAGui(outfileName);
   }

   return 0;
}

//
// This is used if the macro is compiled. If run through ROOT with
// `root -l -b -q MACRO.C` or similar it is unused.
//
int main(int argc, char **argv)
{
   TMVACrossValidation();
}
<commit_msg>[TMVA] CV Avg ROC -- Add avg roc draw to tutorial<commit_after>/// \file
/// \ingroup tutorial_tmva
/// \notebook -nodraw
/// This macro provides an example of how to use TMVA for k-folds cross
/// evaluation.
///
/// As input data is used a toy-MC sample consisting of two guassian
/// distributions.
///
/// The output file "TMVA.root" can be analysed with the use of dedicated
/// macros (simply say: root -l <macro.C>), which can be conveniently
/// invoked through a GUI that will appear at the end of the run of this macro.
/// Launch the GUI via the command:
///
/// ```
/// root -l -e 'TMVA::TMVAGui("TMVA.root")'
/// ```
///
/// ## Cross Evaluation
/// Cross evaluation is a special case of k-folds cross validation where the
/// splitting into k folds is computed deterministically. This ensures that the
/// a given event will always end up in the same fold.
///
/// In addition all resulting classifiers are saved and can be applied to new
/// data using `MethodCrossValidation`. One requirement for this to work is a
/// splitting function that is evaluated for each event to determine into what
/// fold it goes (for training/evaluation) or to what classifier (for
/// application).
///
/// ## Split Expression
/// Cross evaluation uses a deterministic split to partition the data into
/// folds called the split expression. The expression can be any valid
/// `TFormula` as long as all parts used are defined.
///
/// For each event the split expression is evaluated to a number and the event
/// is put in the fold corresponding to that number.
///
/// It is recommended to always use `%int([NumFolds])` at the end of the
/// expression.
///
/// The split expression has access to all spectators and variables defined in
/// the dataloader. Additionally, the number of folds in the split can be
/// accessed with `NumFolds` (or `numFolds`).
///
/// ### Example
///  ```
///  "int(fabs([eventID]))%int([NumFolds])"
///  ```
///
/// - Project   : TMVA - a ROOT-integrated toolkit for multivariate data analysis
/// - Package   : TMVA
/// - Root Macro: TMVACrossValidation
///
/// \macro_output
/// \macro_code
/// \author Kim Albertsson (adapted from code originally by Andreas Hoecker)

#include <cstdlib>
#include <iostream>
#include <map>
#include <string>

#include "TChain.h"
#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TObjString.h"
#include "TSystem.h"
#include "TROOT.h"

#include "TMVA/CrossValidation.h"
#include "TMVA/DataLoader.h"
#include "TMVA/Factory.h"
#include "TMVA/Tools.h"
#include "TMVA/TMVAGui.h"

// Helper function to load data into TTrees.
TTree *genTree(Int_t nPoints, Double_t offset, Double_t scale, UInt_t seed = 100)
{
   TRandom3 rng(seed);
   Float_t x = 0;
   Float_t y = 0;
   UInt_t eventID = 0;

   TTree *data = new TTree();
   data->Branch("x", &x, "x/F");
   data->Branch("y", &y, "y/F");
   data->Branch("eventID", &eventID, "eventID/I");

   for (Int_t n = 0; n < nPoints; ++n) {
      x = rng.Gaus(offset, scale);
      y = rng.Gaus(offset, scale);

      // For our simple example it is enough that the id's are uniformly
      // distributed and independent of the data.
      ++eventID;

      data->Fill();
   }

   // Important: Disconnects the tree from the memory locations of x and y.
   data->ResetBranchAddresses();
   return data;
}

int TMVACrossValidation()
{
   // This loads the library
   TMVA::Tools::Instance();

   // --------------------------------------------------------------------------

   // Load the data into TTrees. If you load data from file you can use a
   // variant of
   // ```
   // TString filename = "/path/to/file";
   // TFile * input = TFile::Open( filename );
   // TTree * signalTree = (TTree*)input->Get("TreeName");
   // ```
   TTree *sigTree = genTree(1000, 1.0, 1.0, 100);
   TTree *bkgTree = genTree(1000, -1.0, 1.0, 101);

   // Create a ROOT output file where TMVA will store ntuples, histograms, etc.
   TString outfileName("TMVA.root");
   TFile *outputFile = TFile::Open(outfileName, "RECREATE");

   // DataLoader definitions; We declare variables in the tree so that TMVA can
   // find them. For more information see TMVAClassification tutorial.
   TMVA::DataLoader *dataloader = new TMVA::DataLoader("dataset");

   // Data variables
   dataloader->AddVariable("x", 'F');
   dataloader->AddVariable("y", 'F');

   // Spectator used for split
   dataloader->AddSpectator("eventID", 'I');

   // Attaches the trees so they can be read from
   dataloader->AddSignalTree(sigTree, 1.0);
   dataloader->AddBackgroundTree(bkgTree, 1.0);

   // The CV mechanism of TMVA splits up the training set into several folds.
   // The test set is currently left unused. The `nTest_ClassName=1` assigns
   // one event to the the test set for each class and puts the rest in the
   // training set. A value of 0 is a special value and would split the
   // datasets 50 / 50.
   dataloader->PrepareTrainingAndTestTree("", "",
                                          "nTest_Signal=1"
                                          ":nTest_Background=1"
                                          ":SplitMode=Random"
                                          ":NormMode=NumEvents"
                                          ":!V");

   // --------------------------------------------------------------------------

   //
   // This sets up a CrossValidation class (which wraps a TMVA::Factory
   // internally) for 2-fold cross validation.
   //
   UInt_t numFolds = 2;
   TString analysisType = "Classification";
   TString splitExpr = "";

   //
   // One can also use a custom splitting function for producing the folds.
   // The example uses a dataset spectator `eventID`.
   //
   // The idea here is that eventID should be an event number that is integral,
   // random and independent of the data, generated only once. This last
   // property ensures that if a calibration is changed the same event will
   // still be assigned the same fold.
   //
   // This can be used to use the cross validated classifiers in application,
   // a technique that can simplify statistical analysis.
   //
   // If you want to run TMVACrossValidationApplication, make sure you have
   // run this tutorial with the below line uncommented first.
   //

   // TString splitExpr = "int(fabs([eventID]))%int([NumFolds])";

   TString cvOptions = Form("!V"
                            ":!Silent"
                            ":ModelPersistence"
                            ":AnalysisType=%s"
                            ":NumFolds=%i"
                            ":SplitExpr=%s",
                            analysisType.Data(), numFolds, splitExpr.Data());

   TMVA::CrossValidation cv{"TMVACrossValidation", dataloader, outputFile, cvOptions};

   // --------------------------------------------------------------------------

   //
   // Books a method to use for evaluation
   //
   cv.BookMethod(TMVA::Types::kBDT, "BDTG",
                 "!H:!V:NTrees=100:MinNodeSize=2.5%:BoostType=Grad"
                 ":NegWeightTreatment=Pray:Shrinkage=0.10:nCuts=20"
                 ":MaxDepth=2");

   cv.BookMethod(TMVA::Types::kFisher, "Fisher",
                 "!H:!V:Fisher:VarTransform=None");

   // --------------------------------------------------------------------------

   //
   // Train, test and evaluate the booked methods.
   // Evaluates the booked methods once for each fold and aggregates the result
   // in the specified output file.
   //
   cv.Evaluate();

   // --------------------------------------------------------------------------

   //
   // Process some output programatically, printing the ROC score for each
   // booked method.
   //
   size_t iMethod = 0;
   for (auto && result : cv.GetResults()) {
      std::cout << "Summary for method " << cv.GetMethods()[iMethod++].GetValue<TString>("MethodName")
                << std::endl;
      for (UInt_t iFold = 0; iFold<cv.GetNumFolds(); ++iFold) {
         std::cout << "\tFold " << iFold << ": "
                   << "ROC int: " << result.GetROCValues()[iFold]
                   << ", "
                   << "BkgEff@SigEff=0.3: " << result.GetEff30Values()[iFold]
                   << std::endl;
      }
   }

   // --------------------------------------------------------------------------

   //
   // Save the output
   //
   outputFile->Close();

   std::cout << "==> Wrote root file: " << outputFile->GetName() << std::endl;
   std::cout << "==> TMVACrossValidation is done!" << std::endl;

   // --------------------------------------------------------------------------

   //
   // Launch the GUI for the root macros
   //
   if (!gROOT->IsBatch()) {
      // Draw cv-specific graphs
      cv.GetResults()[0].DrawAvgROCCurve(kTRUE, "Avg ROC for BDTG");
      cv.GetResults()[0].DrawAvgROCCurve(kTRUE, "Avg ROC for Fisher");

      // You can also use the classical gui
      TMVA::TMVAGui(outfileName);
   }

   return 0;
}

//
// This is used if the macro is compiled. If run through ROOT with
// `root -l -b -q MACRO.C` or similar it is unused.
//
int main(int argc, char **argv)
{
   TMVACrossValidation();
}
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2012 Preferred Infrastracture and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include <string>
#include <utility>
#include <vector>

#include <gtest/gtest.h>
#include <pficommon/data/string/utility.h>
#include <pficommon/lang/shared_ptr.h>
#include <pficommon/math/random.h>

#include "euclid_lsh.hpp"
#include "../common/hash.hpp"
#include "../common/portable_mixer.hpp"  // TODO(suma): use linear_mixer
#include "../storage/lsh_index_storage.hpp"

using std::istringstream;
using std::make_pair;
using std::pair;
using std::string;
using std::vector;
using pfi::lang::lexical_cast;
using pfi::math::random::mtrand;
using jubatus::core::storage::lsh_index_storage;

namespace jubatus {
namespace core {
namespace recommender {

namespace {

common::sfv_t make_dense_sfv(const string& s) {
  common::sfv_t sfv;
  istringstream iss(s);

  size_t i = 0;
  float x = 0;
  while (iss >> x) {
    sfv.push_back(make_pair(lexical_cast<string>(i++), x));
  }

  return sfv;
}

lsh_index_storage* get_storage(euclid_lsh& r) {
  framework::mixable_holder holder;
  r.register_mixables_to_holder(holder);
  storage::mixable_lsh_index_storage* mixable_storage =
      dynamic_cast<storage::mixable_lsh_index_storage*>(
          holder.get_mixables().front().get());
  return mixable_storage->get_model().get();
}

}  // namespace

TEST(euclid_lsh, complete_row) {
  euclid_lsh::config config;
  config.lsh_num = 4;
  config.table_num = 4;
  config.bin_width = 10;
  config.probe_num = 0;
  config.seed = 1091;
  config.retain_projection = false;

  euclid_lsh r(config);
  r.update_row("1", make_dense_sfv("1 1 0 1"));
  r.update_row("2", make_dense_sfv("1 0 1 1"));

  common::sfv_t ret;
  r.complete_row(make_dense_sfv("1 0 0 1"), ret);

  EXPECT_EQ(4u, ret.size());
  EXPECT_EQ("0", ret[0].first);
  EXPECT_EQ("1", ret[1].first);
  EXPECT_EQ("2", ret[2].first);
  EXPECT_EQ("3", ret[3].first);

  EXPECT_EQ(1, ret[0].second);
  EXPECT_LE(0, ret[1].second);
  EXPECT_LE(0, ret[2].second);
  EXPECT_EQ(1, ret[3].second);
}

class euclid_lsh_mix_test
    : public ::testing::TestWithParam<pair<int, euclid_lsh::config> > {
 protected:
  static const uint32_t kSeed = 1340764259;  // It may be any FIXED value

  common::sfv_t generate_gaussian(const common::sfv_t& mean, float deviation) {
    common::sfv_t sfv(mean);
    for (size_t i = 0; i < sfv.size(); ++i) {
      sfv[i].second += rand_.next_gaussian() * deviation;
    }
    return sfv;
  }

  void update(const string& name, const common::sfv_t& mean, float deviation) {
    const common::sfv_t x = generate_gaussian(mean, deviation);
    euclid_lsh* recom =
      recoms_[common::hash_util::calc_string_hash(name) % recoms_.size()].get();
    recom->update_row(name, x);

    single_recom_->update_row(name, x);
  }

  void mix() {
    portable_mixer_.mix();
  }

  virtual void SetUp() {
    rand_ = mtrand(kSeed);

    const pair<int, euclid_lsh::config>& param = GetParam();
    const int num_models = param.first;
    const euclid_lsh::config& config = param.second;

    recoms_.resize(num_models);
    for (int i = 0; i < num_models; ++i) {
      recoms_[i].reset(new euclid_lsh(config));
    }
    single_recom_.reset(new euclid_lsh(config));

    for (int i = 0; i < num_models; ++i) {
      portable_mixer_.add(get_storage(*recoms_[i]));
    }
  }

  vector<pfi::lang::shared_ptr<euclid_lsh> > recoms_;
  pfi::lang::shared_ptr<euclid_lsh> single_recom_;
  common::portable_mixer<lsh_index_storage, storage::lsh_master_table_t>
  portable_mixer_;

  mtrand rand_;
};

TEST_P(euclid_lsh_mix_test, consistency) {
  static const size_t kNumSample = 100;
  static const size_t kNumRetrieval = 10;
  static const size_t kNumQuery = 5;
  static const float kDeviation = 1;

  const common::sfv_t mu0 = make_dense_sfv("1 1");
  const common::sfv_t mu1 = make_dense_sfv("2 1");

  for (size_t i = 0; i < kNumSample; ++i) {
    update(lexical_cast<string>(i), mu0, kDeviation);
  }
  mix();

  for (size_t i = 0; i < kNumQuery; ++i) {
    const common::sfv_t x = generate_gaussian(mu1, 1);
    vector<pair<string, float> > expect, actual;

    single_recom_->neighbor_row(x, expect, kNumRetrieval);

    for (size_t j = 0; j < recoms_.size(); ++j) {
      recoms_[j]->neighbor_row(x, actual, kNumRetrieval);

      for (size_t k = 0; k < expect.size(); ++k) {
        EXPECT_EQ(expect[k].first, actual[k].first);
        EXPECT_FLOAT_EQ(expect[k].second, actual[k].second);
      }
    }
  }
}

euclid_lsh::config make_euclid_lsh_config() {
  euclid_lsh::config config;

  config.lsh_num = 16;
  config.table_num = 4;
  config.bin_width = 1;
  return config;
}

INSTANTIATE_TEST_CASE_P(
    euclid_lsh_mix_test_instance,
    euclid_lsh_mix_test,
    ::testing::Values(make_pair(2, make_euclid_lsh_config())));

}  // namespace recommender
}  // namespace core
}  // namespace jubatus
<commit_msg>Change complete_row test for checking unweighted averaging<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2012 Preferred Infrastracture and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include <string>
#include <utility>
#include <vector>

#include <gtest/gtest.h>
#include <pficommon/data/string/utility.h>
#include <pficommon/lang/shared_ptr.h>
#include <pficommon/math/random.h>

#include "euclid_lsh.hpp"
#include "../common/hash.hpp"
#include "../common/portable_mixer.hpp"  // TODO(suma): use linear_mixer
#include "../storage/lsh_index_storage.hpp"

using std::istringstream;
using std::make_pair;
using std::pair;
using std::string;
using std::vector;
using pfi::lang::lexical_cast;
using pfi::math::random::mtrand;
using jubatus::core::storage::lsh_index_storage;

namespace jubatus {
namespace core {
namespace recommender {

namespace {

common::sfv_t make_dense_sfv(const string& s) {
  common::sfv_t sfv;
  istringstream iss(s);

  size_t i = 0;
  float x = 0;
  while (iss >> x) {
    sfv.push_back(make_pair(lexical_cast<string>(i++), x));
  }

  return sfv;
}

lsh_index_storage* get_storage(euclid_lsh& r) {
  framework::mixable_holder holder;
  r.register_mixables_to_holder(holder);
  storage::mixable_lsh_index_storage* mixable_storage =
      dynamic_cast<storage::mixable_lsh_index_storage*>(
          holder.get_mixables().front().get());
  return mixable_storage->get_model().get();
}

}  // namespace

TEST(euclid_lsh, complete_row) {
  euclid_lsh::config config;
  config.lsh_num = 4;
  config.table_num = 4;
  config.bin_width = 10;
  config.probe_num = 0;
  config.seed = 1091;
  config.retain_projection = false;

  euclid_lsh r(config);
  r.update_row("1", make_dense_sfv("1 1 0 1"));
  r.update_row("2", make_dense_sfv("1 0 3 1"));

  common::sfv_t ret;
  r.complete_row(make_dense_sfv("1 0 0 1"), ret);

  EXPECT_EQ(4u, ret.size());
  EXPECT_EQ("0", ret[0].first);
  EXPECT_EQ("1", ret[1].first);
  EXPECT_EQ("2", ret[2].first);
  EXPECT_EQ("3", ret[3].first);

  // expect unweighted mean of nearest neighbors
  EXPECT_EQ(1, ret[0].second);
  EXPECT_EQ(0.5, ret[1].second);
  EXPECT_EQ(1.5, ret[2].second);
  EXPECT_EQ(1, ret[3].second);
}

class euclid_lsh_mix_test
    : public ::testing::TestWithParam<pair<int, euclid_lsh::config> > {
 protected:
  static const uint32_t kSeed = 1340764259;  // It may be any FIXED value

  common::sfv_t generate_gaussian(const common::sfv_t& mean, float deviation) {
    common::sfv_t sfv(mean);
    for (size_t i = 0; i < sfv.size(); ++i) {
      sfv[i].second += rand_.next_gaussian() * deviation;
    }
    return sfv;
  }

  void update(const string& name, const common::sfv_t& mean, float deviation) {
    const common::sfv_t x = generate_gaussian(mean, deviation);
    euclid_lsh* recom =
      recoms_[common::hash_util::calc_string_hash(name) % recoms_.size()].get();
    recom->update_row(name, x);

    single_recom_->update_row(name, x);
  }

  void mix() {
    portable_mixer_.mix();
  }

  virtual void SetUp() {
    rand_ = mtrand(kSeed);

    const pair<int, euclid_lsh::config>& param = GetParam();
    const int num_models = param.first;
    const euclid_lsh::config& config = param.second;

    recoms_.resize(num_models);
    for (int i = 0; i < num_models; ++i) {
      recoms_[i].reset(new euclid_lsh(config));
    }
    single_recom_.reset(new euclid_lsh(config));

    for (int i = 0; i < num_models; ++i) {
      portable_mixer_.add(get_storage(*recoms_[i]));
    }
  }

  vector<pfi::lang::shared_ptr<euclid_lsh> > recoms_;
  pfi::lang::shared_ptr<euclid_lsh> single_recom_;
  common::portable_mixer<lsh_index_storage, storage::lsh_master_table_t>
  portable_mixer_;

  mtrand rand_;
};

TEST_P(euclid_lsh_mix_test, consistency) {
  static const size_t kNumSample = 100;
  static const size_t kNumRetrieval = 10;
  static const size_t kNumQuery = 5;
  static const float kDeviation = 1;

  const common::sfv_t mu0 = make_dense_sfv("1 1");
  const common::sfv_t mu1 = make_dense_sfv("2 1");

  for (size_t i = 0; i < kNumSample; ++i) {
    update(lexical_cast<string>(i), mu0, kDeviation);
  }
  mix();

  for (size_t i = 0; i < kNumQuery; ++i) {
    const common::sfv_t x = generate_gaussian(mu1, 1);
    vector<pair<string, float> > expect, actual;

    single_recom_->neighbor_row(x, expect, kNumRetrieval);

    for (size_t j = 0; j < recoms_.size(); ++j) {
      recoms_[j]->neighbor_row(x, actual, kNumRetrieval);

      for (size_t k = 0; k < expect.size(); ++k) {
        EXPECT_EQ(expect[k].first, actual[k].first);
        EXPECT_FLOAT_EQ(expect[k].second, actual[k].second);
      }
    }
  }
}

euclid_lsh::config make_euclid_lsh_config() {
  euclid_lsh::config config;

  config.lsh_num = 16;
  config.table_num = 4;
  config.bin_width = 1;
  return config;
}

INSTANTIATE_TEST_CASE_P(
    euclid_lsh_mix_test_instance,
    euclid_lsh_mix_test,
    ::testing::Values(make_pair(2, make_euclid_lsh_config())));

}  // namespace recommender
}  // namespace core
}  // namespace jubatus
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/hwas/common/hwasCallout.H $                   */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2013              */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef  __HWAS_HWASCALLOUT_H
#define __HWAS_HWASCALLOUT_H
/**
 *  @file hwasCallout.H
 *
 *  HardWare Availability Service Callout prototypes.
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#ifndef PARSER
#include <targeting/common/target.H>
#endif // not PARSER

namespace HWAS
{
// from hwsv/server/hwsvTypes.H:
// Legacy HOM deconfig enum
enum DeconfigEnum
{
    NO_DECONFIG,
    DECONFIG,
    DELAYED_DECONFIG,
};

typedef enum {
    GARD_NULL                   = 0x00,
    GARD_User_Manual            = 0xD2, //Manual Guard.
    GARD_Unrecoverable          = 0xE2, //TODO:RTC-76814
    GARD_Fatal                  = 0xE3, //IPL Failures, and others.
    GARD_Predictive             = 0xE6, //Policy flag to disable.
    GARD_Func                   = 0xE7, //Policy flag to disable.
    GARD_Power                  = 0xE9, //Needed since PLID is NOT passed in.
    GARD_PHYP                   = 0xEA, //Needed since PLID is NOT passed in.
    GARD_Void                   = 0xFF
} GARD_ErrorType;

// from src/epub/fsp/epub_service_codes.H
// nuVersionSID  1.24.14.36                  versionSID    1.24.14.36
    /** @enum epubProcedureID
     *  This enumeration contains all the Procedures to be used with a callout
     *  in an SRC.
     */
enum epubProcedureID
{
    EPUB_PRC_NONE                   = 0x00,
    EPUB_PRC_FIND_DECONFIGURED_PART = 0x01,
    EPUB_PRC_SP_CODE                = 0x04,
    EPUB_PRC_PHYP_CODE              = 0x05,
    EPUB_PRC_ALL_PROCS              = 0x08,
    EPUB_PRC_ALL_MEMCRDS            = 0x09,
    EPUB_PRC_INVALID_PART           = 0x0A,
    EPUB_PRC_LVL_SUPP               = 0x10,
    EPUB_PRC_PROCPATH               = 0x16,
    EPUB_PRC_NO_VPD_FOR_FRU         = 0x1C,
    EPUB_PRC_MEMORY_PLUGGING_ERROR  = 0x22,
    EPUB_PRC_FSI_PATH               = 0x2D,
    EPUB_PRC_PROC_AB_BUS            = 0x30,
    EPUB_PRC_PROC_XYZ_BUS           = 0x31,
    EPUB_PRC_MEMBUS_ERROR           = 0x34,
    EPUB_PRC_EIBUS_ERROR            = 0x37,
    EPUB_PRC_POWER_ERROR            = 0x3F,
    EPUB_PRC_PERFORMANCE_DEGRADED   = 0x4D,
    EPUB_PRC_HB_CODE                = 0x51
};

// from srci/fsp/srci.H
enum callOutPriority
{
    SRCI_PRIORITY_LOW   = 1,
    SRCI_PRIORITY_MEDC  = 2,
    SRCI_PRIORITY_MEDB  = 3,
    SRCI_PRIORITY_MEDA  = 4,
    SRCI_PRIORITY_MED   = 5,
    SRCI_PRIORITY_HIGH  = 6
};

enum busTypeEnum
{
    FSI_BUS_TYPE    = 1,
    DMI_BUS_TYPE    = 2,
    A_BUS_TYPE      = 3,
    X_BUS_TYPE      = 4,
    I2C_BUS_TYPE    = 5,
    PSI_BUS_TYPE    = 6
};

//
const uint8_t HW_CALLOUT        = 0x01;
const uint8_t PROCEDURE_CALLOUT = 0x02;
const uint8_t BUS_CALLOUT       = 0x03;

const uint8_t TARGET_IS_SENTINEL = 0xF0;

typedef struct callout_ud
{
    uint8_t             type;
    uint8_t             pad[3];
    callOutPriority     priority; // uint32_t
    union {
        struct {    // deconfigure / gard
            DeconfigEnum    deconfigState; // uint32_t
            GARD_ErrorType  gardErrorType; // uint32_t
            uint32_t        cpuid;
        };
        struct {    // callout
            epubProcedureID procedure;  // uint32_t
        };
        struct {
            busTypeEnum     busType;
        };
    };
} callout_ud_t;

#ifndef PARSER

/**
 *  @brief processCallout process the userdetail for a callout, calling
 *              the deconfigure and/or GARD funcationality as appropriate
 *
 *  @param[in]  i_errl Error log handle
 *  @param[in]  i_pData  Pointer to the callout bundle
 *  @param[in]  i_Size  size of the data in the callout bundle
 *  @param[in]  i_DeferredOnly  bool - true if ONLY check for defered deconfig
 *
 */
void processCallout(errlHndl_t i_errl,
        uint8_t *i_pData,
        uint64_t i_Size,
        bool i_DeferredOnly = false);

// typedef for function pointer that the errlog class will use.
typedef bool (*processCalloutFn)(errlHndl_t, uint8_t *, uint64_t, bool);

/**
 * @brief platform specific code to handle a procedure callout that has been
 *  found in an errlog
 *
 * @param[in]  i_errl       errlHndl for this errlog.
 * @param[in]  i_procedure  Enum indicating which procedure to add to the
 *                          error log
 * @param[in]  i_priority   Enum indicating the priority of the callout
 *
 * @return errlHndl_t       valid errlHndl_t handle if there was an error,
 *                          NULL if no errors;
 */
errlHndl_t platHandleProcedureCallout(errlHndl_t i_errl,
        epubProcedureID i_procedure,
        callOutPriority i_priority);

/**
 * @brief platform specific code to handle a hardware callout that has been
 *  found in an errlog
 *
 * @param[in]  i_pTarget        target
 * @param[in]  i_priority       Enum indicating the priority of the callout
 * @param[in]  i_deconfigState  Enum indicating whether to deconfig or not
 * @param[in]  i_errl           errlHnld for this errlog
 * @param[in]  i_gardErrType    Enum indicating the type of failure
 *
 * @return errlHndl_t       valid errlHndl_t handle if there was an error,
 *                          NULL if no errors;
 */
errlHndl_t platHandleHWCallout(
        TARGETING::Target *i_pTarget,
        callOutPriority i_priority,
        DeconfigEnum    i_deconfigState,
        errlHndl_t i_errl,
        GARD_ErrorType  i_gardErrorType);

/**
 * @brief platform specific code to handle a bus callout that has been
 *  found in an errlog
 *
 * @param[in]  i_pTarget1       target endpoint1
 * @param[in]  i_pTarget2       target endpoint2
 * @param[in]  i_busType        bus type Enum
 * @param[in]  i_priority       Enum indicating the priority of the callout
 * @param[in]  i_errl           errlHnld for this errlog
 *
 * @return errlHndl_t       valid errlHndl_t handle if there was an error,
 *                          NULL if no errors;
 */
errlHndl_t platHandleBusCallout(
        TARGETING::Target *i_pTarget1,
        TARGETING::Target *i_pTarget2,
        busTypeEnum i_busType,
        callOutPriority i_priority,
        errlHndl_t i_errl);

#endif // not PARSER

};   // end namespace

#endif
<commit_msg>Update PRC_HB_CODE value<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/hwas/common/hwasCallout.H $                   */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2013              */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef  __HWAS_HWASCALLOUT_H
#define __HWAS_HWASCALLOUT_H
/**
 *  @file hwasCallout.H
 *
 *  HardWare Availability Service Callout prototypes.
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#ifndef PARSER
#include <targeting/common/target.H>
#endif // not PARSER

namespace HWAS
{
// from hwsv/server/hwsvTypes.H:
// Legacy HOM deconfig enum
enum DeconfigEnum
{
    NO_DECONFIG,
    DECONFIG,
    DELAYED_DECONFIG,
};

typedef enum {
    GARD_NULL                   = 0x00,
    GARD_User_Manual            = 0xD2, //Manual Guard.
    GARD_Unrecoverable          = 0xE2, //TODO:RTC-76814
    GARD_Fatal                  = 0xE3, //IPL Failures, and others.
    GARD_Predictive             = 0xE6, //Policy flag to disable.
    GARD_Func                   = 0xE7, //Policy flag to disable.
    GARD_Power                  = 0xE9, //Needed since PLID is NOT passed in.
    GARD_PHYP                   = 0xEA, //Needed since PLID is NOT passed in.
    GARD_Void                   = 0xFF
} GARD_ErrorType;

// from src/epub/fsp/epub_service_codes.H v1.24.24.4
// - Any additions should be added to FipS code first

/** @enum epubProcedureID
 *  This enumeration contains all the Procedures to be used with a callout
 *  in an SRC.
 */
enum epubProcedureID
{
    EPUB_PRC_NONE                   = 0x00,
    EPUB_PRC_FIND_DECONFIGURED_PART = 0x01,
    EPUB_PRC_SP_CODE                = 0x04,
    EPUB_PRC_PHYP_CODE              = 0x05,
    EPUB_PRC_ALL_PROCS              = 0x08,
    EPUB_PRC_ALL_MEMCRDS            = 0x09,
    EPUB_PRC_INVALID_PART           = 0x0A,
    EPUB_PRC_LVL_SUPP               = 0x10,
    EPUB_PRC_PROCPATH               = 0x16,
    EPUB_PRC_NO_VPD_FOR_FRU         = 0x1C,
    EPUB_PRC_MEMORY_PLUGGING_ERROR  = 0x22,
    EPUB_PRC_FSI_PATH               = 0x2D,
    EPUB_PRC_PROC_AB_BUS            = 0x30,
    EPUB_PRC_PROC_XYZ_BUS           = 0x31,
    EPUB_PRC_MEMBUS_ERROR           = 0x34,
    EPUB_PRC_EIBUS_ERROR            = 0x37,
    EPUB_PRC_POWER_ERROR            = 0x3F,
    EPUB_PRC_PERFORMANCE_DEGRADED   = 0x4D,
    EPUB_PRC_HB_CODE                = 0x55
};

// from srci/fsp/srci.H
enum callOutPriority
{
    SRCI_PRIORITY_LOW   = 1,
    SRCI_PRIORITY_MEDC  = 2,
    SRCI_PRIORITY_MEDB  = 3,
    SRCI_PRIORITY_MEDA  = 4,
    SRCI_PRIORITY_MED   = 5,
    SRCI_PRIORITY_HIGH  = 6
};

enum busTypeEnum
{
    FSI_BUS_TYPE    = 1,
    DMI_BUS_TYPE    = 2,
    A_BUS_TYPE      = 3,
    X_BUS_TYPE      = 4,
    I2C_BUS_TYPE    = 5,
    PSI_BUS_TYPE    = 6
};

//
const uint8_t HW_CALLOUT        = 0x01;
const uint8_t PROCEDURE_CALLOUT = 0x02;
const uint8_t BUS_CALLOUT       = 0x03;

const uint8_t TARGET_IS_SENTINEL = 0xF0;

typedef struct callout_ud
{
    uint8_t             type;
    uint8_t             pad[3];
    callOutPriority     priority; // uint32_t
    union {
        struct {    // deconfigure / gard
            DeconfigEnum    deconfigState; // uint32_t
            GARD_ErrorType  gardErrorType; // uint32_t
            uint32_t        cpuid;
        };
        struct {    // callout
            epubProcedureID procedure;  // uint32_t
        };
        struct {
            busTypeEnum     busType;
        };
    };
} callout_ud_t;

#ifndef PARSER

/**
 *  @brief processCallout process the userdetail for a callout, calling
 *              the deconfigure and/or GARD funcationality as appropriate
 *
 *  @param[in]  i_errl Error log handle
 *  @param[in]  i_pData  Pointer to the callout bundle
 *  @param[in]  i_Size  size of the data in the callout bundle
 *  @param[in]  i_DeferredOnly  bool - true if ONLY check for defered deconfig
 *
 */
void processCallout(errlHndl_t i_errl,
        uint8_t *i_pData,
        uint64_t i_Size,
        bool i_DeferredOnly = false);

// typedef for function pointer that the errlog class will use.
typedef bool (*processCalloutFn)(errlHndl_t, uint8_t *, uint64_t, bool);

/**
 * @brief platform specific code to handle a procedure callout that has been
 *  found in an errlog
 *
 * @param[in]  i_errl       errlHndl for this errlog.
 * @param[in]  i_procedure  Enum indicating which procedure to add to the
 *                          error log
 * @param[in]  i_priority   Enum indicating the priority of the callout
 *
 * @return errlHndl_t       valid errlHndl_t handle if there was an error,
 *                          NULL if no errors;
 */
errlHndl_t platHandleProcedureCallout(errlHndl_t i_errl,
        epubProcedureID i_procedure,
        callOutPriority i_priority);

/**
 * @brief platform specific code to handle a hardware callout that has been
 *  found in an errlog
 *
 * @param[in]  i_pTarget        target
 * @param[in]  i_priority       Enum indicating the priority of the callout
 * @param[in]  i_deconfigState  Enum indicating whether to deconfig or not
 * @param[in]  i_errl           errlHnld for this errlog
 * @param[in]  i_gardErrType    Enum indicating the type of failure
 *
 * @return errlHndl_t       valid errlHndl_t handle if there was an error,
 *                          NULL if no errors;
 */
errlHndl_t platHandleHWCallout(
        TARGETING::Target *i_pTarget,
        callOutPriority i_priority,
        DeconfigEnum    i_deconfigState,
        errlHndl_t i_errl,
        GARD_ErrorType  i_gardErrorType);

/**
 * @brief platform specific code to handle a bus callout that has been
 *  found in an errlog
 *
 * @param[in]  i_pTarget1       target endpoint1
 * @param[in]  i_pTarget2       target endpoint2
 * @param[in]  i_busType        bus type Enum
 * @param[in]  i_priority       Enum indicating the priority of the callout
 * @param[in]  i_errl           errlHnld for this errlog
 *
 * @return errlHndl_t       valid errlHndl_t handle if there was an error,
 *                          NULL if no errors;
 */
errlHndl_t platHandleBusCallout(
        TARGETING::Target *i_pTarget1,
        TARGETING::Target *i_pTarget2,
        busTypeEnum i_busType,
        callOutPriority i_priority,
        errlHndl_t i_errl);

#endif // not PARSER

};   // end namespace

#endif
<|endoftext|>