<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/gpu/gpu_channel.h"

#if defined(OS_WIN)
#include <windows.h>
#endif

#include "base/command_line.h"
#include "base/lock.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/common/child_process.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_thread.h"
#include "chrome/gpu/gpu_video_service.h"

#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif

GpuChannel::GpuChannel(int renderer_id)
    : renderer_id_(renderer_id)
#if defined(OS_POSIX)
    , renderer_fd_(-1)
#endif
{
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
}

GpuChannel::~GpuChannel() {
#if defined(OS_POSIX)
  // If we still have the renderer FD, close it.
  if (renderer_fd_ != -1) {
    close(renderer_fd_);
  }
#endif
}

void GpuChannel::OnChannelConnected(int32 peer_pid) {
  if (!renderer_process_.Open(peer_pid)) {
    NOTREACHED();
  }
}

void GpuChannel::OnMessageReceived(const IPC::Message& message) {
  if (log_messages_) {
    VLOG(1) << "received message @" << &message << " on channel @" << this
            << " with type " << message.type();
  }

  if (message.routing_id() == MSG_ROUTING_CONTROL) {
    OnControlMessageReceived(message);
  } else {
    // Fail silently if the GPU process has destroyed while the IPC message was
    // en-route.
    router_.RouteMessage(message);
  }
}

void GpuChannel::OnChannelError() {
  static_cast<GpuThread*>(ChildThread::current())->RemoveChannel(renderer_id_);
}

bool GpuChannel::Send(IPC::Message* message) {
  if (log_messages_) {
    VLOG(1) << "sending message @" << message << " on channel @" << this
            << " with type " << message->type();
  }

  if (!channel_.get()) {
    delete message;
    return false;
  }

  return channel_->Send(message);
}

void GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateViewCommandBuffer,
        OnCreateViewCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
        OnCreateOffscreenCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
        OnDestroyCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder,
        OnCreateVideoDecoder)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyVideoDecoder,
        OnDestroyVideoDecoder)
    IPC_MESSAGE_UNHANDLED_ERROR()
  IPC_END_MESSAGE_MAP()
}

int GpuChannel::GenerateRouteID() {
  static int last_id = 0;
  return ++last_id;
}

void GpuChannel::OnCreateViewCommandBuffer(
    gfx::NativeViewId view_id,
    int32 render_view_id,
    const GPUCreateCommandBufferConfig& init_params,
    int32* route_id) {
  *route_id = 0;

#if defined(ENABLE_GPU)

  gfx::PluginWindowHandle handle = gfx::kNullPluginWindow;
#if defined(OS_WIN)
  gfx::NativeView view = gfx::NativeViewFromId(view_id);

  // Check that the calling renderer is allowed to render to this window.
  // TODO(apatrick): consider killing the renderer process rather than failing.
  int view_renderer_id = reinterpret_cast<int>(
      GetProp(view, chrome::kChromiumRendererIdProperty));
  if (view_renderer_id != renderer_id_)
    return;
  handle = view;
#elif defined(OS_LINUX)
  ChildThread* gpu_thread = ChildThread::current();
  // Ask the browser for the view's XID.
  // TODO(piman): This assumes that it doesn't change. It can change however
  // when tearing off tabs. This needs a fix in the browser UI code. A possible
  // alternative would be to add a socket/plug pair like with plugins but that
  // has issues with events and focus.
  gpu_thread->Send(new GpuHostMsg_GetViewXID(view_id, &handle));
#elif defined(OS_MACOSX)
  // On Mac OS X we currently pass a (fake) PluginWindowHandle for the
  // NativeViewId. We could allocate fake NativeViewIds on the browser
  // side as well, and map between those and PluginWindowHandles, but
  // this seems excessive.
  handle = static_cast<gfx::PluginWindowHandle>(
      static_cast<intptr_t>(view_id));
#else
  // TODO(apatrick): This needs to be something valid for mac and linux.
  // Offscreen rendering will work on these platforms but not rendering to the
  // window.
  DCHECK_EQ(view_id, 0);
#endif

  *route_id = GenerateRouteID();
  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this, handle, NULL, gfx::Size(), init_params.allowed_extensions,
      init_params.attribs, 0, *route_id, renderer_id_, render_view_id));
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
#endif  // ENABLE_GPU
}

void GpuChannel::OnCreateOffscreenCommandBuffer(
    int32 parent_route_id,
    const gfx::Size& size,
    const GPUCreateCommandBufferConfig& init_params,
    uint32 parent_texture_id,
    int32* route_id) {
#if defined(ENABLE_GPU)
  *route_id = GenerateRouteID();
  GpuCommandBufferStub* parent_stub = NULL;
  if (parent_route_id != 0)
    parent_stub = stubs_.Lookup(parent_route_id);

  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this,
      gfx::kNullPluginWindow,
      parent_stub,
      size,
      init_params.allowed_extensions,
      init_params.attribs,
      parent_texture_id,
      *route_id,
      0, 0));
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
#else
  *route_id = 0;
#endif
}

void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
#if defined(ENABLE_GPU)
  router_.RemoveRoute(route_id);
  stubs_.Remove(route_id);
#endif
}

void GpuChannel::OnCreateVideoDecoder(int32 context_route_id,
                                      int32 decoder_host_id) {
#if defined(ENABLE_GPU)
  VLOG(1) << "GpuChannel::OnCreateVideoDecoder";
  GpuVideoService* service = GpuVideoService::get();
  if (service == NULL) {
    // TODO(hclam): Need to send a failure message.
    return;
  }

  // The context ID corresponds to the command buffer used.
  GpuCommandBufferStub* stub = stubs_.Lookup(context_route_id);
  int32 decoder_id = GenerateRouteID();

  // TODO(hclam): Need to be careful about the lifetime of the command buffer
  // decoder.
  bool ret = service->CreateVideoDecoder(
      this, &router_, decoder_host_id, decoder_id,
      stub->processor()->decoder());
  DCHECK(ret) << "Failed to create a GpuVideoDecoder";
#endif
}

void GpuChannel::OnDestroyVideoDecoder(int32 decoder_id) {
#if defined(ENABLE_GPU)
  LOG(ERROR) << "GpuChannel::OnDestroyVideoDecoder";
  GpuVideoService* service = GpuVideoService::get();
  if (service == NULL)
    return;
  service->DestroyVideoDecoder(&router_, decoder_id);
#endif
}

bool GpuChannel::Init() {
  // Check whether we're already initialized.
  if (channel_.get())
    return true;

  // Map renderer ID to a (single) channel to that process.
  std::string channel_name = GetChannelName();
#if defined(OS_POSIX)
  // This gets called when the GpuChannel is initially created. At this
  // point, create the socketpair and assign the GPU side FD to the channel
  // name. Keep the renderer side FD as a member variable in the PluginChannel
  // to be able to transmit it through IPC.
  int gpu_fd;
  IPC::SocketPair(&gpu_fd, &renderer_fd_);
  IPC::AddChannelSocket(channel_name, gpu_fd);
#endif
  channel_.reset(new IPC::SyncChannel(
      channel_name, IPC::Channel::MODE_SERVER, this, NULL,
      ChildProcess::current()->io_message_loop(), false,
      ChildProcess::current()->GetShutDownEvent()));

  return true;
}

std::string GpuChannel::GetChannelName() {
  return StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id_);
}
<commit_msg>Gpu: Unregister channel name in the gpu process when a channel closes.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/gpu/gpu_channel.h"

#if defined(OS_WIN)
#include <windows.h>
#endif

#include "base/command_line.h"
#include "base/lock.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/common/child_process.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_thread.h"
#include "chrome/gpu/gpu_video_service.h"

#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif

GpuChannel::GpuChannel(int renderer_id)
    : renderer_id_(renderer_id)
#if defined(OS_POSIX)
    , renderer_fd_(-1)
#endif
{
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
}

GpuChannel::~GpuChannel() {
#if defined(OS_POSIX)
  IPC::RemoveAndCloseChannelSocket(GetChannelName());

  // If we still have the renderer FD, close it.
  if (renderer_fd_ != -1) {
    close(renderer_fd_);
  }
#endif
}

void GpuChannel::OnChannelConnected(int32 peer_pid) {
  if (!renderer_process_.Open(peer_pid)) {
    NOTREACHED();
  }
}

void GpuChannel::OnMessageReceived(const IPC::Message& message) {
  if (log_messages_) {
    VLOG(1) << "received message @" << &message << " on channel @" << this
            << " with type " << message.type();
  }

  if (message.routing_id() == MSG_ROUTING_CONTROL) {
    OnControlMessageReceived(message);
  } else {
    // Fail silently if the GPU process has destroyed while the IPC message was
    // en-route.
    router_.RouteMessage(message);
  }
}

void GpuChannel::OnChannelError() {
  static_cast<GpuThread*>(ChildThread::current())->RemoveChannel(renderer_id_);
}

bool GpuChannel::Send(IPC::Message* message) {
  if (log_messages_) {
    VLOG(1) << "sending message @" << message << " on channel @" << this
            << " with type " << message->type();
  }

  if (!channel_.get()) {
    delete message;
    return false;
  }

  return channel_->Send(message);
}

void GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateViewCommandBuffer,
        OnCreateViewCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
        OnCreateOffscreenCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
        OnDestroyCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder,
        OnCreateVideoDecoder)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyVideoDecoder,
        OnDestroyVideoDecoder)
    IPC_MESSAGE_UNHANDLED_ERROR()
  IPC_END_MESSAGE_MAP()
}

int GpuChannel::GenerateRouteID() {
  static int last_id = 0;
  return ++last_id;
}

