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

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you 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.

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

//==============================================================================
// Main
//==============================================================================

#include "common.h"
#include "guiutils.h"
#include "mainwindow.h"
#include "splashscreenwindow.h"

//==============================================================================

#include <QDir>
#include <QProcess>
#include <QSettings>

#ifdef Q_OS_WIN
    #include <QWebSettings>
#endif

//==============================================================================

#include <QtSingleApplication>

//==============================================================================

#include <stdlib.h>

//==============================================================================

int main(int pArgC, char *pArgV[])
{
    // Create our application
    // Note: on Linux and OS X, we first try to run the CLI version of OpenCOR
    //       while on Windows, we go straight for the GUI version. Indeed, in
    //       the case of Windows, we have two binaries (.com and .exe that are
    //       for the CLI and GUI versions of OpenCOR, respectively). This means
    //       that when a console window is open, to enter something like:
    //           C:\>OpenCOR
    //       will effectively call OpenCOR.com. From there, should there be no
    //       argument that requires CLI treatment, then the GUI version of
    //       OpenCOR will be launched. This is, unfortunately, the only way to
    //       have OpenCOR to behave as both a CLI and a GUI application on
    //       Windows, hence the [OpenCOR]/windows/main.cpp file which is used to
    //       generate the CLI version of OpenCOR...

#if defined(Q_OS_WIN)
    SharedTools::QtSingleApplication *app = new SharedTools::QtSingleApplication(QFileInfo(pArgV[0]).baseName(),
                                                                                pArgC, pArgV);
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    QCoreApplication *cliApp = new QCoreApplication(pArgC, pArgV);
#else
    #error Unsupported platform
#endif

    // Remove all 'global' instances, in case OpenCOR previously crashed or
    // something (and therefore didn't remove all of them before quitting)

    OpenCOR::removeGlobalInstances();

    // Some general initialisations

#if defined(Q_OS_WIN)
    OpenCOR::initApplication(app);
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    OpenCOR::initApplication(cliApp);
#else
    #error Unsupported platform
#endif

    // Try to run OpenCOR as a CLI application

#if defined(Q_OS_WIN)
    // Do nothing...
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    int res;

    bool runCliApplication = OpenCOR::cliApplication(cliApp, &res);

    delete cliApp;

    if (runCliApplication) {
        // OpenCOR was run as a CLI application, so...

        OpenCOR::removeGlobalInstances();

        return res;
    }

    // At this stage, we tried to run the CLI version of OpenCOR, but in the end
    // we need to run the GUI version, so start over but with the GUI version of
    // OpenCOR this time

    // Make sure that we always use indirect rendering on Linux
    // Note: indeed, depending on which plugins are selected, OpenCOR may need
    //       LLVM. If that's the case, and in case the user's video card uses a
    //       driver that relies on LLVM (e.g. Gallium3D and Mesa 3D), then
    //       there may be a conflict between the version of LLVM used by
    //       OpenCOR and the one used by the video card. One way to address this
    //       issue is by using indirect rendering...

#ifdef Q_OS_LINUX
    setenv("LIBGL_ALWAYS_INDIRECT", "1", 1);
#endif

    // Create our application
    // Note: the CLI version of OpenCOR didn't actually do anything, so no need
    //       to re-remove all 'global' instances...

    SharedTools::QtSingleApplication *app = new SharedTools::QtSingleApplication(QFileInfo(pArgV[0]).baseName(),
                                                                                pArgC, pArgV);

    // Some general initialisations

    OpenCOR::initApplication(app);
#else
    #error Unsupported platform
#endif

    // Initialise our colours by 'updating' them

    OpenCOR::Core::updateColors();

#ifndef QT_DEBUG
    // Show our splash screen

    OpenCOR::SplashScreenWindow *splashScreen = new OpenCOR::SplashScreenWindow();

    splashScreen->show();

    app->processEvents();
#endif

    // Send a message (containing the arguments that were passed to this
    // instance of OpenCOR minus the first one since it corresponds to the full
    // path to our executable, which we are not interested in) to our 'official'
    // instance of OpenCOR, should there be one. If there is no none, then just
    // carry on as normal, otherwise exit since we want only one instance of
    // OpenCOR at any given time

    QStringList appArguments = app->arguments();

    appArguments.removeFirst();

    QString arguments = appArguments.join("|");

    if (app->isRunning()) {
        app->sendMessage(arguments);

        delete app;

        return 0;
    }

#ifdef Q_OS_WIN
    // Specify where to find non-OpenCOR plugins (only required on Windows)

    app->addLibraryPath( QDir(app->applicationDirPath()).canonicalPath()
                        +QDir::separator()+QString("..")
                        +QDir::separator()+"plugins");
#endif

    // Create our main window

    OpenCOR::MainWindow *win = new OpenCOR::MainWindow(app);

    // Keep track of our main window (required by QtSingleApplication so that it
    // can do what it's supposed to be doing)

    app->setActivationWindow(win);

    // Handle our arguments

    win->handleArguments(arguments);

    // Show our main window

    win->show();

#ifndef QT_DEBUG
    // Get rid of our splash screen once our main window is visible

    splashScreen->finish(win);

    // Make sure that our main window is in the foreground
    // Note: indeed, on Linux, to show our splash screen may result in our main
    //       window being shown in the background, so...

    win->showSelf();
#endif

    // Execute our application

#ifdef Q_OS_WIN
    int
#endif
    res = app->exec();

    // Keep track of our application file and directory paths (in case we need
    // to restart OpenCOR)

    QString appFilePath = app->applicationFilePath();
    QString appDirPath  = app->applicationDirPath();

    // Delete our main window

    delete win;

    // If we use QtWebKit, and QWebPage in particular, then leak messages will
    // get generated on Windows when leaving OpenCOR. This is because an object
    // cache is shared between all QWebPage instances. So to destroy a QWebPage
    // instance won't clear the cache, hence the leak messages. However, these
    // messages are 'only' warnings, so we can safely live with them. Still, it
    // doesn't look 'good', so we clear the memory caches, thus avoiding those
    // leak messages...
    // Note: the below must absolutely be done after calling app->exec() and
    //       before deleting app...

#ifdef Q_OS_WIN
    QWebSettings::clearMemoryCaches();
#endif

    // Delete our application

    delete app;

    // Remove all 'global' instances that were created and used during this
    // session

    OpenCOR::removeGlobalInstances();

    // We are done with the execution of our application, so now the question is
    // whether we need to restart
    // Note: we do this here rather than 'within' the GUI because once we have
    //       launched a new instance of OpenCOR, we want this instance of
    //       OpenCOR to finish as soon as possible which will be the case here
    //       since all that remains to be done is to return the result of the
    //       execution of our application...

    if (res == OpenCOR::NeedRestart)
        // Restart OpenCOR, but without providing any of the arguments that were
        // originally passed to us since we want to reset everything

        QProcess::startDetached(appFilePath, QStringList(), appDirPath);

    // We are done, so...

    return res;
}

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Fixed a small memory leak [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you 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.

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

//==============================================================================
// Main
//==============================================================================

#include "common.h"
#include "guiutils.h"
#include "mainwindow.h"
#include "splashscreenwindow.h"

//==============================================================================

#include <QDir>
#include <QProcess>
#include <QSettings>

#ifdef Q_OS_WIN
    #include <QWebSettings>
#endif

//==============================================================================

#include <QtSingleApplication>

//==============================================================================

#include <stdlib.h>

//==============================================================================

int main(int pArgC, char *pArgV[])
{
    // Create our application
    // Note: on Linux and OS X, we first try to run the CLI version of OpenCOR
    //       while on Windows, we go straight for the GUI version. Indeed, in
    //       the case of Windows, we have two binaries (.com and .exe that are
    //       for the CLI and GUI versions of OpenCOR, respectively). This means
    //       that when a console window is open, to enter something like:
    //           C:\>OpenCOR
    //       will effectively call OpenCOR.com. From there, should there be no
    //       argument that requires CLI treatment, then the GUI version of
    //       OpenCOR will be launched. This is, unfortunately, the only way to
    //       have OpenCOR to behave as both a CLI and a GUI application on
    //       Windows, hence the [OpenCOR]/windows/main.cpp file which is used to
    //       generate the CLI version of OpenCOR...

#if defined(Q_OS_WIN)
    SharedTools::QtSingleApplication *app = new SharedTools::QtSingleApplication(QFileInfo(pArgV[0]).baseName(),
                                                                                pArgC, pArgV);
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    QCoreApplication *cliApp = new QCoreApplication(pArgC, pArgV);
#else
    #error Unsupported platform
#endif

    // Remove all 'global' instances, in case OpenCOR previously crashed or
    // something (and therefore didn't remove all of them before quitting)

    OpenCOR::removeGlobalInstances();

    // Some general initialisations

#if defined(Q_OS_WIN)
    OpenCOR::initApplication(app);
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    OpenCOR::initApplication(cliApp);
#else
    #error Unsupported platform
#endif

    // Try to run OpenCOR as a CLI application

#if defined(Q_OS_WIN)
    // Do nothing...
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    int res;

    bool runCliApplication = OpenCOR::cliApplication(cliApp, &res);

    delete cliApp;

    if (runCliApplication) {
        // OpenCOR was run as a CLI application, so...

        OpenCOR::removeGlobalInstances();

        return res;
    }

    // At this stage, we tried to run the CLI version of OpenCOR, but in the end
    // we need to run the GUI version, so start over but with the GUI version of
    // OpenCOR this time

    // Make sure that we always use indirect rendering on Linux
    // Note: indeed, depending on which plugins are selected, OpenCOR may need
    //       LLVM. If that's the case, and in case the user's video card uses a
    //       driver that relies on LLVM (e.g. Gallium3D and Mesa 3D), then
    //       there may be a conflict between the version of LLVM used by
    //       OpenCOR and the one used by the video card. One way to address this
    //       issue is by using indirect rendering...

#ifdef Q_OS_LINUX
    setenv("LIBGL_ALWAYS_INDIRECT", "1", 1);
#endif

    // Create our application
    // Note: the CLI version of OpenCOR didn't actually do anything, so no need
    //       to re-remove all 'global' instances...

    SharedTools::QtSingleApplication *app = new SharedTools::QtSingleApplication(QFileInfo(pArgV[0]).baseName(),
                                                                                pArgC, pArgV);

    // Some general initialisations

    OpenCOR::initApplication(app);
#else
    #error Unsupported platform
#endif

    // Initialise our colours by 'updating' them

    OpenCOR::Core::updateColors();

#ifndef QT_DEBUG
    // Show our splash screen

    OpenCOR::SplashScreenWindow *splashScreen = new OpenCOR::SplashScreenWindow();

    splashScreen->show();

    app->processEvents();
#endif

    // Send a message (containing the arguments that were passed to this
    // instance of OpenCOR minus the first one since it corresponds to the full
    // path to our executable, which we are not interested in) to our 'official'
    // instance of OpenCOR, should there be one. If there is no none, then just
    // carry on as normal, otherwise exit since we want only one instance of
    // OpenCOR at any given time

    QStringList appArguments = app->arguments();

    appArguments.removeFirst();

    QString arguments = appArguments.join("|");

    if (app->isRunning()) {
        app->sendMessage(arguments);

        delete app;

        return 0;
    }

#ifdef Q_OS_WIN
    // Specify where to find non-OpenCOR plugins (only required on Windows)

    app->addLibraryPath( QDir(app->applicationDirPath()).canonicalPath()
                        +QDir::separator()+QString("..")
                        +QDir::separator()+"plugins");
#endif

    // Create our main window

    OpenCOR::MainWindow *win = new OpenCOR::MainWindow(app);

    // Keep track of our main window (required by QtSingleApplication so that it
    // can do what it's supposed to be doing)

    app->setActivationWindow(win);

    // Handle our arguments

    win->handleArguments(arguments);

    // Show our main window

    win->show();

#ifndef QT_DEBUG
    // Get rid of our splash screen once our main window is visible

    splashScreen->finish(win);

    delete splashScreen;

    // Make sure that our main window is in the foreground
    // Note: indeed, on Linux, to show our splash screen may result in our main
    //       window being shown in the background, so...

    win->showSelf();
#endif

    // Execute our application

#ifdef Q_OS_WIN
    int
#endif
    res = app->exec();

    // Keep track of our application file and directory paths (in case we need
    // to restart OpenCOR)

    QString appFilePath = app->applicationFilePath();
    QString appDirPath  = app->applicationDirPath();

    // Delete our main window

    delete win;

    // If we use QtWebKit, and QWebPage in particular, then leak messages will
    // get generated on Windows when leaving OpenCOR. This is because an object
    // cache is shared between all QWebPage instances. So to destroy a QWebPage
    // instance won't clear the cache, hence the leak messages. However, these
    // messages are 'only' warnings, so we can safely live with them. Still, it
    // doesn't look 'good', so we clear the memory caches, thus avoiding those
    // leak messages...
    // Note: the below must absolutely be done after calling app->exec() and
    //       before deleting app...

#ifdef Q_OS_WIN
    QWebSettings::clearMemoryCaches();
#endif

    // Delete our application

    delete app;

    // Remove all 'global' instances that were created and used during this
    // session

    OpenCOR::removeGlobalInstances();

    // We are done with the execution of our application, so now the question is
    // whether we need to restart
    // Note: we do this here rather than 'within' the GUI because once we have
    //       launched a new instance of OpenCOR, we want this instance of
    //       OpenCOR to finish as soon as possible which will be the case here
    //       since all that remains to be done is to return the result of the
    //       execution of our application...

    if (res == OpenCOR::NeedRestart)
        // Restart OpenCOR, but without providing any of the arguments that were
        // originally passed to us since we want to reset everything

        QProcess::startDetached(appFilePath, QStringList(), appDirPath);

    // We are done, so...

    return res;
}

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/* Copyright (C) 2014-2015 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <efyj/model.hpp>
#include <efyj/exception.hpp>
#include <efyj/problem.hpp>

#include <iostream>
#include <algorithm>
#include <chrono>
#include <fstream>
#include <iterator>
#include <random>
#include <cstdlib>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <getopt.h>

#ifdef EFYj_MPI_SUPPORT
    #include <mpi.h>
#endif

namespace {

void usage() noexcept
{
    std::cout << "efyj [-h][-m file.dexi][-o file.csv]\n\n"
              << "Options:\n"
              << "    -h                   This help message\n"
              << "    -m model.dexi        The model file\n"
              << "    -o options.csv       The options file\n"
              << "    -s solver_name       Select the specified solver\n"
              << "\n"
              << "Available solvers:\n"
              << "   classic            the default tree path\n"
              << "   stack              stack and reverse polish notation\n"
              << "   bigmem             default solver fill a big memory space\n"
              << std::endl;
}

} // anonymous namespace

int main(int argc, char *argv[])
{
    int ret = EXIT_SUCCESS;
    int opt;
    std::string modelfilepath, optionfilepath;
    std::string solvername;

    while ((opt = ::getopt(argc, argv, "m:o:s:h")) != -1) {
        switch (opt) {
        case 'm':
            modelfilepath.assign(::optarg);
            break;

        case 'o':
            optionfilepath.assign(::optarg);
            break;

        case 's':
            solvername.assign(::optarg);
            break;

        case 'h':
        default:
            ::usage();
            exit(EXIT_SUCCESS);
        }
    }

    if (::optind > argc) {
        std::cerr << "Expected argument after -m, -o or -s options\n";
        exit(EXIT_FAILURE);
    }

    try {
        efyj::Context ctx = std::make_shared <efyj::ContextImpl>(efyj::LOG_OPTION_ERR);
        efyj::problem pb(ctx, modelfilepath, optionfilepath);

        if (solvername == "stack")
          pb.compute <efyj::solver_stack>(0, 1);
        else if (solvername == "bigmem")
          pb.compute <efyj::solver_bigmem>(0, 1);
        else
          pb.compute <efyj::solver_basic>(0, 1);
    } catch (const std::exception &e) {
        std::cerr << "failure: " << e.what() << '\n';
    }

    return ret;
}
<commit_msg>main: cleanup headers<commit_after>/* Copyright (C) 2014-2015 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <efyj/model.hpp>
#include <efyj/exception.hpp>
#include <efyj/problem.hpp>

#include <iostream>
#include <chrono>
#include <fstream>
#include <getopt.h>

#ifdef EFYj_MPI_SUPPORT
    #include <mpi.h>
#endif

namespace {

void usage() noexcept
{
    std::cout << "efyj [-h][-m file.dexi][-o file.csv]\n\n"
              << "Options:\n"
              << "    -h                   This help message\n"
              << "    -m model.dexi        The model file\n"
              << "    -o options.csv       The options file\n"
              << "    -s solver_name       Select the specified solver\n"
              << "\n"
              << "Available solvers:\n"
              << "   classic            the default tree path\n"
              << "   stack              stack and reverse polish notation\n"
              << "   bigmem             default solver fill a big memory space\n"
              << std::endl;
}

} // anonymous namespace

int main(int argc, char *argv[])
{
    int ret = EXIT_SUCCESS;
    int opt;
    std::string modelfilepath, optionfilepath;
    std::string solvername;

    while ((opt = ::getopt(argc, argv, "m:o:s:h")) != -1) {
        switch (opt) {
        case 'm':
            modelfilepath.assign(::optarg);
            break;

        case 'o':
            optionfilepath.assign(::optarg);
            break;

        case 's':
            solvername.assign(::optarg);
            break;

        case 'h':
        default:
            ::usage();
            exit(EXIT_SUCCESS);
        }
    }

    if (::optind > argc) {
        std::cerr << "Expected argument after -m, -o or -s options\n";
        exit(EXIT_FAILURE);
    }

    try {
        efyj::Context ctx = std::make_shared <efyj::ContextImpl>(efyj::LOG_OPTION_ERR);
        efyj::problem pb(ctx, modelfilepath, optionfilepath);

        if (solvername == "stack")
          pb.compute <efyj::solver_stack>(0, 1);
        else if (solvername == "bigmem")
          pb.compute <efyj::solver_bigmem>(0, 1);
        else
          pb.compute <efyj::solver_basic>(0, 1);
    } catch (const std::exception &e) {
        std::cerr << "failure: " << e.what() << '\n';
    }

    return ret;
}
<|endoftext|>


<commit_before>#include "../ui/mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
#ifdef Q_OS_LINUX
  QCoreApplication::addLibraryPath("/usr/lib/viqo");
#endif

  QApplication a(argc, argv);

  QCoreApplication::setApplicationName("Viqo");
  QCoreApplication::setApplicationVersion("2.3.1");

  QCommandLineParser parser;
  parser.setApplicationDescription(
        QStringLiteral("Qt で作成されたマルチプラットフォームコメントビューワです"));
  parser.addHelpOption();
  parser.addVersionOption();

  // Process the actual command line arguments given by the user
  parser.process(a);

  MainWindow w;
  w.show();

  return a.exec();
}
<commit_msg>version 2.3.3<commit_after>#include "../ui/mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
#ifdef Q_OS_LINUX
  QCoreApplication::addLibraryPath("/usr/lib/viqo");
#endif

  QApplication a(argc, argv);

  QCoreApplication::setApplicationName("Viqo");
  QCoreApplication::setApplicationVersion("2.3.3");

  QCommandLineParser parser;
  parser.setApplicationDescription(
        QStringLiteral("Qt で作成されたマルチプラットフォームコメントビューワです"));
  parser.addHelpOption();
  parser.addVersionOption();

  // Process the actual command line arguments given by the user
  parser.process(a);

  MainWindow w;
  w.show();

  return a.exec();
}
<|endoftext|>


<commit_before>#include <QApplication>
#include <QMessageBox>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>
#include <QWidget>

#include <glib-object.h>

#include "utils/process.h"
#include "seafile-applet.h"
#include "QtAwesome.h"

#ifdef Q_OS_MAC
static bool dockClickHandler(id self,SEL _cmd,...)
{
    Q_UNUSED(self)
    Q_UNUSED(_cmd)
    if (seafApplet) {
        MainWindow *main_win = seafApplet->mainWindow();
        main_win->showWindow();
    }
    return true;
}

Application::Application (int& argc, char **argv)
: QApplication(argc, argv)
{
    objc_object* cls = objc_getClass("NSApplication");
    SEL sharedApplication = sel_registerName("sharedApplication");
    objc_object* appInst = objc_msgSend(cls,sharedApplication);

    if(appInst != NULL)
    {
        objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
        objc_object* delClass = objc_msgSend(delegate,  sel_registerName("class"));
        class_addMethod((objc_class*)delClass, sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"), (IMP)dockClickHandler,"B@:");
    }
}

#endif

int main(int argc, char *argv[])
{
    if (count_process("seafile-applet") > 1) {
        QMessageBox::warning(NULL, "Seafile",
                             QObject::tr("Seafile is already running"),
                             QMessageBox::Ok);
        return -1;
    }

#ifdef Q_WS_MAC
    Application app(argc, argv);
#else
    QApplication app(argc, argv);
#endif

    app.setQuitOnLastWindowClosed(false);

    // see QSettings documentation
    QCoreApplication::setOrganizationName("Seafile");
    QCoreApplication::setOrganizationDomain("seafile.com");
    QCoreApplication::setApplicationName("Seafile Client");

    // initialize i18n
    QTranslator qtTranslator;
    qtTranslator.load("qt_" + QLocale::system().name(),
                      QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    app.installTranslator(&qtTranslator);

    QTranslator myappTranslator;
    myappTranslator.load(QString(":/i18n/seafile_%1.qm").arg(QLocale::system().name()));
    app.installTranslator(&myappTranslator);

#if !GLIB_CHECK_VERSION(2, 35, 0)
    g_type_init();
#endif
#if !GLIB_CHECK_VERSION(2, 31, 0)
    g_thread_init(NULL);
#endif

    awesome = new QtAwesome(qApp);
    awesome->initFontAwesome();

    seafApplet = new SeafileApplet;
    seafApplet->start();

    return app.exec();
}
<commit_msg>fixed a bug when running two instances of seafile-client<commit_after>#include <QApplication>
#include <QMessageBox>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>
#include <QWidget>

#include <glib-object.h>
#include <stdio.h>

#include "utils/process.h"
#include "seafile-applet.h"
#include "QtAwesome.h"

#ifdef Q_OS_MAC
static bool dockClickHandler(id self,SEL _cmd,...)
{
    Q_UNUSED(self)
    Q_UNUSED(_cmd)
    if (seafApplet) {
        MainWindow *main_win = seafApplet->mainWindow();
        main_win->showWindow();
    }
    return true;
}

Application::Application (int& argc, char **argv)
: QApplication(argc, argv)
{
    objc_object* cls = objc_getClass("NSApplication");
    SEL sharedApplication = sel_registerName("sharedApplication");
    objc_object* appInst = objc_msgSend(cls,sharedApplication);

    if(appInst != NULL)
    {
        objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
        objc_object* delClass = objc_msgSend(delegate,  sel_registerName("class"));
        class_addMethod((objc_class*)delClass, sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"), (IMP)dockClickHandler,"B@:");
    }
}

#endif

int main(int argc, char *argv[])
{
#ifdef Q_WS_MAC
    Application app(argc, argv);
#else
    QApplication app(argc, argv);
#endif

    if (count_process("seafile-applet") > 1) {
        QMessageBox::warning(NULL, "Seafile",
                             QObject::tr("Seafile is already running"),
                             QMessageBox::Ok);
        return -1;
    }

    app.setQuitOnLastWindowClosed(false);

    // see QSettings documentation
    QCoreApplication::setOrganizationName("Seafile");
    QCoreApplication::setOrganizationDomain("seafile.com");
    QCoreApplication::setApplicationName("Seafile Client");

    // initialize i18n
    QTranslator qtTranslator;
    qtTranslator.load("qt_" + QLocale::system().name(),
                      QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    app.installTranslator(&qtTranslator);

    QTranslator myappTranslator;
    myappTranslator.load(QString(":/i18n/seafile_%1.qm").arg(QLocale::system().name()));
    app.installTranslator(&myappTranslator);

#if !GLIB_CHECK_VERSION(2, 35, 0)
    g_type_init();
#endif
#if !GLIB_CHECK_VERSION(2, 31, 0)
    g_thread_init(NULL);
#endif

    awesome = new QtAwesome(qApp);
    awesome->initFontAwesome();

    seafApplet = new SeafileApplet;
    seafApplet->start();

    return app.exec();
}
<|endoftext|>


<commit_before>/**
 *
 * Terminology (Matroid - Graph) for escalated version of algorithm:
 *  Basis - Spanning forest
 *  Independent set - Tree (i.e. subset of a basis)
 *  Circuit - cycle
 *  Cocircuit - minimal edge-cut
 *  Hyperplane - maximal set not containing any basis (= complement of a min-cut)
 *
 *  Spanning forest - union of spanning trees of each component of an unconnected graph
 *
 */

enum {
    BLACK,
    RED,
    BLUE
};

#include <iostream>
#include <stdexcept>
#include <ogdf/basic/Queue.h>
#include <ogdf/basic/Graph.h>
#include <ogdf/basic/Stack.h>
#include <ogdf/basic/simple_graph_alg.h>

#include "helpers.hpp"
#include "graphcoloring.h"

using namespace std;
using namespace ogdf;

int m; // Cocircuit size bound

/**
 * @brief Takes a csv file with lines "<id>;<source>;<target>;<edge name>;..." and transforms it into graph
 * @param sEdgesFileName
 * @return Graph
 */
Graph csvToGraph(string sEdgesFileName) { // This copies Graph on exit, to speed up, extend Graph and let this be a new method in our extended class
    Graph G;

    ifstream fEdges(sEdgesFileName);
    if (!fEdges.is_open())
        throw new invalid_argument("Edges file doesn't exist or could not be accessed");

    vector<node> nodes;
    int id, u, v, nSize = 0;

    for (string line; getline(fEdges, line);) {
        sscanf(line.c_str(), "%d;%d;%d;", &id, &u, &v);

        if (u > nSize) {
            nodes.resize(u + 1);
            nSize = u;
        }

        if (v > nSize) {
            nodes.resize(v + 1);
            nSize = v;
        }

        if(nodes.at(u) == nullptr)
            nodes[u] = G.newNode(u);

        if(nodes[v] == nullptr)
            nodes[v] = G.newNode(v);

        G.newEdge(nodes[u], nodes[v], id);
    }

    return G;
}

/**
 * Performs BFS to find the shortest path from s to t in graph g without using any edge from the forbidden edges.
 * Returns empty set if no such path exists.
 */
List<edge> shortestPath(const Graph &G, const GraphColoring &coloring, node s, node t, const List<edge> &forbidden) {
    List<edge> path;
    node v, u;
    edge e;

    Queue<node> Q;

    NodeArray<node> predecessor(G);
    NodeArray<bool> visited(G, false);

    Q.append(s);
    visited[s] = true;

    while(!Q.empty()) {
        v = Q.pop();

        if (v == t) {
            // traceback predecessors and reconstruct path
            for (node n = t; n != s; n = predecessor[n]) {
                path.pushFront(G.searchEdge(predecessor[n], n));
            }
            break;
        }

        forall_adj_edges(e, v) {
            if (forbidden.search(e).valid() || coloring[e] == Color::RED) continue; // TODO: Use BST or array (id -> bool) to represent forbidden?

            u = e->opposite(v);
            if (!visited[u]) {
                predecessor[u] = v; // TODO: Unite predecessor and visited?
                visited[u] = true;
                Q.append(u);
            }
        }
    }

    return path;
}

/**
 * Explores the component from node s and counts nodes colored blue, stops if nBluesInGraph is reached
 */
int countConnectedBlueNodes(const Graph &G, const GraphColoring &coloring, const node &s, int nBluesInGraph) {
    int nFoundBlues = 0;

    NodeArray<bool> discovered(G, false);
    Stack<node> S;
    S.push(s);

    node v, u;
    adjEntry adj;
    while(!S.empty()) {
        v = S.pop();

        if (!discovered[v]) {
            discovered[v] = true;

            if (coloring[v] == Color::BLUE) {
                nFoundBlues++;
                if (nFoundBlues == nBluesInGraph) break; // There can't be more blue vertices
            }

            forall_adj(adj, v) {
                u = adj->twinNode();
                S.push(u);
            }
        }
    }

    return nFoundBlues;
}

/**
 * E(G)\X contains a k-way hyperplane of G\X iff G\V(R) contains a connected subgraph G_b spanning all the blue vertices of X
 * @param G
 * @param X
 * @param coloring
 * @param blue
 * @return
 */
bool hasHyperplane(Graph &G, const GraphColoring &coloring, const List<edge> &X) {
    for(List<edge>::const_iterator iterator = X.begin(); iterator != X.end(); ++iterator) {
        G.hideEdge(*iterator);
    }

    node v, s;
    int nBlues = 0;

    forall_nodes(v, G) {
        if (coloring[v] == Color::BLUE) {
            nBlues++;
            s = v;
        }
    }

    int nBluesReached = 0;

    if (nBlues == 0) { // TODO: THIS SHOULD NEVER HAPPEN (yet it does... how to fix? Never color red any blue node in X)
        G.restoreAllEdges();
        //cout << "ups it happened" << endl;
        return false;
    } else {
        // Perform a DFS on G\X from s and see if all vertices are contained
        nBluesReached = countConnectedBlueNodes(G, coloring, s, nBlues);
    }

    G.restoreAllEdges();

    return nBluesReached == nBlues;
}

void GenCocircuits(List<List<edge>> &Cocircuits, Graph &G, GraphColoring coloring, List<edge> X, node red, node blue) {
    if (X.size() > m) return;

    if(!hasHyperplane(G, coloring, X) ) { // E\X contains no hyperplane of M
        //cout << "NO HYPERPLANE END" << endl; // TODO: This should not happen
        return;
    }

    // Find set D = (a short circuit C in G, s. t. |C ∩ X| = 1) \ X
    List<edge> D = shortestPath(G, coloring, red, blue, X);
    //cout << "now in x: " << X << endl;
    //cout << "r(" << red->index() << ")-b(" << blue->index() << ") path: " << D << endl;
    if (D.size() > 0) {

        // for each c ∈ D, recursively call GenCocircuits(X ∪ {c}).
        for(List<edge>::iterator iterator = D.begin(); iterator != D.end(); iterator++) {
            edge c = *iterator;

            //cout << "PROcessing " << c->index() << "(" << c->source()->index() << "," << c->target()->index() << ")" << endl;
            //printColoring(G, coloring);

            List<edge> newX = X;
            newX.pushBack(c);

            //TODO: If c = (u, v) is blue, reconnect blue subgraph (find the shortest path from u to v using only nonred edges)

            node n1 = red, n2 = blue, // after the first of the following for cycles these are the
                                      // nodes of the last red edge (one of them has to be incident with c)
                                      // initialized to red and blue since the first for can have 0 iterations
                 u, v; // c = (u,v), say u is red (and so will be all vertices on the path from the first red to u)

            for(List<edge>::iterator j = D.begin(); j != iterator; j++) {
                edge e = *j;

                n1 = e->source();
                n2 = e->target();

                coloring[n1] = Color::RED;
                coloring[n2] = Color::RED;

                coloring[e] = Color::RED;
            }

            if (c->source() == n1 || c->target() == n1) { // if n1 is in c then n1 == u
                u = n1;
            } else { // n2 is in c so n2 == u
                u = n2;
            }

            v = c->opposite(u);

            // Color the rest of the path blue
            for(List<edge>::iterator j = iterator.succ(); j != D.end(); j++) {
                edge e = *j;

                coloring[e->source()] = Color::BLUE;
                coloring[e->target()] = Color::BLUE;

                coloring[e] = Color::BLUE;
            }

            GenCocircuits(Cocircuits, G, coloring, newX, u, v);
        }

    } else {
        // If there is no such circuit C above (line 4), then return ‘Cocircuit: X’.
        //cout << "Cocircuit: " << X << endl;
        Cocircuits.pushBack(X);
    }
}

/**
 * Returns edges spanning forest of (possibly disconnected) graph G
 * @param G
 */
List<edge> spanningEdges(const Graph &G) {
    EdgeArray<bool> isBackedge(G, false);

    List<edge> backedges;
    isAcyclicUndirected(G, backedges);

    for(List<edge>::iterator i = backedges.begin(); i != backedges.end(); i++) {
        isBackedge[*i] = true;
    }

    List<edge> spanningEdges;
    edge e;
    forall_edges(e, G) {
        if (!isBackedge[e]) {
            spanningEdges.pushBack(e);
        }
    }

    return spanningEdges;
}

int main(int argc, char* argv[])
{
    if (argc != 3 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
        cout << "Usage: " << argv[0] << " <graph.csv> <cocircuit size bound>" << endl;
        exit(1);
    }

    string graphFile(argv[1]);
    m = stoi(argv[2]);
    if (m < 1) {
        cerr << "Cocircuit size bound lower than 1. Terminating." << endl;
        exit(2);
    }

    try {
        Graph G = csvToGraph(graphFile);
        List<edge> base = spanningEdges(G);
        List<List<edge> > Cocircuits;

        edge e;
        for(List<edge>::iterator i = base.begin(); i != base.end(); i++) {

            e = *i;
            List<edge> X; // (Indexes might be sufficient? Check later)
            GraphColoring coloring(G);
            X.pushBack(e);
            coloring[e->source()] = Color::RED;
            coloring[e->target()] = Color::BLUE;

            //cout << "STARTing with edge " << e->index() << " (vertex " << e->source()->index() << " is red)" << endl;

            GenCocircuits(Cocircuits, G, coloring, X, e->source(), e->target());
        }

        for(List<List<edge> >::iterator it = Cocircuits.begin(); it != Cocircuits.end(); ++it) {
            cout << "Cocircuit: " << *it << endl;
        }

    } catch (invalid_argument *e) {
        cerr << "Error: " << e->what() << endl;
        return 1;
    }

    return 0;
}

<commit_msg>Don't check the existence of a hyperplane every time, just reconnect G_b if it has been disconnected<commit_after>/**
 *
 * Terminology (Matroid - Graph) for escalated version of algorithm:
 *  Basis - Spanning forest
 *  Independent set - Tree (i.e. subset of a basis)
 *  Circuit - cycle
 *  Cocircuit - minimal edge-cut
 *  Hyperplane - maximal set not containing any basis (= complement of a min-cut)
 *
 *  Spanning forest - union of spanning trees of each component of an unconnected graph
 *
 */

enum {
    BLACK,
    RED,
    BLUE
};

#include <iostream>
#include <stdexcept>
#include <ogdf/basic/Queue.h>
#include <ogdf/basic/Graph.h>
#include <ogdf/basic/Stack.h>
#include <ogdf/basic/simple_graph_alg.h>

#include "helpers.hpp"
#include "graphcoloring.h"

using namespace std;
using namespace ogdf;

int m; // Cocircuit size bound

/**
 * @brief Takes a csv file with lines "<id>;<source>;<target>;<edge name>;..." and transforms it into graph
 * @param sEdgesFileName
 * @return Graph
 */
Graph csvToGraph(string sEdgesFileName) { // This copies Graph on exit, to speed up, extend Graph and let this be a new method in our extended class
    Graph G;

    ifstream fEdges(sEdgesFileName);
    if (!fEdges.is_open())
        throw new invalid_argument("Edges file doesn't exist or could not be accessed");

    vector<node> nodes;
    int id, u, v, nSize = 0;

    for (string line; getline(fEdges, line);) {
        sscanf(line.c_str(), "%d;%d;%d;", &id, &u, &v);

        if (u > nSize) {
            nodes.resize(u + 1);
            nSize = u;
        }

        if (v > nSize) {
            nodes.resize(v + 1);
            nSize = v;
        }

        // Skip if there already is an edge between these two nodes
        if (nodes.at(u) && nodes.at(v) &&
            (G.searchEdge(nodes.at(u), nodes.at(v)) || G.searchEdge(nodes.at(v), nodes.at(u))))
            continue;

        if(nodes.at(u) == nullptr)
            nodes[u] = G.newNode(u);

        if(nodes[v] == nullptr)
            nodes[v] = G.newNode(v);

        G.newEdge(nodes[u], nodes[v], id);
    }

    return G;
}

/**
 * Performs BFS to find the shortest path from s to t in graph g without using any red edges and any edge from the forbidden edges.
 * Returns empty set if no such path exists.
 */
List<edge> shortestPath(const Graph &G, const GraphColoring &coloring, node s, node t, const List<edge> &forbidden) {
    List<edge> path;
    node v, u;
    edge e;

    Queue<node> Q;

    NodeArray<bool> visited(G, false);
    NodeArray<node> predecessor(G);

    Q.append(s);
    visited[s] = true;

    while(!Q.empty()) {
        v = Q.pop();

        if (v == t) {
            // traceback predecessors and reconstruct path
            for (node n = t; n != s; n = predecessor[n]) {
                e = G.searchEdge(n, predecessor[n]); // Takes O(min(deg(v), deg(w))) (that's fast on sparse graphs)
                if (coloring[e] != Color::RED)
                    path.pushFront(e);
            }
            break;
        }

        forall_adj_edges(e, v) {
            // TODO: Use BST or array (id -> bool) to represent forbidden and fasten the following search? (Probably not
            // necessary as forbidden size is bound by the constant m)
            if (forbidden.search(e).valid()) continue;

            u = e->opposite(v);
            if (!visited[u]) {
                predecessor[u] = v;
                visited[u] = true;
                Q.append(u);
            }
        }
    }

    return path;
}

/**
 * @brief hideConnectedBlueSubgraph
 * @param G
 * @param coloring
 * @param u
 */
void hideConnectedBlueSubgraph(Graph &G, const GraphColoring &coloring, node start) {
    Queue<node> Q;
    Q.append(start);

    NodeArray<bool> visited(G, false);

    node u, v;
    edge e;
    while(!Q.empty()) {
        u = Q.pop();
        forall_adj_edges(e, u) {
            if (coloring[e] == Color::BLUE) {
                v = e->opposite(u);
                if (!visited[v]) {
                    visited[v] = true;
                    Q.append(v);
                }
                G.hideEdge(e);
            }
        }
    }
}

bool findPathToAnyBlueAndColorItBlue(const Graph &G, GraphColoring &coloring, node start) {
    Queue<node> Q;
    Q.append(start);

    NodeArray<bool> visited(G, false);
    NodeArray<edge> accessEdge(G);

    node u, n;
    edge e;
    while(!Q.empty()) {
        u = Q.pop();

        if (coloring[u] == Color::BLUE && u != start) {
            // reconstruct path and go on
            edge ae;
            node n1, n2;
            for (n1 = u; n1 != start;) {
                // TODO: Use search edge instead?
                ae = accessEdge[n1];
                n2 = ae->opposite(n1);

                coloring[n1] = Color::BLUE;
                coloring[n2] = Color::BLUE;
                coloring[ae] = Color::BLUE;
                n1 = n2;
            }
            return true;
        }

        forall_adj_edges(e, u) {
            n = e->opposite(u);
            if (!visited[n]) {
                visited[n] = true;
                accessEdge[n] = e;
                Q.append(n);
            }
        }
    }

    return false;
}

void GenCocircuits(List<List<edge>> &Cocircuits, Graph &G, GraphColoring coloring, List<edge> X, node red, node blue) {
    if (X.size() > m) return;

    // Find set D = (a short circuit C in G, s. t. |C ∩ X| = 1) \ X
    List<edge> D = shortestPath(G, coloring, red, blue, X);
    //cout << "now in x: " << X << endl;
    //cout << "r(" << red->index() << ")-b(" << blue->index() << ") path: " << D << endl;
    //printColoring(G, coloring); cout << endl;
    if (D.size() > 0) {

        // for each c ∈ D, recursively call GenCocircuits(X ∪ {c}).
        for(List<edge>::iterator iterator = D.begin(); iterator != D.end(); iterator++) {
            edge c = *iterator;

            //cout << "PROcessing " << c->index() << "(" << c->source()->index() << "," << c->target()->index() << ")" << endl;
            //printColoring(G, coloring);

            List<edge> newX = X;
            newX.pushBack(c);

            // Coloring red-c path red, determining u and v, coloring the rest blue
            node n1 = red, n2 = blue, // after the first of the following for cycles these are the
                                      // nodes of the last red edge (one of them has to be incident with c)
                                      // initialized to red and blue since the first for can have 0 iterations
                 u, v; // c = (u,v), say u is red (and so will be all vertices on the path from the first red to u)

            for(List<edge>::iterator j = D.begin(); j != iterator; j++) {
                edge e = *j;

                n1 = e->source();
                n2 = e->target();

                coloring[n1] = Color::RED;
                coloring[n2] = Color::RED;

                coloring[e] = Color::RED;
            }

            // Determine u, v, s.t. u is really red and v blue
            if (c->source() == n1 || c->target() == n1) { // if n1 is in c then n1 == u
                u = n1;
            } else { // n2 is in c so n2 == u
                u = n2;
            }

            v = c->opposite(u);

            // Color the rest of the path blue
            for(List<edge>::iterator j = iterator.succ(); j != D.end(); j++) {
                edge e = *j;

                coloring[e->source()] = Color::BLUE;
                coloring[e->target()] = Color::BLUE;

                coloring[e] = Color::BLUE;
            }

            // If c = (u, v) is blue, reconnect blue subgraph (find the shortest path from u to v using only nonred edges)

            // if c = (u,v) is blue
            //    if u has blue adjacent edges (except of c) AND v has blue adjacent edges (exc. of c) then
            //       enumerate one blue subgraph, call it G_b1
            //       create graph G_rest = G \ X \ G_r \ G_b1 and BFS in it to until blue is found (use hideEdge!)
            //       (or BFS (avoid red and X) from u to first blue edge not in G_b1)
            //       -> path found, color it blue and continue
            //       -> path not found, fail here (return;)

            if (coloring[c] == Color::BLUE) {
                G.hideEdge(c); // Don't consider c

                bool uaIsEmpty = true, vaIsEmpty = true;
                edge e;

                forall_adj_edges(e, u) {
                    if (coloring[e] == Color::BLUE) {
                        uaIsEmpty = false;
                        break;
                    }
                }

                forall_adj_edges(e, v) {
                    if (coloring[e] == Color::BLUE) {
                        vaIsEmpty = false;
                        break;
                    }
                }

                if (!uaIsEmpty && !vaIsEmpty) {
                    //cout << "X: " << X << "; D: " << D << "; c = " << c->index() << " --- ";
                    //printColoring(G, coloring);
                    //cout<< endl;

                    // G_b has been disconnected, hide X, G_r and one component of blue subgraph (TODO: Maintain G_rest through the whole algorithm and not recompute here every time?)
                    for(List<edge>::iterator it = X.begin(); it != X.end(); it++) G.hideEdge(*it);
                    forall_edges(e, G) { if(coloring[e] == Color::RED) G.hideEdge(e); }
                    hideConnectedBlueSubgraph(G, coloring, u);

                    // BFS in G from u to the first found blue edge
                    //  -> not found => fail here
                    //  -> path found => color it blue and continue

                    if (!findPathToAnyBlueAndColorItBlue(G, coloring, u)) {
                        G.restoreAllEdges();
                        return;
                    }

                } // else c is just a branch with a single leaf, nothing happened G_b stays connected

                G.restoreAllEdges();
            }

            GenCocircuits(Cocircuits, G, coloring, newX, u, v);
        }

    } else {
        // If there is no such circuit C above (line 4), then return ‘Cocircuit: X’.
        //cout << "Cocircuit: " << X << endl;
        Cocircuits.pushBack(X);
    }
}

/**
 * Returns edges spanning forest of (possibly disconnected) graph G
 * @param G
 */
List<edge> spanningEdges(const Graph &G) {
    EdgeArray<bool> isBackedge(G, false);

    List<edge> backedges;
    isAcyclicUndirected(G, backedges);

    for(List<edge>::iterator i = backedges.begin(); i != backedges.end(); i++) {
        isBackedge[*i] = true;
    }

    List<edge> spanningEdges;
    edge e;
    forall_edges(e, G) {
        if (!isBackedge[e]) {
            spanningEdges.pushBack(e);
        }
    }

    return spanningEdges;
}

int main(int argc, char* argv[])
{
    if (argc != 3 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
        cout << "Usage: " << argv[0] << " <graph.csv> <cocircuit size bound>" << endl;
        exit(1);
    }

    string graphFile(argv[1]);
    m = stoi(argv[2]);
    if (m < 1) {
        cerr << "Cocircuit size bound lower than 1. Terminating." << endl;
        exit(2);
    }

    int size[7] = {0};

    try {
        Graph G = csvToGraph(graphFile);
        List<edge> base = spanningEdges(G);
        List<List<edge> > Cocircuits;

        edge e;
        for(List<edge>::iterator i = base.begin(); i != base.end(); i++) {
            e = *i;
            List<edge> X; // (Indexes might be sufficient? Check later)
            GraphColoring coloring(G);
            X.pushBack(e);
            coloring[e->source()] = Color::RED;
            coloring[e->target()] = Color::BLUE;

            //cout << "STARTing with edge " << e->index() << " (vertex " << e->source()->index() << " is red)" << endl;

            GenCocircuits(Cocircuits, G, coloring, X, e->source(), e->target());
        }

        for(List<List<edge> >::iterator it = Cocircuits.begin(); it != Cocircuits.end(); ++it) {
            //cout << "Cocircuit: " << *it << endl;
            size[(*it).size()]++;
        }

    } catch (invalid_argument *e) {
        cerr << "Error: " << e->what() << endl;
        return 1;
    }

    cout << endl;
    for(int i = 1; i <= 6; i++)
        cout << "Size " << i << ": " << size[i] << endl;

    return 0;
}

<|endoftext|>


<commit_before>/*
 * File:   main.cpp
 * Author: vlad
 *
 * Created on December 12, 2013, 10:38 PM
 */

#include <iostream>

#include "qpp.h"
//#include "matlab.h" // support for MATLAB

// TODO: expandout function
// TODO: dyad function
// TODO: proj (dya) function
// TODO: ip (inner product function) function, make it general to return matrices
// TODO: check that everything works for expressions in ALL FILES!!!!
// TODO: Error class
// TODO: .template issues...

using namespace std;

using namespace qpp;
using namespace qpp::types;

//int main(int argc, char **argv)
int main()
{
	_init();

	cout << "Starting qpp..." << endl;

	displn(rand_unitary(3));

	cout << endl << "Exiting qpp..." << endl;
}
<commit_msg>commit<commit_after>/*
 * File:   main.cpp
 * Author: vlad
 *
 * Created on December 12, 2013, 10:38 PM
 */

#include <iostream>

#include "qpp.h"
//#include "matlab.h" // support for MATLAB

// TODO: expandout function
// TODO: dyad function
// TODO: proj (dya) function
// TODO: ip (inner product function) function, make it general to return matrices
// TODO: check that everything works for expressions in ALL FILES!!!!
// TODO: Error class
// TODO: change all for(s) to column major order
// TODO: use .data() raw pointer instead of looping

using namespace std;

using namespace qpp;
using namespace qpp::types;

//int main(int argc, char **argv)
int main()
{
	_init();

	cout << "Starting qpp..." << endl;

	displn(rand_unitary(3));

	cout << endl << "Exiting qpp..." << endl;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <numeric>
#include <algorithm>
#include <vector>
#include <map>
#include <chrono>
#include <memory>
#include <typeinfo>

#include <hpx/hpx.hpp>
#include <hpx/hpx_init.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/iostreams.hpp>
#include <hpx/include/serialization.hpp>

#include "incumbent_component.hpp"
#include "workqueue_component.hpp"

#include "DimacsParser.hpp"
#include "BitGraph.hpp"
#include "BitSet.hpp"

// 64 bit words
// 8 words covers 400 vertices
// Later we can specialise this at compile time
#define NWORDS 8

// Forward action decls
namespace graph {
  template<unsigned n_words_>
  auto maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) -> void;

  std::atomic<int> globalBound(0);

  // Atomically update the global bound
  auto updateBound(int newBound) -> void {
    while(true) {
      auto curBnd = globalBound.load();
      if (newBound < curBnd) {
        break;
      }

      if (globalBound.compare_exchange_weak(curBnd, newBound)) {
        break;
      }
    }
  }
}
HPX_PLAIN_ACTION(graph::maxcliqueTask<NWORDS>, maxcliqueTask400Action)
HPX_PLAIN_ACTION(graph::updateBound, updateBoundAction)

// For distributed promises
HPX_REGISTER_ACTION(hpx::lcos::base_lco_with_value<int>::set_value_action, set_value_action_int);

namespace graph {
  // Order a graphFromFile and return an ordered graph alongside a map to invert
  // the vertex numbering at the end.
  template<unsigned n_words_>
  auto orderGraphFromFile(const dimacs::GraphFromFile & g, std::map<int,int> & inv) -> BitGraph<n_words_> {
    std::vector<int> order(g.first);
    std::iota(order.begin(), order.end(), 0);

    // Order by degree, tie break on number
    std::vector<int> degrees;
    std::transform(order.begin(), order.end(), std::back_inserter(degrees),
                    [&] (int v) { return g.second.find(v)->second.size(); });

    std::sort(order.begin(), order.end(),
            [&] (int a, int b) { return ! (degrees[a] < degrees[b] || (degrees[a] == degrees[b] && a > b)); });

    // Construct a new graph with this new ordering
    BitGraph<n_words_> graph;
    graph.resize(g.first);

    for (unsigned i = 0 ; i < g.first ; ++i)
      for (unsigned j = 0 ; j < g.first ; ++j)
        if (g.second.find(order[i])->second.count(order[j]))
          graph.add_edge(i, j);

    // Create inv map (maybe just return order?)
    for (int i = 0; i < order.size(); i++) {
      inv[i] = order[i];
    }

    return graph;
    }

  template<unsigned n_words_>
  auto colour_class_order(const BitGraph<n_words_> & graph,
                          const BitSet<n_words_> & p,
                          std::array<unsigned, n_words_ * bits_per_word> & p_order,
                          std::array<unsigned, n_words_ * bits_per_word> & p_bounds) -> void {
    BitSet<n_words_> p_left = p; // not coloured yet
    unsigned colour = 0;         // current colour
    unsigned i = 0;              // position in p_bounds

    // while we've things left to colour
    while (! p_left.empty()) {
      // next colour
      ++colour;
      // things that can still be given this colour
      BitSet<n_words_> q = p_left;

      // while we can still give something this colour
      while (! q.empty()) {
        // first thing we can colour
        int v = q.first_set_bit();
        p_left.unset(v);
        q.unset(v);

        // can't give anything adjacent to this the same colour
        graph.intersect_with_row_complement(v, q);

        // record in result
        p_bounds[i] = colour;
        p_order[i] = v;
        ++i;
      }
    }
  }

  template <unsigned n_words_>
  auto expand(const BitGraph<n_words_> & graph,
              const hpx::naming::id_type & incumbent,
              std::vector<unsigned> & c,
              BitSet<n_words_> & p) -> void {
    // initial colouring
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    // for each v in p... (v comes later)
    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      auto bnd = globalBound.load();
      if (c.size() + p_bounds[n] <= bnd)
        return;

      auto v = p_order[n];

      // consider taking v
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (new_p.empty()) {
        if (c.size() > bnd) {
          std::set<int> members;
          for (auto & v : c) {
            members.insert(v);
          }

          // Fire and forget updates
          hpx::apply<globalBound::incumbent::updateBound_action>(incumbent, c.size(), members);
          hpx::async<updateBoundAction>(hpx::find_here(), c.size()).get();
        }
      }
      else {
        expand(graph, incumbent, c, new_p);
      }

      // now consider not taking v
      c.pop_back();
      p.unset(v);
    }
  }

  template<unsigned n_words_>
  auto runMaxClique(const BitGraph<n_words_> & graph, hpx::naming::id_type incumbent, hpx::naming::id_type workqueue) -> void {
    BitSet<n_words_> p;
    p.resize(graph.size());
    p.set_all();

    // Spawn top level only (for now)
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    std::vector<std::shared_ptr<hpx::promise<int>>> promises;
    std::vector<hpx::future<int>> futures;

    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      std::vector<unsigned> c;
      c.reserve(graph.size());
      auto v = p_order[n];
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (new_p.empty()) {
        auto bnd = hpx::async<globalBound::incumbent::getBound_action>(incumbent).get();
        if (c.size() > bnd) {
          std::set<int> members;
          for (auto & v : c) {
            members.insert(v);
          }
          hpx::apply<globalBound::incumbent::updateBound_action>(incumbent, c.size(), members);
        }
      } else {
        // This spawning isn't quite right, need to avoid spawning duplicates.
        // Spawn it as a new task
        auto promise = std::shared_ptr<hpx::promise<int>>(new hpx::promise<int>());
        auto f = promise->get_future();
        auto promise_id = promise->get_id();

        promises.push_back(std::move(promise));
        futures.push_back(std::move(f));

        hpx::util::function<void(hpx::naming::id_type)> task = hpx::util::bind(maxcliqueTask400Action(), _1, graph, incumbent, c, new_p, promise_id);
        hpx::apply<workstealing::workqueue::addWork_action>(workqueue, task);

        c.pop_back();
        p.unset(v);
      }
    }
    hpx::wait_all(futures);
  }

  template<unsigned n_words_>
  void maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) {
    expand(graph, incumbent, c, p);
    hpx::apply<hpx::lcos::base_lco_with_value<int>::set_value_action>(promise, 1);
    return;
  }
}

