<commit_before>#pragma once

#include <deque>
#include <memory>
#include <iostream>
#include <map>
#include <utility>

template <typename T>
class MessageBusProxy;

namespace {
	using Cursor = long unsigned int;

}

template <typename MessageType>
class MessageBus {
	public:

		MessageBus()=default;

		void push(const MessageType& message);

		static MessageBus<MessageType>* getBus();

		MessageType* next(MessageBusProxy<MessageType>* proxy);

	private:
		using MessageQueue = std::deque<MessageType>;
		friend class MessageBusProxy<MessageType>;

		void registerProxy(MessageBusProxy<MessageType>* proxy);
		void unregisterProxy(MessageBusProxy<MessageType>* proxy);

		MessageQueue m_messages;
		std::map<MessageBusProxy<MessageType>*, typename MessageQueue::iterator> m_proxys;

		static std::unique_ptr<MessageBus<MessageType>> m_bus;
};

#include "messagebusqueue.hpp"
#include "messagebusproxy.hpp"

template <typename MessageType>
void MessageBus<MessageType>::push(const MessageType& message)
{
	if (m_proxys.size() == 0)
		return;
	MessageBusQueue::instance()->push<MessageType>();
	m_messages.push_back(message);
}

template <typename MessageType>
MessageBus<MessageType>* MessageBus<MessageType>::getBus()
{
	if (m_bus == nullptr)
	{
		std::cout << "bus expired"<< std::endl;
		m_bus.reset(new MessageBus<MessageType>());
	}
	return m_bus.get();
}

template <typename MessageType>
void MessageBus<MessageType>::registerProxy(MessageBusProxy<MessageType>* proxy) {
	auto cursor = m_messages.begin();
	if (m_messages.size() > 0)
		std::advance(cursor, m_messages.size()-1);
	m_proxys.emplace(proxy, cursor);
}

template <typename MessageType>
void MessageBus<MessageType>::unregisterProxy(MessageBusProxy<MessageType>* proxy) {
	auto _search = m_proxys.find(proxy);
	if (_search == m_proxys.end())
		return;
	m_proxys.erase(_search);

	if (m_proxys.size() == 0)
		delete m_bus.release();
}

template <typename MessageType>
MessageType* MessageBus<MessageType>::next(MessageBusProxy<MessageType>* proxy) {
	// TODO : implement next function
	auto& iterator = m_proxys.at(proxy);
	if (iterator == m_messages.end())
		return nullptr;
	return &*(++iterator);
}

template <typename MessageType>
std::unique_ptr<MessageBus<MessageType>> MessageBus<MessageType>::m_bus = nullptr;

template <typename MessageType>
void SendMessage(const MessageType& message) {
	MessageBus<MessageType>::getBus()->push(message);
}
<commit_msg>Add API to messagebus to send requests.<commit_after>#pragma once

#include <deque>
#include <memory>
#include <iostream>
#include <map>
#include <utility>

template <typename T>
class MessageBusProxy;

namespace {
	using Cursor = long unsigned int;

}

template <typename MessageType>
class MessageBus {
	public:

		MessageBus()=default;

		void push(const MessageType& message);

		template<typename ResponseType>
		const std::vector<ResponseType>&& request(const MessageType& message);

		static MessageBus<MessageType>* getBus();

		MessageType* next(MessageBusProxy<MessageType>* proxy);

	private:
		using MessageQueue = std::deque<MessageType>;
		friend class MessageBusProxy<MessageType>;

		void registerProxy(MessageBusProxy<MessageType>* proxy);
		void unregisterProxy(MessageBusProxy<MessageType>* proxy);

		MessageQueue m_messages;
		std::map<MessageBusProxy<MessageType>*, typename MessageQueue::iterator> m_proxys;

		static std::unique_ptr<MessageBus<MessageType>> m_bus;
};

#include "messagebusqueue.hpp"
#include "messagebusproxy.hpp"

template <typename MessageType>
void MessageBus<MessageType>::push(const MessageType& message)
{
	if (m_proxys.size() == 0)
		return;
	MessageBusQueue::instance()->push<MessageType>();
	m_messages.push_back(message);
}

template <typename MessageType>
MessageBus<MessageType>* MessageBus<MessageType>::getBus()
{
	if (m_bus == nullptr)
	{
		std::cout << "bus expired"<< std::endl;
		m_bus.reset(new MessageBus<MessageType>());
	}
	return m_bus.get();
}

template <typename MessageType>
void MessageBus<MessageType>::registerProxy(MessageBusProxy<MessageType>* proxy) {
	auto cursor = m_messages.begin();
	if (m_messages.size() > 0)
		std::advance(cursor, m_messages.size()-1);
	m_proxys.emplace(proxy, cursor);
}

template <typename MessageType>
void MessageBus<MessageType>::unregisterProxy(MessageBusProxy<MessageType>* proxy) {
	auto _search = m_proxys.find(proxy);
	if (_search == m_proxys.end())
		return;
	m_proxys.erase(_search);

	if (m_proxys.size() == 0)
		delete m_bus.release();
}

template <typename MessageType>
MessageType* MessageBus<MessageType>::next(MessageBusProxy<MessageType>* proxy) {
	// TODO : implement next function
	auto& iterator = m_proxys.at(proxy);
	if (iterator == m_messages.end())
		return nullptr;
	return &*(++iterator);
}

template <typename MessageType>
std::unique_ptr<MessageBus<MessageType>> MessageBus<MessageType>::m_bus = nullptr;

template <typename MessageType>
void SendMessage(const MessageType& message) {
	MessageBus<MessageType>::getBus()->push(message);
}

template <typename MessageType, typename ResponseType>
const std::vector<ResponseType>&& RequestMessage(const MessageType& message)
{
	MessageBus<MessageType>::getBus()->request(message);
}

template <typename MessageType, typename ResponseType>
const ResponseType& RequestUnique(const MessageType& message)
{
	auto& response = RequestMessage<MessageType, ResponseType>(message);
	if (response.size() != 1) throw std::runtime_error("More than 1 response");
	return response[0];
}

<|endoftext|>


<commit_before>//===-- Internalize.cpp - Mark functions internal -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions in the input module, looking for a
// main function.  If a main function is found, all other functions and all
// global variables with initializers are marked as internal.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include <fstream>
#include <set>
using namespace llvm;

namespace {
  Statistic<> NumFunctions("internalize", "Number of functions internalized");
  Statistic<> NumGlobals  ("internalize", "Number of global vars internalized");

  // APIFile - A file which contains a list of symbols that should not be marked
  // external.
  cl::opt<std::string>
  APIFile("internalize-public-api-file", cl::value_desc("filename"),
          cl::desc("A file containing list of symbol names to preserve"));

  // APIList - A list of symbols that should not be marked internal.
  cl::list<std::string>
  APIList("internalize-public-api-list", cl::value_desc("list"),
          cl::desc("A list of symbol names to preserve"),
          cl::CommaSeparated);

  class InternalizePass : public ModulePass {
    std::set<std::string> ExternalNames;
  public:
    InternalizePass() {
      if (!APIFile.empty())           // If a filename is specified, use it
        LoadFile(APIFile.c_str());
      else                            // Else, if a list is specified, use it.
        ExternalNames.insert(APIList.begin(), APIList.end());
    }

    void LoadFile(const char *Filename) {
      // Load the APIFile...
      std::ifstream In(Filename);
      if (!In.good()) {
        std::cerr << "WARNING: Internalize couldn't load file '" << Filename
                  << "'!\n";
        return;   // Do not internalize anything...
      }
      while (In) {
        std::string Symbol;
        In >> Symbol;
        if (!Symbol.empty())
          ExternalNames.insert(Symbol);
      }
    }

    virtual bool runOnModule(Module &M) {
      // If no list or file of symbols was specified, check to see if there is a
      // "main" symbol defined in the module.  If so, use it, otherwise do not
      // internalize the module, it must be a library or something.
      //
      if (ExternalNames.empty()) {
        Function *MainFunc = M.getMainFunction();
        if (MainFunc == 0 || MainFunc->isExternal())
          return false;  // No main found, must be a library...

        // Preserve main, internalize all else.
        ExternalNames.insert(MainFunc->getName());
      }

      bool Changed = false;

      // Found a main function, mark all functions not named main as internal.
      for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
        if (!I->isExternal() &&         // Function must be defined here
            !I->hasInternalLinkage() &&  // Can't already have internal linkage
            !ExternalNames.count(I->getName())) {// Not marked to keep external?
          I->setLinkage(GlobalValue::InternalLinkage);
          Changed = true;
          ++NumFunctions;
          DEBUG(std::cerr << "Internalizing func " << I->getName() << "\n");
        }

      // Mark all global variables with initializers as internal as well...
      for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I)
        if (!I->isExternal() && !I->hasInternalLinkage() &&
            !ExternalNames.count(I->getName())) {
          // Special case handling of the global ctor and dtor list.  When we
          // internalize it, we mark it constant, which allows elimination of
          // the list if it's empty.
          //
          if (I->hasAppendingLinkage() && (I->getName() == "llvm.global_ctors"||
                                           I->getName() == "llvm.global_dtors"))
            I->setConstant(true);

          I->setLinkage(GlobalValue::InternalLinkage);
          Changed = true;
          ++NumGlobals;
          DEBUG(std::cerr << "Internalizing gvar " << I->getName() << "\n");
        }