void GpuChannel::OnCreateViewCommandBuffer(
    gfx::NativeViewId view_id,
    int32 render_view_id,
    const GPUCreateCommandBufferConfig& init_params,
    int32* route_id) {
  *route_id = 0;

#if defined(ENABLE_GPU)

  gfx::PluginWindowHandle handle = gfx::kNullPluginWindow;
#if defined(OS_WIN)
  gfx::NativeView view = gfx::NativeViewFromId(view_id);

  // Check that the calling renderer is allowed to render to this window.
  // TODO(apatrick): consider killing the renderer process rather than failing.
  int view_renderer_id = reinterpret_cast<int>(
      GetProp(view, chrome::kChromiumRendererIdProperty));
  if (view_renderer_id != renderer_id_)
    return;
  handle = view;
#elif defined(OS_LINUX)
  ChildThread* gpu_thread = ChildThread::current();
  // Ask the browser for the view's XID.
  // TODO(piman): This assumes that it doesn't change. It can change however
  // when tearing off tabs. This needs a fix in the browser UI code. A possible
  // alternative would be to add a socket/plug pair like with plugins but that
  // has issues with events and focus.
  gpu_thread->Send(new GpuHostMsg_GetViewXID(view_id, &handle));
#elif defined(OS_MACOSX)
  // On Mac OS X we currently pass a (fake) PluginWindowHandle for the
  // NativeViewId. We could allocate fake NativeViewIds on the browser
  // side as well, and map between those and PluginWindowHandles, but
  // this seems excessive.
  handle = static_cast<gfx::PluginWindowHandle>(
      static_cast<intptr_t>(view_id));
#else
  // TODO(apatrick): This needs to be something valid for mac and linux.
  // Offscreen rendering will work on these platforms but not rendering to the
  // window.
  DCHECK_EQ(view_id, 0);
#endif

  *route_id = GenerateRouteID();
  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this, handle, NULL, gfx::Size(), init_params.allowed_extensions,
      init_params.attribs, 0, *route_id, renderer_id_, render_view_id));
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
#endif  // ENABLE_GPU
}

void GpuChannel::OnCreateOffscreenCommandBuffer(
    int32 parent_route_id,
    const gfx::Size& size,
    const GPUCreateCommandBufferConfig& init_params,
    uint32 parent_texture_id,
    int32* route_id) {
#if defined(ENABLE_GPU)
  *route_id = GenerateRouteID();
  GpuCommandBufferStub* parent_stub = NULL;
  if (parent_route_id != 0)
    parent_stub = stubs_.Lookup(parent_route_id);

  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this,
      gfx::kNullPluginWindow,
      parent_stub,
      size,
      init_params.allowed_extensions,
      init_params.attribs,
      parent_texture_id,
      *route_id,
      0, 0));
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
#else
  *route_id = 0;
#endif
}

void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
#if defined(ENABLE_GPU)
  router_.RemoveRoute(route_id);
  stubs_.Remove(route_id);
#endif
}

void GpuChannel::OnCreateVideoDecoder(int32 context_route_id,
                                      int32 decoder_host_id) {
#if defined(ENABLE_GPU)
  VLOG(1) << "GpuChannel::OnCreateVideoDecoder";
  GpuVideoService* service = GpuVideoService::get();
  if (service == NULL) {
    // TODO(hclam): Need to send a failure message.
    return;
  }

  // The context ID corresponds to the command buffer used.
  GpuCommandBufferStub* stub = stubs_.Lookup(context_route_id);
  int32 decoder_id = GenerateRouteID();

  // TODO(hclam): Need to be careful about the lifetime of the command buffer
  // decoder.
  bool ret = service->CreateVideoDecoder(
      this, &router_, decoder_host_id, decoder_id,
      stub->processor()->decoder());
  DCHECK(ret) << "Failed to create a GpuVideoDecoder";
#endif
}

void GpuChannel::OnDestroyVideoDecoder(int32 decoder_id) {
#if defined(ENABLE_GPU)
  LOG(ERROR) << "GpuChannel::OnDestroyVideoDecoder";
  GpuVideoService* service = GpuVideoService::get();
  if (service == NULL)
    return;
  service->DestroyVideoDecoder(&router_, decoder_id);
#endif
}

bool GpuChannel::Init() {
  // Check whether we're already initialized.
  if (channel_.get())
    return true;

  // Map renderer ID to a (single) channel to that process.
  std::string channel_name = GetChannelName();
#if defined(OS_POSIX)
  // This gets called when the GpuChannel is initially created. At this
  // point, create the socketpair and assign the GPU side FD to the channel
  // name. Keep the renderer side FD as a member variable in the PluginChannel
  // to be able to transmit it through IPC.
  int gpu_fd;
  IPC::SocketPair(&gpu_fd, &renderer_fd_);
  IPC::AddChannelSocket(channel_name, gpu_fd);
#endif
  channel_.reset(new IPC::SyncChannel(
      channel_name, IPC::Channel::MODE_SERVER, this, NULL,
      ChildProcess::current()->io_message_loop(), false,
      ChildProcess::current()->GetShutDownEvent()));

  return true;
}

std::string GpuChannel::GetChannelName() {
  return StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id_);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/views/combo_box.h"

#include "base/gfx/native_theme.h"
#include "base/gfx/rect.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"

// Limit how small a combobox can be.
static const int kMinComboboxWidth = 148;

// Add a couple extra pixels to the widths of comboboxes and combobox
// dropdowns so that text isn't too crowded.
static const int kComboboxExtraPaddingX = 6;

namespace views {

ComboBox::ComboBox(Model* model)
    : model_(model), selected_item_(0), listener_(NULL), content_width_(0) {
}

ComboBox::~ComboBox() {
}

void ComboBox::SetListener(Listener* listener) {
  listener_ = listener;
}

gfx::Size ComboBox::GetPreferredSize() {
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return gfx::Size();

  COMBOBOXINFO cbi;
  memset(reinterpret_cast<unsigned char*>(&cbi), 0, sizeof(cbi));
  cbi.cbSize = sizeof(cbi);
  ::SendMessage(hwnd, CB_GETCOMBOBOXINFO, 0, reinterpret_cast<LPARAM>(&cbi));
  gfx::Rect rect_item(cbi.rcItem);
  gfx::Rect rect_button(cbi.rcButton);
  gfx::Size border = gfx::NativeTheme::instance()->GetThemeBorderSize(
      gfx::NativeTheme::MENULIST);

  // The padding value of '3' is the xy offset from the corner of the control
  // to the corner of rcItem.  It does not seem to be queryable from the theme.
  // It is consistent on all versions of Windows from 2K to Vista, and is
  // invariant with respect to the combobox border size.  We could conceivably
  // get this number from rect_item.x, but it seems fragile to depend on position
  // here, inside of the layout code.
  const int kItemOffset = 3;
  int item_to_button_distance = std::max(kItemOffset - border.width(), 0);

  // The cx computation can be read as measuring from left to right.
  int pref_width = std::max(kItemOffset + content_width_ +
                                kComboboxExtraPaddingX +
                                item_to_button_distance + rect_button.width() +
                                 border.width(), kMinComboboxWidth);
  // The two arguments to ::max below should be typically be equal.
  int pref_height = std::max(rect_item.height() + 2 * kItemOffset,
                             rect_button.height() + 2 * border.height());
  return gfx::Size(pref_width, pref_height);
}

HWND ComboBox::CreateNativeControl(HWND parent_container) {
  HWND r = ::CreateWindowEx(GetAdditionalExStyle(), L"COMBOBOX", L"",
                            WS_CHILD | WS_VSCROLL | CBS_DROPDOWNLIST,
                            0, 0, width(), height(),
                            parent_container, NULL, NULL, NULL);
  HFONT font = ResourceBundle::GetSharedInstance().
      GetFont(ResourceBundle::BaseFont).hfont();
  SendMessage(r, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);
  UpdateComboBoxFromModel(r);
  return r;
}

LRESULT ComboBox::OnCommand(UINT code, int id, HWND source) {
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return 0;

  if (code == CBN_SELCHANGE && source == hwnd) {
    LRESULT r = ::SendMessage(hwnd, CB_GETCURSEL, 0, 0);
    if (r != CB_ERR) {
      int prev_selected_item = selected_item_;
      selected_item_ = static_cast<int>(r);
      if (listener_)
        listener_->ItemChanged(this, prev_selected_item, selected_item_);
    }
  }
  return 0;
}

LRESULT ComboBox::OnNotify(int w_param, LPNMHDR l_param) {
  return 0;
}

void ComboBox::UpdateComboBoxFromModel(HWND hwnd) {
  ::SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
  ChromeFont font = ResourceBundle::GetSharedInstance().GetFont(
      ResourceBundle::BaseFont);
  int max_width = 0;
  int num_items = model_->GetItemCount(this);
  for (int i = 0; i < num_items; ++i) {
    const std::wstring& text = model_->GetItemAt(this, i);

    // Inserting the Unicode formatting characters if necessary so that the
    // text is displayed correctly in right-to-left UIs.
    std::wstring localized_text;
    const wchar_t* text_ptr = text.c_str();
    if (l10n_util::AdjustStringForLocaleDirection(text, &localized_text))
      text_ptr = localized_text.c_str();

    ::SendMessage(hwnd, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(text_ptr));
    max_width = std::max(max_width, font.GetStringWidth(text));

  }
  content_width_ = max_width;

  if (num_items > 0) {
    ::SendMessage(hwnd, CB_SETCURSEL, selected_item_, 0);

    // Set the width for the drop down while accounting for the scrollbar and
    // borders.
    if (num_items > ComboBox_GetMinVisible(hwnd))
      max_width += ::GetSystemMetrics(SM_CXVSCROLL);
    // SM_CXEDGE would not be correct here, since the dropdown is flat, not 3D.
    int kComboboxDropdownBorderSize = 1;
    max_width += 2 * kComboboxDropdownBorderSize + kComboboxExtraPaddingX;
    ::SendMessage(hwnd, CB_SETDROPPEDWIDTH, max_width, 0);
  }
}

void ComboBox::ModelChanged() {
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return;
  selected_item_ = std::min(0, model_->GetItemCount(this));
  UpdateComboBoxFromModel(hwnd);
}

void ComboBox::SetSelectedItem(int index) {
  selected_item_ = index;
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return;

  // Note that we use CB_SETCURSEL and not CB_SELECTSTRING because on RTL
  // locales the strings we get from our ComboBox::Model might be augmented
  // with Unicode directionality marks before we insert them into the combo box
  // and therefore we can not assume that the string we get from
  // ComboBox::Model can be safely searched for and selected (which is what
  // CB_SELECTSTRING does).
  ::SendMessage(hwnd, CB_SETCURSEL, selected_item_, 0);
}

int ComboBox::GetSelectedItem() {
  return selected_item_;
}

}  // namespace views