void scheduler(hpx::naming::id_type workqueue) {
  auto threads = hpx::get_os_thread_count() == 1 ? 1 : hpx::get_os_thread_count() - 1;
  hpx::threads::executors::local_queue_executor scheduler(threads);

  // Debugging
  std::cout << "Running with: " << threads << " scheduler threads" << std::endl;

  bool running = true;
  while (running) {
    auto pending = scheduler.num_pending_closures();
    if (pending < threads) {
      auto task = hpx::async<workstealing::workqueue::steal_action>(workqueue).get();
      if (task) {
        auto t = hpx::util::bind(task, hpx::find_here());
        scheduler.add(t);
      }
    } else {
      hpx::this_thread::suspend();
    }
  }
}

int hpx_main(int argc, char* argv[]) {
  if (2 != argc) {
    std::cout << "Usage: " << argv[0] << " file" << std::endl;
    hpx::finalize();
    return EXIT_FAILURE;
  }

  auto gFile = dimacs::read_dimacs(std::string(argv[1]));

  // Order the graph (keep a hold of the map)
  std::map<int, int> invMap;
  auto graph = graph::orderGraphFromFile<NWORDS>(gFile, invMap);

  // Run Maxclique
  auto incumbent = hpx::new_<globalBound::incumbent>(hpx::find_here()).get();
  auto workqueue = hpx::new_<workstealing::workqueue>(hpx::find_here()).get();

  // Start a scheduler threads
  hpx::apply(scheduler, workqueue);

  auto start_time = std::chrono::steady_clock::now();
  graph::runMaxClique(graph, incumbent, workqueue);
  auto overall_time = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - start_time);

  // Output result
  hpx::cout << "Size: " << hpx::async<globalBound::incumbent::getBound_action>(incumbent).get() << hpx::endl;

  auto members = hpx::async<globalBound::incumbent::getMembers_action>(incumbent).get();
  hpx::cout << "Members: " << hpx::endl;
  for (auto const& m : members) {
    hpx::cout << invMap[m] + 1 << " ";
  }
  hpx::cout << hpx::endl << hpx::flush;

  hpx::cout << "cpu = " << overall_time.count() << std::endl;

  // TODO: A nicer termination
  //hpx::finalize();
  hpx::this_thread::suspend(2000);
  hpx::terminate();
}