      return Changed;
    }
  };

  RegisterOpt<InternalizePass> X("internalize", "Internalize Global Symbols");
} // end anonymous namespace

ModulePass *llvm::createInternalizePass() {
  return new InternalizePass();
}
<commit_msg>Add an option to this pass.  If it is set, we are allowed to internalize all but main.  If it's not set, we can still internalize, but only if an explicit symbol list is provided.<commit_after>//===-- Internalize.cpp - Mark functions internal -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions in the input module, looking for a
// main function.  If a main function is found, all other functions and all
// global variables with initializers are marked as internal.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include <fstream>
#include <set>
using namespace llvm;

namespace {
  Statistic<> NumFunctions("internalize", "Number of functions internalized");
  Statistic<> NumGlobals  ("internalize", "Number of global vars internalized");

  // APIFile - A file which contains a list of symbols that should not be marked
  // external.
  cl::opt<std::string>
  APIFile("internalize-public-api-file", cl::value_desc("filename"),
          cl::desc("A file containing list of symbol names to preserve"));

  // APIList - A list of symbols that should not be marked internal.
  cl::list<std::string>
  APIList("internalize-public-api-list", cl::value_desc("list"),
          cl::desc("A list of symbol names to preserve"),
          cl::CommaSeparated);

  class InternalizePass : public ModulePass {
    std::set<std::string> ExternalNames;
    bool DontInternalize;
  public:
    InternalizePass(bool InternalizeEverything = true) : DontInternalize(false){
      if (!APIFile.empty())           // If a filename is specified, use it
        LoadFile(APIFile.c_str());
      else if (!APIList.empty())      // Else, if a list is specified, use it.
        ExternalNames.insert(APIList.begin(), APIList.end());
      else if (!InternalizeEverything)
        // Finally, if we're allowed to, internalize all but main.
        DontInternalize = true;
    }

    void LoadFile(const char *Filename) {
      // Load the APIFile...
      std::ifstream In(Filename);
      if (!In.good()) {
        std::cerr << "WARNING: Internalize couldn't load file '" << Filename
                  << "'!\n";
        return;   // Do not internalize anything...
      }
      while (In) {
        std::string Symbol;
        In >> Symbol;
        if (!Symbol.empty())
          ExternalNames.insert(Symbol);
      }
    }

    virtual bool runOnModule(Module &M) {
      if (DontInternalize) return false;

      // If no list or file of symbols was specified, check to see if there is a
      // "main" symbol defined in the module.  If so, use it, otherwise do not
      // internalize the module, it must be a library or something.
      //
      if (ExternalNames.empty()) {
        Function *MainFunc = M.getMainFunction();
        if (MainFunc == 0 || MainFunc->isExternal())
          return false;  // No main found, must be a library...

        // Preserve main, internalize all else.
        ExternalNames.insert(MainFunc->getName());
      }

      bool Changed = false;

      // Found a main function, mark all functions not named main as internal.
      for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
        if (!I->isExternal() &&         // Function must be defined here
            !I->hasInternalLinkage() &&  // Can't already have internal linkage
            !ExternalNames.count(I->getName())) {// Not marked to keep external?
          I->setLinkage(GlobalValue::InternalLinkage);
          Changed = true;
          ++NumFunctions;
          DEBUG(std::cerr << "Internalizing func " << I->getName() << "\n");
        }

      // Mark all global variables with initializers as internal as well...
      for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I)
        if (!I->isExternal() && !I->hasInternalLinkage() &&
            !ExternalNames.count(I->getName())) {
          // Special case handling of the global ctor and dtor list.  When we
          // internalize it, we mark it constant, which allows elimination of
          // the list if it's empty.
          //
          if (I->hasAppendingLinkage() && (I->getName() == "llvm.global_ctors"||
                                           I->getName() == "llvm.global_dtors"))
            I->setConstant(true);

          I->setLinkage(GlobalValue::InternalLinkage);
          Changed = true;
          ++NumGlobals;
          DEBUG(std::cerr << "Internalizing gvar " << I->getName() << "\n");
        }

      return Changed;
    }
  };

  RegisterOpt<InternalizePass> X("internalize", "Internalize Global Symbols");
} // end anonymous namespace

ModulePass *llvm::createInternalizePass(bool InternalizeEverything) {
  return new InternalizePass(InternalizeEverything);
}
<|endoftext|>


<commit_before>//===-- Internalize.cpp - Mark functions internal -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions in the input module, looking for a
// main function.  If a main function is found, all other functions and all
// global variables with initializers are marked as internal.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include <fstream>
#include <set>
using namespace llvm;

namespace {
  Statistic<> NumFunctions("internalize", "Number of functions internalized");
  Statistic<> NumGlobals  ("internalize", "Number of global vars internalized");

  // APIFile - A file which contains a list of symbols that should not be marked
  // external.
  cl::opt<std::string>
  APIFile("internalize-public-api-file", cl::value_desc("filename"),
          cl::desc("A file containing list of symbol names to preserve"));

  // APIList - A list of symbols that should not be marked internal.
  cl::list<std::string>
  APIList("internalize-public-api-list", cl::value_desc("list"),
          cl::desc("A list of symbol names to preserve"),
          cl::CommaSeparated);

  class InternalizePass : public ModulePass {
    std::set<std::string> ExternalNames;
    bool DontInternalize;
  public:
    InternalizePass(bool InternalizeEverything = true) : DontInternalize(false){
      if (!APIFile.empty())           // If a filename is specified, use it
        LoadFile(APIFile.c_str());
      else if (!APIList.empty())      // Else, if a list is specified, use it.
        ExternalNames.insert(APIList.begin(), APIList.end());
      else if (!InternalizeEverything)
        // Finally, if we're allowed to, internalize all but main.
        DontInternalize = true;
    }

    void LoadFile(const char *Filename) {
      // Load the APIFile...
      std::ifstream In(Filename);
      if (!In.good()) {
        std::cerr << "WARNING: Internalize couldn't load file '" << Filename
                  << "'!\n";
        return;   // Do not internalize anything...
      }
      while (In) {
        std::string Symbol;
        In >> Symbol;
        if (!Symbol.empty())
          ExternalNames.insert(Symbol);
      }
    }

    virtual bool runOnModule(Module &M) {
      if (DontInternalize) return false;

      // If no list or file of symbols was specified, check to see if there is a
      // "main" symbol defined in the module.  If so, use it, otherwise do not
      // internalize the module, it must be a library or something.
      //
      if (ExternalNames.empty()) {
        Function *MainFunc = M.getMainFunction();
        if (MainFunc == 0 || MainFunc->isExternal())
          return false;  // No main found, must be a library...

        // Preserve main, internalize all else.
        ExternalNames.insert(MainFunc->getName());
      }

      bool Changed = false;

      // Found a main function, mark all functions not named main as internal.
      for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
        if (!I->isExternal() &&         // Function must be defined here
            !I->hasInternalLinkage() &&  // Can't already have internal linkage
            !ExternalNames.count(I->getName())) {// Not marked to keep external?
          I->setLinkage(GlobalValue::InternalLinkage);
          Changed = true;
          ++NumFunctions;
          DEBUG(std::cerr << "Internalizing func " << I->getName() << "\n");
        }

      // Mark all global variables with initializers as internal as well...
      for (Module::global_iterator I = M.global_begin(), E = M.global_end();
           I != E; ++I)
        if (!I->isExternal() && !I->hasInternalLinkage() &&
            !ExternalNames.count(I->getName()) &&
            // *never* internalize the llvm.used symbol, used to implement
            // attribute((used)).
            I->getName() != "llvm.used") {
          // Special case handling of the global ctor and dtor list.  When we
          // internalize it, we mark it constant, which allows elimination of
          // the list if it's empty.
          //
          if (I->hasAppendingLinkage() && (I->getName() == "llvm.global_ctors"||
                                           I->getName() == "llvm.global_dtors"))
            I->setConstant(true);

          I->setLinkage(GlobalValue::InternalLinkage);
          Changed = true;
          ++NumGlobals;
          DEBUG(std::cerr << "Internalizing gvar " << I->getName() << "\n");
        }

      return Changed;
    }
  };

  RegisterOpt<InternalizePass> X("internalize", "Internalize Global Symbols");
} // end anonymous namespace

ModulePass *llvm::createInternalizePass(bool InternalizeEverything) {
  return new InternalizePass(InternalizeEverything);
}
<commit_msg>Pull inline methods out of the pass class definition to make it easier to read the code.<commit_after>//===-- Internalize.cpp - Mark functions internal -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions in the input module, looking for a
// main function.  If a main function is found, all other functions and all
// global variables with initializers are marked as internal.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include <fstream>
#include <set>
using namespace llvm;