<commit_msg>Fix a crash on 64-bit systems when an external message hook is installed. The proxying for CB_GETCOMBOXINFO is wrong and will crash. Instead, call GetComboBoxInfo.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/views/combo_box.h"

#include "base/gfx/native_theme.h"
#include "base/gfx/rect.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"

// Limit how small a combobox can be.
static const int kMinComboboxWidth = 148;

// Add a couple extra pixels to the widths of comboboxes and combobox
// dropdowns so that text isn't too crowded.
static const int kComboboxExtraPaddingX = 6;

namespace views {

ComboBox::ComboBox(Model* model)
    : model_(model), selected_item_(0), listener_(NULL), content_width_(0) {
}

ComboBox::~ComboBox() {
}

void ComboBox::SetListener(Listener* listener) {
  listener_ = listener;
}

gfx::Size ComboBox::GetPreferredSize() {
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return gfx::Size();

  COMBOBOXINFO cbi;
  memset(reinterpret_cast<unsigned char*>(&cbi), 0, sizeof(cbi));
  cbi.cbSize = sizeof(cbi);
  // Note: Don't use CB_GETCOMBOBOXINFO since that crashes on WOW64 systems
  // when you have a global message hook installed.
  GetComboBoxInfo(hwnd, &cbi);
  gfx::Rect rect_item(cbi.rcItem);
  gfx::Rect rect_button(cbi.rcButton);
  gfx::Size border = gfx::NativeTheme::instance()->GetThemeBorderSize(
      gfx::NativeTheme::MENULIST);

  // The padding value of '3' is the xy offset from the corner of the control
  // to the corner of rcItem.  It does not seem to be queryable from the theme.
  // It is consistent on all versions of Windows from 2K to Vista, and is
  // invariant with respect to the combobox border size.  We could conceivably
  // get this number from rect_item.x, but it seems fragile to depend on position
  // here, inside of the layout code.
  const int kItemOffset = 3;
  int item_to_button_distance = std::max(kItemOffset - border.width(), 0);

  // The cx computation can be read as measuring from left to right.
  int pref_width = std::max(kItemOffset + content_width_ +
                                kComboboxExtraPaddingX +
                                item_to_button_distance + rect_button.width() +
                                 border.width(), kMinComboboxWidth);
  // The two arguments to ::max below should be typically be equal.
  int pref_height = std::max(rect_item.height() + 2 * kItemOffset,
                             rect_button.height() + 2 * border.height());
  return gfx::Size(pref_width, pref_height);
}

HWND ComboBox::CreateNativeControl(HWND parent_container) {
  HWND r = ::CreateWindowEx(GetAdditionalExStyle(), L"COMBOBOX", L"",
                            WS_CHILD | WS_VSCROLL | CBS_DROPDOWNLIST,
                            0, 0, width(), height(),
                            parent_container, NULL, NULL, NULL);
  HFONT font = ResourceBundle::GetSharedInstance().
      GetFont(ResourceBundle::BaseFont).hfont();
  SendMessage(r, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);
  UpdateComboBoxFromModel(r);
  return r;
}

LRESULT ComboBox::OnCommand(UINT code, int id, HWND source) {
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return 0;

  if (code == CBN_SELCHANGE && source == hwnd) {
    LRESULT r = ::SendMessage(hwnd, CB_GETCURSEL, 0, 0);
    if (r != CB_ERR) {
      int prev_selected_item = selected_item_;
      selected_item_ = static_cast<int>(r);
      if (listener_)
        listener_->ItemChanged(this, prev_selected_item, selected_item_);
    }
  }
  return 0;
}

LRESULT ComboBox::OnNotify(int w_param, LPNMHDR l_param) {
  return 0;
}

void ComboBox::UpdateComboBoxFromModel(HWND hwnd) {
  ::SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
  ChromeFont font = ResourceBundle::GetSharedInstance().GetFont(
      ResourceBundle::BaseFont);
  int max_width = 0;
  int num_items = model_->GetItemCount(this);
  for (int i = 0; i < num_items; ++i) {
    const std::wstring& text = model_->GetItemAt(this, i);

    // Inserting the Unicode formatting characters if necessary so that the
    // text is displayed correctly in right-to-left UIs.
    std::wstring localized_text;
    const wchar_t* text_ptr = text.c_str();
    if (l10n_util::AdjustStringForLocaleDirection(text, &localized_text))
      text_ptr = localized_text.c_str();

    ::SendMessage(hwnd, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(text_ptr));
    max_width = std::max(max_width, font.GetStringWidth(text));

  }
  content_width_ = max_width;

  if (num_items > 0) {
    ::SendMessage(hwnd, CB_SETCURSEL, selected_item_, 0);

    // Set the width for the drop down while accounting for the scrollbar and
    // borders.
    if (num_items > ComboBox_GetMinVisible(hwnd))
      max_width += ::GetSystemMetrics(SM_CXVSCROLL);
    // SM_CXEDGE would not be correct here, since the dropdown is flat, not 3D.
    int kComboboxDropdownBorderSize = 1;
    max_width += 2 * kComboboxDropdownBorderSize + kComboboxExtraPaddingX;
    ::SendMessage(hwnd, CB_SETDROPPEDWIDTH, max_width, 0);
  }
}

void ComboBox::ModelChanged() {
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return;
  selected_item_ = std::min(0, model_->GetItemCount(this));
  UpdateComboBoxFromModel(hwnd);
}

void ComboBox::SetSelectedItem(int index) {
  selected_item_ = index;
  HWND hwnd = GetNativeControlHWND();
  if (!hwnd)
    return;

  // Note that we use CB_SETCURSEL and not CB_SELECTSTRING because on RTL
  // locales the strings we get from our ComboBox::Model might be augmented
  // with Unicode directionality marks before we insert them into the combo box
  // and therefore we can not assume that the string we get from
  // ComboBox::Model can be safely searched for and selected (which is what
  // CB_SELECTSTRING does).
  ::SendMessage(hwnd, CB_SETCURSEL, selected_item_, 0);
}

int ComboBox::GetSelectedItem() {
  return selected_item_;
}

}  // namespace views

<|endoftext|>


<commit_before>/**
 * @file network_util_test.cpp
 * @author Marcus edel
 *
 * Simple tests for things in the network_util file.
 */
#include <mlpack/core.hpp>

#include <mlpack/methods/ann/network_util.hpp>
#include <mlpack/methods/ann/layer/linear_layer.hpp>
#include <mlpack/methods/ann/layer/base_layer.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::ann;

BOOST_AUTO_TEST_SUITE(NetworkUtilTest);

/**
 * Test the network size auxiliary function.
 */
BOOST_AUTO_TEST_CASE(NetworkSizeTest)
{
  // // Create a two layer network without weights.
  // BaseLayer<> baseLayer1;
  // BaseLayer<> baseLayer2;
  // auto noneWeightNetwork = std::tie(baseLayer1, baseLayer2);

  // BOOST_REQUIRE_EQUAL(NetworkSize(noneWeightNetwork), 0);

  // // Create a two layer network.
  // LinearLayer<> linearLayer1(10, 10);
  // LinearLayer<> linearLayer2(10, 100);

  // // Reuse the layer form the first network.
  // auto weightNetwork = std::tie(linearLayer1, baseLayer1, linearLayer2,
  //     baseLayer2);

  // BOOST_REQUIRE_EQUAL(NetworkSize(weightNetwork), 1100);
}

/**
 * Test the layer size auxiliary function.
 */
BOOST_AUTO_TEST_CASE(LayerSizeTest)
{
  // // Create layer without weights.
  // BaseLayer<> baseLayer;
  // BOOST_REQUIRE_EQUAL(LayerSize(baseLayer, baseLayer.OutputParameter()), 0);

  // LinearLayer<> linearLayer(10, 10);
  // BOOST_REQUIRE_EQUAL(LayerSize(linearLayer,
  //     linearLayer.OutputParameter()), 100);

}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Add test case for the layer input size and network input size function.<commit_after>/**
 * @file network_util_test.cpp
 * @author Marcus edel
 *
 * Simple tests for things in the network_util file.
 */
#include <mlpack/core.hpp>

#include <mlpack/methods/ann/network_util.hpp>
#include <mlpack/methods/ann/layer/linear_layer.hpp>
#include <mlpack/methods/ann/layer/base_layer.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::ann;

BOOST_AUTO_TEST_SUITE(NetworkUtilTest);

/**
 * Test the network size auxiliary function.
 */
BOOST_AUTO_TEST_CASE(NetworkSizeTest)
{
  // Create a two layer network without weights.
  BaseLayer<> baseLayer1;
  BaseLayer<> baseLayer2;
  auto noneWeightNetwork = std::tie(baseLayer1, baseLayer2);

  BOOST_REQUIRE_EQUAL(NetworkSize(noneWeightNetwork), 0);

  // Create a two layer network.
  LinearLayer<> linearLayer1(10, 10);
  LinearLayer<> linearLayer2(10, 100);

  // Reuse the layer form the first network.
  auto weightNetwork = std::tie(linearLayer1, baseLayer1, linearLayer2,
      baseLayer2);

  BOOST_REQUIRE_EQUAL(NetworkSize(weightNetwork), 1100);
}

/**
 * Test the layer size auxiliary function.
 */
BOOST_AUTO_TEST_CASE(LayerSizeTest)
{
  // Create layer without weights.
  BaseLayer<> baseLayer;
  BOOST_REQUIRE_EQUAL(LayerSize(baseLayer, baseLayer.OutputParameter()), 0);

  // Create layer with weights.
  LinearLayer<> linearLayer(10, 10);
  BOOST_REQUIRE_EQUAL(LayerSize(linearLayer,
      linearLayer.OutputParameter()), 100);
}

/**
 * Test the network input size auxiliary function.
 */
BOOST_AUTO_TEST_CASE(NetworkInputSizeTest)
{
  // Create a two layer network without weights.
  BaseLayer<> baseLayer1;
  BaseLayer<> baseLayer2;
  auto noneWeightNetwork = std::tie(baseLayer1, baseLayer2);

  BOOST_REQUIRE_EQUAL(NetworkInputSize(noneWeightNetwork), 0);

  // Create a two layer network.
  LinearLayer<> linearLayer1(5, 10);
  LinearLayer<> linearLayer2(10, 100);

  // Reuse the layer form the first network.
  auto weightNetwork = std::tie(linearLayer1, baseLayer1, linearLayer2,
      baseLayer2);

  BOOST_REQUIRE_EQUAL(NetworkInputSize(weightNetwork), 5);
}