int main (int argc, char* argv[]) {
  return hpx::init(argc, argv);
}

<commit_msg>Have update bounds force updates on all nodes<commit_after>#include <iostream>
#include <numeric>
#include <algorithm>
#include <vector>
#include <map>
#include <chrono>
#include <memory>
#include <typeinfo>

#include <hpx/hpx.hpp>
#include <hpx/hpx_init.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/iostreams.hpp>
#include <hpx/include/serialization.hpp>

#include "incumbent_component.hpp"
#include "workqueue_component.hpp"

#include "DimacsParser.hpp"
#include "BitGraph.hpp"
#include "BitSet.hpp"

// 64 bit words
// 8 words covers 400 vertices
// Later we can specialise this at compile time
#define NWORDS 8

// Forward action decls
namespace graph {
  template<unsigned n_words_>
  auto maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) -> void;

  std::atomic<int> globalBound(0);
  auto updateBound(int newBound) -> void;

}
HPX_PLAIN_ACTION(graph::maxcliqueTask<NWORDS>, maxcliqueTask400Action)
HPX_PLAIN_ACTION(graph::updateBound, updateBoundAction)

// For distributed promises
HPX_REGISTER_ACTION(hpx::lcos::base_lco_with_value<int>::set_value_action, set_value_action_int);