namespace {
  Statistic<> NumFunctions("internalize", "Number of functions internalized");
  Statistic<> NumGlobals  ("internalize", "Number of global vars internalized");

  // APIFile - A file which contains a list of symbols that should not be marked
  // external.
  cl::opt<std::string>
  APIFile("internalize-public-api-file", cl::value_desc("filename"),
          cl::desc("A file containing list of symbol names to preserve"));

  // APIList - A list of symbols that should not be marked internal.
  cl::list<std::string>
  APIList("internalize-public-api-list", cl::value_desc("list"),
          cl::desc("A list of symbol names to preserve"),
          cl::CommaSeparated);

  class InternalizePass : public ModulePass {
    std::set<std::string> ExternalNames;
    bool DontInternalize;
  public:
    InternalizePass(bool InternalizeEverything = true);
    void LoadFile(const char *Filename);
    virtual bool runOnModule(Module &M);
  };
  RegisterOpt<InternalizePass> X("internalize", "Internalize Global Symbols");
} // end anonymous namespace

InternalizePass::InternalizePass(bool InternalizeEverything)
  : DontInternalize(false){
  if (!APIFile.empty())           // If a filename is specified, use it
    LoadFile(APIFile.c_str());
  else if (!APIList.empty())      // Else, if a list is specified, use it.
    ExternalNames.insert(APIList.begin(), APIList.end());
  else if (!InternalizeEverything)
    // Finally, if we're allowed to, internalize all but main.
    DontInternalize = true;
}

void InternalizePass::LoadFile(const char *Filename) {
  // Load the APIFile...
  std::ifstream In(Filename);
  if (!In.good()) {
    std::cerr << "WARNING: Internalize couldn't load file '" << Filename
    << "'!\n";
    return;   // Do not internalize anything...
  }
  while (In) {
    std::string Symbol;
    In >> Symbol;
    if (!Symbol.empty())
      ExternalNames.insert(Symbol);
  }
}

bool InternalizePass::runOnModule(Module &M) {
  if (DontInternalize) return false;

  // If no list or file of symbols was specified, check to see if there is a
  // "main" symbol defined in the module.  If so, use it, otherwise do not
  // internalize the module, it must be a library or something.
  //
  if (ExternalNames.empty()) {
    Function *MainFunc = M.getMainFunction();
    if (MainFunc == 0 || MainFunc->isExternal())
      return false;  // No main found, must be a library...

    // Preserve main, internalize all else.
    ExternalNames.insert(MainFunc->getName());
  }

  bool Changed = false;

  // Found a main function, mark all functions not named main as internal.
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (!I->isExternal() &&         // Function must be defined here
        !I->hasInternalLinkage() &&  // Can't already have internal linkage
        !ExternalNames.count(I->getName())) {// Not marked to keep external?
      I->setLinkage(GlobalValue::InternalLinkage);
      Changed = true;
      ++NumFunctions;
      DEBUG(std::cerr << "Internalizing func " << I->getName() << "\n");
    }

  // Never internalize the llvm.used symbol.  It is used to implement
  // attribute((used)).
  ExternalNames.insert("llvm.used");

  // Never internalize anchors used by the debugger, else the debugger won't
  // find them.
  ExternalNames.insert("llvm.dbg.translation_units");
  ExternalNames.insert("llvm.dbg.globals");

  // Mark all global variables with initializers as internal as well.
  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
       I != E; ++I)
    if (!I->isExternal() && !I->hasInternalLinkage() &&
        !ExternalNames.count(I->getName())) {
      // Special case handling of the global ctor and dtor list.  When we
      // internalize it, we mark it constant, which allows elimination of
      // the list if it's empty.
      //
      if (I->hasAppendingLinkage() && (I->getName() == "llvm.global_ctors" ||
                                       I->getName() == "llvm.global_dtors"))
        I->setConstant(true);

      I->setLinkage(GlobalValue::InternalLinkage);
      Changed = true;
      ++NumGlobals;
      DEBUG(std::cerr << "Internalizing gvar " << I->getName() << "\n");
    }

  return Changed;
}

ModulePass *llvm::createInternalizePass(bool InternalizeEverything) {
  return new InternalizePass(InternalizeEverything);
}
<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2018 Michael Fink
//
/// \file GeoTagTool\MainFrame.cpp GeoTagTool main frame
//
#include "stdafx.h"
#include "res/Ribbon.h"
#include "resource.h"
#include "AboutDlg.hpp"
#include "GeoTagToolView.hpp"
#include "MainFrame.hpp"
#include "SerialPortDlg.hpp"

BOOL MainFrame::PreTranslateMessage(MSG* pMsg)
{
   if (CRibbonFrameWindowImpl<MainFrame>::PreTranslateMessage(pMsg))
      return TRUE;

   return m_view.PreTranslateMessage(pMsg);
}

BOOL MainFrame::OnIdle()
{
   return FALSE;
}

LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   UIAddMenu(GetMenu(), true);
   m_cmdBar.Create(m_hWnd, rcDefault, NULL, WS_CHILD);
   m_cmdBar.AttachMenu(GetMenu());
   m_cmdBar.LoadImages(IDR_MAINFRAME);

   CreateSimpleStatusBar();

   m_hWndClient = m_view.Create(m_hWnd);
   UISetCheck(ID_VIEW_STATUS_BAR, 1);

   // register object for message filtering and idle updates
   CMessageLoop* pLoop = _Module.GetMessageLoop();
   ATLASSERT(pLoop != NULL);
   pLoop->AddMessageFilter(this);
   pLoop->AddIdleHandler(this);

   ShowRibbonUI(true);

   return 0;
}

LRESULT MainFrame::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
   // unregister message filtering and idle updates
   CMessageLoop* pLoop = _Module.GetMessageLoop();
   ATLASSERT(pLoop != NULL);
   pLoop->RemoveMessageFilter(this);
   pLoop->RemoveIdleHandler(this);

   bHandled = FALSE;
   return 1;
}

LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   PostMessage(WM_CLOSE);
   return 0;
}

LRESULT MainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   AboutDlg dlg;
   dlg.DoModal();

   return 0;
}

LRESULT MainFrame::OnDataSourceOpenGPSReceiver(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   SerialPortDlg dlg;
   if (IDOK != dlg.DoModal(m_hWnd))
      return 0;

   return 0;
}

LRESULT MainFrame::OnDataSourceImportTrack(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{

   return 0;
}

LRESULT MainFrame::OnActionsTagImages(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   return 0;
}

LRESULT MainFrame::OnActionsSaveLiveTrack(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   return 0;
}
<commit_msg>removed ASSERT when starting main frame, due do missing menu resource<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2018 Michael Fink
//
/// \file GeoTagTool\MainFrame.cpp GeoTagTool main frame
//
#include "stdafx.h"
#include "res/Ribbon.h"
#include "resource.h"
#include "AboutDlg.hpp"
#include "GeoTagToolView.hpp"
#include "MainFrame.hpp"
#include "SerialPortDlg.hpp"

BOOL MainFrame::PreTranslateMessage(MSG* pMsg)
{
   if (CRibbonFrameWindowImpl<MainFrame>::PreTranslateMessage(pMsg))
      return TRUE;

   return m_view.PreTranslateMessage(pMsg);
}

BOOL MainFrame::OnIdle()
{
   return FALSE;
}

LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   m_cmdBar.Create(m_hWnd, rcDefault, NULL, WS_CHILD);
   m_cmdBar.AttachMenu(GetMenu());
   m_cmdBar.LoadImages(IDR_MAINFRAME);

   CreateSimpleStatusBar();

   m_hWndClient = m_view.Create(m_hWnd);
   UISetCheck(ID_VIEW_STATUS_BAR, 1);

   // register object for message filtering and idle updates
   CMessageLoop* pLoop = _Module.GetMessageLoop();
   ATLASSERT(pLoop != NULL);
   pLoop->AddMessageFilter(this);
   pLoop->AddIdleHandler(this);

   ShowRibbonUI(true);

   return 0;
}

LRESULT MainFrame::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
   // unregister message filtering and idle updates
   CMessageLoop* pLoop = _Module.GetMessageLoop();
   ATLASSERT(pLoop != NULL);
   pLoop->RemoveMessageFilter(this);
   pLoop->RemoveIdleHandler(this);

   bHandled = FALSE;
   return 1;
}

LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   PostMessage(WM_CLOSE);
   return 0;
}

LRESULT MainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   AboutDlg dlg;
   dlg.DoModal();

   return 0;
}

LRESULT MainFrame::OnDataSourceOpenGPSReceiver(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   SerialPortDlg dlg;
   if (IDOK != dlg.DoModal(m_hWnd))
      return 0;

   return 0;
}