/**
 * Test the layer input size auxiliary function.
 */
BOOST_AUTO_TEST_CASE(LayerInputSizeTest)
{
  // Create layer without weights.
  BaseLayer<> baseLayer;
  BOOST_REQUIRE_EQUAL(LayerInputSize(baseLayer,
    baseLayer.OutputParameter()), 0);

  // Create layer with weights.
  LinearLayer<> linearLayer(5, 10);
  BOOST_REQUIRE_EQUAL(LayerInputSize(linearLayer,
      linearLayer.OutputParameter()), 5);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>#include "../../Lepus3D/Source/RenderEngine.h"
#include "../../Lepus3D/Source/Camera/FPPCamera.h"
#include "../../Lepus3D/Source/Assets.h"

using namespace LepusEngine;

int main()
{
	Lepus3D::RenderEngine engine("LepusDemo", 800, 600);

	bool isRunning = true;

	Lepus3D::Assets::ModelImporter modelImp("Models/mycube_test.obj");
	modelImp.Read();
	modelImp.Close();

	Lepus3D::Scene scene;
	Lepus3D::Material testMat("Material", "Phong");
	Lepus3D::Renderable* box = new Lepus3D::Renderable(modelImp.GetSubMesh());
	Lepus3D::Light sceneLight(Lepus3D::Vector3(0.0f, 1.25f, 0.0f), Lepus3D::Color(255, 255, 255, 255), 1.0f);
	testMat.SetAttributeF("_SpecularStrength", 0.5f);
	testMat.SetAttributeI("_SpecularShininess", 256);
	testMat.SetAttributeF3("_DiffColor", Lepus3D::Color(100, 149, 237, 255).GetVector3());
	box->GetMesh()->SetMaterial(testMat);

	Lepus3D::FPPCamera cam(*(new Lepus3D::Transform())); // init a transformable fpp camera
	cam.SetWindow(engine.GetWindowPtr()); // bind camera to window to receive input

	scene.AddLight(&sceneLight);
	scene.AddMesh(box);

	sf::Clock timer;
	float dTime; // delta time between frames
	float elapsedTime = 0.0f;

	while (isRunning)
	{
		elapsedTime += dTime = timer.restart().asSeconds(); // running time is needed for the scene light to orbit

		sceneLight.SetPosition(Lepus3D::Vector3(0.0f, 1.25f * sin(elapsedTime), 1.25f * cos(elapsedTime))); // orbit the light around the box

		engine.Update(); // update window before drawing
		cam.ProcessInput(dTime); // move camera according to input
		engine.StartScene(&cam); // set current camera, prepare engine for drawing
		engine.DrawScene(scene); // draw objects in scene
		engine.EndScene(); // finish rendering and present
		isRunning = engine.Update(); // update window and check if engine is still running
	}

	engine.Shutdown();

	return 0;
}
<commit_msg>Increased orbiting light distance<commit_after>#include "../../Lepus3D/Source/RenderEngine.h"
#include "../../Lepus3D/Source/Camera/FPPCamera.h"
#include "../../Lepus3D/Source/Assets.h"

using namespace LepusEngine;

int main()
{
	Lepus3D::RenderEngine engine("LepusDemo", 800, 600);

	bool isRunning = true;

	Lepus3D::Assets::ModelImporter modelImp("Models/mycube_test.obj");
	modelImp.Read();
	modelImp.Close();

	Lepus3D::Scene scene;
	Lepus3D::Material testMat("Material", "Phong");
	Lepus3D::Renderable* box = new Lepus3D::Renderable(modelImp.GetSubMesh());
	Lepus3D::Light sceneLight(Lepus3D::Vector3(0.0f, 2.50f, 0.0f), Lepus3D::Color(255, 255, 255, 255), 1.0f);
	testMat.SetAttributeF("_SpecularStrength", 0.5f);
	testMat.SetAttributeI("_SpecularShininess", 256);
	testMat.SetAttributeF3("_DiffColor", Lepus3D::Color(100, 149, 237, 255).GetVector3());
	box->GetMesh()->SetMaterial(testMat);

	Lepus3D::FPPCamera cam(*(new Lepus3D::Transform())); // init a transformable fpp camera
	cam.SetWindow(engine.GetWindowPtr()); // bind camera to window to receive input

	scene.AddLight(&sceneLight);
	scene.AddMesh(box);

	sf::Clock timer;
	float dTime; // delta time between frames
	float elapsedTime = 0.0f;

	while (isRunning)
	{
		elapsedTime += dTime = timer.restart().asSeconds(); // running time is needed for the scene light to orbit

		sceneLight.SetPosition(Lepus3D::Vector3(0.0f, 2.50f * sin(elapsedTime), 2.50f * cos(elapsedTime))); // orbit the light around the box

		engine.Update(); // update window before drawing
		cam.ProcessInput(dTime); // move camera according to input
		engine.StartScene(&cam); // set current camera, prepare engine for drawing
		engine.DrawScene(scene); // draw objects in scene
		engine.EndScene(); // finish rendering and present
		isRunning = engine.Update(); // update window and check if engine is still running
	}

	engine.Shutdown();

	return 0;
}
<|endoftext|>


<commit_before>/*!
 * Copyright 2015 by Contributors
 * \file regression.cc
 * \brief Definition of single-value regression and classification objectives.
 * \author Tianqi Chen, Kailong Chen
 */
#include <dmlc/omp.h>
#include <xgboost/logging.h>
#include <xgboost/objective.h>
#include <vector>
#include <algorithm>
#include <utility>
#include "../common/math.h"

namespace xgboost {
namespace obj {

DMLC_REGISTRY_FILE_TAG(regression_obj);

// common regressions
// linear regression
struct LinearSquareLoss {
  static float PredTransform(float x) { return x; }
  static bool CheckLabel(float x) { return true; }
  static float FirstOrderGradient(float predt, float label) { return predt - label; }
  static float SecondOrderGradient(float predt, float label) { return 1.0f; }
  static float ProbToMargin(float base_score) { return base_score; }
  static const char* LabelErrorMsg() { return ""; }
  static const char* DefaultEvalMetric() { return "rmse"; }
};
// logistic loss for probability regression task
struct LogisticRegression {
  static float PredTransform(float x) { return common::Sigmoid(x); }
  static bool CheckLabel(float x) { return x >= 0.0f && x <= 1.0f; }
  static float FirstOrderGradient(float predt, float label) { return predt - label; }
  static float SecondOrderGradient(float predt, float label) {
    const float eps = 1e-16f;
    return std::max(predt * (1.0f - predt), eps);
  }
  static float ProbToMargin(float base_score) {
    CHECK(base_score > 0.0f && base_score < 1.0f)
        << "base_score must be in (0,1) for logistic loss";
    return -std::log(1.0f / base_score - 1.0f);
  }
  static const char* LabelErrorMsg() {
    return "label must be in [0,1] for logistic regression";
  }
  static const char* DefaultEvalMetric() { return "rmse"; }
};
// logistic loss for binary classification task.
struct LogisticClassification : public LogisticRegression {
  static const char* DefaultEvalMetric() { return "error"; }
};
// logistic loss, but predict un-transformed margin
struct LogisticRaw : public LogisticRegression {
  static float PredTransform(float x) { return x; }
  static float FirstOrderGradient(float predt, float label) {
    predt = common::Sigmoid(predt);
    return predt - label;
  }
  static float SecondOrderGradient(float predt, float label) {
    const float eps = 1e-16f;
    predt = common::Sigmoid(predt);
    return std::max(predt * (1.0f - predt), eps);
  }
  static const char* DefaultEvalMetric() { return "auc"; }
};

struct RegLossParam : public dmlc::Parameter<RegLossParam> {
  float scale_pos_weight;
  // declare parameters
  DMLC_DECLARE_PARAMETER(RegLossParam) {
    DMLC_DECLARE_FIELD(scale_pos_weight).set_default(1.0f).set_lower_bound(0.0f)
        .describe("Scale the weight of positive examples by this factor");
  }
};

// regression los function
template<typename Loss>
class RegLossObj : public ObjFunction {
 public:
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
    param_.InitAllowUnknown(args);
  }
  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size())
        << "labels are not correctly provided"
        << "preds.size=" << preds.size() << ", label.size=" << info.labels.size();
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size());
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) {
      float p = Loss::PredTransform(preds[i]);
      float w = info.GetWeight(i);
      if (info.labels[i] == 1.0f) w *= param_.scale_pos_weight;
      if (!Loss::CheckLabel(info.labels[i])) label_correct = false;
      out_gpair->at(i) = bst_gpair(Loss::FirstOrderGradient(p, info.labels[i]) * w,
                                   Loss::SecondOrderGradient(p, info.labels[i]) * w);
    }
    if (!label_correct) {
      LOG(FATAL) << Loss::LabelErrorMsg();
    }
  }
  const char* DefaultEvalMetric() const override {
    return Loss::DefaultEvalMetric();
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const bst_omp_uint ndata = static_cast<bst_omp_uint>(preds.size());
    #pragma omp parallel for schedule(static)
    for (bst_omp_uint j = 0; j < ndata; ++j) {
      preds[j] = Loss::PredTransform(preds[j]);
    }
  }
  float ProbToMargin(float base_score) const override {
    return Loss::ProbToMargin(base_score);
  }

 protected:
  RegLossParam param_;
};

// register the ojective functions
DMLC_REGISTER_PARAMETER(RegLossParam);

XGBOOST_REGISTER_OBJECTIVE(LinearRegression, "reg:linear")
.describe("Linear regression.")
.set_body([]() { return new RegLossObj<LinearSquareLoss>(); });

XGBOOST_REGISTER_OBJECTIVE(LogisticRegression, "reg:logistic")
.describe("Logistic regression for probability regression task.")
.set_body([]() { return new RegLossObj<LogisticRegression>(); });

XGBOOST_REGISTER_OBJECTIVE(LogisticClassification, "binary:logistic")
.describe("Logistic regression for binary classification task.")
.set_body([]() { return new RegLossObj<LogisticClassification>(); });