namespace graph {
  // Order a graphFromFile and return an ordered graph alongside a map to invert
  // the vertex numbering at the end.
  template<unsigned n_words_>
  auto orderGraphFromFile(const dimacs::GraphFromFile & g, std::map<int,int> & inv) -> BitGraph<n_words_> {
    std::vector<int> order(g.first);
    std::iota(order.begin(), order.end(), 0);

    // Order by degree, tie break on number
    std::vector<int> degrees;
    std::transform(order.begin(), order.end(), std::back_inserter(degrees),
                    [&] (int v) { return g.second.find(v)->second.size(); });

    std::sort(order.begin(), order.end(),
            [&] (int a, int b) { return ! (degrees[a] < degrees[b] || (degrees[a] == degrees[b] && a > b)); });

    // Construct a new graph with this new ordering
    BitGraph<n_words_> graph;
    graph.resize(g.first);

    for (unsigned i = 0 ; i < g.first ; ++i)
      for (unsigned j = 0 ; j < g.first ; ++j)
        if (g.second.find(order[i])->second.count(order[j]))
          graph.add_edge(i, j);

    // Create inv map (maybe just return order?)
    for (int i = 0; i < order.size(); i++) {
      inv[i] = order[i];
    }

    return graph;
    }

  template<unsigned n_words_>
  auto colour_class_order(const BitGraph<n_words_> & graph,
                          const BitSet<n_words_> & p,
                          std::array<unsigned, n_words_ * bits_per_word> & p_order,
                          std::array<unsigned, n_words_ * bits_per_word> & p_bounds) -> void {
    BitSet<n_words_> p_left = p; // not coloured yet
    unsigned colour = 0;         // current colour
    unsigned i = 0;              // position in p_bounds

    // while we've things left to colour
    while (! p_left.empty()) {
      // next colour
      ++colour;
      // things that can still be given this colour
      BitSet<n_words_> q = p_left;

      // while we can still give something this colour
      while (! q.empty()) {
        // first thing we can colour
        int v = q.first_set_bit();
        p_left.unset(v);
        q.unset(v);

        // can't give anything adjacent to this the same colour
        graph.intersect_with_row_complement(v, q);

        // record in result
        p_bounds[i] = colour;
        p_order[i] = v;
        ++i;
      }
    }
  }