LRESULT MainFrame::OnDataSourceImportTrack(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{

   return 0;
}

LRESULT MainFrame::OnActionsTagImages(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   return 0;
}

LRESULT MainFrame::OnActionsSaveLiveTrack(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   return 0;
}
<|endoftext|>


<commit_before>#include <YCommon/Headers/stdincludes.h>
#include "AtomicQueue.h"

#include <string>

#include <YCommon/Headers/AtomicNumberMask.h>
#include <YCommon/Headers/Atomics.h>

namespace YCommon { namespace YContainers {

AtomicQueue::AtomicQueue()
    : mBuffer(NULL),
      mItemSize(0),
      mNumItems(0),
      mHead(0),
      mTail(0) {
}

AtomicQueue::AtomicQueue(void* buffer, size_t buffer_size,
                         size_t item_size, size_t num_items)
    : mBuffer(NULL),
      mItemSize(0),
      mNumItems(0),
      mHead(0),
      mTail(0) {
  Initialize(buffer, buffer_size, item_size, num_items);
}

AtomicQueue::~AtomicQueue() {
}

void AtomicQueue::Initialize(void* buffer, size_t buffer_size,
                             size_t item_size, size_t num_items) {
  mBuffer = buffer;
  mItemSize = item_size;
  mNumItems = num_items;
  mHead = 0;
  mTail = 0;

  (void) buffer_size;
  YASSERT(buffer_size >= (item_size * num_items),
          "Atomic Queue %u[%u] requires at least %u bytes, supplied %u bytes.",
          static_cast<uint32_t>(item_size), num_items,
          static_cast<uint32_t>(item_size * num_items),
          static_cast<uint32_t>(buffer_size));
}

bool AtomicQueue::Enqueue(const void* data_item) {
  const uint64_t cur_head = mHead;
  const uint64_t cur_tail = mTail;
  MemoryBarrier();

  const uint64_t cur_head_num = GET_NUM(cur_head);
  const uint64_t cur_tail_num = GET_NUM(cur_tail);

  // Check if full (numbers match, but counters do not)
  if (cur_head_num == cur_tail_num && cur_head != cur_tail)
    return false;

  memcpy(static_cast<char*>(mBuffer) + cur_tail_num, data_item, mItemSize);

  const uint64_t new_tail_num = cur_tail_num + mItemSize;
  const uint64_t tail_cnt = GET_CNT(cur_tail);

  // Check if looped through buffer.
  mTail = (new_tail_num == (mItemSize * mNumItems)) ?
          CONSTRUCT_NEXT_VALUE(tail_cnt, 0) :
          CONSTRUCT_VALUE(tail_cnt, new_tail_num);

  return true;
}

bool AtomicQueue::Dequeue(void* data_item) {
  const size_t buffer_size = mItemSize * mNumItems;
  for (;;) {
    const uint64_t cur_head = mHead;
    const uint64_t cur_tail = mTail;
    MemoryBarrier();

    // Check if empty (both counter and numbers match)
    if (cur_head == cur_tail)
      return false;

    const uint64_t cur_head_num = GET_NUM(cur_head);

    memcpy(data_item, static_cast<char*>(mBuffer) + cur_head_num, mItemSize);

    const uint64_t new_head_num = cur_head_num + mItemSize;
    const uint64_t head_cnt = GET_CNT(cur_head);

    // Check if looped through buffer.
    const uint64_t new_head_val = (new_head_num == buffer_size) ?
                                  CONSTRUCT_NEXT_VALUE(head_cnt, 0) :
                                  CONSTRUCT_VALUE(head_cnt, new_head_num);

    if (AtomicCmpSet64(&mHead, cur_head, new_head_val))
      break;
  }

  return true;
}

size_t AtomicQueue::CurrentSize() const {
  const uint64_t cur_head = mHead;
  const uint64_t cur_tail = mTail;
  MemoryBarrier();

  const uint64_t cur_head_num = GET_NUM(cur_head);
  const uint64_t cur_tail_num = GET_NUM(cur_tail);

  if (cur_head_num == cur_tail_num) {
    // Empty if the counters match, full otherwise.
    return (cur_head == cur_tail) ? 0 : mItemSize;
  } else if (cur_tail_num > cur_head_num) {
    return (cur_tail_num - cur_head_num) / mItemSize;
  } else {
    const uint64_t looped_tail = cur_tail_num + (mItemSize * mNumItems);
    return (looped_tail - cur_head_num) / mItemSize;
  }
}

}} // namespace YCommon { namespace YContainers {
<commit_msg>Fixed some type problems<commit_after>#include <YCommon/Headers/stdincludes.h>
#include "AtomicQueue.h"

#include <string>

#include <YCommon/Headers/AtomicNumberMask.h>
#include <YCommon/Headers/Atomics.h>

namespace YCommon { namespace YContainers {

AtomicQueue::AtomicQueue()
    : mBuffer(NULL),
      mItemSize(0),
      mNumItems(0),
      mHead(0),
      mTail(0) {
}

AtomicQueue::AtomicQueue(void* buffer, size_t buffer_size,
                         size_t item_size, size_t num_items)
    : mBuffer(NULL),
      mItemSize(0),
      mNumItems(0),
      mHead(0),
      mTail(0) {
  Initialize(buffer, buffer_size, item_size, num_items);
}

AtomicQueue::~AtomicQueue() {
}

void AtomicQueue::Initialize(void* buffer, size_t buffer_size,
                             size_t item_size, size_t num_items) {
  mBuffer = buffer;
  mItemSize = item_size;
  mNumItems = num_items;
  mHead = 0;
  mTail = 0;

  (void) buffer_size;
  YASSERT(buffer_size >= (item_size * num_items),
          "Atomic Queue %u[%u] requires at least %u bytes, supplied %u bytes.",
          static_cast<uint32_t>(item_size), num_items,
          static_cast<uint32_t>(item_size * num_items),
          static_cast<uint32_t>(buffer_size));
}

bool AtomicQueue::Enqueue(const void* data_item) {
  const uint64_t cur_head = mHead;
  const uint64_t cur_tail = mTail;
  MemoryBarrier();

  const uint64_t cur_head_num = GET_NUM(cur_head);
  const uint64_t cur_tail_num = GET_NUM(cur_tail);

  // Check if full (numbers match, but counters do not)
  if (cur_head_num == cur_tail_num && cur_head != cur_tail)
    return false;

  memcpy(static_cast<char*>(mBuffer) + cur_tail_num, data_item, mItemSize);

  const uint64_t new_tail_num = cur_tail_num + mItemSize;
  const uint64_t tail_cnt = GET_CNT(cur_tail);

  // Check if looped through buffer.
  mTail = (new_tail_num == (mItemSize * mNumItems)) ?
          CONSTRUCT_NEXT_VALUE(tail_cnt, 0) :
          CONSTRUCT_VALUE(tail_cnt, new_tail_num);

  return true;
}

bool AtomicQueue::Dequeue(void* data_item) {
  const size_t buffer_size = mItemSize * mNumItems;
  for (;;) {
    const uint64_t cur_head = mHead;
    const uint64_t cur_tail = mTail;
    MemoryBarrier();

    // Check if empty (both counter and numbers match)
    if (cur_head == cur_tail)
      return false;

    const uint64_t cur_head_num = GET_NUM(cur_head);

    memcpy(data_item, static_cast<char*>(mBuffer) + cur_head_num, mItemSize);

    const uint64_t new_head_num = cur_head_num + mItemSize;
    const uint64_t head_cnt = GET_CNT(cur_head);

    // Check if looped through buffer.
    const uint64_t new_head_val = (new_head_num == buffer_size) ?
                                  CONSTRUCT_NEXT_VALUE(head_cnt, 0) :
                                  CONSTRUCT_VALUE(head_cnt, new_head_num);

    if (AtomicCmpSet64(&mHead, cur_head, new_head_val))
      break;
  }

  return true;
}

size_t AtomicQueue::CurrentSize() const {
  const uint64_t cur_head = mHead;
  const uint64_t cur_tail = mTail;
  MemoryBarrier();

  const uint64_t size = static_cast<uint64_t>(mItemSize);
  const uint64_t cur_head_num = GET_NUM(cur_head);
  const uint64_t cur_tail_num = GET_NUM(cur_tail);

  if (cur_head_num == cur_tail_num) {
    // Empty if the counters match, full otherwise.
    return (cur_head == cur_tail) ? 0 : mItemSize;
  } else if (cur_tail_num > cur_head_num) {
    return static_cast<size_t>((cur_tail_num - cur_head_num) / size);
  } else {
    const uint64_t looped_tail = cur_tail_num + (size * mNumItems);
    return static_cast<size_t>((looped_tail - cur_head_num) / size);
  }
}

}} // namespace YCommon { namespace YContainers {
<|endoftext|>


<commit_before>///
/// @file  P2_mpi.cpp
/// @brief 2nd partial sieve function.
///        P2(x, y) counts the numbers <= x that have exactly 2 prime
///        factors each exceeding the a-th prime.
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <aligned_vector.hpp>
#include <int128.hpp>
#include <min_max.hpp>
#include <mpi_reduce_sum.hpp>
#include <pmath.hpp>
#include <print.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <iomanip>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Count the primes inside [prime, stop]
template <typename T>
int64_t count_primes(primesieve::iterator& it, int64_t& prime, T stop)
{
  int64_t count = 0;

  for (; prime <= stop; count++)
    prime = it.next_prime();

  return count;
}

/// Calculate the thread sieving distance. The idea is to
/// gradually increase the thread_distance in order to
/// keep all CPU cores busy.
///
void balanceLoad(int64_t* thread_distance,
                 int64_t low,
                 int64_t z,
                 int threads,
                 double start_time)
{
  double seconds = get_wtime() - start_time;

  int64_t min_distance = 1 << 20;
  int64_t max_distance = ceil_div(z - low, threads);

  if (seconds < 60)
    *thread_distance *= 2;
  if (seconds > 60)
    *thread_distance /= 2;

  *thread_distance = in_between(min_distance, *thread_distance, max_distance);
}

template <typename T>
T P2_OpenMP_thread(T x,
                   int64_t y,
                   int64_t z,
                   int64_t thread_distance,
                   int64_t thread_num,
                   int64_t low,
                   int64_t& pix,
                   int64_t& pix_count)
{
  pix = 0;
  pix_count = 0;
  low += thread_distance * thread_num;
  z = min(low + thread_distance, z);
  int64_t start = (int64_t) max(x / z, y);
  int64_t stop = (int64_t) min(x / low, isqrt(x));

  primesieve::iterator rit(stop + 1, start);
  primesieve::iterator it(low - 1, z);

  int64_t next = it.next_prime();
  int64_t prime = rit.previous_prime();
  T P2_thread = 0;

  // \sum_{i = pi[start]+1}^{pi[stop]} pi(x / primes[i])
  while (prime > start &&
         x / prime < z)
  {
    pix += count_primes(it, next, x / prime);
    P2_thread += pix;
    pix_count++;
    prime = rit.previous_prime();
  }

  pix += count_primes(it, next, z - 1);

  return P2_thread;
}

/// P2(x, y) counts the numbers <= x that have exactly 2
/// prime factors each exceeding the a-th prime.
/// Space complexity: O(z^(1/2)).
///
template <typename T>
T P2_mpi_master(T x, int64_t y, int threads)
{
#if __cplusplus >= 201103L
  static_assert(prt::is_signed<T>::value,
                "P2(T x, ...): T must be signed integer type");
#endif

  if (x < 4)
    return 0;

  T a = pi_legendre(y, threads);
  T b = pi_legendre((int64_t) isqrt(x), threads);

  if (a >= b)
    return 0;

  int64_t low = 2;
  int64_t z = (int64_t)(x / max(y, 1));
  int64_t min_distance = 1 << 20;
  int64_t thread_distance = min_distance;

  int proc_id = mpi_proc_id();
  int procs = mpi_num_procs();

  int64_t distance = z - low;
  int64_t proc_distance = ceil_div(distance, procs);
  low += proc_distance * proc_id;
  z = min(low + proc_distance, z);

  T p2 = 0;
  T pix_total = pi_legendre(low - 1, threads);

  if (is_mpi_master_proc())
    p2 = (a - 2) * (a + 1) / 2 - (b - 2) * (b + 1) / 2;

  threads = ideal_num_threads(threads, z);
  aligned_vector<int64_t> pix(threads);
  aligned_vector<int64_t> pix_counts(threads);

  // \sum_{i=a+1}^{b} pi(x / primes[i])
  while (low < z)
  {
    int64_t max_threads = ceil_div(z - low, thread_distance);
    threads = in_between(1, threads, max_threads);
    double time = get_wtime();

    #pragma omp parallel for num_threads(threads) reduction(+: p2)
    for (int i = 0; i < threads; i++)
      p2 += P2_OpenMP_thread(x, y, z, thread_distance, i, low, pix[i], pix_counts[i]);

    low += thread_distance * threads;
    balanceLoad(&thread_distance, low, z, threads, time);

    // Add missing sum contributions in order
    for (int i = 0; i < threads; i++)
    {
      p2 += pix_total * pix_counts[i];
      pix_total += pix[i];
    }

    if (print_status())
    {
      double percent = get_percent((double) low, (double) z);
      cout << "\rStatus: " << fixed << setprecision(get_status_precision(x))
           << percent << '%' << flush;
    }
  }

  p2 = mpi_reduce_sum(p2);

  return p2;
}

} // namespace