XGBOOST_REGISTER_OBJECTIVE(LogisticRaw, "binary:logitraw")
.describe("Logistic regression for classification, output score before logistic transformation")
.set_body([]() { return new RegLossObj<LogisticRaw>(); });

// declare parameter
struct PoissonRegressionParam : public dmlc::Parameter<PoissonRegressionParam> {
  float max_delta_step;
  DMLC_DECLARE_PARAMETER(PoissonRegressionParam) {
    DMLC_DECLARE_FIELD(max_delta_step).set_lower_bound(0.0f)
        .describe("Maximum delta step we allow each weight estimation to be." \
                  " This parameter is required for possion regression.");
  }
};

// poisson regression for count
class PoissonRegression : public ObjFunction {
 public:
  // declare functions
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
    param_.InitAllowUnknown(args);
  }

  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size()) << "labels are not correctly provided";
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) { // NOLINT(*)
      float p = preds[i];
      float w = info.GetWeight(i);
      float y = info.labels[i];
      if (y >= 0.0f) {
        out_gpair->at(i) = bst_gpair((std::exp(p) - y) * w,
                                     std::exp(p + param_.max_delta_step) * w);
      } else {
        label_correct = false;
      }
    }
    CHECK(label_correct) << "PoissonRegression: label must be nonnegative";
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const long ndata = static_cast<long>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (long j = 0; j < ndata; ++j) {  // NOLINT(*)
      preds[j] = std::exp(preds[j]);
    }
  }
  void EvalTransform(std::vector<float> *io_preds) override {
    PredTransform(io_preds);
  }
  float ProbToMargin(float base_score) const override {
    return std::log(base_score);
  }
  const char* DefaultEvalMetric(void) const override {
    return "poisson-nloglik";
  }

 private:
  PoissonRegressionParam param_;
};

// register the ojective functions
DMLC_REGISTER_PARAMETER(PoissonRegressionParam);

XGBOOST_REGISTER_OBJECTIVE(PoissonRegression, "count:poisson")
.describe("Possion regression for count data.")
.set_body([]() { return new PoissonRegression(); });

// gamma regression
class GammaRegression : public ObjFunction {
 public:
  // declare functions
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
  }

  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size()) << "labels are not correctly provided";
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) { // NOLINT(*)
      float p = preds[i];
      float w = info.GetWeight(i);
      float y = info.labels[i];
      if (y >= 0.0f) {
        out_gpair->at(i) = bst_gpair((1 - y / std::exp(p)) * w, y / std::exp(p) * w);
      } else {
        label_correct = false;
      }
    }
    CHECK(label_correct) << "GammaRegression: label must be positive";
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const long ndata = static_cast<long>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (long j = 0; j < ndata; ++j) {  // NOLINT(*)
      preds[j] = std::exp(preds[j]);
    }
  }
  void EvalTransform(std::vector<float> *io_preds) override {
    PredTransform(io_preds);
  }
  float ProbToMargin(float base_score) const override {
    return std::log(base_score);
  }
  const char* DefaultEvalMetric(void) const override {
    return "gamma-nloglik";
  }
};

// register the ojective functions
XGBOOST_REGISTER_OBJECTIVE(GammaRegression, "reg:gamma")
.describe("Gamma regression for severity data.")
.set_body([]() { return new GammaRegression(); });

// declare parameter
struct TweedieRegressionParam : public dmlc::Parameter<TweedieRegressionParam> {
  float tweedie_variance_power;
  DMLC_DECLARE_PARAMETER(TweedieRegressionParam) {
    DMLC_DECLARE_FIELD(tweedie_variance_power).set_range(1.0f, 2.0f).set_default(1.5f)
      .describe("Tweedie variance power.  Must be between in range [1, 2).");
  }
};

// tweedie regression
class TweedieRegression : public ObjFunction {
 public:
  // declare functions
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
    param_.InitAllowUnknown(args);
  }

  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size()) << "labels are not correctly provided";
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) { // NOLINT(*)
      float p = preds[i];
      float w = info.GetWeight(i);
      float y = info.labels[i];
      float rho = param_.tweedie_variance_power;
      if (y >= 0.0f) {
        float grad = -y * std::exp((1 - rho) * p) + std::exp((2 - rho) * p);
        float hess = -y * (1 - rho) * std::exp((1 - rho) * p) + (2 - rho) * std::exp((2 - rho) * p);
        out_gpair->at(i) = bst_gpair(grad * w, hess * w);
      } else {
        label_correct = false;
      }
    }
    CHECK(label_correct) << "TweedieRegression: label must be nonnegative";
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const long ndata = static_cast<long>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (long j = 0; j < ndata; ++j) {  // NOLINT(*)
      preds[j] = std::exp(preds[j]);
    }
  }
  const char* DefaultEvalMetric(void) const override {
    std::ostringstream os;
    os << "tweedie-nloglik@" << param_.tweedie_variance_power;
    std::string metric = os.str();
    return metric.c_str();
  }

 private:
  TweedieRegressionParam param_;
};

// register the ojective functions
DMLC_REGISTER_PARAMETER(TweedieRegressionParam);

XGBOOST_REGISTER_OBJECTIVE(TweedieRegression, "reg:tweedie")
.describe("Tweedie regression for insurance data.")
.set_body([]() { return new TweedieRegression(); });
}  // namespace obj
}  // namespace xgboost
<commit_msg>add default to poisson -> max_delta_step to enable loading/saving/dumping of model (#1781)<commit_after>/*!
 * Copyright 2015 by Contributors
 * \file regression.cc
 * \brief Definition of single-value regression and classification objectives.
 * \author Tianqi Chen, Kailong Chen
 */
#include <dmlc/omp.h>
#include <xgboost/logging.h>
#include <xgboost/objective.h>
#include <vector>
#include <algorithm>
#include <utility>
#include "../common/math.h"

namespace xgboost {
namespace obj {

DMLC_REGISTRY_FILE_TAG(regression_obj);

// common regressions
// linear regression
struct LinearSquareLoss {
  static float PredTransform(float x) { return x; }
  static bool CheckLabel(float x) { return true; }
  static float FirstOrderGradient(float predt, float label) { return predt - label; }
  static float SecondOrderGradient(float predt, float label) { return 1.0f; }
  static float ProbToMargin(float base_score) { return base_score; }
  static const char* LabelErrorMsg() { return ""; }
  static const char* DefaultEvalMetric() { return "rmse"; }
};
// logistic loss for probability regression task
struct LogisticRegression {
  static float PredTransform(float x) { return common::Sigmoid(x); }
  static bool CheckLabel(float x) { return x >= 0.0f && x <= 1.0f; }
  static float FirstOrderGradient(float predt, float label) { return predt - label; }
  static float SecondOrderGradient(float predt, float label) {
    const float eps = 1e-16f;
    return std::max(predt * (1.0f - predt), eps);
  }
  static float ProbToMargin(float base_score) {
    CHECK(base_score > 0.0f && base_score < 1.0f)
        << "base_score must be in (0,1) for logistic loss";
    return -std::log(1.0f / base_score - 1.0f);
  }
  static const char* LabelErrorMsg() {
    return "label must be in [0,1] for logistic regression";
  }
  static const char* DefaultEvalMetric() { return "rmse"; }
};
// logistic loss for binary classification task.
struct LogisticClassification : public LogisticRegression {
  static const char* DefaultEvalMetric() { return "error"; }
};
// logistic loss, but predict un-transformed margin
struct LogisticRaw : public LogisticRegression {
  static float PredTransform(float x) { return x; }
  static float FirstOrderGradient(float predt, float label) {
    predt = common::Sigmoid(predt);
    return predt - label;
  }
  static float SecondOrderGradient(float predt, float label) {
    const float eps = 1e-16f;
    predt = common::Sigmoid(predt);
    return std::max(predt * (1.0f - predt), eps);
  }
  static const char* DefaultEvalMetric() { return "auc"; }
};

struct RegLossParam : public dmlc::Parameter<RegLossParam> {
  float scale_pos_weight;
  // declare parameters
  DMLC_DECLARE_PARAMETER(RegLossParam) {
    DMLC_DECLARE_FIELD(scale_pos_weight).set_default(1.0f).set_lower_bound(0.0f)
        .describe("Scale the weight of positive examples by this factor");
  }
};

// regression los function
template<typename Loss>
class RegLossObj : public ObjFunction {
 public:
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
    param_.InitAllowUnknown(args);
  }
  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size())
        << "labels are not correctly provided"
        << "preds.size=" << preds.size() << ", label.size=" << info.labels.size();
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size());
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) {
      float p = Loss::PredTransform(preds[i]);
      float w = info.GetWeight(i);
      if (info.labels[i] == 1.0f) w *= param_.scale_pos_weight;
      if (!Loss::CheckLabel(info.labels[i])) label_correct = false;
      out_gpair->at(i) = bst_gpair(Loss::FirstOrderGradient(p, info.labels[i]) * w,
                                   Loss::SecondOrderGradient(p, info.labels[i]) * w);
    }
    if (!label_correct) {
      LOG(FATAL) << Loss::LabelErrorMsg();
    }
  }
  const char* DefaultEvalMetric() const override {
    return Loss::DefaultEvalMetric();
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const bst_omp_uint ndata = static_cast<bst_omp_uint>(preds.size());
    #pragma omp parallel for schedule(static)
    for (bst_omp_uint j = 0; j < ndata; ++j) {
      preds[j] = Loss::PredTransform(preds[j]);
    }
  }
  float ProbToMargin(float base_score) const override {
    return Loss::ProbToMargin(base_score);
  }

 protected:
  RegLossParam param_;
};

// register the ojective functions
DMLC_REGISTER_PARAMETER(RegLossParam);

XGBOOST_REGISTER_OBJECTIVE(LinearRegression, "reg:linear")
.describe("Linear regression.")
.set_body([]() { return new RegLossObj<LinearSquareLoss>(); });

XGBOOST_REGISTER_OBJECTIVE(LogisticRegression, "reg:logistic")
.describe("Logistic regression for probability regression task.")
.set_body([]() { return new RegLossObj<LogisticRegression>(); });

XGBOOST_REGISTER_OBJECTIVE(LogisticClassification, "binary:logistic")
.describe("Logistic regression for binary classification task.")
.set_body([]() { return new RegLossObj<LogisticClassification>(); });