  template <unsigned n_words_>
  auto expand(const BitGraph<n_words_> & graph,
              const hpx::naming::id_type & incumbent,
              std::vector<unsigned> & c,
              BitSet<n_words_> & p) -> void {
    // initial colouring
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    // for each v in p... (v comes later)
    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      auto bnd = globalBound.load();
      if (c.size() + p_bounds[n] <= bnd)
        return;

      auto v = p_order[n];

      // consider taking v
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (new_p.empty()) {
        if (c.size() > bnd) {
          std::set<int> members;
          for (auto & v : c) {
            members.insert(v);
          }

          // Fire and forget updates
          hpx::apply<globalBound::incumbent::updateBound_action>(incumbent, c.size(), members);
          hpx::async<updateBoundAction>(hpx::find_here(), c.size()).get();
        }
      }
      else {
        expand(graph, incumbent, c, new_p);
      }

      // now consider not taking v
      c.pop_back();
      p.unset(v);
    }
  }

  template<unsigned n_words_>
  auto runMaxClique(const BitGraph<n_words_> & graph, hpx::naming::id_type incumbent, hpx::naming::id_type workqueue) -> void {
    BitSet<n_words_> p;
    p.resize(graph.size());
    p.set_all();

    // Spawn top level only (for now)
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    std::vector<std::shared_ptr<hpx::promise<int>>> promises;
    std::vector<hpx::future<int>> futures;

    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      std::vector<unsigned> c;
      c.reserve(graph.size());
      auto v = p_order[n];
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (new_p.empty()) {
        auto bnd = hpx::async<globalBound::incumbent::getBound_action>(incumbent).get();
        if (c.size() > bnd) {
          std::set<int> members;
          for (auto & v : c) {
            members.insert(v);
          }
          hpx::apply<globalBound::incumbent::updateBound_action>(incumbent, c.size(), members);
        }
      } else {
        // This spawning isn't quite right, need to avoid spawning duplicates.
        // Spawn it as a new task
        auto promise = std::shared_ptr<hpx::promise<int>>(new hpx::promise<int>());
        auto f = promise->get_future();
        auto promise_id = promise->get_id();

        promises.push_back(std::move(promise));
        futures.push_back(std::move(f));

        hpx::util::function<void(hpx::naming::id_type)> task = hpx::util::bind(maxcliqueTask400Action(), _1, graph, incumbent, c, new_p, promise_id);
        hpx::apply<workstealing::workqueue::addWork_action>(workqueue, task);

        c.pop_back();
        p.unset(v);
      }
    }
    hpx::wait_all(futures);
  }

  template<unsigned n_words_>
  void maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) {
    expand(graph, incumbent, c, p);
    hpx::apply<hpx::lcos::base_lco_with_value<int>::set_value_action>(promise, 1);
    return;
  }

  // Atomically update the global bound on all localities
  auto updateBound(int newBound) -> void {
    while(true) {
      auto curBnd = globalBound.load();
      if (newBound < curBnd) {
        break;
      }

      if (globalBound.compare_exchange_weak(curBnd, newBound)) {
        break;
      }
    }

    // Broadcast it by pushing work items to all other nodes
    auto localities = hpx::find_all_localities();
    for (auto const & node : localities) {
      hpx::apply<updateBoundAction>(node, newBound);
    }

  }
}