namespace primecount {

int64_t P2_mpi(int64_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int64_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#ifdef HAVE_INT128_T

int128_t P2_mpi(int128_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int128_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#endif

} // namespace
<commit_msg>ideal_num_threads() not needed<commit_after>///
/// @file  P2_mpi.cpp
/// @brief 2nd partial sieve function.
///        P2(x, y) counts the numbers <= x that have exactly 2 prime
///        factors each exceeding the a-th prime.
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <aligned_vector.hpp>
#include <int128.hpp>
#include <min_max.hpp>
#include <mpi_reduce_sum.hpp>
#include <pmath.hpp>
#include <print.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <iomanip>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Count the primes inside [prime, stop]
template <typename T>
int64_t count_primes(primesieve::iterator& it, int64_t& prime, T stop)
{
  int64_t count = 0;

  for (; prime <= stop; count++)
    prime = it.next_prime();

  return count;
}

/// Calculate the thread sieving distance. The idea is to
/// gradually increase the thread_distance in order to
/// keep all CPU cores busy.
///
void balanceLoad(int64_t* thread_distance,
                 int64_t low,
                 int64_t z,
                 int threads,
                 double start_time)
{
  double seconds = get_wtime() - start_time;

  int64_t min_distance = 1 << 20;
  int64_t max_distance = ceil_div(z - low, threads);

  if (seconds < 60)
    *thread_distance *= 2;
  if (seconds > 60)
    *thread_distance /= 2;

  *thread_distance = in_between(min_distance, *thread_distance, max_distance);
}

template <typename T>
T P2_OpenMP_thread(T x,
                   int64_t y,
                   int64_t z,
                   int64_t thread_distance,
                   int64_t thread_num,
                   int64_t low,
                   int64_t& pix,
                   int64_t& pix_count)
{
  pix = 0;
  pix_count = 0;
  low += thread_distance * thread_num;
  z = min(low + thread_distance, z);
  int64_t start = (int64_t) max(x / z, y);
  int64_t stop = (int64_t) min(x / low, isqrt(x));

  primesieve::iterator rit(stop + 1, start);
  primesieve::iterator it(low - 1, z);

  int64_t next = it.next_prime();
  int64_t prime = rit.previous_prime();
  T P2_thread = 0;

  // \sum_{i = pi[start]+1}^{pi[stop]} pi(x / primes[i])
  while (prime > start &&
         x / prime < z)
  {
    pix += count_primes(it, next, x / prime);
    P2_thread += pix;
    pix_count++;
    prime = rit.previous_prime();
  }

  pix += count_primes(it, next, z - 1);

  return P2_thread;
}

/// P2(x, y) counts the numbers <= x that have exactly 2
/// prime factors each exceeding the a-th prime.
/// Space complexity: O(z^(1/2)).
///
template <typename T>
T P2_mpi_master(T x, int64_t y, int threads)
{
#if __cplusplus >= 201103L
  static_assert(prt::is_signed<T>::value,
                "P2(T x, ...): T must be signed integer type");
#endif

  if (x < 4)
    return 0;

  T a = pi_legendre(y, threads);
  T b = pi_legendre((int64_t) isqrt(x), threads);

  if (a >= b)
    return 0;

  int64_t low = 2;
  int64_t z = (int64_t)(x / max(y, 1));
  int64_t min_distance = 1 << 20;
  int64_t thread_distance = min_distance;

  int proc_id = mpi_proc_id();
  int procs = mpi_num_procs();

  int64_t distance = z - low;
  int64_t proc_distance = ceil_div(distance, procs);
  low += proc_distance * proc_id;
  z = min(low + proc_distance, z);

  T p2 = 0;
  T pix_total = pi_legendre(low - 1, threads);

  if (is_mpi_master_proc())
    p2 = (a - 2) * (a + 1) / 2 - (b - 2) * (b + 1) / 2;

  aligned_vector<int64_t> pix(threads);
  aligned_vector<int64_t> pix_counts(threads);

  // \sum_{i=a+1}^{b} pi(x / primes[i])
  while (low < z)
  {
    int64_t max_threads = ceil_div(z - low, thread_distance);
    threads = in_between(1, threads, max_threads);
    double time = get_wtime();

    #pragma omp parallel for num_threads(threads) reduction(+: p2)
    for (int i = 0; i < threads; i++)
      p2 += P2_OpenMP_thread(x, y, z, thread_distance, i, low, pix[i], pix_counts[i]);

    low += thread_distance * threads;
    balanceLoad(&thread_distance, low, z, threads, time);

    // Add missing sum contributions in order
    for (int i = 0; i < threads; i++)
    {
      p2 += pix_total * pix_counts[i];
      pix_total += pix[i];
    }

    if (print_status())
    {
      double percent = get_percent((double) low, (double) z);
      cout << "\rStatus: " << fixed << setprecision(get_status_precision(x))
           << percent << '%' << flush;
    }
  }

  p2 = mpi_reduce_sum(p2);

  return p2;
}

} // namespace

namespace primecount {

int64_t P2_mpi(int64_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int64_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#ifdef HAVE_INT128_T

int128_t P2_mpi(int128_t x, int64_t y, int threads)
{
  print("");
  print("=== P2_mpi(x, y) ===");
  print("Computation of the 2nd partial sieve function");
  print(x, y, threads);

  double time = get_wtime();
  int128_t p2 = P2_mpi_master(x, y, threads);

  print("P2", p2, time);
  return p2;
}

#endif

} // namespace
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Disa Mhembere (disa@jhu.edu)
 *
 * This file is part of FlashGraph.
 *
 * 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 CURRENT_KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "kmeans.h"
#define KM_TEST 1
#define VERBOSE 0

#ifdef PROFILER
#include <gperftools/profiler.h>
#endif

namespace {
	static unsigned NUM_COLS;
	static size_t K;
	static unsigned NUM_ROWS;
	short OMP_MAX_THREADS;
	static unsigned g_num_changed = 0;
    static const unsigned INVALID_CLUSTER_ID = std::numeric_limits<unsigned>::max();
	static struct timeval start, end;
    static init_type_t g_init_type;