XGBOOST_REGISTER_OBJECTIVE(LogisticRaw, "binary:logitraw")
.describe("Logistic regression for classification, output score before logistic transformation")
.set_body([]() { return new RegLossObj<LogisticRaw>(); });

// declare parameter
struct PoissonRegressionParam : public dmlc::Parameter<PoissonRegressionParam> {
  float max_delta_step;
  DMLC_DECLARE_PARAMETER(PoissonRegressionParam) {
    DMLC_DECLARE_FIELD(max_delta_step).set_lower_bound(0.0f).set_default(0.7f)
        .describe("Maximum delta step we allow each weight estimation to be." \
                  " This parameter is required for possion regression.");
  }
};

// poisson regression for count
class PoissonRegression : public ObjFunction {
 public:
  // declare functions
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
    param_.InitAllowUnknown(args);
  }

  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size()) << "labels are not correctly provided";
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) { // NOLINT(*)
      float p = preds[i];
      float w = info.GetWeight(i);
      float y = info.labels[i];
      if (y >= 0.0f) {
        out_gpair->at(i) = bst_gpair((std::exp(p) - y) * w,
                                     std::exp(p + param_.max_delta_step) * w);
      } else {
        label_correct = false;
      }
    }
    CHECK(label_correct) << "PoissonRegression: label must be nonnegative";
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const long ndata = static_cast<long>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (long j = 0; j < ndata; ++j) {  // NOLINT(*)
      preds[j] = std::exp(preds[j]);
    }
  }
  void EvalTransform(std::vector<float> *io_preds) override {
    PredTransform(io_preds);
  }
  float ProbToMargin(float base_score) const override {
    return std::log(base_score);
  }
  const char* DefaultEvalMetric(void) const override {
    return "poisson-nloglik";
  }

 private:
  PoissonRegressionParam param_;
};

// register the ojective functions
DMLC_REGISTER_PARAMETER(PoissonRegressionParam);

XGBOOST_REGISTER_OBJECTIVE(PoissonRegression, "count:poisson")
.describe("Possion regression for count data.")
.set_body([]() { return new PoissonRegression(); });

// gamma regression
class GammaRegression : public ObjFunction {
 public:
  // declare functions
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
  }

  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size()) << "labels are not correctly provided";
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) { // NOLINT(*)
      float p = preds[i];
      float w = info.GetWeight(i);
      float y = info.labels[i];
      if (y >= 0.0f) {
        out_gpair->at(i) = bst_gpair((1 - y / std::exp(p)) * w, y / std::exp(p) * w);
      } else {
        label_correct = false;
      }
    }
    CHECK(label_correct) << "GammaRegression: label must be positive";
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const long ndata = static_cast<long>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (long j = 0; j < ndata; ++j) {  // NOLINT(*)
      preds[j] = std::exp(preds[j]);
    }
  }
  void EvalTransform(std::vector<float> *io_preds) override {
    PredTransform(io_preds);
  }
  float ProbToMargin(float base_score) const override {
    return std::log(base_score);
  }
  const char* DefaultEvalMetric(void) const override {
    return "gamma-nloglik";
  }
};

// register the ojective functions
XGBOOST_REGISTER_OBJECTIVE(GammaRegression, "reg:gamma")
.describe("Gamma regression for severity data.")
.set_body([]() { return new GammaRegression(); });

// declare parameter
struct TweedieRegressionParam : public dmlc::Parameter<TweedieRegressionParam> {
  float tweedie_variance_power;
  DMLC_DECLARE_PARAMETER(TweedieRegressionParam) {
    DMLC_DECLARE_FIELD(tweedie_variance_power).set_range(1.0f, 2.0f).set_default(1.5f)
      .describe("Tweedie variance power.  Must be between in range [1, 2).");
  }
};

// tweedie regression
class TweedieRegression : public ObjFunction {
 public:
  // declare functions
  void Configure(const std::vector<std::pair<std::string, std::string> >& args) override {
    param_.InitAllowUnknown(args);
  }

  void GetGradient(const std::vector<float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
    CHECK_NE(info.labels.size(), 0) << "label set cannot be empty";
    CHECK_EQ(preds.size(), info.labels.size()) << "labels are not correctly provided";
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) { // NOLINT(*)
      float p = preds[i];
      float w = info.GetWeight(i);
      float y = info.labels[i];
      float rho = param_.tweedie_variance_power;
      if (y >= 0.0f) {
        float grad = -y * std::exp((1 - rho) * p) + std::exp((2 - rho) * p);
        float hess = -y * (1 - rho) * std::exp((1 - rho) * p) + (2 - rho) * std::exp((2 - rho) * p);
        out_gpair->at(i) = bst_gpair(grad * w, hess * w);
      } else {
        label_correct = false;
      }
    }
    CHECK(label_correct) << "TweedieRegression: label must be nonnegative";
  }
  void PredTransform(std::vector<float> *io_preds) override {
    std::vector<float> &preds = *io_preds;
    const long ndata = static_cast<long>(preds.size()); // NOLINT(*)
    #pragma omp parallel for schedule(static)
    for (long j = 0; j < ndata; ++j) {  // NOLINT(*)
      preds[j] = std::exp(preds[j]);
    }
  }
  const char* DefaultEvalMetric(void) const override {
    std::ostringstream os;
    os << "tweedie-nloglik@" << param_.tweedie_variance_power;
    std::string metric = os.str();
    return metric.c_str();
  }

 private:
  TweedieRegressionParam param_;
};

// register the ojective functions
DMLC_REGISTER_PARAMETER(TweedieRegressionParam);

XGBOOST_REGISTER_OBJECTIVE(TweedieRegression, "reg:tweedie")
.describe("Tweedie regression for insurance data.")
.set_body([]() { return new TweedieRegression(); });
}  // namespace obj
}  // namespace xgboost
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cassert>
#include <stdexcept>
#include <map>
#include <unordered_map>  // TODO Replace with something really fast.
#include <set>
#include "graph.hpp"

namespace simple_graph {

template <bool Dir, typename V, typename E, typename W>
class ListGraph : public Graph<Dir, V, E, W> {
    using Edges = std::map<vertex_index_t, std::map<vertex_index_t, Edge<E, W>>>;
    using FilteredEdges = std::unordered_map<vertex_index_t, std::set<vertex_index_t>>;

private:
    /**
     * Service class to implement iterator.
     */
    class ListEdgesWrapper : public Graph<Dir, V, E, W>::EdgesWrapper {
    private:
        /**
         * Iterator implementation for edges.
         */
        class EdgeIterator : public IIterator<Edge<E, W>> {
            using Iterator1 = typename Edges::iterator;
            using Iterator2 = typename Edges::mapped_type::iterator;

        public:
            /**
             * Constructor.
             *
             * @param edges All edges in the graph.
             * @param filtered_edges All filtered edges in the graph.
             * @param is_end Flag indicating that iterator traversed all edges.
             */
            EdgeIterator(Edges *edges, FilteredEdges *filtered_edges, bool is_end)
                : edges_(edges), filtered_edges_(filtered_edges), is_end_(is_end)
            {
                if (is_end_) {
                    return;
                }

                // TODO Use const_iterator.
                it1_ = edges_->begin();
                if (it1_ == edges_->end()) {
                    is_end_ = true;
                }
                else {
                    it2_ = it1_->second.begin();
                    assert(it2_ != it1_->second.end());
                }
            }

            /**
             * Check if two iterators are equal to each other.
             *
             * @param it Iterator to compare with.
             * @return True if iterators contain the same edge, false otherwise.
             */
            bool operator==(const IIterator<Edge<E, W>> &it) const override
            {
                const auto *tmp = dynamic_cast<const EdgeIterator*>(&it);
                return tmp && is_end_ == tmp->is_end_;
            }

            /**
             * Check if two iterators differ from each other.
             *
             * @param it Iterator to compare with.
             * @return True if iterators differ, false otherwise.
             */
            bool operator!=(const IIterator<Edge<E, W>> &it) const override
            {
                return !this->operator==(it);
            }

            /**
             * Increment iterator.
             *
             * @return Reference to iterator itself.
             */
            IIterator<Edge<E, W>> &operator++() override
            {
                if (is_end_) {
                    return *this;
                }

                /// Loop is needed for ignoring filtered edges.
                while (!is_end_) {
                    ++it2_;

                    /// Traversed all edges for an index, go to next index.
                    if (it2_ == it1_->second.end()) {
                        ++it1_;
                        if (it1_ != edges_->end()) {
                            it2_ = it1_->second.begin();
                            assert(it2_ != it1_->second.end());
                        }
                        /// Traversed all edges.
                        else {
                            is_end_ = true;
                        }
                    }

                    /// Ignore filtered edges.
                    if (!is_end_ && (filtered_edges_->count(it2_->second.idx1()) > 0)
                            && (filtered_edges_->at(it2_->second.idx1()).count(it2_->second.idx2()) > 0)) {
                        continue;
                    }

                    return *this;
                }

                return *this;
            }

            /**
             * Get underlying edge.
             *
             * @return Current edge.
             */
            Edge<E, W> &operator*() override
            {
                return it2_->second;
            }

        private:
            Edges *edges_;
            FilteredEdges *filtered_edges_;
            bool is_end_;
            Iterator1 it1_;
            Iterator2 it2_;
        };

    public:
        explicit ListEdgesWrapper(Edges *edges, FilteredEdges *filtered_edges)
            : edges_(edges), filtered_edges_(filtered_edges) {}

        IteratorWrapper<Edge<E, W>> begin() override
        {
            IteratorWrapper<Edge<E, W>> iter(std::make_shared<EdgeIterator>(
                    EdgeIterator(edges_, filtered_edges_, false)));
            return iter;
        }

        IteratorWrapper<Edge<E, W>> end() override
        {
            IteratorWrapper<Edge<E, W>> iter(std::make_shared<EdgeIterator>(
                    EdgeIterator(edges_, filtered_edges_, true)));
            return iter;
        }

    private:
        Edges *edges_;
        FilteredEdges *filtered_edges_;
    };

public:
    ListGraph() : vertex_num_(0), vertices_(), inbounds_(), outbounds_(), edges_(), filtered_edges_(),
            edges_wrapper_(&edges_, &filtered_edges_) {}