void scheduler(hpx::naming::id_type workqueue) {
  auto threads = hpx::get_os_thread_count() == 1 ? 1 : hpx::get_os_thread_count() - 1;
  hpx::threads::executors::local_queue_executor scheduler(threads);

  // Debugging
  std::cout << "Running with: " << threads << " scheduler threads" << std::endl;

  bool running = true;
  while (running) {
    auto pending = scheduler.num_pending_closures();
    if (pending < threads) {
      auto task = hpx::async<workstealing::workqueue::steal_action>(workqueue).get();
      if (task) {
        auto t = hpx::util::bind(task, hpx::find_here());
        scheduler.add(t);
      }
    } else {
      hpx::this_thread::suspend();
    }
  }
}

int hpx_main(int argc, char* argv[]) {
  if (2 != argc) {
    std::cout << "Usage: " << argv[0] << " file" << std::endl;
    hpx::finalize();
    return EXIT_FAILURE;
  }

  auto gFile = dimacs::read_dimacs(std::string(argv[1]));

  // Order the graph (keep a hold of the map)
  std::map<int, int> invMap;
  auto graph = graph::orderGraphFromFile<NWORDS>(gFile, invMap);

  // Run Maxclique
  auto incumbent = hpx::new_<globalBound::incumbent>(hpx::find_here()).get();
  auto workqueue = hpx::new_<workstealing::workqueue>(hpx::find_here()).get();

  // Start a scheduler threads
  hpx::apply(scheduler, workqueue);

  auto start_time = std::chrono::steady_clock::now();
  graph::runMaxClique(graph, incumbent, workqueue);
  auto overall_time = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - start_time);

  // Output result
  hpx::cout << "Size: " << hpx::async<globalBound::incumbent::getBound_action>(incumbent).get() << hpx::endl;

  auto members = hpx::async<globalBound::incumbent::getMembers_action>(incumbent).get();
  hpx::cout << "Members: " << hpx::endl;
  for (auto const& m : members) {
    hpx::cout << invMap[m] + 1 << " ";
  }
  hpx::cout << hpx::endl << hpx::flush;

  hpx::cout << "cpu = " << overall_time.count() << std::endl;

  // TODO: A nicer termination
  //hpx::finalize();
  hpx::this_thread::suspend(2000);
  hpx::terminate();
}

int main (int argc, char* argv[]) {
  return hpx::init(argc, argv);
}

<|endoftext|>


<commit_before>#include <GLFW/glfw3.h>

#include "PhysSystem.h"

#include "microprofile/microprofile.h"
#include "microprofile/microprofileui.h"

struct Vertex
{
    Vector2f position;
    unsigned char r, g, b, a;

};

void RenderBox(std::vector<Vertex>& vertices, Coords2f coords, Vector2f size, int r, int g, int b, int a)
{
    Vector2f axisX = coords.xVector * size.x;
    Vector2f axisY = coords.yVector * size.y;

    Vertex v;

    v.r = r;
    v.g = g;
    v.b = b;
    v.a = a;

    v.position = coords.pos - axisX - axisY;
    vertices.push_back(v);

    v.position = coords.pos + axisX - axisY;
    vertices.push_back(v);

    v.position = coords.pos + axisX + axisY;
    vertices.push_back(v);

    v.position = coords.pos - axisX + axisY;
    vertices.push_back(v);
}