	/**
	 * \brief This initializes clusters by randomly choosing sample
	 *		membership in a cluster.
	 * See: http://en.wikipedia.org/wiki/K-means_clustering#Initialization_methods
	 *	\param cluster_assignments Which cluster each sample falls into.
	 */
	static void random_partition_init(unsigned* cluster_assignments,
            const double* matrix, clusters::ptr clusters) {
		BOOST_LOG_TRIVIAL(info) << "Random init start";

		// #pragma omp parallel for firstprivate(cluster_assignments, K) shared(cluster_assignments)
		for (unsigned row = 0; row < NUM_ROWS; row++) {
			size_t asgnd_clust = random() % K; // 0...K
            clusters->add_member(&matrix[row*NUM_COLS], asgnd_clust);
			cluster_assignments[row] = asgnd_clust;
		}

		// NOTE: M-Step called in compute func to update cluster counts & centers
#if VERBOSE
		printf("After rand paritions cluster_asgns: "); print_arr(cluster_assignments, NUM_ROWS);
#endif
		BOOST_LOG_TRIVIAL(info) << "Random init end\n";
	}

	/**
	 * \brief Forgy init takes `K` random samples from the matrix
	 *		and uses them as cluster centers.
	 * \param matrix the flattened matrix who's rows are being clustered.
	 * \param clusters The cluster centers (means) flattened matrix.
	 */
	static void forgy_init(const double* matrix, clusters::ptr clusters) {

		BOOST_LOG_TRIVIAL(info) << "Forgy init start";

		for (unsigned clust_idx = 0; clust_idx < K; clust_idx++) { // 0...K
			unsigned rand_idx = random() % (NUM_ROWS - 1); // 0...(n-1)
            clusters->set_mean(&matrix[rand_idx*NUM_COLS], clust_idx);
		}

		BOOST_LOG_TRIVIAL(info) << "Forgy init end";
	}

	/**
	 * \brief A parallel version of the kmeans++ initialization alg.
	 *  See: http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf for algorithm
	 */
	static void kmeanspp_init(const double* matrix, clusters::ptr clusters,
            unsigned* cluster_assignments, std::vector<double>& dist_v) {

		// Choose c1 uniiformly at random
		unsigned selected_idx = random() % NUM_ROWS; // 0...(NUM_ROWS-1)

        clusters->set_mean(&matrix[selected_idx*NUM_COLS], 0);
		dist_v[selected_idx] = 0.0;

#if KM_TEST
		BOOST_LOG_TRIVIAL(info) << "\nChoosing "
            << selected_idx << " as center K = 0";
#endif

		unsigned clust_idx = 0; // The number of clusters assigned

		// Choose next center c_i with weighted prob
		while ((clust_idx + 1) < K) {
			double cum_dist = 0;
#pragma omp parallel for reduction(+:cum_dist) shared (dist_v)
			for (size_t row = 0; row < NUM_ROWS; row++) {
                double dist = dist_comp_raw(&matrix[row*NUM_COLS],
                            &((clusters->get_means())[clust_idx*NUM_COLS]), NUM_COLS);

				if (dist < dist_v[row]) { // Found a closer cluster than before
					dist_v[row] = dist;
                    cluster_assignments[row] = clust_idx;
				}
				cum_dist += dist_v[row];
			}

			cum_dist = (cum_dist * ((double)random())) / (RAND_MAX - 1.0);
			clust_idx++;

			for (size_t i=0; i < NUM_ROWS; i++) {
				cum_dist -= dist_v[i];
				if (cum_dist <= 0) {
#if KM_TEST
					BOOST_LOG_TRIVIAL(info) << "Choosing "
                        << i << " as center K = " << clust_idx;
#endif
                    clusters->set_mean(&(matrix[i*NUM_COLS]), clust_idx);
					break;
				}
			}
			assert (cum_dist <= 0);
		}

#if VERBOSE
		BOOST_LOG_TRIVIAL(info) << "\nCluster centers after kmeans++"; clusters->print_means();
#endif
	}