    void add_vertex(Vertex<V> vertex) override
    {
        if (vertex.idx() == static_cast<vertex_index_t >(-1)) {
            throw std::out_of_range("Vertex with invalid index");
        }

        if (vertices_.count(vertex.idx()) == 0) {
            ++vertex_num_;
        }
        vertices_.emplace(vertex.idx(), std::move(vertex));
        inbounds_[vertex.idx()] = std::set<vertex_index_t>();
        outbounds_[vertex.idx()] = std::set<vertex_index_t>();
    }

    void rm_vertex(vertex_index_t idx) override
    {
        if (vertices_.count(idx) == 0) {
            // FIXME Exception is highly ineffective.
            throw std::out_of_range("Vertex index is not presented");
        }

        // TODO Use inbounds_ and outbounds_.
        for (const auto &v : vertices_) {
            /// Remove edges 'idx -> some_vertex'.
            if ((edges_.count(idx) > 0) && (edges_.at(idx).count(v.first) > 0)) {
                rm_edge(edges_.at(idx).at(v.first));
            }
            /// Remove edges 'some_vertex -> idx'.
            if ((edges_.count(v.first) > 0) && (edges_.at(v.first).count(idx) > 0)) {
                rm_edge(edges_.at(v.first).at(idx));
            }
        }

        vertices_.erase(idx);
        assert(vertex_num_ > 0);
        --vertex_num_;
    }

    std::set<vertex_index_t> inbounds(vertex_index_t idx) const override
    {
        if (inbounds_.count(idx) == 0) {
            return {};
        }

        std::set<vertex_index_t> res;
        for (const auto &idx2 : inbounds_.at(idx)) {
            if ((filtered_edges_.count(idx2) == 0) || (filtered_edges_.at(idx2).count(idx) == 0)) {
                res.insert(idx2);
            }
        }

        return res;
    }

    std::set<vertex_index_t> outbounds(vertex_index_t idx, int mode) const override
    {
        if (outbounds_.count(idx) == 0) {
            return {};
        }

        /// No filters were applied, return all outbounds.
        if ((mode == 1) || (filtered_edges_.count(idx) == 0)) {
            return outbounds_.at(idx);
        }

        /// Return all outbounds except filtered ones.
        std::set<vertex_index_t> res;
        for (const auto &idx2 : outbounds_.at(idx)) {
            if (filtered_edges_.at(idx).count(idx2) == 0) {
                res.insert(idx2);
            }
        }

        return res;
    }

    const Vertex<V> &vertex(vertex_index_t idx) const override
    {
        return vertices_.at(idx);
    }

    size_t vertex_num() const override { return vertex_num_; };

    void add_edge(Edge<E, W> edge) override
    {
        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }
        inbounds_[edge.idx2()].insert(edge.idx1());
        outbounds_[edge.idx1()].insert(edge.idx2());
        if (!Dir) {
            inbounds_[edge.idx1()].insert(edge.idx2());
            outbounds_[edge.idx2()].insert(edge.idx1());
        }

        /// Store undirected edge as min_idx->max_idx.
        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        edges_[edge.idx1()].emplace(edge.idx2(), std::move(edge));
    }

    const Edge<E, W> &edge(vertex_index_t idx1, vertex_index_t idx2) const override
    {
        if (Dir) {
            return edges_.at(idx1).at(idx2);
        }
        else {
            auto p = std::minmax(idx1, idx2);
            return edges_.at(p.first).at(p.second);
        }
    }

    bool edge_exists(Edge<E, W> edge) const override
    {
        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }
        return (edges_.count(edge.idx1()) > 0) && (edges_.at(edge.idx1()).count(edge.idx2()) > 0);
    }

    /**
     * @brief Remove specified edge from the graph
     * @param edge Edge to remove.
     */
    void rm_edge(Edge<E, W> edge) override
    {
        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }

        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        if ((edges_.count(edge.idx1()) == 0) || (edges_.at(edge.idx1()).count(edge.idx2()) == 0)) {
            return;
        }

        outbounds_[edge.idx1()].erase(edge.idx2());
        if (!Dir) {
            outbounds_[edge.idx2()].erase(edge.idx1());
        }

        inbounds_[edge.idx2()].erase(edge.idx1());
        if (!Dir) {
            inbounds_[edge.idx1()].erase(edge.idx2());
        }

        edges_[edge.idx1()].erase(edge.idx2());
        if (edges_[edge.idx1()].size() == 0) {
            edges_.erase(edge.idx1());
        }
    }

    /**
     * Get number of edges in the graph.
     *
     * @return Number of edges.
     * @note Filtered edges are not taken into consideration.
     */
    size_t edge_num() const
    {
        return edges_.size();
    }

    /**
     * @brief Temporarily remove specified edge from the graph.
     * @param edge Edge to filter out.
     * @return False if edge is invalid or is not present in the graph, true otherwise.
     * @note If edge is valid, it is added to filtered edges regardless of it's presence in the graph.
     */
    bool filter_edge(Edge<E, W> edge) override
    {
        bool rc = true;

        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }

        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        filtered_edges_[edge.idx1()].insert(edge.idx2());

        /// Check if edge was actually filtered out.
        if (!edges_.count(edge.idx1()) || !edges_.at(edge.idx1()).count(edge.idx2())) {
            rc = false;
        }

        return rc;
    }

    /**
     * @brief Temporarily remove specified edges from the graph.
     * @param edges Edges to filter out.
     * @return True if all edges filtered out, false otherwise.
     */
    bool filter_edges(const std::vector<Edge<E, W>> &edges) override
    {
        bool rc = true;

        for (const auto &edge : edges) {
            if (!filter_edge(edge)) {
                rc = false;
            }
        }

        return rc;
    }

    /**
     * @brief Restore temporarily removed edge.
     * @param edge Edge to restore.
     */
    bool restore_edge(Edge<E, W> edge) override
    {
        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }

        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        if ((filtered_edges_.count(edge.idx1()) > 0) && (filtered_edges_.at(edge.idx1()).count(edge.idx2()) > 0)) {
            filtered_edges_[edge.idx1()].erase(edge.idx2());
            if (filtered_edges_.at(edge.idx1()).size() == 0) {
                filtered_edges_.erase(edge.idx1());
            }
            return true;
        }

        return false;
    }

    /**
     * @brief Restore temporarily removed edges.
     * @param edges
     */
    bool restore_edges(const std::vector<Edge<E, W>> &edges) override
    {
        bool rc = true;

        for (const auto &edge : edges) {
            if (!restore_edge(edge)) {
                rc = false;
            }
        }

        return rc;
    }

    /**
     * @brief Restore all temporarily removed edges.
     * @param edges
     */
    void restore_edges() override
    {
        filtered_edges_.clear();
    }

    /**
     *
     * @return
     */
    typename Graph<Dir, V, E, W>::EdgesWrapper &edges() override
    {
        return edges_wrapper_;
    }

private:
    vertex_index_t vertex_num_;
    std::unordered_map<vertex_index_t, Vertex<V>> vertices_;
    std::unordered_map<vertex_index_t, std::set<vertex_index_t>> inbounds_;
    std::unordered_map<vertex_index_t, std::set<vertex_index_t>> outbounds_;
    Edges edges_;
    FilteredEdges filtered_edges_;
    ListEdgesWrapper edges_wrapper_;
};

}  // namespace simple_graph
<commit_msg>Use unordered_map to store edges<commit_after>#pragma once

#include <algorithm>
#include <cassert>
#include <stdexcept>
#include <map>
#include <unordered_map>  // TODO Replace with something really fast.
#include <set>
#include "graph.hpp"

namespace simple_graph {

template <bool Dir, typename V, typename E, typename W>
class ListGraph : public Graph<Dir, V, E, W> {
    using Edges = std::unordered_map<vertex_index_t, std::unordered_map<vertex_index_t, Edge<E, W>>>;
    using FilteredEdges = std::unordered_map<vertex_index_t, std::set<vertex_index_t>>;

private:
    /**
     * Service class to implement iterator.
     */
    class ListEdgesWrapper : public Graph<Dir, V, E, W>::EdgesWrapper {
    private:
        /**
         * Iterator implementation for edges.
         */
        class EdgeIterator : public IIterator<Edge<E, W>> {
            using Iterator1 = typename Edges::iterator;
            using Iterator2 = typename Edges::mapped_type::iterator;

        public:
            /**
             * Constructor.
             *
             * @param edges All edges in the graph.
             * @param filtered_edges All filtered edges in the graph.
             * @param is_end Flag indicating that iterator traversed all edges.
             */
            EdgeIterator(Edges *edges, FilteredEdges *filtered_edges, bool is_end)
                : edges_(edges), filtered_edges_(filtered_edges), is_end_(is_end)
            {
                if (is_end_) {
                    return;
                }

                // TODO Use const_iterator.
                it1_ = edges_->begin();
                if (it1_ == edges_->end()) {
                    is_end_ = true;
                }
                else {
                    it2_ = it1_->second.begin();
                    assert(it2_ != it1_->second.end());
                }
            }

            /**
             * Check if two iterators are equal to each other.
             *
             * @param it Iterator to compare with.
             * @return True if iterators contain the same edge, false otherwise.
             */
            bool operator==(const IIterator<Edge<E, W>> &it) const override
            {
                const auto *tmp = dynamic_cast<const EdgeIterator*>(&it);
                return tmp && is_end_ == tmp->is_end_;
            }

            /**
             * Check if two iterators differ from each other.
             *
             * @param it Iterator to compare with.
             * @return True if iterators differ, false otherwise.
             */
            bool operator!=(const IIterator<Edge<E, W>> &it) const override
            {
                return !this->operator==(it);
            }

            /**
             * Increment iterator.
             *
             * @return Reference to iterator itself.
             */
            IIterator<Edge<E, W>> &operator++() override
            {
                if (is_end_) {
                    return *this;
                }

                /// Loop is needed for ignoring filtered edges.
                while (!is_end_) {
                    ++it2_;

                    /// Traversed all edges for an index, go to next index.
                    if (it2_ == it1_->second.end()) {
                        ++it1_;
                        if (it1_ != edges_->end()) {
                            it2_ = it1_->second.begin();
                            assert(it2_ != it1_->second.end());
                        }
                        /// Traversed all edges.
                        else {
                            is_end_ = true;
                        }
                    }

                    /// Ignore filtered edges.
                    if (!is_end_ && (filtered_edges_->count(it2_->second.idx1()) > 0)
                            && (filtered_edges_->at(it2_->second.idx1()).count(it2_->second.idx2()) > 0)) {
                        continue;
                    }

                    return *this;
                }

                return *this;
            }