float random(float min, float max)
{
    return min + (max - min) * (float(rand()) / float(RAND_MAX));
}

const struct
{
    PhysSystem::SolveMode mode;
    const char* name;
} kModes[] =
    {
     {PhysSystem::Solve_Baseline, "Baseline"},
     {PhysSystem::Solve_AoS, "AoS"},
     {PhysSystem::Solve_SoA_Scalar, "SoA Scalar"},
     {PhysSystem::Solve_SoA_SSE2, "SoA SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoA_AVX2, "SoA AVX2"},
#endif

     {PhysSystem::Solve_SoAPacked_Scalar, "SoA Packed Scalar"},
     {PhysSystem::Solve_SoAPacked_SSE2, "SoA Packed SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoAPacked_AVX2, "SoA Packed AVX2"},
#endif

#if defined(__AVX2__) && defined(__FMA__)
     {PhysSystem::Solve_SoAPacked_FMA, "SoA Packed FMA"},
#endif
};

bool keyPressed[GLFW_KEY_LAST + 1];
int mouseScrollDelta = 0;

static void errorCallback(int error, const char* description)
{
    fputs(description, stderr);
}

static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    keyPressed[key] = (action == GLFW_PRESS);
}

static void scrollCallback(GLFWwindow* window, double x, double y)
{
    mouseScrollDelta = y;
}

void MicroProfileDrawInit();
void MicroProfileBeginDraw();
void MicroProfileEndDraw();

int main(int argc, char** argv)
{
    MicroProfileOnThreadCreate("Main");

    int windowWidth = 1280, windowHeight = 1024;

    std::unique_ptr<WorkQueue> queue(new WorkQueue(WorkQueue::getIdealWorkerCount()));

    PhysSystem physSystem;

    RigidBody* groundBody = physSystem.AddBody(Coords2f(Vector2f(0, 0), 0.0f), Vector2f(10000.f, 10.0f));
    groundBody->invInertia = 0.0f;
    groundBody->invMass = 0.0f;

    int currentMode = sizeof(kModes) / sizeof(kModes[0]) - 1;

    const float gravity = -200.0f;
    const float integrationTime = 1 / 60.f;
    const int contactIterationsCount = 15;
    const int penetrationIterationsCount = 15;

    physSystem.gravity = gravity;

    physSystem.AddBody(Coords2f(Vector2f(-500, 500), 0.0f), Vector2f(30.0f, 30.0f));

    float bodyRadius = 2.f;
    int bodyCount = 20000;

    for (int bodyIndex = 0; bodyIndex < bodyCount; bodyIndex++)
    {
        Vector2f pos = Vector2f(random(-500.0f, 500.0f), random(50.f, 1000.0f));
        Vector2f size(bodyRadius * 2.f, bodyRadius * 2.f);

        physSystem.AddBody(Coords2f(pos, 0.f), size);
    }

    if (argc > 1 && strcmp(argv[1], "profile") == 0)
    {
        for (int mode = 0; mode < sizeof(kModes) / sizeof(kModes[0]); ++mode)
        {
            PhysSystem testSystem;

            testSystem.gravity = gravity;

            for (auto& body: physSystem.bodies)
            {
                RigidBody* testBody = testSystem.AddBody(body.coords, body.geom.size);
                testBody->invInertia = body.invInertia;
                testBody->invMass = body.invMass;
            }

            double collisionTime = 0;
            double mergeTime = 0;
            double solveTime = 0;
            float iterations = 0;

            for (int i = 0; i < 50; ++i)
            {
                testSystem.Update(*queue, 1.f / 30.f, kModes[mode].mode, contactIterationsCount, penetrationIterationsCount);

                collisionTime += testSystem.collisionTime;
                mergeTime += testSystem.mergeTime;
                solveTime += testSystem.solveTime;
                iterations += testSystem.iterations;
            }

            printf("%s: collision %.2f ms, merge %.2f ms, solve %.2f ms, %.2f iterations\n", kModes[mode].name, collisionTime * 1000, mergeTime * 1000, solveTime * 1000, iterations);
        }

        return 0;
    }

    glfwSetErrorCallback(errorCallback);

    if (!glfwInit()) return 1;

    GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, "PhyX", NULL, NULL);
    if (!window) return 1;

    glfwMakeContextCurrent(window);
    glfwSwapInterval(0);
    glfwSetKeyCallback(window, keyCallback);
    glfwSetScrollCallback(window, scrollCallback);

    MicroProfileDrawInit();
    MicroProfileToggleDisplayMode();

    double prevUpdateTime = 0.0f;

    std::vector<Vertex> vertices;

    while (!glfwWindowShouldClose(window))
    {
        MICROPROFILE_SCOPEI("MAIN", "Frame", 0xffee00);

        int width, height;
        glfwGetWindowSize(window, &width, &height);

        int frameWidth, frameHeight;
        glfwGetFramebufferSize(window, &frameWidth, &frameHeight);

        double mouseX, mouseY;
        glfwGetCursorPos(window, &mouseX, &mouseY);

        glViewport(0, 0, frameWidth, frameHeight);
        glClearColor(0.2f, 0.2f, 0.2f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT);

        float offsetx = -width / 2;
        float offsety = -40;
        float scale = 0.5f;

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(offsetx / scale, width / scale + offsetx / scale, offsety / scale, height / scale + offsety / scale, 1.f, -1.f);

        vertices.clear();

        if (glfwGetTime() > prevUpdateTime + integrationTime)
        {
            prevUpdateTime += integrationTime;

            float time = integrationTime;

            Vector2f mousePos = Vector2f(mouseX + offsetx, height + offsety - mouseY) / scale;

            RigidBody* draggedBody = &physSystem.bodies[1];
            Vector2f dstVelocity = (mousePos - draggedBody->coords.pos) * 5e1f;
            draggedBody->acceleration += (dstVelocity - draggedBody->velocity) * 5e0;

            physSystem.Update(*queue, time, kModes[currentMode].mode, contactIterationsCount, penetrationIterationsCount);
        }

        {
            MICROPROFILE_SCOPEI("Render", "Prepare", 0xff0000);

            for (size_t bodyIndex = 0; bodyIndex < physSystem.bodies.size(); bodyIndex++)
            {
                RigidBody* body = &physSystem.bodies[bodyIndex];
                Coords2f bodyCoords = body->coords;
                Vector2f size = body->geom.size;

                float colorMult = float(bodyIndex) / float(physSystem.bodies.size()) * 0.5f + 0.5f;
                int r = 50 * colorMult;
                int g = 125 * colorMult;
                int b = 218 * colorMult;

                if (bodyIndex == 1) //dragged body
                {
                    r = 242;
                    g = 236;
                    b = 164;
                }

                RenderBox(vertices, bodyCoords, size, r, g, b, 255);
            }

            if (glfwGetKey(window, GLFW_KEY_V))
            {
                for (size_t manifoldIndex = 0; manifoldIndex < physSystem.collider.manifolds.size(); manifoldIndex++)
                {
                    Manifold& man = physSystem.collider.manifolds[manifoldIndex];

                    for (int collisionNumber = 0; collisionNumber < man.collisionsCount; collisionNumber++)
                    {
                        Coords2f coords = Coords2f(Vector2f(0.0f, 0.0f), 3.1415f / 4.0f);

                        coords.pos = man.body1->coords.pos + man.collisions[collisionNumber].delta1;

                        float redMult = man.collisions[collisionNumber].isNewlyCreated ? 0.5f : 1.0f;

                        RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), 100, 100 * redMult, 100 * redMult, 100);

                        coords.pos = man.body2->coords.pos + man.collisions[collisionNumber].delta2;

                        RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), 150, 150 * redMult, 150 * redMult, 100);
                    }
                }
            }
        }

        {
            MICROPROFILE_SCOPEI("Render", "Perform", 0xff0000);

            if (!vertices.empty())
            {
                glEnableClientState(GL_VERTEX_ARRAY);
                glEnableClientState(GL_COLOR_ARRAY);

                glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].position);
                glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &vertices[0].r);

                glDrawArrays(GL_QUADS, 0, vertices.size());

                glDisableClientState(GL_VERTEX_ARRAY);
                glDisableClientState(GL_COLOR_ARRAY);
            }
        }

//MICROPROFILEUI_API void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters);
        /*
            << "Bodies: " << physSystem.bodies.size()
            << " Contacts: " << physSystem.solver.contactJoints.size()
            << " Iterations: " << physSystem.iterations;

            << queue->getWorkerCount() << " cores; "
            << "Mode: " << kModes[currentMode].name << "; "
            << "Physics time: " << std::setw(5) << physicsTime * 1000.0f << "ms (c: " << std::setw(5) << physSystem.collisionTime * 1000.0f << "ms, m: " << std::setw(5) << physSystem.mergeTime * 1000.0f << "ms, s: " << std::setw(5) << physSystem.solveTime * 1000.0f << "ms)";
        */

        MicroProfileFlip();

        {
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0, width, height, 0, 1.f, -1.f);

            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDisable(GL_DEPTH_TEST);

            MicroProfileBeginDraw();

            MicroProfileDraw(width, height);

            MicroProfileEndDraw();

            glDisable(GL_BLEND);
        }

        {
            MICROPROFILE_SCOPEI("MAIN", "Flip", 0xffee00);

            glfwSwapBuffers(window);
        }

        {
            MICROPROFILE_SCOPEI("MAIN", "Input", 0xffee00);

            // Handle input
            memset(keyPressed, 0, sizeof(keyPressed));
            mouseScrollDelta = 0;

            glfwPollEvents();

            bool mouseDown0 = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
            bool mouseDown1 = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;

            MicroProfileMouseButton(mouseDown0, mouseDown1);
            MicroProfileMousePosition(mouseX, mouseY, mouseScrollDelta);
            MicroProfileModKey(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS);

            if (keyPressed[GLFW_KEY_ESCAPE])
                break;

            if (keyPressed[GLFW_KEY_O])
                MicroProfileToggleDisplayMode();

            if (keyPressed[GLFW_KEY_P])
                MicroProfileTogglePause();

            if (keyPressed[GLFW_KEY_M])
                currentMode = (currentMode + 1) % (sizeof(kModes) / sizeof(kModes[0]));

            if (keyPressed[GLFW_KEY_C])
            {
                size_t workers =
                    (queue->getWorkerCount() == WorkQueue::getIdealWorkerCount())
                    ? 1
                    : std::min(queue->getWorkerCount() * 2, WorkQueue::getIdealWorkerCount());

                queue.reset(new WorkQueue(workers));
            }
        }
    }

    glfwDestroyWindow(window);
    glfwTerminate();
}<commit_msg>Add stats display back<commit_after>#include <GLFW/glfw3.h>

#include "PhysSystem.h"

#include "microprofile/microprofile.h"
#include "microprofile/microprofileui.h"

struct Vertex
{
    Vector2f position;
    unsigned char r, g, b, a;

};