	/**
	 * \brief Update the cluster assignments while recomputing distance matrix.
	 * \param matrix The flattened matrix who's rows are being clustered.
	 * \param clusters The cluster centers (means) flattened matrix.
	 *	\param cluster_assignments Which cluster each sample falls into.
	 */
	static void EM_step(const double* matrix, clusters::ptr cls,
            unsigned* cluster_assignments, unsigned* cluster_assignment_counts,
            const bool prune_init=false) {

		std::vector<clusters::ptr> pt_cl(OMP_MAX_THREADS);
        // Per thread changed cluster count. OMP_MAX_THREADS
		std::vector<size_t> pt_num_change(OMP_MAX_THREADS);

        for (int i = 0; i < OMP_MAX_THREADS; i++)
            pt_cl[i] = clusters::create(K, NUM_COLS);

#pragma omp parallel for firstprivate(matrix, pt_cl)\
        shared(cluster_assignments) schedule(static)
		for (unsigned row = 0; row < NUM_ROWS; row++) {

            size_t asgnd_clust = INVALID_CLUSTER_ID;
            double best, dist;
            dist = best = std::numeric_limits<double>::max();

            for (unsigned clust_idx = 0; clust_idx < K; clust_idx++) {
                dist = dist_comp_raw(&matrix[row*NUM_COLS],
                        &(cls->get_means()[clust_idx*NUM_COLS]), NUM_COLS);

                if (dist < best) {
                    best = dist;
                    asgnd_clust = clust_idx;
                }
            }

            BOOST_VERIFY(asgnd_clust != INVALID_CLUSTER_ID);

            if (asgnd_clust != cluster_assignments[row]) {
                pt_num_change[omp_get_thread_num()]++;
            }
            cluster_assignments[row] = asgnd_clust;
            pt_cl[omp_get_thread_num()]->add_member(&matrix[row*NUM_COLS], asgnd_clust);
            // Accumulate for local copies
		}

#if VERBOSE
		BOOST_LOG_TRIVIAL(info) << "Clearing cluster assignment counts";
		BOOST_LOG_TRIVIAL(info) << "Clearing cluster centers ...";
#endif
        cls->clear();

		// Serial aggreate of OMP_MAX_THREADS vectors
        // TODO: Pool these
		for (int thd = 0; thd < OMP_MAX_THREADS; thd++) {
			// Updated the changed cluster count
			g_num_changed += pt_num_change[thd];
			// Summation for cluster centers
            cls->peq(pt_cl[thd]);
		}

        unsigned chk_nmemb = 0;
        for (unsigned clust_idx = 0; clust_idx < K; clust_idx++) {
            cls->finalize(clust_idx);
            cluster_assignment_counts[clust_idx] = cls->get_num_members(clust_idx);
            chk_nmemb += cluster_assignment_counts[clust_idx];
        }
        BOOST_VERIFY(chk_nmemb == NUM_ROWS);

#if KM_TEST
		BOOST_LOG_TRIVIAL(info) << "Global number of changes: " << g_num_changed;
#endif
	}
}

namespace fg
{
	unsigned compute_kmeans(const double* matrix, double* clusters_ptr,
			unsigned* cluster_assignments, unsigned* cluster_assignment_counts,
			const unsigned num_rows, const unsigned num_cols, const unsigned k,
            const unsigned MAX_ITERS, const int max_threads, const std::string init,
            const double tolerance, const std::string dist_type)
	{
#ifdef PROFILER
		ProfilerStart("matrix/kmeans.perf");
#endif
		NUM_COLS = num_cols;
		K = k;
		NUM_ROWS = num_rows;
		assert(max_threads > 0);

		OMP_MAX_THREADS = std::min(max_threads, get_num_omp_threads());
		omp_set_num_threads(OMP_MAX_THREADS);
		BOOST_LOG_TRIVIAL(info) << "Running on " << OMP_MAX_THREADS << " threads!";

        // Check k
		if (K > NUM_ROWS || K < 2 || K == (unsigned)-1) {
			BOOST_LOG_TRIVIAL(fatal)
				<< "'k' must be between 2 and the number of rows in the matrix" <<
				"k = " << K;
			exit(-1);
		}

		gettimeofday(&start , NULL);
		/*** Begin VarInit of data structures ***/
        std::fill(&cluster_assignments[0], (&cluster_assignments[0])+NUM_ROWS, -1);
        std::fill(&cluster_assignment_counts[0], (&cluster_assignment_counts[0])+K, 0);

        clusters::ptr clusters = clusters::create(K, NUM_COLS);

        if (init == "none")
            clusters->set_mean(clusters_ptr);

        // For pruning
        std::vector<double> dist_v;
        dist_v.assign(NUM_ROWS, std::numeric_limits<double>::max());

		/*** End VarInit ***/
        BOOST_LOG_TRIVIAL(info) << "Dist_type is " << dist_type;
        if (dist_type == "eucl") {
            g_dist_type = EUCL;
        } else if (dist_type == "cos") {
            g_dist_type = COS;
        } else {
            BOOST_LOG_TRIVIAL(fatal)
                << "[ERROR]: param dist_type must be one of: 'eucl', 'cos'.It is '"
                << dist_type << "'";
            exit(-1);
        }

        if (init == "random") {
            random_partition_init(cluster_assignments, matrix, clusters);
            g_init_type = RANDOM;
        } else if (init == "forgy") {
            forgy_init(matrix, clusters);
            g_init_type = FORGY;
        } else if (init == "kmeanspp") {
            kmeanspp_init(matrix, clusters, cluster_assignments, dist_v);
            g_init_type = PLUSPLUS;
        } else if (init == "none") {
            g_init_type = NONE;
        } else {
            BOOST_LOG_TRIVIAL(fatal)
                << "[ERROR]: param init must be one of: "
                "'random', 'forgy', 'kmeanspp'.It is '"
                << init << "'";
            exit(-1);
        }

        if (g_init_type == NONE || g_init_type == FORGY
                || g_init_type == RANDOM) {
			EM_step(matrix, clusters, cluster_assignments,
                    cluster_assignment_counts, true);
        }

        BOOST_LOG_TRIVIAL(info) << "Init is '" << init << "'";
		BOOST_LOG_TRIVIAL(info) << "Matrix K-means starting ...";

		bool converged = false;
		std::string str_iters = MAX_ITERS == std::numeric_limits<unsigned>::max() ?
			"until convergence ...":
			std::to_string(MAX_ITERS) + " iterations ...";
		BOOST_LOG_TRIVIAL(info) << "Computing " << str_iters;
		unsigned iter = 1;

		while (iter < MAX_ITERS) {
			// Hold cluster assignment counter
			BOOST_LOG_TRIVIAL(info) << "E-step Iteration " << iter <<
				". Computing cluster assignments ...";
			EM_step(matrix, clusters, cluster_assignments,
                    cluster_assignment_counts);
#if KM_TEST
            printf("Cluster assignment counts: ");
            print_arr(cluster_assignment_counts, K);
#endif

			if (g_num_changed == 0 || ((g_num_changed/(double)NUM_ROWS))
                    <= tolerance) {
				converged = true;
				break;
			} else {
				g_num_changed = 0;
			}
			iter++;
		}

		gettimeofday(&end, NULL);
		BOOST_LOG_TRIVIAL(info) << "\n\nAlgorithmic time taken = " <<
			time_diff(start, end) << " sec\n";

#ifdef PROFILER
		ProfilerStop();
#endif
		BOOST_LOG_TRIVIAL(info) << "\n******************************************\n";

		if (converged) {
			BOOST_LOG_TRIVIAL(info) <<
				"K-means converged in " << iter << " iterations";
		} else {
			BOOST_LOG_TRIVIAL(warning) << "[Warning]: K-means failed to converge in "
				<< iter << " iterations";
		}
		BOOST_LOG_TRIVIAL(info) << "\n******************************************\n";

		return iter;
	}
}
<commit_msg>[Matrix]: removed no-op oerg and added bic & spherical projection code<commit_after>/*
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Disa Mhembere (disa@jhu.edu)
 *
 * This file is part of FlashGraph.
 *
 * 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 CURRENT_KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "kmeans.h"
#define KM_TEST 0
#define VERBOSE 0

#ifdef PROFILER
#include <gperftools/profiler.h>
#endif

namespace {
	static unsigned NUM_COLS;
	static size_t K;
	static unsigned NUM_ROWS;
	short OMP_MAX_THREADS;
	static unsigned g_num_changed = 0;
    static const unsigned INVALID_CLUSTER_ID = std::numeric_limits<unsigned>::max();
	static struct timeval start, end;
    static init_type_t g_init_type;

	/**
	 * \brief This initializes clusters by randomly choosing sample
	 *		membership in a cluster.
	 * See: http://en.wikipedia.org/wiki/K-means_clustering#Initialization_methods
	 *	\param cluster_assignments Which cluster each sample falls into.
	 */
	static void random_partition_init(unsigned* cluster_assignments,
            const double* matrix, clusters::ptr clusters) {
		BOOST_LOG_TRIVIAL(info) << "Random init start";

		// #pragma omp parallel for firstprivate(cluster_assignments, K) shared(cluster_assignments)
		for (unsigned row = 0; row < NUM_ROWS; row++) {
			size_t asgnd_clust = random() % K; // 0...K
            clusters->add_member(&matrix[row*NUM_COLS], asgnd_clust);
			cluster_assignments[row] = asgnd_clust;
		}

		// NOTE: M-Step called in compute func to update cluster counts & centers
#if VERBOSE
		printf("After rand paritions cluster_asgns: "); print_arr(cluster_assignments, NUM_ROWS);
#endif
		BOOST_LOG_TRIVIAL(info) << "Random init end\n";
	}

	/**
	 * \brief Forgy init takes `K` random samples from the matrix
	 *		and uses them as cluster centers.
	 * \param matrix the flattened matrix who's rows are being clustered.
	 * \param clusters The cluster centers (means) flattened matrix.
	 */
	static void forgy_init(const double* matrix, clusters::ptr clusters) {

		BOOST_LOG_TRIVIAL(info) << "Forgy init start";

		for (unsigned clust_idx = 0; clust_idx < K; clust_idx++) { // 0...K
			unsigned rand_idx = random() % (NUM_ROWS - 1); // 0...(n-1)
            clusters->set_mean(&matrix[rand_idx*NUM_COLS], clust_idx);
		}

		BOOST_LOG_TRIVIAL(info) << "Forgy init end";
	}

	/**
	 * \brief A parallel version of the kmeans++ initialization alg.
	 *  See: http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf for algorithm
	 */
	static void kmeanspp_init(const double* matrix, clusters::ptr clusters,
            unsigned* cluster_assignments, std::vector<double>& dist_v) {

		// Choose c1 uniiformly at random
		unsigned selected_idx = random() % NUM_ROWS; // 0...(NUM_ROWS-1)

        clusters->set_mean(&matrix[selected_idx*NUM_COLS], 0);
		dist_v[selected_idx] = 0.0;

#if KM_TEST
		BOOST_LOG_TRIVIAL(info) << "\nChoosing "
            << selected_idx << " as center K = 0";
#endif

		unsigned clust_idx = 0; // The number of clusters assigned

		// Choose next center c_i with weighted prob
		while ((clust_idx + 1) < K) {
			double cum_dist = 0;
#pragma omp parallel for reduction(+:cum_dist) shared (dist_v)
			for (size_t row = 0; row < NUM_ROWS; row++) {
                double dist = dist_comp_raw(&matrix[row*NUM_COLS],
                            &((clusters->get_means())[clust_idx*NUM_COLS]), NUM_COLS);

				if (dist < dist_v[row]) { // Found a closer cluster than before
					dist_v[row] = dist;
                    cluster_assignments[row] = clust_idx;
				}
				cum_dist += dist_v[row];
			}

			cum_dist = (cum_dist * ((double)random())) / (RAND_MAX - 1.0);
			clust_idx++;

			for (size_t i=0; i < NUM_ROWS; i++) {
				cum_dist -= dist_v[i];
				if (cum_dist <= 0) {
#if KM_TEST
					BOOST_LOG_TRIVIAL(info) << "Choosing "
                        << i << " as center K = " << clust_idx;
#endif
                    clusters->set_mean(&(matrix[i*NUM_COLS]), clust_idx);
					break;
				}
			}
			assert (cum_dist <= 0);
		}

#if VERBOSE
		BOOST_LOG_TRIVIAL(info) << "\nCluster centers after kmeans++"; clusters->print_means();
#endif
	}