            /**
             * Get underlying edge.
             *
             * @return Current edge.
             */
            Edge<E, W> &operator*() override
            {
                return it2_->second;
            }

        private:
            Edges *edges_;
            FilteredEdges *filtered_edges_;
            bool is_end_;
            Iterator1 it1_;
            Iterator2 it2_;
        };

    public:
        explicit ListEdgesWrapper(Edges *edges, FilteredEdges *filtered_edges)
            : edges_(edges), filtered_edges_(filtered_edges) {}

        IteratorWrapper<Edge<E, W>> begin() override
        {
            IteratorWrapper<Edge<E, W>> iter(std::make_shared<EdgeIterator>(
                    EdgeIterator(edges_, filtered_edges_, false)));
            return iter;
        }

        IteratorWrapper<Edge<E, W>> end() override
        {
            IteratorWrapper<Edge<E, W>> iter(std::make_shared<EdgeIterator>(
                    EdgeIterator(edges_, filtered_edges_, true)));
            return iter;
        }

    private:
        Edges *edges_;
        FilteredEdges *filtered_edges_;
    };

public:
    ListGraph() : vertex_num_(0), vertices_(), inbounds_(), outbounds_(), edges_(), filtered_edges_(),
            edges_wrapper_(&edges_, &filtered_edges_) {}

    void add_vertex(Vertex<V> vertex) override
    {
        if (vertex.idx() == static_cast<vertex_index_t >(-1)) {
            throw std::out_of_range("Vertex with invalid index");
        }

        if (vertices_.count(vertex.idx()) == 0) {
            ++vertex_num_;
        }
        vertices_.emplace(vertex.idx(), std::move(vertex));
        inbounds_[vertex.idx()] = std::set<vertex_index_t>();
        outbounds_[vertex.idx()] = std::set<vertex_index_t>();
    }

    void rm_vertex(vertex_index_t idx) override
    {
        if (vertices_.count(idx) == 0) {
            // FIXME Exception is highly ineffective.
            throw std::out_of_range("Vertex index is not presented");
        }

        // TODO Use inbounds_ and outbounds_.
        for (const auto &v : vertices_) {
            /// Remove edges 'idx -> some_vertex'.
            if ((edges_.count(idx) > 0) && (edges_.at(idx).count(v.first) > 0)) {
                rm_edge(edges_.at(idx).at(v.first));
            }
            /// Remove edges 'some_vertex -> idx'.
            if ((edges_.count(v.first) > 0) && (edges_.at(v.first).count(idx) > 0)) {
                rm_edge(edges_.at(v.first).at(idx));
            }
        }

        vertices_.erase(idx);
        assert(vertex_num_ > 0);
        --vertex_num_;
    }

    std::set<vertex_index_t> inbounds(vertex_index_t idx) const override
    {
        if (inbounds_.count(idx) == 0) {
            return {};
        }

        std::set<vertex_index_t> res;
        for (const auto &idx2 : inbounds_.at(idx)) {
            if ((filtered_edges_.count(idx2) == 0) || (filtered_edges_.at(idx2).count(idx) == 0)) {
                res.insert(idx2);
            }
        }

        return res;
    }

    std::set<vertex_index_t> outbounds(vertex_index_t idx, int mode) const override
    {
        if (outbounds_.count(idx) == 0) {
            return {};
        }

        /// No filters were applied, return all outbounds.
        if ((mode == 1) || (filtered_edges_.count(idx) == 0)) {
            return outbounds_.at(idx);
        }

        /// Return all outbounds except filtered ones.
        std::set<vertex_index_t> res;
        for (const auto &idx2 : outbounds_.at(idx)) {
            if (filtered_edges_.at(idx).count(idx2) == 0) {
                res.insert(idx2);
            }
        }

        return res;
    }

    const Vertex<V> &vertex(vertex_index_t idx) const override
    {
        return vertices_.at(idx);
    }

    size_t vertex_num() const override { return vertex_num_; };

    void add_edge(Edge<E, W> edge) override
    {
        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }
        inbounds_[edge.idx2()].insert(edge.idx1());
        outbounds_[edge.idx1()].insert(edge.idx2());
        if (!Dir) {
            inbounds_[edge.idx1()].insert(edge.idx2());
            outbounds_[edge.idx2()].insert(edge.idx1());
        }

        /// Store undirected edge as min_idx->max_idx.
        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        edges_[edge.idx1()].emplace(edge.idx2(), std::move(edge));
    }

    const Edge<E, W> &edge(vertex_index_t idx1, vertex_index_t idx2) const override
    {
        if (Dir) {
            return edges_.at(idx1).at(idx2);
        }
        else {
            auto p = std::minmax(idx1, idx2);
            return edges_.at(p.first).at(p.second);
        }
    }

    bool edge_exists(Edge<E, W> edge) const override
    {
        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }
        return (edges_.count(edge.idx1()) > 0) && (edges_.at(edge.idx1()).count(edge.idx2()) > 0);
    }

    /**
     * @brief Remove specified edge from the graph
     * @param edge Edge to remove.
     */
    void rm_edge(Edge<E, W> edge) override
    {
        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }

        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        if ((edges_.count(edge.idx1()) == 0) || (edges_.at(edge.idx1()).count(edge.idx2()) == 0)) {
            return;
        }

        outbounds_[edge.idx1()].erase(edge.idx2());
        if (!Dir) {
            outbounds_[edge.idx2()].erase(edge.idx1());
        }

        inbounds_[edge.idx2()].erase(edge.idx1());
        if (!Dir) {
            inbounds_[edge.idx1()].erase(edge.idx2());
        }

        edges_[edge.idx1()].erase(edge.idx2());
        if (edges_[edge.idx1()].size() == 0) {
            edges_.erase(edge.idx1());
        }
    }

    /**
     * Get number of edges in the graph.
     *
     * @return Number of edges.
     * @note Filtered edges are not taken into consideration.
     */
    size_t edge_num() const
    {
        return edges_.size();
    }

    /**
     * @brief Temporarily remove specified edge from the graph.
     * @param edge Edge to filter out.
     * @return False if edge is invalid or is not present in the graph, true otherwise.
     * @note If edge is valid, it is added to filtered edges regardless of it's presence in the graph.
     */
    bool filter_edge(Edge<E, W> edge) override
    {
        bool rc = true;

        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }

        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        filtered_edges_[edge.idx1()].insert(edge.idx2());

        /// Check if edge was actually filtered out.
        if (!edges_.count(edge.idx1()) || !edges_.at(edge.idx1()).count(edge.idx2())) {
            rc = false;
        }

        return rc;
    }

    /**
     * @brief Temporarily remove specified edges from the graph.
     * @param edges Edges to filter out.
     * @return True if all edges filtered out, false otherwise.
     */
    bool filter_edges(const std::vector<Edge<E, W>> &edges) override
    {
        bool rc = true;

        for (const auto &edge : edges) {
            if (!filter_edge(edge)) {
                rc = false;
            }
        }

        return rc;
    }

    /**
     * @brief Restore temporarily removed edge.
     * @param edge Edge to restore.
     */
    bool restore_edge(Edge<E, W> edge) override
    {
        if ((vertices_.count(edge.idx1()) == 0) || (vertices_.count(edge.idx2()) == 0)) {
            throw std::out_of_range("Vertex index is not presented");
        }

        if (!Dir && (edge.idx1() > edge.idx2())) {
            edge.swap_vertices();
        }

        if ((filtered_edges_.count(edge.idx1()) > 0) && (filtered_edges_.at(edge.idx1()).count(edge.idx2()) > 0)) {
            filtered_edges_[edge.idx1()].erase(edge.idx2());
            if (filtered_edges_.at(edge.idx1()).size() == 0) {
                filtered_edges_.erase(edge.idx1());
            }
            return true;
        }

        return false;
    }

    /**
     * @brief Restore temporarily removed edges.
     * @param edges
     */
    bool restore_edges(const std::vector<Edge<E, W>> &edges) override
    {
        bool rc = true;

        for (const auto &edge : edges) {
            if (!restore_edge(edge)) {
                rc = false;
            }
        }

        return rc;
    }

    /**
     * @brief Restore all temporarily removed edges.
     * @param edges
     */
    void restore_edges() override
    {
        filtered_edges_.clear();
    }

    /**
     *
     * @return
     */
    typename Graph<Dir, V, E, W>::EdgesWrapper &edges() override
    {
        return edges_wrapper_;
    }

private:
    vertex_index_t vertex_num_;
    std::unordered_map<vertex_index_t, Vertex<V>> vertices_;
    std::unordered_map<vertex_index_t, std::set<vertex_index_t>> inbounds_;
    std::unordered_map<vertex_index_t, std::set<vertex_index_t>> outbounds_;
    Edges edges_;
    FilteredEdges filtered_edges_;
    ListEdgesWrapper edges_wrapper_;
};

}  // namespace simple_graph
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_ddr_phy_reset.C
/// @brief Initialize dram
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

using fapi2::TARGET_TYPE_MCBIST;

extern "C"
{
///
/// @brief Reset the DDR PHY
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode p9_mss_ddr_phy_reset( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
    {
        FAPI_INF("Start ddr phy reset");
        FAPI_INF("End ddr phy reset");
        return fapi2::FAPI2_RC_SUCCESS;
    }
}
<commit_msg>Include .H files in their respective C files to avoid compilation error<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_ddr_phy_reset.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_ddr_phy_reset.C
/// @brief Initialize dram
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include "p9_mss_ddr_phy_reset.H"

using fapi2::TARGET_TYPE_MCBIST;

extern "C"
{
///
/// @brief Reset the DDR PHY
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode p9_mss_ddr_phy_reset( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
    {
        FAPI_INF("Start ddr phy reset");
        FAPI_INF("End ddr phy reset");
        return fapi2::FAPI2_RC_SUCCESS;
    }
}
<|endoftext|>