void RenderBox(std::vector<Vertex>& vertices, Coords2f coords, Vector2f size, int r, int g, int b, int a)
{
    Vector2f axisX = coords.xVector * size.x;
    Vector2f axisY = coords.yVector * size.y;

    Vertex v;

    v.r = r;
    v.g = g;
    v.b = b;
    v.a = a;

    v.position = coords.pos - axisX - axisY;
    vertices.push_back(v);

    v.position = coords.pos + axisX - axisY;
    vertices.push_back(v);

    v.position = coords.pos + axisX + axisY;
    vertices.push_back(v);

    v.position = coords.pos - axisX + axisY;
    vertices.push_back(v);
}

float random(float min, float max)
{
    return min + (max - min) * (float(rand()) / float(RAND_MAX));
}

const struct
{
    PhysSystem::SolveMode mode;
    const char* name;
} kModes[] =
    {
     {PhysSystem::Solve_Baseline, "Baseline"},
     {PhysSystem::Solve_AoS, "AoS"},
     {PhysSystem::Solve_SoA_Scalar, "SoA Scalar"},
     {PhysSystem::Solve_SoA_SSE2, "SoA SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoA_AVX2, "SoA AVX2"},
#endif

     {PhysSystem::Solve_SoAPacked_Scalar, "SoA Packed Scalar"},
     {PhysSystem::Solve_SoAPacked_SSE2, "SoA Packed SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoAPacked_AVX2, "SoA Packed AVX2"},
#endif

#if defined(__AVX2__) && defined(__FMA__)
     {PhysSystem::Solve_SoAPacked_FMA, "SoA Packed FMA"},
#endif
};

bool keyPressed[GLFW_KEY_LAST + 1];
int mouseScrollDelta = 0;

static void errorCallback(int error, const char* description)
{
    fputs(description, stderr);
}

static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    keyPressed[key] = (action == GLFW_PRESS);
}

static void scrollCallback(GLFWwindow* window, double x, double y)
{
    mouseScrollDelta = y;
}

void MicroProfileDrawInit();
void MicroProfileBeginDraw();
void MicroProfileEndDraw();

int main(int argc, char** argv)
{
    MicroProfileOnThreadCreate("Main");

    int windowWidth = 1280, windowHeight = 1024;

    std::unique_ptr<WorkQueue> queue(new WorkQueue(WorkQueue::getIdealWorkerCount()));

    PhysSystem physSystem;

    RigidBody* groundBody = physSystem.AddBody(Coords2f(Vector2f(0, 0), 0.0f), Vector2f(10000.f, 10.0f));
    groundBody->invInertia = 0.0f;
    groundBody->invMass = 0.0f;

    int currentMode = sizeof(kModes) / sizeof(kModes[0]) - 1;

    const float gravity = -200.0f;
    const float integrationTime = 1 / 60.f;
    const int contactIterationsCount = 15;
    const int penetrationIterationsCount = 15;

    physSystem.gravity = gravity;

    physSystem.AddBody(Coords2f(Vector2f(-500, 500), 0.0f), Vector2f(30.0f, 30.0f));

    float bodyRadius = 2.f;
    int bodyCount = 20000;

    for (int bodyIndex = 0; bodyIndex < bodyCount; bodyIndex++)
    {
        Vector2f pos = Vector2f(random(-500.0f, 500.0f), random(50.f, 1000.0f));
        Vector2f size(bodyRadius * 2.f, bodyRadius * 2.f);

        physSystem.AddBody(Coords2f(pos, 0.f), size);
    }

    if (argc > 1 && strcmp(argv[1], "profile") == 0)
    {
        for (int mode = 0; mode < sizeof(kModes) / sizeof(kModes[0]); ++mode)
        {
            PhysSystem testSystem;

            testSystem.gravity = gravity;

            for (auto& body: physSystem.bodies)
            {
                RigidBody* testBody = testSystem.AddBody(body.coords, body.geom.size);
                testBody->invInertia = body.invInertia;
                testBody->invMass = body.invMass;
            }

            double collisionTime = 0;
            double mergeTime = 0;
            double solveTime = 0;
            float iterations = 0;

            for (int i = 0; i < 50; ++i)
            {
                testSystem.Update(*queue, 1.f / 30.f, kModes[mode].mode, contactIterationsCount, penetrationIterationsCount);

                collisionTime += testSystem.collisionTime;
                mergeTime += testSystem.mergeTime;
                solveTime += testSystem.solveTime;
                iterations += testSystem.iterations;
            }

            printf("%s: collision %.2f ms, merge %.2f ms, solve %.2f ms, %.2f iterations\n", kModes[mode].name, collisionTime * 1000, mergeTime * 1000, solveTime * 1000, iterations);
        }

        return 0;
    }

    glfwSetErrorCallback(errorCallback);

    if (!glfwInit()) return 1;

    GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, "PhyX", NULL, NULL);
    if (!window) return 1;

    glfwMakeContextCurrent(window);
    glfwSwapInterval(0);
    glfwSetKeyCallback(window, keyCallback);
    glfwSetScrollCallback(window, scrollCallback);

    MicroProfileDrawInit();

    double prevUpdateTime = 0.0f;

    std::vector<Vertex> vertices;

    while (!glfwWindowShouldClose(window))
    {
        MICROPROFILE_SCOPEI("MAIN", "Frame", 0xffee00);

        int width, height;
        glfwGetWindowSize(window, &width, &height);

        int frameWidth, frameHeight;
        glfwGetFramebufferSize(window, &frameWidth, &frameHeight);

        double mouseX, mouseY;
        glfwGetCursorPos(window, &mouseX, &mouseY);

        glViewport(0, 0, frameWidth, frameHeight);
        glClearColor(0.2f, 0.2f, 0.2f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT);

        float offsetx = -width / 2;
        float offsety = -40;
        float scale = 0.5f;

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(offsetx / scale, width / scale + offsetx / scale, offsety / scale, height / scale + offsety / scale, 1.f, -1.f);

        vertices.clear();

        if (glfwGetTime() > prevUpdateTime + integrationTime)
        {
            prevUpdateTime += integrationTime;

            float time = integrationTime;

            Vector2f mousePos = Vector2f(mouseX + offsetx, height + offsety - mouseY) / scale;

            RigidBody* draggedBody = &physSystem.bodies[1];
            Vector2f dstVelocity = (mousePos - draggedBody->coords.pos) * 5e1f;
            draggedBody->acceleration += (dstVelocity - draggedBody->velocity) * 5e0;

            physSystem.Update(*queue, time, kModes[currentMode].mode, contactIterationsCount, penetrationIterationsCount);
        }

        {
            MICROPROFILE_SCOPEI("Render", "Prepare", 0xff0000);

            for (size_t bodyIndex = 0; bodyIndex < physSystem.bodies.size(); bodyIndex++)
            {
                RigidBody* body = &physSystem.bodies[bodyIndex];
                Coords2f bodyCoords = body->coords;
                Vector2f size = body->geom.size;

                float colorMult = float(bodyIndex) / float(physSystem.bodies.size()) * 0.5f + 0.5f;
                int r = 50 * colorMult;
                int g = 125 * colorMult;
                int b = 218 * colorMult;

                if (bodyIndex == 1) //dragged body
                {
                    r = 242;
                    g = 236;
                    b = 164;
                }

                RenderBox(vertices, bodyCoords, size, r, g, b, 255);
            }

            if (glfwGetKey(window, GLFW_KEY_V))
            {
                for (size_t manifoldIndex = 0; manifoldIndex < physSystem.collider.manifolds.size(); manifoldIndex++)
                {
                    Manifold& man = physSystem.collider.manifolds[manifoldIndex];

                    for (int collisionNumber = 0; collisionNumber < man.collisionsCount; collisionNumber++)
                    {
                        Coords2f coords = Coords2f(Vector2f(0.0f, 0.0f), 3.1415f / 4.0f);

                        coords.pos = man.body1->coords.pos + man.collisions[collisionNumber].delta1;

                        float redMult = man.collisions[collisionNumber].isNewlyCreated ? 0.5f : 1.0f;

                        RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), 100, 100 * redMult, 100 * redMult, 100);

                        coords.pos = man.body2->coords.pos + man.collisions[collisionNumber].delta2;

                        RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), 150, 150 * redMult, 150 * redMult, 100);
                    }
                }
            }
        }

        {
            MICROPROFILE_SCOPEI("Render", "Perform", 0xff0000);

            if (!vertices.empty())
            {
                glEnableClientState(GL_VERTEX_ARRAY);
                glEnableClientState(GL_COLOR_ARRAY);

                glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].position);
                glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &vertices[0].r);

                glDrawArrays(GL_QUADS, 0, vertices.size());

                glDisableClientState(GL_VERTEX_ARRAY);
                glDisableClientState(GL_COLOR_ARRAY);
            }
        }

        char stats[256];
        sprintf(stats, "Bodies: %d Manifolds: %d Contacts: %d | Cores: %d; Mode: %s; Iterations: %.2f",
            int(physSystem.bodies.size()),
            int(physSystem.collider.manifolds.size()),
            int(physSystem.solver.contactJoints.size()),
            int(queue->getWorkerCount()),
            kModes[currentMode].name,
            physSystem.iterations);

        MicroProfileFlip();

        {
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0, width, height, 0, 1.f, -1.f);

            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDisable(GL_DEPTH_TEST);

            MicroProfileBeginDraw();

            MicroProfileDraw(width, height);
            MicroProfileDrawText(2, height - 12, 0xffffffff, stats, strlen(stats));

            MicroProfileEndDraw();

            glDisable(GL_BLEND);
        }

        {
            MICROPROFILE_SCOPEI("MAIN", "Flip", 0xffee00);

            glfwSwapBuffers(window);
        }

        {
            MICROPROFILE_SCOPEI("MAIN", "Input", 0xffee00);

            // Handle input
            memset(keyPressed, 0, sizeof(keyPressed));
            mouseScrollDelta = 0;

            glfwPollEvents();

            bool mouseDown0 = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
            bool mouseDown1 = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;

            MicroProfileMouseButton(mouseDown0, mouseDown1);
            MicroProfileMousePosition(mouseX, mouseY, mouseScrollDelta);
            MicroProfileModKey(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS);

            if (keyPressed[GLFW_KEY_ESCAPE])
                break;

            if (keyPressed[GLFW_KEY_O])
                MicroProfileToggleDisplayMode();

            if (keyPressed[GLFW_KEY_P])
                MicroProfileTogglePause();

            if (keyPressed[GLFW_KEY_M])
                currentMode = (currentMode + 1) % (sizeof(kModes) / sizeof(kModes[0]));

            if (keyPressed[GLFW_KEY_C])
            {
                size_t workers =
                    (queue->getWorkerCount() == WorkQueue::getIdealWorkerCount())
                    ? 1
                    : std::min(queue->getWorkerCount() * 2, WorkQueue::getIdealWorkerCount());

                queue.reset(new WorkQueue(workers));
            }
        }
    }

    glfwDestroyWindow(window);
    glfwTerminate();
}<|endoftext|>