	/**
	 * \brief Update the cluster assignments while recomputing distance matrix.
	 * \param matrix The flattened matrix who's rows are being clustered.
	 * \param clusters The cluster centers (means) flattened matrix.
	 *	\param cluster_assignments Which cluster each sample falls into.
	 */
	static void EM_step(const double* matrix, clusters::ptr cls,
            unsigned* cluster_assignments, unsigned* cluster_assignment_counts) {

		std::vector<clusters::ptr> pt_cl(OMP_MAX_THREADS);
        // Per thread changed cluster count. OMP_MAX_THREADS
		std::vector<size_t> pt_num_change(OMP_MAX_THREADS);

        for (int i = 0; i < OMP_MAX_THREADS; i++)
            pt_cl[i] = clusters::create(K, NUM_COLS);

#pragma omp parallel for firstprivate(matrix, pt_cl)\
        shared(cluster_assignments) schedule(static)
		for (unsigned row = 0; row < NUM_ROWS; row++) {

            size_t asgnd_clust = INVALID_CLUSTER_ID;
            double best, dist;
            dist = best = std::numeric_limits<double>::max();

            for (unsigned clust_idx = 0; clust_idx < K; clust_idx++) {
                dist = dist_comp_raw(&matrix[row*NUM_COLS],
                        &(cls->get_means()[clust_idx*NUM_COLS]), NUM_COLS);

                if (dist < best) {
                    best = dist;
                    asgnd_clust = clust_idx;
                }
            }

            BOOST_VERIFY(asgnd_clust != INVALID_CLUSTER_ID);

            if (asgnd_clust != cluster_assignments[row]) {
                pt_num_change[omp_get_thread_num()]++;
            }
            cluster_assignments[row] = asgnd_clust;
            pt_cl[omp_get_thread_num()]->add_member(&matrix[row*NUM_COLS], asgnd_clust);
            // Accumulate for local copies
		}

#if VERBOSE
		BOOST_LOG_TRIVIAL(info) << "Clearing cluster assignment counts";
		BOOST_LOG_TRIVIAL(info) << "Clearing cluster centers ...";
#endif
        cls->clear();

		// Serial aggreate of OMP_MAX_THREADS vectors
        // TODO: Pool these
		for (int thd = 0; thd < OMP_MAX_THREADS; thd++) {
			// Updated the changed cluster count
			g_num_changed += pt_num_change[thd];
			// Summation for cluster centers
            cls->peq(pt_cl[thd]);
		}

        unsigned chk_nmemb = 0;
        for (unsigned clust_idx = 0; clust_idx < K; clust_idx++) {
            cls->finalize(clust_idx);
            cluster_assignment_counts[clust_idx] = cls->get_num_members(clust_idx);
            chk_nmemb += cluster_assignment_counts[clust_idx];
        }
        BOOST_VERIFY(chk_nmemb == NUM_ROWS);

#if KM_TEST
		BOOST_LOG_TRIVIAL(info) << "Global number of changes: " << g_num_changed;
#endif
	}
}

namespace fg
{
	unsigned compute_kmeans(const double* matrix, double* clusters_ptr,
			unsigned* cluster_assignments, unsigned* cluster_assignment_counts,
			const unsigned num_rows, const unsigned num_cols, const unsigned k,
            const unsigned MAX_ITERS, const int max_threads, const std::string init,
            const double tolerance, const std::string dist_type)
	{
#ifdef PROFILER
		ProfilerStart("matrix/kmeans.perf");
#endif
		NUM_COLS = num_cols;
		K = k;
		NUM_ROWS = num_rows;
		assert(max_threads > 0);

		OMP_MAX_THREADS = std::min(max_threads, get_num_omp_threads());
		omp_set_num_threads(OMP_MAX_THREADS);
		BOOST_LOG_TRIVIAL(info) << "Running on " << OMP_MAX_THREADS << " threads!";

        // Check k
		if (K > NUM_ROWS || K < 2 || K == (unsigned)-1) {
			BOOST_LOG_TRIVIAL(fatal)
				<< "'k' must be between 2 and the number of rows in the matrix" <<
				"k = " << K;
			exit(-1);
		}

        /*BOOST_LOG_TRIVIAL(info) << "Projecting onto a sphere:";
        spherical_projection(matrix, NUM_ROWS, NUM_COLS);*/

		gettimeofday(&start , NULL);
		/*** Begin VarInit of data structures ***/
        std::fill(&cluster_assignments[0], (&cluster_assignments[0])+NUM_ROWS, -1);
        std::fill(&cluster_assignment_counts[0], (&cluster_assignment_counts[0])+K, 0);

        clusters::ptr clusters = clusters::create(K, NUM_COLS);

        if (init == "none")
            clusters->set_mean(clusters_ptr);

        std::vector<double> dist_v;
        dist_v.assign(NUM_ROWS, std::numeric_limits<double>::max());

		/*** End VarInit ***/
        BOOST_LOG_TRIVIAL(info) << "Dist_type is " << dist_type;
        if (dist_type == "eucl") {
            g_dist_type = EUCL;
        } else if (dist_type == "cos") {
            g_dist_type = COS;
        } else {
            BOOST_LOG_TRIVIAL(fatal)
                << "[ERROR]: param dist_type must be one of: 'eucl', 'cos'.It is '"
                << dist_type << "'";
            exit(-1);
        }

        if (init == "random") {
            random_partition_init(cluster_assignments, matrix, clusters);
            g_init_type = RANDOM;
        } else if (init == "forgy") {
            forgy_init(matrix, clusters);
            g_init_type = FORGY;
        } else if (init == "kmeanspp") {
            kmeanspp_init(matrix, clusters, cluster_assignments, dist_v);
            g_init_type = PLUSPLUS;
        } else if (init == "none") {
            g_init_type = NONE;
        } else {
            BOOST_LOG_TRIVIAL(fatal)
                << "[ERROR]: param init must be one of: "
                "'random', 'forgy', 'kmeanspp'.It is '"
                << init << "'";
            exit(-1);
        }

        if (g_init_type == NONE || g_init_type == FORGY
                || g_init_type == RANDOM) {
			EM_step(matrix, clusters, cluster_assignments,
                    cluster_assignment_counts);
        }

		gettimeofday(&end, NULL);
		BOOST_LOG_TRIVIAL(info) << "\n\nInitialization time taken = " <<
			time_diff(start, end) << " sec\n";
		gettimeofday(&start , NULL);

        BOOST_LOG_TRIVIAL(info) << "Init is '" << init << "'";
		BOOST_LOG_TRIVIAL(info) << "Matrix K-means starting ...";
#if 0
        FILE* f;
        BOOST_VERIFY(f =
                fopen("/mnt/nfs/disa/data/big/friendster-8-10centers", "wb"));
        fwrite(&((clusters->get_means())[0]),
                sizeof(double)*NUM_COLS*K, 1, f);
        fclose(f);
        printf("\n\nCenters should be:\n");
        clusters->print_means();
        exit(1);
#endif
		bool converged = false;
		std::string str_iters = MAX_ITERS == std::numeric_limits<unsigned>::max() ?
			"until convergence ...":
			std::to_string(MAX_ITERS) + " iterations ...";
		BOOST_LOG_TRIVIAL(info) << "Computing " << str_iters;
		unsigned iter = 1;

		while (iter < MAX_ITERS) {
			// Hold cluster assignment counter
			BOOST_LOG_TRIVIAL(info) << "E-step Iteration " << iter <<
				". Computing cluster assignments ...";
			EM_step(matrix, clusters, cluster_assignments,
                    cluster_assignment_counts);
#if KM_TEST
            printf("Cluster assignment counts: ");
            print_arr(cluster_assignment_counts, K);
#endif

			if (g_num_changed == 0 || ((g_num_changed/(double)NUM_ROWS))
                    <= tolerance) {
				converged = true;
				break;
			} else {
				g_num_changed = 0;
			}
			iter++;
		}

		gettimeofday(&end, NULL);
		BOOST_LOG_TRIVIAL(info) << "\n\nAlgorithmic time taken = " <<
			time_diff(start, end) << " sec\n";

#ifdef PROFILER
		ProfilerStop();
#endif
		BOOST_LOG_TRIVIAL(info) << "\n******************************************\n";

		if (converged) {
			BOOST_LOG_TRIVIAL(info) <<
				"K-means converged in " << iter << " iterations";
		} else {
			BOOST_LOG_TRIVIAL(warning) << "[Warning]: K-means failed to converge in "
				<< iter << " iterations";
		}
		BOOST_LOG_TRIVIAL(info) << "\n******************************************\n";

#if VERBOSE
        printf("Computed bic: %f\n", get_bic(dist_v, NUM_ROWS, NUM_COLS, K));
        unsigned max_index = (std::max_element(cluster_assignment_counts,
                    cluster_assignment_counts+K) - cluster_assignment_counts);

        store_cluster(max_index, matrix, cluster_assignment_counts[max_index],
                cluster_assignments, NUM_ROWS, NUM_COLS, "/mnt/nfs/disa/data/big/");
#endif

		return iter;
	}
}
<|endoftext|>


<commit_before><commit_msg>119 solved<commit_after><|endoftext|>