<commit_before>/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "fileformatdialog.h"

#include <avogadro/core/molecule.h>
#include <avogadro/io/fileformatmanager.h>

#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>

#include <QtCore/QSettings>

#include <vector>

using Avogadro::Io::FileFormat;
using Avogadro::Io::FileFormatManager;
using std::vector;

namespace Avogadro::QtGui {

FileFormatDialog::FileFormatDialog(QWidget* parentW) : QFileDialog(parentW) {}

FileFormatDialog::~FileFormatDialog() {}

FileFormatDialog::FormatFilePair FileFormatDialog::fileToRead(
  QWidget* parent, const QString& caption, const QString& dir,
  const QString& filter)
{
  FormatFilePair result(nullptr, QString());
  // Use the default read filter if none specified:
  const QString realFilter = filter.isEmpty() ? readFileFilter() : filter;

  bool done = false;
  do { // jump point for continue statements on retry
    QString fileName =
      QFileDialog::getOpenFileName(parent, caption, dir, realFilter);

    if (fileName.isEmpty()) // user cancel
      return result;

    const Io::FileFormat* format = findFileFormat(
      parent, caption, fileName, FileFormat::File | FileFormat::Read);

    // If none found, give user the option to retry.
    if (!format) {
      QMessageBox::StandardButton reply = QMessageBox::question(
        parent, caption,
        tr("Unable to find a suitable file reader for "
           "the selected file."),
        QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry);
      switch (reply) {
        default:
        case QMessageBox::Retry:
          continue;
        case QMessageBox::Abort:
          return result;
      }
    }

    result.first = format;
    result.second = fileName;
    done = true;

  } while (!done);

  return result;
}

FileFormatDialog::FormatFilePair FileFormatDialog::fileToWrite(
  QWidget* parentWidget, const QString& caption, const QString& dir,
  const QString& filter)
{
  FormatFilePair result(nullptr, QString());
  // Use the default read filter if none specified:
  const QString realFilter = filter.isEmpty() ? writeFileFilter() : filter;

  QString fileName;
  do { // jump point for continue statements on retry
    fileName =
      QFileDialog::getSaveFileName(parentWidget, caption, dir, realFilter);

    if (fileName.isEmpty()) // user cancel
      return result;

    const Io::FileFormat* format = findFileFormat(
      parentWidget, caption, fileName, FileFormat::File | FileFormat::Write);

    // If none found, give user the option to retry.
    if (!format) {
      QString extension = QFileInfo(fileName).suffix().toLower();

      if (extension.isEmpty()) {
        QMessageBox::StandardButton reply = QMessageBox::question(
          parentWidget, caption,
          tr(
            "The file extension is missing, so the format cannot be determined."
            "Do you want to add it?"),
          QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry);
        switch (reply) {
          default:
          case QMessageBox::Retry:
            continue;
          case QMessageBox::Abort:
            return result;
        }
      }

      QMessageBox::StandardButton reply = QMessageBox::question(
        parentWidget, caption,
        tr("Unable to find a suitable file writer for "
           "the selected format."),
        QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry);
      switch (reply) {
        default:
        case QMessageBox::Retry:
          continue;
        case QMessageBox::Abort:
          return result;
      }
    }

    result.first = format;
    result.second = fileName;

  } while (fileName.isEmpty());

  return result;
}

const Io::FileFormat* FileFormatDialog::findFileFormat(
  QWidget* parentWidget, const QString& caption, const QString& fileName,
  const FileFormat::Operations formatFlags, const QString& formatPrefix)
{
  if (fileName.isEmpty())
    return nullptr;

  // Extract extension from filename.
  QFileInfo fileInfo(fileName);
  QString extension = fileInfo.suffix();
  if (extension.isEmpty())
    extension = fileInfo.fileName();

  // Lookup matching file formats.
  vector<const FileFormat*> matches(
    FileFormatManager::instance().fileFormatsFromFileExtension(
      extension.toStdString(), formatFlags));

  // Prepare the strings for selectFileFormat:
  QString noun;
  QString verb;
  QString key;

  // TODO: This does not work for translation...
  //  particularly since len(matches) is known
  if ((formatFlags & FileFormat::Read && formatFlags & FileFormat::Write) ||
      ((formatFlags & FileFormat::Read) == 0 &&
       (formatFlags & FileFormat::Write) == 0)) {
    // Both or neither read/write
    noun = tr("handlers", "File handlers");
    verb = tr("handle", "e.g. file handlers that can 'handle' this file.");
    key = QLatin1String("fileToWrite"); // Just use the write settings
  } else if (formatFlags & FileFormat::Read) {
    // Read
    noun = tr("readers", "File readers");
    verb = tr("read", "e.g. file readers that can 'read' this file.");
    key = QLatin1String("fileToRead");
  } else if (formatFlags & FileFormat::Write) {
    // Write
    noun = tr("writers", "File writers");
    verb = tr("write", "e.g. file writers that can 'write' this file.");
    key = QLatin1String("fileToWrite");
  }

  return selectFileFormat(parentWidget, matches, caption,
                          tr("Multiple %1 found that can %2 this format. "
                             "Which should be used?")
                            .arg(noun, verb),
                          QString("FileFormatDialog/%1/%2"
                                  "/lastUsed")
                            .arg(key, extension),
                          formatPrefix);
}

QString FileFormatDialog::readFileFilter()
{
  static QString readFilter;
  if (readFilter.isEmpty()) {
    vector<const FileFormat*> formats =
      FileFormatManager::instance().fileFormats(FileFormat::Read |
                                                FileFormat::File);

    readFilter = generateFilterString(formats, AllFiles | AllFormats);
  }

  return readFilter;
}

QString FileFormatDialog::writeFileFilter()
{
  static QString writeFilter;
  if (writeFilter.isEmpty()) {
    vector<const FileFormat*> formats =
      FileFormatManager::instance().fileFormats(FileFormat::Write |
                                                FileFormat::File);

    writeFilter = generateFilterString(formats, WriteFormats | AllFiles);
  }

  return writeFilter;
}

QString FileFormatDialog::generateFilterString(
  const std::vector<const Io::FileFormat*>& ffs,
  FileFormatDialog::FilterStringOptions options)
{
  QString filterString;
  // Create a map that groups the file extensions by name:
  QMap<QString, QString> formatMap;
  for (auto ff : ffs) {
    QString name(QString::fromStdString(ff->name()));
    std::vector<std::string> exts = ff->fileExtensions();
    for (auto & eit : exts) {
      QString ext(QString::fromStdString(eit));
      if (!formatMap.values(name).contains(ext)) {
        formatMap.insertMulti(name, ext);
      }
    }
  }

  // This is a list of "extensions" returned by OB that are not actually
  // file extensions, but rather the full filename of the file. These
  // will be used as-is in the filter string, while others will be prepended
  // with "*.".
  QStringList nonExtensions;
  nonExtensions << QStringLiteral("POSCAR")  // VASP input geometry
                << QStringLiteral("CONTCAR") // VASP output geometry
                << QStringLiteral("HISTORY") // DL-POLY history file
                << QStringLiteral("CONFIG")  // DL-POLY config file
    ;

  // This holds all known extensions:
  QStringList allExtensions;

  foreach (const QString& desc, formatMap.uniqueKeys()) {
    QStringList extensions;
    QStringList formatExtensions = formatMap.values(desc);

    // When writing formats, only list one common extension
    // .. to ensure the OS appends the extension to the filename
    if (options & WriteFormats) {
      if (formatExtensions.contains(QStringLiteral("cml")))
        formatExtensions = QStringList("cml");
      else if (formatExtensions.contains(QStringLiteral("mol2")))
        formatExtensions = QStringList("mol2");
      else if (formatExtensions.contains(QStringLiteral("pdb")))
        formatExtensions = QStringList("pdb");
      else if (formatExtensions.contains(QStringLiteral("sdf")))
        formatExtensions = QStringList("sdf");
      else if (formatExtensions.contains(QStringLiteral("xyz")))
        formatExtensions = QStringList("xyz");
    }

    foreach (QString extension, formatExtensions) {
      if (!nonExtensions.contains(extension))
        extension.prepend("*.");
      extensions << extension;
    }
    if (options & AllFormats)
      allExtensions << extensions;
    filterString += QStringLiteral("%1 (%2);;")
                      .arg(desc, extensions.join(QStringLiteral(" ")));
  }

  if (options & AllFiles)
    filterString.prepend(tr("All files (*);;"));

  if (options & AllFormats) {
    filterString.prepend(tr("All supported formats (%1);;")
                           .arg(allExtensions.join(QStringLiteral(" "))));
  }

  return filterString;
}

const Io::FileFormat* FileFormatDialog::selectFileFormat(
  QWidget* parentWidget, const std::vector<const Io::FileFormat*>& ffs,
  const QString& caption, const QString& prompt, const QString& settingsKey,
  const QString& formatPrefix)
{
  if (ffs.empty())
    return nullptr;
  else if (ffs.size() == 1)
    return ffs[0];

  // If more than one format found, prompt user to select one.
  QStringList idents;
  for (auto ff : ffs) {
    idents << QString::fromStdString(ff->identifier());
  }

  // If there is a format prefix, see if that can reduce the results down.
  QStringList preferred;
  foreach (const QString& id, idents)
    if (id.startsWith(formatPrefix))
      preferred << id;
  if (preferred.size() == 1)
    return ffs[idents.indexOf(preferred.first())];

  // See if they used one before:
  QString lastIdent = settingsKey.isNull()
                        ? QString()
                        : QSettings().value(settingsKey).toString();

  int lastIdentIndex = idents.indexOf(lastIdent);
  if (lastIdentIndex < 0)
    lastIdentIndex = 0;

  bool ok;
  QString item = QInputDialog::getItem(parentWidget, caption, prompt, idents,
                                       lastIdentIndex, false, &ok);
  int index = idents.indexOf(item);

  // user cancel
  if (!ok || index < 0 || index + 1 > static_cast<int>(ffs.size()))
    return nullptr;

  // Store chosen reader for next time
  if (!settingsKey.isNull())
    QSettings().setValue(settingsKey, item);

  return ffs[index];
}

} // namespace Avogadro
<commit_msg>Fix mis-translated export dialog (#1133)<commit_after>/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "fileformatdialog.h"

#include <avogadro/core/molecule.h>
#include <avogadro/io/fileformatmanager.h>

#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>

#include <QtCore/QSettings>

#include <vector>

using Avogadro::Io::FileFormat;
using Avogadro::Io::FileFormatManager;
using std::vector;

namespace Avogadro::QtGui {

FileFormatDialog::FileFormatDialog(QWidget* parentW) : QFileDialog(parentW) {}

FileFormatDialog::~FileFormatDialog() {}

FileFormatDialog::FormatFilePair FileFormatDialog::fileToRead(
  QWidget* parent, const QString& caption, const QString& dir,
  const QString& filter)
{
  FormatFilePair result(nullptr, QString());
  // Use the default read filter if none specified:
  const QString realFilter = filter.isEmpty() ? readFileFilter() : filter;

  bool done = false;
  do { // jump point for continue statements on retry
    QString fileName =
      QFileDialog::getOpenFileName(parent, caption, dir, realFilter);

    if (fileName.isEmpty()) // user cancel
      return result;

    const Io::FileFormat* format = findFileFormat(
      parent, caption, fileName, FileFormat::File | FileFormat::Read);

    // If none found, give user the option to retry.
    if (!format) {
      QMessageBox::StandardButton reply = QMessageBox::question(
        parent, caption,
        tr("Unable to find a suitable file reader for "
           "the selected file."),
        QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry);
      switch (reply) {
        default:
        case QMessageBox::Retry:
          continue;
        case QMessageBox::Abort:
          return result;
      }
    }

    result.first = format;
    result.second = fileName;
    done = true;

  } while (!done);

  return result;
}

FileFormatDialog::FormatFilePair FileFormatDialog::fileToWrite(
  QWidget* parentWidget, const QString& caption, const QString& dir,
  const QString& filter)
{
  FormatFilePair result(nullptr, QString());
  // Use the default read filter if none specified:
  const QString realFilter = filter.isEmpty() ? writeFileFilter() : filter;

  QString fileName;
  do { // jump point for continue statements on retry
    fileName =
      QFileDialog::getSaveFileName(parentWidget, caption, dir, realFilter);

    if (fileName.isEmpty()) // user cancel
      return result;

    const Io::FileFormat* format = findFileFormat(
      parentWidget, caption, fileName, FileFormat::File | FileFormat::Write);

    // If none found, give user the option to retry.
    if (!format) {
      QString extension = QFileInfo(fileName).suffix().toLower();

      if (extension.isEmpty()) {
        QMessageBox::StandardButton reply = QMessageBox::question(
          parentWidget, caption,
          tr(
            "The file extension is missing, so the format cannot be determined."
            "Do you want to add it?"),
          QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry);
        switch (reply) {
          default:
          case QMessageBox::Retry:
            continue;
          case QMessageBox::Abort:
            return result;
        }
      }

      QMessageBox::StandardButton reply = QMessageBox::question(
        parentWidget, caption,
        tr("Unable to find a suitable file writer for "
           "the selected format."),
        QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry);
      switch (reply) {
        default:
        case QMessageBox::Retry:
          continue;
        case QMessageBox::Abort:
          return result;
      }
    }

    result.first = format;
    result.second = fileName;

  } while (fileName.isEmpty());

  return result;
}

const Io::FileFormat* FileFormatDialog::findFileFormat(
  QWidget* parentWidget, const QString& caption, const QString& fileName,
  const FileFormat::Operations formatFlags, const QString& formatPrefix)
{
  if (fileName.isEmpty())
    return nullptr;

  // Extract extension from filename.
  QFileInfo fileInfo(fileName);
  QString extension = fileInfo.suffix();
  if (extension.isEmpty())
    extension = fileInfo.fileName();

  // Lookup matching file formats.
  vector<const FileFormat*> matches(
    FileFormatManager::instance().fileFormatsFromFileExtension(
      extension.toStdString(), formatFlags));

  // Prepare the strings for selectFileFormat:
  QString noun;
  QString verb;
  QString key;

  // TODO: This does not work for translation...
  //  particularly since len(matches) is known
  if ((formatFlags & FileFormat::Read && formatFlags & FileFormat::Write) ||
      ((formatFlags & FileFormat::Read) == 0 &&
       (formatFlags & FileFormat::Write) == 0)) {
    // Both or neither read/write
    noun = tr("handlers", "File handlers");
    verb = tr("handle", "e.g. file handlers that can 'handle' this file.");
    key = QLatin1String("fileToWrite"); // Just use the write settings
  } else if (formatFlags & FileFormat::Read) {
    // Read
    noun = tr("readers", "File readers");
    verb = tr("read", "e.g. file readers that can 'read' this file.");
    key = QLatin1String("fileToRead");
  } else if (formatFlags & FileFormat::Write) {
    // Write
    noun = tr("writers", "File writers");
    verb = tr("write", "e.g. file writers that can 'write' this file.");
    key = QLatin1String("fileToWrite");
  }

  return selectFileFormat(parentWidget, matches, caption,
                          tr("Multiple %1 found that can %2 this format. "
                             "Which should be used?")
                            .arg(noun, verb),
                          QString("FileFormatDialog/%1/%2"
                                  "/lastUsed")
                            .arg(key, extension),
                          formatPrefix);
}

QString FileFormatDialog::readFileFilter()
{
  static QString readFilter;
  if (readFilter.isEmpty()) {
    vector<const FileFormat*> formats =
      FileFormatManager::instance().fileFormats(FileFormat::Read |
                                                FileFormat::File);

    readFilter = generateFilterString(formats, AllFiles | AllFormats);
  }

  return readFilter;
}

QString FileFormatDialog::writeFileFilter()
{
  static QString writeFilter;
  if (writeFilter.isEmpty()) {
    vector<const FileFormat*> formats =
      FileFormatManager::instance().fileFormats(FileFormat::Write |
                                                FileFormat::File);

    writeFilter = generateFilterString(formats, WriteFormats | AllFiles);
  }

  return writeFilter;
}

QString FileFormatDialog::generateFilterString(
  const std::vector<const Io::FileFormat*>& ffs,
  FileFormatDialog::FilterStringOptions options)
{
  QString filterString;
  // Create a map that groups the file extensions by name:
  QMap<QString, QString> formatMap;
  for (auto ff : ffs) {
    QString name(QString::fromStdString(ff->name()));
    std::vector<std::string> exts = ff->fileExtensions();
    for (auto & eit : exts) {
      QString ext(QString::fromStdString(eit));
      if (!formatMap.values(name).contains(ext)) {
        formatMap.insertMulti(name, ext);
      }
    }
  }

  // This is a list of "extensions" returned by OB that are not actually
  // file extensions, but rather the full filename of the file. These
  // will be used as-is in the filter string, while others will be prepended
  // with "*.".
  QStringList nonExtensions;
  nonExtensions << QStringLiteral("POSCAR")  // VASP input geometry
                << QStringLiteral("CONTCAR") // VASP output geometry
                << QStringLiteral("HISTORY") // DL-POLY history file
                << QStringLiteral("CONFIG")  // DL-POLY config file
    ;

  // This holds all known extensions:
  QStringList allExtensions;

  foreach (const QString& desc, formatMap.uniqueKeys()) {
    QStringList extensions;
    QStringList formatExtensions = formatMap.values(desc);

    // When writing formats, only list one common extension
    // .. to ensure the OS appends the extension to the filename
    if (options & WriteFormats) {
      if (formatExtensions.contains(QStringLiteral("cml")))
        formatExtensions = QStringList("cml");
      else if (formatExtensions.contains(QStringLiteral("mol2")))
        formatExtensions = QStringList("mol2");
      else if (formatExtensions.contains(QStringLiteral("pdb")))
        formatExtensions = QStringList("pdb");
      else if (formatExtensions.contains(QStringLiteral("sdf")))
        formatExtensions = QStringList("sdf");
      else if (formatExtensions.contains(QStringLiteral("xyz")))
        formatExtensions = QStringList("xyz");
    }

    foreach (QString extension, formatExtensions) {
      if (!nonExtensions.contains(extension))
        extension.prepend("*.");
      extensions << extension;
    }
    if (options & AllFormats)
      allExtensions << extensions;
    filterString += QStringLiteral("%1 (%2);;")
                      .arg(desc, extensions.join(QStringLiteral(" ")));
  }

  if (options & AllFiles)
    filterString.prepend(tr("All files") + " (*);;");

  if (options & AllFormats) {
    filterString.prepend((tr("All supported formats") + " (%1);;")
                           .arg(allExtensions.join(QStringLiteral(" "))));
  }

  return filterString;
}

const Io::FileFormat* FileFormatDialog::selectFileFormat(
  QWidget* parentWidget, const std::vector<const Io::FileFormat*>& ffs,
  const QString& caption, const QString& prompt, const QString& settingsKey,
  const QString& formatPrefix)
{
  if (ffs.empty())
    return nullptr;
  else if (ffs.size() == 1)
    return ffs[0];

  // If more than one format found, prompt user to select one.
  QStringList idents;
  for (auto ff : ffs) {
    idents << QString::fromStdString(ff->identifier());
  }

  // If there is a format prefix, see if that can reduce the results down.
  QStringList preferred;
  foreach (const QString& id, idents)
    if (id.startsWith(formatPrefix))
      preferred << id;
  if (preferred.size() == 1)
    return ffs[idents.indexOf(preferred.first())];

  // See if they used one before:
  QString lastIdent = settingsKey.isNull()
                        ? QString()
                        : QSettings().value(settingsKey).toString();

  int lastIdentIndex = idents.indexOf(lastIdent);
  if (lastIdentIndex < 0)
    lastIdentIndex = 0;

  bool ok;
  QString item = QInputDialog::getItem(parentWidget, caption, prompt, idents,
                                       lastIdentIndex, false, &ok);
  int index = idents.indexOf(item);

  // user cancel
  if (!ok || index < 0 || index + 1 > static_cast<int>(ffs.size()))
    return nullptr;

  // Store chosen reader for next time
  if (!settingsKey.isNull())
    QSettings().setValue(settingsKey, item);

  return ffs[index];
}

} // namespace Avogadro
<|endoftext|>


<commit_before>// IFC SDK : IFC2X3 C++ Early Classes
// Copyright (C) 2009 CSTB
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full license is in Licence.txt file included with this
// distribution or is available at :
//     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

#include "precompiled.h"

#include <ifc2x3/IfcTerminatorSymbol.h>

#include <ifc2x3/CopyOp.h>
#include <ifc2x3/IfcAnnotationCurveOccurrence.h>
#include <ifc2x3/IfcAnnotationSymbolOccurrence.h>
#include <ifc2x3/IfcDimensionCurve.h>
#include <ifc2x3/Visitor.h>
#include <Step/BaseExpressDataSet.h>
#include <Step/BaseObject.h>
#include <Step/ClassType.h>
#include <Step/Referenced.h>
#include <Step/SPFFunctions.h>
#include <Step/logger.h>

#include <string>

using namespace ifc2x3;

IfcTerminatorSymbol::IfcTerminatorSymbol(Step::Id id, Step::SPFData *args) : IfcAnnotationSymbolOccurrence(id, args) {
    m_annotatedCurve = NULL;
}

IfcTerminatorSymbol::~IfcTerminatorSymbol() {
}

bool IfcTerminatorSymbol::acceptVisitor(Step::BaseVisitor *visitor) {
    return static_cast< Visitor * > (visitor)->visitIfcTerminatorSymbol(this);
}

const std::string &IfcTerminatorSymbol::type() const {
    return IfcTerminatorSymbol::s_type.getName();
}

const Step::ClassType &IfcTerminatorSymbol::getClassType() {
    return IfcTerminatorSymbol::s_type;
}

const Step::ClassType &IfcTerminatorSymbol::getType() const {
    return IfcTerminatorSymbol::s_type;
}

bool IfcTerminatorSymbol::isOfType(const Step::ClassType &t) const {
    return IfcTerminatorSymbol::s_type == t ? true : IfcAnnotationSymbolOccurrence::isOfType(t);
}

IfcAnnotationCurveOccurrence *IfcTerminatorSymbol::getAnnotatedCurve() {
    if (Step::BaseObject::inited()) {
        return m_annotatedCurve.get();
    }
    else {
        return NULL;
    }
}

const IfcAnnotationCurveOccurrence *IfcTerminatorSymbol::getAnnotatedCurve() const {
    IfcTerminatorSymbol * deConstObject = const_cast< IfcTerminatorSymbol * > (this);
    return deConstObject->getAnnotatedCurve();
}

void IfcTerminatorSymbol::setAnnotatedCurve(const Step::RefPtr< IfcAnnotationCurveOccurrence > &value) {
    if (dynamic_cast< IfcDimensionCurve * > (m_annotatedCurve.get()) != NULL) {
        ((IfcDimensionCurve *) (m_annotatedCurve.get()))->m_annotatedBySymbols.erase(this);
    }
	m_annotatedCurve = value;
	if (dynamic_cast< IfcDimensionCurve * > (m_annotatedCurve.get()) != NULL) {
        ((IfcDimensionCurve *) (m_annotatedCurve.get()))->m_annotatedBySymbols.insert(this);
    }

}

void IfcTerminatorSymbol::unsetAnnotatedCurve() {
    m_annotatedCurve = Step::getUnset(getAnnotatedCurve());
}

bool IfcTerminatorSymbol::testAnnotatedCurve() const {
    return !Step::isUnset(getAnnotatedCurve());
}

bool IfcTerminatorSymbol::init() {
    bool status = IfcAnnotationSymbolOccurrence::init();
    std::string arg;
    if (!status) {
        return false;
    }
    arg = m_args->getNext();
    if (arg == "$" || arg == "*") {
        m_annotatedCurve = NULL;
    }
    else {
        m_annotatedCurve = static_cast< IfcAnnotationCurveOccurrence * > (m_expressDataSet->get(Step::getIdParam(arg)));
    }
    return true;
}

void IfcTerminatorSymbol::copy(const IfcTerminatorSymbol &obj, const CopyOp &copyop) {
    IfcAnnotationSymbolOccurrence::copy(obj, copyop);
    setAnnotatedCurve((IfcAnnotationCurveOccurrence*)copyop(obj.m_annotatedCurve.get()));
    return;
}

IFC2X3_EXPORT Step::ClassType IfcTerminatorSymbol::s_type("IfcTerminatorSymbol");
<commit_msg>also update inverse relation when unsetting value<commit_after>// IFC SDK : IFC2X3 C++ Early Classes
// Copyright (C) 2009 CSTB
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full license is in Licence.txt file included with this
// distribution or is available at :
//     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

#include "precompiled.h"

#include <ifc2x3/IfcTerminatorSymbol.h>

#include <ifc2x3/CopyOp.h>
#include <ifc2x3/IfcAnnotationCurveOccurrence.h>
#include <ifc2x3/IfcAnnotationSymbolOccurrence.h>
#include <ifc2x3/IfcDimensionCurve.h>
#include <ifc2x3/Visitor.h>
#include <Step/BaseExpressDataSet.h>
#include <Step/BaseObject.h>
#include <Step/ClassType.h>
#include <Step/Referenced.h>
#include <Step/SPFFunctions.h>
#include <Step/logger.h>

#include <string>

using namespace ifc2x3;

IfcTerminatorSymbol::IfcTerminatorSymbol(Step::Id id, Step::SPFData *args) : IfcAnnotationSymbolOccurrence(id, args) {
    m_annotatedCurve = NULL;
}

IfcTerminatorSymbol::~IfcTerminatorSymbol() {
}

bool IfcTerminatorSymbol::acceptVisitor(Step::BaseVisitor *visitor) {
    return static_cast< Visitor * > (visitor)->visitIfcTerminatorSymbol(this);
}

const std::string &IfcTerminatorSymbol::type() const {
    return IfcTerminatorSymbol::s_type.getName();
}

const Step::ClassType &IfcTerminatorSymbol::getClassType() {
    return IfcTerminatorSymbol::s_type;
}

const Step::ClassType &IfcTerminatorSymbol::getType() const {
    return IfcTerminatorSymbol::s_type;
}

bool IfcTerminatorSymbol::isOfType(const Step::ClassType &t) const {
    return IfcTerminatorSymbol::s_type == t ? true : IfcAnnotationSymbolOccurrence::isOfType(t);
}

IfcAnnotationCurveOccurrence *IfcTerminatorSymbol::getAnnotatedCurve() {
    if (Step::BaseObject::inited()) {
        return m_annotatedCurve.get();
    }
    else {
        return NULL;
    }
}

const IfcAnnotationCurveOccurrence *IfcTerminatorSymbol::getAnnotatedCurve() const {
    IfcTerminatorSymbol * deConstObject = const_cast< IfcTerminatorSymbol * > (this);
    return deConstObject->getAnnotatedCurve();
}

void IfcTerminatorSymbol::setAnnotatedCurve(const Step::RefPtr< IfcAnnotationCurveOccurrence > &value) {
    if (dynamic_cast< IfcDimensionCurve * > (m_annotatedCurve.get()) != NULL) {
        ((IfcDimensionCurve *) (m_annotatedCurve.get()))->m_annotatedBySymbols.erase(this);
    }
	m_annotatedCurve = value;
	if (dynamic_cast< IfcDimensionCurve * > (m_annotatedCurve.get()) != NULL) {
        ((IfcDimensionCurve *) (m_annotatedCurve.get()))->m_annotatedBySymbols.insert(this);
    }

}

void IfcTerminatorSymbol::unsetAnnotatedCurve() {
    if (dynamic_cast< IfcDimensionCurve * > (m_annotatedCurve.get()) != NULL) {
        ((IfcDimensionCurve *) (m_annotatedCurve.get()))->m_annotatedBySymbols.erase(this);
    }
    m_annotatedCurve = Step::getUnset(getAnnotatedCurve());
}

bool IfcTerminatorSymbol::testAnnotatedCurve() const {
    return !Step::isUnset(getAnnotatedCurve());
}

bool IfcTerminatorSymbol::init() {
    bool status = IfcAnnotationSymbolOccurrence::init();
    std::string arg;
    if (!status) {
        return false;
    }
    arg = m_args->getNext();
    if (arg == "$" || arg == "*") {
        m_annotatedCurve = NULL;
    }
    else {
        m_annotatedCurve = static_cast< IfcAnnotationCurveOccurrence * > (m_expressDataSet->get(Step::getIdParam(arg)));
    }
    return true;
}

void IfcTerminatorSymbol::copy(const IfcTerminatorSymbol &obj, const CopyOp &copyop) {
    IfcAnnotationSymbolOccurrence::copy(obj, copyop);
    setAnnotatedCurve((IfcAnnotationCurveOccurrence*)copyop(obj.m_annotatedCurve.get()));
    return;
}

IFC2X3_EXPORT Step::ClassType IfcTerminatorSymbol::s_type("IfcTerminatorSymbol");
<|endoftext|>


<commit_before>#include "ui/ScrollWidget.hpp"
#include "app.hpp"

namespace rack {
namespace ui {

ScrollWidget::ScrollWidget() {
	container = new widget::Widget;
	addChild(container);

	horizontalScrollBar = new ScrollBar;
	horizontalScrollBar->orientation = ScrollBar::HORIZONTAL;
	horizontalScrollBar->visible = false;
	addChild(horizontalScrollBar);

	verticalScrollBar = new ScrollBar;
	verticalScrollBar->orientation = ScrollBar::VERTICAL;
	verticalScrollBar->visible = false;
	addChild(verticalScrollBar);
}

void ScrollWidget::scrollTo(math::Rect r) {
	math::Rect bound = math::Rect::fromMinMax(r.getBottomRight().minus(box.size), r.pos);
	offset = offset.clampSafe(bound);
}

void ScrollWidget::draw(const DrawArgs &args) {
	nvgScissor(args.vg, RECT_ARGS(args.clipBox));
	Widget::draw(args);
	nvgResetScissor(args.vg);
}

void ScrollWidget::step() {
	Widget::step();

	// Clamp scroll offset
	math::Rect containerBox = container->getChildrenBoundingBox();
	math::Rect offsetBounds = containerBox;
	offsetBounds.size = offsetBounds.size.minus(box.size);
	offset = offset.clamp(offsetBounds);

	// Update the container's position from the offset
	container->box.pos = offset.neg().round();

	// Update scrollbar offsets and sizes
	math::Vec scrollbarOffset = offset.minus(containerBox.pos).div(offsetBounds.size);
	math::Vec scrollbarSize = box.size.div(containerBox.size);

	horizontalScrollBar->visible = (0.0 < scrollbarSize.x && scrollbarSize.x < 1.0);
	verticalScrollBar->visible = (0.0 < scrollbarSize.y && scrollbarSize.y < 1.0);
	horizontalScrollBar->offset = scrollbarOffset.x;
	verticalScrollBar->offset = scrollbarOffset.y;
	horizontalScrollBar->size = scrollbarSize.x;
	verticalScrollBar->size = scrollbarSize.y;

	// Reposition and resize scroll bars
	math::Vec inner = box.size.minus(math::Vec(verticalScrollBar->box.size.x, horizontalScrollBar->box.size.y));
	horizontalScrollBar->box.pos.y = inner.y;
	verticalScrollBar->box.pos.x = inner.x;
	horizontalScrollBar->box.size.x = verticalScrollBar->visible ? inner.x : box.size.x;
	verticalScrollBar->box.size.y = horizontalScrollBar->visible ? inner.y : box.size.y;
}

void ScrollWidget::onButton(const event::Button &e) {
	Widget::onButton(e);
	if (e.isConsumed())
		return;

	// Consume right button only if the scrollbars are visible
	if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
		return;

	if (e.button == GLFW_MOUSE_BUTTON_MIDDLE) {
		e.consume(this);
	}
}

void ScrollWidget::onDragStart(const event::DragStart &e) {
	if (e.button == GLFW_MOUSE_BUTTON_MIDDLE) {
		e.consume(this);
	}
}

void ScrollWidget::onDragMove(const event::DragMove &e) {
	// Scroll only if the scrollbars are visible
	if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
		return;

	offset = offset.minus(e.mouseDelta);
}

void ScrollWidget::onHoverScroll(const event::HoverScroll &e) {
	OpaqueWidget::onHoverScroll(e);
	if (e.isConsumed())
		return;

	math::Vec scrollDelta = e.scrollDelta;
	// Flip coordinates if shift is held
	if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
		scrollDelta = scrollDelta.flip();

	offset = offset.minus(scrollDelta);
	e.consume(this);
}

} // namespace ui
} // namespace rack
<commit_msg>Handle HoverScroll only if scrollbars are visible.<commit_after>#include "ui/ScrollWidget.hpp"
#include "app.hpp"

namespace rack {
namespace ui {

ScrollWidget::ScrollWidget() {
	container = new widget::Widget;
	addChild(container);

	horizontalScrollBar = new ScrollBar;
	horizontalScrollBar->orientation = ScrollBar::HORIZONTAL;
	horizontalScrollBar->visible = false;
	addChild(horizontalScrollBar);

	verticalScrollBar = new ScrollBar;
	verticalScrollBar->orientation = ScrollBar::VERTICAL;
	verticalScrollBar->visible = false;
	addChild(verticalScrollBar);
}

void ScrollWidget::scrollTo(math::Rect r) {
	math::Rect bound = math::Rect::fromMinMax(r.getBottomRight().minus(box.size), r.pos);
	offset = offset.clampSafe(bound);
}

void ScrollWidget::draw(const DrawArgs &args) {
	nvgScissor(args.vg, RECT_ARGS(args.clipBox));
	Widget::draw(args);
	nvgResetScissor(args.vg);
}

void ScrollWidget::step() {
	Widget::step();

	// Clamp scroll offset
	math::Rect containerBox = container->getChildrenBoundingBox();
	math::Rect offsetBounds = containerBox;
	offsetBounds.size = offsetBounds.size.minus(box.size);
	offset = offset.clamp(offsetBounds);

	// Update the container's position from the offset
	container->box.pos = offset.neg().round();

	// Update scrollbar offsets and sizes
	math::Vec scrollbarOffset = offset.minus(containerBox.pos).div(offsetBounds.size);
	math::Vec scrollbarSize = box.size.div(containerBox.size);

	horizontalScrollBar->visible = (0.0 < scrollbarSize.x && scrollbarSize.x < 1.0);
	verticalScrollBar->visible = (0.0 < scrollbarSize.y && scrollbarSize.y < 1.0);
	horizontalScrollBar->offset = scrollbarOffset.x;
	verticalScrollBar->offset = scrollbarOffset.y;
	horizontalScrollBar->size = scrollbarSize.x;
	verticalScrollBar->size = scrollbarSize.y;

	// Reposition and resize scroll bars
	math::Vec inner = box.size.minus(math::Vec(verticalScrollBar->box.size.x, horizontalScrollBar->box.size.y));
	horizontalScrollBar->box.pos.y = inner.y;
	verticalScrollBar->box.pos.x = inner.x;
	horizontalScrollBar->box.size.x = verticalScrollBar->visible ? inner.x : box.size.x;
	verticalScrollBar->box.size.y = horizontalScrollBar->visible ? inner.y : box.size.y;
}

void ScrollWidget::onButton(const event::Button &e) {
	Widget::onButton(e);
	if (e.isConsumed())
		return;

	// Consume right button only if the scrollbars are visible
	if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
		return;

	if (e.button == GLFW_MOUSE_BUTTON_MIDDLE) {
		e.consume(this);
	}
}

void ScrollWidget::onDragStart(const event::DragStart &e) {
	if (e.button == GLFW_MOUSE_BUTTON_MIDDLE) {
		e.consume(this);
	}
}

void ScrollWidget::onDragMove(const event::DragMove &e) {
	// Scroll only if the scrollbars are visible
	if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
		return;

	offset = offset.minus(e.mouseDelta);
}

void ScrollWidget::onHoverScroll(const event::HoverScroll &e) {
	OpaqueWidget::onHoverScroll(e);
	if (e.isConsumed())
		return;

	// Scroll only if the scrollbars are visible
	if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
		return;

	math::Vec scrollDelta = e.scrollDelta;
	// Flip coordinates if shift is held
	if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
		scrollDelta = scrollDelta.flip();

	offset = offset.minus(scrollDelta);
	e.consume(this);
}

} // namespace ui
} // namespace rack
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012 Viktor Gal
 * Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
 */

#include <shogun/io/SGIO.h>
#include <shogun/preprocessor/HomogeneousKernelMap.h>

#include <math.h>
#include <iostream>

using namespace shogun;

CHomogeneousKernelMap::CHomogeneousKernelMap ()
	: CSimplePreprocessor<float64_t> ()
{

}

CHomogeneousKernelMap::CHomogeneousKernelMap
	(HomogeneousKernelType kernel, HomogeneousKernelMapWindowType wType,
	 float64_t gamma, uint64_t order, float64_t period)
	: CSimplePreprocessor<float64_t> (),
		m_kernel (kernel),
		m_window (wType),
		m_gamma (gamma),
		m_period (period),
		m_order (order)

{
	init ();
}

CHomogeneousKernelMap::~CHomogeneousKernelMap() {
	m_table.destroy_vector ();
}

bool CHomogeneousKernelMap::init (CFeatures* features) {
	ASSERT(features->get_feature_class()==C_SIMPLE);
	ASSERT(features->get_feature_type()==F_DREAL);

	return true;
}

void CHomogeneousKernelMap::cleanup () {
	m_table.destroy_vector ();
}

void CHomogeneousKernelMap::init () {
	SG_DEBUG ("Initialising homogeneous kernel map...\n");
	ASSERT (m_gamma > 0) ;

  ASSERT (m_kernel == HomogeneousKernelIntersection ||
          m_kernel == HomogeneousKernelChi2 ||
          m_kernel == HomogeneousKernelJS);

  ASSERT (m_window == HomogeneousKernelMapWindowUniform ||
          m_window == HomogeneousKernelMapWindowRectangular);

	if (m_period < 0) {
	  switch (m_window) {
	  case HomogeneousKernelMapWindowUniform:
	    switch (m_kernel) {
		    case HomogeneousKernelChi2:
					m_period = 5.86 * CMath::sqrt (static_cast<float64_t> (m_order))  + 3.65;
					break;
		    case HomogeneousKernelJS:
		      m_period = 6.64 * CMath::sqrt (static_cast<float64_t> (m_order))  + 7.24;
					break;
		    case HomogeneousKernelIntersection:
					m_period = 2.38 * CMath::log (m_order + 0.8) + 5.6;
					break;
	    }
	    break;
	  case HomogeneousKernelMapWindowRectangular:
	    switch (m_kernel) {
		    case HomogeneousKernelChi2:
					m_period = 8.80 * CMath::sqrt (m_order + 4.44) - 12.6;
					break;
		    case HomogeneousKernelJS:
					m_period = 9.63 * CMath::sqrt (m_order + 1.00) - 2.93;
					break;
		    case HomogeneousKernelIntersection:
					m_period = 2.00 * CMath::log (m_order + 0.99) + 3.52;
					break;
	    }
	    break;
	  }
	  m_period = CMath::max (m_period, 1.0) ;
	}

  m_numSubdivisions = 8 + 8*m_order;
  m_subdivision = 1.0 / m_numSubdivisions;
  m_minExponent = -20;
  m_maxExponent = 8;

  int tableHeight = 2*m_order + 1 ;
  int tableWidth = m_numSubdivisions * (m_maxExponent - m_minExponent + 1);
	size_t numElements = (tableHeight * tableWidth + 2*(1+m_order));
	m_table = SGVector<float64_t> (NULL, numElements, true);
	m_table.vlen = numElements;
	m_table.vector = SG_CALLOC (float64_t, numElements);

	/* check whether allocation was ok */
	if (m_table.vector == NULL) {
		throw ShogunException ("CHomogeneousKernelMap::init: could not allocate memory for vector");
	}

	int exponent;
  uint64_t i = 0, j = 0;
  float64_t* tablep = m_table.vector;
  float64_t* kappa = m_table.vector + tableHeight * tableWidth;
  float64_t* freq = kappa + (1+m_order);
  float64_t L = 2.0 * CMath::PI / m_period;

  /* precompute the sampled periodicized spectrum */
  while (i <= m_order) {
    freq[i] = j;
    kappa[i] = get_smooth_spectrum (j * L);
    ++ j;
    if (kappa[i] > 0 || j >= 3*i) ++ i;
  }

  /* fill table */
  for (exponent  = m_minExponent ;
       exponent <= m_maxExponent ; ++ exponent) {

    float64_t x, Lxgamma, Llogx, xgamma;
    float64_t sqrt2kappaLxgamma;
    float64_t mantissa = 1.0;

    for (i = 0 ; i < m_numSubdivisions;
         ++i, mantissa += m_subdivision) {
      x = ldexp (mantissa, exponent);
      xgamma = CMath::pow (x, m_gamma);
      Lxgamma = L * xgamma;
      Llogx = L * CMath::log (x);

      *tablep++ = CMath::sqrt (Lxgamma * kappa[0]);
      for (j = 1 ; j <= m_order; ++j) {
        sqrt2kappaLxgamma = CMath::sqrt (2.0 * Lxgamma * kappa[j]);
        *tablep++ = sqrt2kappaLxgamma * CMath::cos (freq[j] * Llogx);
        *tablep++ = sqrt2kappaLxgamma * CMath::sin (freq[j] * Llogx);
      }
    } /* next mantissa */
  } /* next exponent */

	/* register variables */
	m_parameters->add ((machine_int_t*) &m_kernel, "kernel", "Kernel type to use.");
	m_parameters->add ((machine_int_t*) &m_window, "window", "Window type to use.");
	m_parameters->add (&m_gamma, "gamma", "Homogeneity order.");
	m_parameters->add (&m_period, "period", "Approximation order");
	m_parameters->add (&m_numSubdivisions, "numSubdivisions", "The number of sublevels");
	m_parameters->add (&m_subdivision, "subdivision", "subdivision.");
	m_parameters->add (&m_order, "order", "The order");
	m_parameters->add (&m_minExponent, "minExponent", "Minimum exponent");
	m_parameters->add (&m_maxExponent, "maxExponent", "Maximum exponent");
	m_parameters->add (&m_table, "table", "Lookup-table");
}

SGMatrix<float64_t> CHomogeneousKernelMap::apply_to_feature_matrix (CFeatures* features) {
	CSimpleFeatures<float64_t>* simple_features = (CSimpleFeatures<float64_t>*)features;
	int32_t num_vectors = simple_features->get_num_vectors ();
	int32_t num_features = simple_features->get_num_features ();
	SGMatrix<float64_t> result (num_features*(2*m_order+1), num_vectors);

	for (int i = 0; i < num_vectors; ++i) {
		SGVector<float64_t> v = simple_features->get_feature_vector (i);
		SGVector<float64_t> col (result.get_column_vector (i), result.num_rows);
		apply_to_vector (v, col);
	}

	return result;
}

/// apply preproc on single feature vector
SGVector<float64_t> CHomogeneousKernelMap::apply_to_feature_vector (SGVector<float64_t> vector) {
	uint64_t featureDimension = 2*m_order+1;
	uint64_t m_target_dim = vector.vlen * featureDimension;
	SGVector<float64_t> result = SGVector<float64_t> (m_target_dim);

	apply_to_vector (vector, result);

	return result;
}

void CHomogeneousKernelMap::setKernelType (HomogeneousKernelType k) {
	m_kernel = k;
}

HomogeneousKernelType CHomogeneousKernelMap::getKernelType () const {
	return m_kernel;
}

void CHomogeneousKernelMap::setWindowType (HomogeneousKernelMapWindowType w) {
	m_window = w;
}

HomogeneousKernelMapWindowType CHomogeneousKernelMap::getWindowType () const {
	return m_window;
}

void CHomogeneousKernelMap::setGamma (float64_t g) {
	m_gamma = g;
}

float64_t CHomogeneousKernelMap::getGamma (float64_t g) const {
	return m_gamma;
}

void CHomogeneousKernelMap::setOrder (uint64_t o) {
	m_order = o;
}

uint64_t CHomogeneousKernelMap::getOrder () const {
	return m_order;
}

void CHomogeneousKernelMap::setPeriod (float64_t p) {
	m_period = p;
}

float64_t CHomogeneousKernelMap::getPeriod () const {
	return m_period;
}

inline float64_t
CHomogeneousKernelMap::get_spectrum (float64_t omega) const {
  switch (m_kernel) {
    case HomogeneousKernelIntersection:
      return (2.0 / CMath::PI) / (1 + 4 * omega*omega);
    case HomogeneousKernelChi2:
      return 2.0 / (CMath::exp (CMath::PI * omega) + CMath::exp (-CMath::PI * omega)) ;
    case HomogeneousKernelJS:
      return (2.0 / CMath::log (4.0)) *
      2.0 / (CMath::exp (CMath::PI * omega) + CMath::exp (-CMath::PI * omega)) /
      (1 + 4 * omega*omega);
    default:
			/* throw exception */
			throw ShogunException ("CHomogeneousKernelMap::get_spectrum: no valid kernel has been set!");
  }
}

inline float64_t
CHomogeneousKernelMap::sinc (float64_t x) const {
  if (x == 0.0) return 1.0 ;
  return CMath::sin (x) / x;
}

inline float64_t
CHomogeneousKernelMap::get_smooth_spectrum (float64_t omega) const {
  float64_t kappa_hat = 0;
  float64_t omegap ;
  float64_t epsilon = 1e-2;
  float64_t const omegaRange = 2.0 / (m_period * epsilon);
  float64_t const domega = 2 * omegaRange / (2 * 1024.0 + 1);
  switch (m_window) {
    case HomogeneousKernelMapWindowUniform:
      kappa_hat = get_spectrum (omega);
      break;
    case HomogeneousKernelMapWindowRectangular:
      for (omegap = - omegaRange ; omegap <= omegaRange ; omegap += domega) {
        float64_t win = sinc ((m_period/2.0) * omegap);
        win *= (m_period/(2.0*CMath::PI));
        kappa_hat += win * get_spectrum (omegap + omega);
      }
      kappa_hat *= domega;
      /* project on the postivie orthant (see PAMI) */
      kappa_hat = CMath::max (kappa_hat, 0.0);
      break;
    default:
			/* throw exception */
			throw ShogunException ("CHomogeneousKernelMap::get_smooth_spectrum: no valid kernel has been set!");
  }
  return kappa_hat;
}

inline void CHomogeneousKernelMap::apply_to_vector (const SGVector<float64_t>& in_v,
																										SGVector<float64_t>& out_v) const
{
	/* assert for in and out vectors */
	ASSERT (in_v.vlen > 0 && out_v.vlen);
	ASSERT (in_v.vector != NULL && out_v.vector != NULL);

	uint64_t featureDimension = 2*m_order+1;

	for (int k = 0; k < in_v.vlen; ++k) {
	  /* break value into exponent and mantissa */
	  int exponent;
	  int unsigned j;
	  float64_t mantissa = frexp (in_v[k], &exponent);
	  float64_t sign = (mantissa >= 0.0) ? +1.0 : -1.0;
	  mantissa *= 2*sign;
	  exponent -- ;

	  if (mantissa == 0 ||
	      exponent <= m_minExponent ||
	      exponent >= m_maxExponent)
		{
	    for (j = 0 ; j <= m_order ; ++j) {
	      out_v[k*featureDimension+j] = 0.0;
//				*destination = (T) 0.0 ;
//	      destination += stride ;
	    }
	    continue;
	  }

	  //uint64_t featureDimension = 2*m_order+1;
    float64_t const * v1 = m_table.vector +
    	(exponent - m_minExponent) * m_numSubdivisions * featureDimension;
    float64_t const * v2;
    float64_t f1, f2;

    mantissa -= 1.0;
    while (mantissa >= m_subdivision) {
      mantissa -= m_subdivision;
      v1 += featureDimension;
    }

    v2 = v1 + featureDimension;
    for (j = 0 ; j < featureDimension ; ++j) {
      f1 = *v1++;
      f2 = *v2++;

			out_v[k*featureDimension+j] = sign * ((f2 - f1) * (m_numSubdivisions * mantissa) + f1);
//      *destination = sign * ((f2 - f1) * (m_numSubdivisions * mantissa) + f1) ;
//      destination += stride ;
    }
	}
}<commit_msg>Remove memory allocation check SG_MALLOC checks itself if the memory allocation was successful or not<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012 Viktor Gal
 * Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
 */

#include <shogun/io/SGIO.h>
#include <shogun/preprocessor/HomogeneousKernelMap.h>

#include <math.h>
#include <iostream>

using namespace shogun;

CHomogeneousKernelMap::CHomogeneousKernelMap ()
	: CSimplePreprocessor<float64_t> ()
{

}

CHomogeneousKernelMap::CHomogeneousKernelMap
	(HomogeneousKernelType kernel, HomogeneousKernelMapWindowType wType,
	 float64_t gamma, uint64_t order, float64_t period)
	: CSimplePreprocessor<float64_t> (),
		m_kernel (kernel),
		m_window (wType),
		m_gamma (gamma),
		m_period (period),
		m_order (order)

{
	init ();
}

CHomogeneousKernelMap::~CHomogeneousKernelMap() {
	m_table.destroy_vector ();
}

bool CHomogeneousKernelMap::init (CFeatures* features) {
	ASSERT(features->get_feature_class()==C_SIMPLE);
	ASSERT(features->get_feature_type()==F_DREAL);

	return true;
}

void CHomogeneousKernelMap::cleanup () {
	m_table.destroy_vector ();
}

void CHomogeneousKernelMap::init () {
	SG_DEBUG ("Initialising homogeneous kernel map...\n");
	ASSERT (m_gamma > 0) ;

  ASSERT (m_kernel == HomogeneousKernelIntersection ||
          m_kernel == HomogeneousKernelChi2 ||
          m_kernel == HomogeneousKernelJS);

  ASSERT (m_window == HomogeneousKernelMapWindowUniform ||
          m_window == HomogeneousKernelMapWindowRectangular);

	if (m_period < 0) {
	  switch (m_window) {
	  case HomogeneousKernelMapWindowUniform:
	    switch (m_kernel) {
		    case HomogeneousKernelChi2:
					m_period = 5.86 * CMath::sqrt (static_cast<float64_t> (m_order))  + 3.65;
					break;
		    case HomogeneousKernelJS:
		      m_period = 6.64 * CMath::sqrt (static_cast<float64_t> (m_order))  + 7.24;
					break;
		    case HomogeneousKernelIntersection:
					m_period = 2.38 * CMath::log (m_order + 0.8) + 5.6;
					break;
	    }
	    break;
	  case HomogeneousKernelMapWindowRectangular:
	    switch (m_kernel) {
		    case HomogeneousKernelChi2:
					m_period = 8.80 * CMath::sqrt (m_order + 4.44) - 12.6;
					break;
		    case HomogeneousKernelJS:
					m_period = 9.63 * CMath::sqrt (m_order + 1.00) - 2.93;
					break;
		    case HomogeneousKernelIntersection:
					m_period = 2.00 * CMath::log (m_order + 0.99) + 3.52;
					break;
	    }
	    break;
	  }
	  m_period = CMath::max (m_period, 1.0) ;
	}

  m_numSubdivisions = 8 + 8*m_order;
  m_subdivision = 1.0 / m_numSubdivisions;
  m_minExponent = -20;
  m_maxExponent = 8;

  int tableHeight = 2*m_order + 1 ;
  int tableWidth = m_numSubdivisions * (m_maxExponent - m_minExponent + 1);
	size_t numElements = (tableHeight * tableWidth + 2*(1+m_order));
	m_table = SGVector<float64_t> (NULL, numElements, true);
	m_table.vlen = numElements;
	m_table.vector = SG_CALLOC (float64_t, numElements);

	int exponent;
  uint64_t i = 0, j = 0;
  float64_t* tablep = m_table.vector;
  float64_t* kappa = m_table.vector + tableHeight * tableWidth;
  float64_t* freq = kappa + (1+m_order);
  float64_t L = 2.0 * CMath::PI / m_period;

  /* precompute the sampled periodicized spectrum */
  while (i <= m_order) {
    freq[i] = j;
    kappa[i] = get_smooth_spectrum (j * L);
    ++ j;
    if (kappa[i] > 0 || j >= 3*i) ++ i;
  }

  /* fill table */
  for (exponent  = m_minExponent ;
       exponent <= m_maxExponent ; ++ exponent) {

    float64_t x, Lxgamma, Llogx, xgamma;
    float64_t sqrt2kappaLxgamma;
    float64_t mantissa = 1.0;

    for (i = 0 ; i < m_numSubdivisions;
         ++i, mantissa += m_subdivision) {
      x = ldexp (mantissa, exponent);
      xgamma = CMath::pow (x, m_gamma);
      Lxgamma = L * xgamma;
      Llogx = L * CMath::log (x);

      *tablep++ = CMath::sqrt (Lxgamma * kappa[0]);
      for (j = 1 ; j <= m_order; ++j) {
        sqrt2kappaLxgamma = CMath::sqrt (2.0 * Lxgamma * kappa[j]);
        *tablep++ = sqrt2kappaLxgamma * CMath::cos (freq[j] * Llogx);
        *tablep++ = sqrt2kappaLxgamma * CMath::sin (freq[j] * Llogx);
      }
    } /* next mantissa */
  } /* next exponent */

	/* register variables */
	m_parameters->add ((machine_int_t*) &m_kernel, "kernel", "Kernel type to use.");
	m_parameters->add ((machine_int_t*) &m_window, "window", "Window type to use.");
	m_parameters->add (&m_gamma, "gamma", "Homogeneity order.");
	m_parameters->add (&m_period, "period", "Approximation order");
	m_parameters->add (&m_numSubdivisions, "numSubdivisions", "The number of sublevels");
	m_parameters->add (&m_subdivision, "subdivision", "subdivision.");
	m_parameters->add (&m_order, "order", "The order");
	m_parameters->add (&m_minExponent, "minExponent", "Minimum exponent");
	m_parameters->add (&m_maxExponent, "maxExponent", "Maximum exponent");
	m_parameters->add (&m_table, "table", "Lookup-table");
}

SGMatrix<float64_t> CHomogeneousKernelMap::apply_to_feature_matrix (CFeatures* features) {
	CSimpleFeatures<float64_t>* simple_features = (CSimpleFeatures<float64_t>*)features;
	int32_t num_vectors = simple_features->get_num_vectors ();
	int32_t num_features = simple_features->get_num_features ();
	SGMatrix<float64_t> result (num_features*(2*m_order+1), num_vectors);

	for (int i = 0; i < num_vectors; ++i) {
		SGVector<float64_t> v = simple_features->get_feature_vector (i);
		SGVector<float64_t> col (result.get_column_vector (i), result.num_rows);
		apply_to_vector (v, col);
	}

	return result;
}

/// apply preproc on single feature vector
SGVector<float64_t> CHomogeneousKernelMap::apply_to_feature_vector (SGVector<float64_t> vector) {
	uint64_t featureDimension = 2*m_order+1;
	uint64_t m_target_dim = vector.vlen * featureDimension;
	SGVector<float64_t> result = SGVector<float64_t> (m_target_dim);

	apply_to_vector (vector, result);

	return result;
}

void CHomogeneousKernelMap::setKernelType (HomogeneousKernelType k) {
	m_kernel = k;
}

HomogeneousKernelType CHomogeneousKernelMap::getKernelType () const {
	return m_kernel;
}

void CHomogeneousKernelMap::setWindowType (HomogeneousKernelMapWindowType w) {
	m_window = w;
}

HomogeneousKernelMapWindowType CHomogeneousKernelMap::getWindowType () const {
	return m_window;
}

void CHomogeneousKernelMap::setGamma (float64_t g) {
	m_gamma = g;
}

float64_t CHomogeneousKernelMap::getGamma (float64_t g) const {
	return m_gamma;
}

void CHomogeneousKernelMap::setOrder (uint64_t o) {
	m_order = o;
}

uint64_t CHomogeneousKernelMap::getOrder () const {
	return m_order;
}

void CHomogeneousKernelMap::setPeriod (float64_t p) {
	m_period = p;
}

float64_t CHomogeneousKernelMap::getPeriod () const {
	return m_period;
}

inline float64_t
CHomogeneousKernelMap::get_spectrum (float64_t omega) const {
  switch (m_kernel) {
    case HomogeneousKernelIntersection:
      return (2.0 / CMath::PI) / (1 + 4 * omega*omega);
    case HomogeneousKernelChi2:
      return 2.0 / (CMath::exp (CMath::PI * omega) + CMath::exp (-CMath::PI * omega)) ;
    case HomogeneousKernelJS:
      return (2.0 / CMath::log (4.0)) *
      2.0 / (CMath::exp (CMath::PI * omega) + CMath::exp (-CMath::PI * omega)) /
      (1 + 4 * omega*omega);
    default:
			/* throw exception */
			throw ShogunException ("CHomogeneousKernelMap::get_spectrum: no valid kernel has been set!");
  }
}

inline float64_t
CHomogeneousKernelMap::sinc (float64_t x) const {
  if (x == 0.0) return 1.0 ;
  return CMath::sin (x) / x;
}

inline float64_t
CHomogeneousKernelMap::get_smooth_spectrum (float64_t omega) const {
  float64_t kappa_hat = 0;
  float64_t omegap ;
  float64_t epsilon = 1e-2;
  float64_t const omegaRange = 2.0 / (m_period * epsilon);
  float64_t const domega = 2 * omegaRange / (2 * 1024.0 + 1);
  switch (m_window) {
    case HomogeneousKernelMapWindowUniform:
      kappa_hat = get_spectrum (omega);
      break;
    case HomogeneousKernelMapWindowRectangular:
      for (omegap = - omegaRange ; omegap <= omegaRange ; omegap += domega) {
        float64_t win = sinc ((m_period/2.0) * omegap);
        win *= (m_period/(2.0*CMath::PI));
        kappa_hat += win * get_spectrum (omegap + omega);
      }
      kappa_hat *= domega;
      /* project on the postivie orthant (see PAMI) */
      kappa_hat = CMath::max (kappa_hat, 0.0);
      break;
    default:
			/* throw exception */
			throw ShogunException ("CHomogeneousKernelMap::get_smooth_spectrum: no valid kernel has been set!");
  }
  return kappa_hat;
}

inline void CHomogeneousKernelMap::apply_to_vector (const SGVector<float64_t>& in_v,
																										SGVector<float64_t>& out_v) const
{
	/* assert for in and out vectors */
	ASSERT (in_v.vlen > 0 && out_v.vlen);
	ASSERT (in_v.vector != NULL && out_v.vector != NULL);

	uint64_t featureDimension = 2*m_order+1;

	for (int k = 0; k < in_v.vlen; ++k) {
	  /* break value into exponent and mantissa */
	  int exponent;
	  int unsigned j;
	  float64_t mantissa = frexp (in_v[k], &exponent);
	  float64_t sign = (mantissa >= 0.0) ? +1.0 : -1.0;
	  mantissa *= 2*sign;
	  exponent -- ;

	  if (mantissa == 0 ||
	      exponent <= m_minExponent ||
	      exponent >= m_maxExponent)
		{
	    for (j = 0 ; j <= m_order ; ++j) {
	      out_v[k*featureDimension+j] = 0.0;
//				*destination = (T) 0.0 ;
//	      destination += stride ;
	    }
	    continue;
	  }

	  //uint64_t featureDimension = 2*m_order+1;
    float64_t const * v1 = m_table.vector +
    	(exponent - m_minExponent) * m_numSubdivisions * featureDimension;
    float64_t const * v2;
    float64_t f1, f2;

    mantissa -= 1.0;
    while (mantissa >= m_subdivision) {
      mantissa -= m_subdivision;
      v1 += featureDimension;
    }

    v2 = v1 + featureDimension;
    for (j = 0 ; j < featureDimension ; ++j) {
      f1 = *v1++;
      f2 = *v2++;

			out_v[k*featureDimension+j] = sign * ((f2 - f1) * (m_numSubdivisions * mantissa) + f1);
//      *destination = sign * ((f2 - f1) * (m_numSubdivisions * mantissa) + f1) ;
//      destination += stride ;
    }
	}
}<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012-2013 Heiko Strathmann
 */

#include <shogun/statistics/MMDKernelSelectionComb.h>
#include <shogun/statistics/KernelTwoSampleTestStatistic.h>
#include <shogun/kernel/CombinedKernel.h>

using namespace shogun;

CMMDKernelSelectionComb::CMMDKernelSelectionComb() :
		CMMDKernelSelection()
{
	init();
}

CMMDKernelSelectionComb::CMMDKernelSelectionComb(
		CKernelTwoSampleTestStatistic* mmd) : CMMDKernelSelection(mmd)
{
	init();
}

CMMDKernelSelectionComb::~CMMDKernelSelectionComb()
{
}

void CMMDKernelSelectionComb::init()
{
#ifdef HAVE_LAPACK
	SG_ADD(&m_opt_max_iterations, "opt_max_iterations", "Maximum number of "
			"iterations for qp solver", MS_NOT_AVAILABLE);
	SG_ADD(&m_opt_epsilon, "opt_epsilon", "Stopping criterion for qp solver",
			MS_NOT_AVAILABLE);
	SG_ADD(&m_opt_low_cut, "opt_low_cut", "Low cut value for optimization "
			"kernel weights", MS_NOT_AVAILABLE);

	/* sensible values for optimization */
	m_opt_max_iterations=10000;
	m_opt_epsilon=10E-15;
	m_opt_low_cut=10E-7;
#endif
}

#ifdef HAVE_LAPACK
/* no reference counting, use the static context constructor of SGMatrix */
SGMatrix<float64_t> CMMDKernelSelectionComb::m_Q=SGMatrix<float64_t>(false);

const float64_t* CMMDKernelSelectionComb::get_Q_col(uint32_t i)
{
	return &m_Q[m_Q.num_rows*i];
}

/** helper function that prints current state */
void CMMDKernelSelectionComb::print_state(libqp_state_T state)
{
	SG_SDEBUG("CMMDKernelSelectionComb::print_state: libqp state:"
			" primal=%f\n", state.QP);
}

CKernel* CMMDKernelSelectionComb::select_kernel()
{
	/* cast is safe due to assertion in constructor */
	CCombinedKernel* combined=(CCombinedKernel*)m_mmd->get_kernel();

	/* optimise for kernel weights and set them */
	SGVector<float64_t> weights=compute_measures();
	combined->set_subkernel_weights(weights);

	/* note that kernel is SG_REF'ed from getter above */
	return combined;
}

SGVector<float64_t> CMMDKernelSelectionComb::solve_optimization(
		SGVector<float64_t> mmds)
{
	/* readability */
	index_t num_kernels=mmds.vlen;

	/* compute sum of mmds to generate feasible point for convex program */
	float64_t sum_mmds=0;
	for (index_t i=0; i<mmds.vlen; ++i)
		sum_mmds+=mmds[i];

	/* QP: 0.5*x'*Q*x + f'*x
	 * subject to
	 * mmds'*x = b
	 * LB[i] <= x[i] <= UB[i]   for all i=1..n */
	SGVector<float64_t> Q_diag(num_kernels);
	SGVector<float64_t> f(num_kernels);
	SGVector<float64_t> lb(num_kernels);
	SGVector<float64_t> ub(num_kernels);
	SGVector<float64_t> weights(num_kernels);

	/* init everything, there are two cases possible: i) at least one mmd is
	 * is positive, ii) all mmds are negative */
	bool one_pos;
	for (index_t i=0; i<mmds.vlen; ++i)
	{
		if (mmds[i]>0)
		{
			SG_DEBUG("found at least one positive MMD\n")
			one_pos=true;
			break;
		}
		one_pos=false;
	}

	if (!one_pos)
	{
		SG_WARNING("%CMMDKernelSelectionComb::solve_optimization(): all mmd "
				"estimates are negative. This is techically possible, although "
				"extremely rare. Consider using different kernels. "
				"This combination will lead to a bad two-sample test. Since any"
				"combination is bad, will now just return equally distributed "
				"kernel weights\n");

		/* if no element is positive, we can choose arbritary weights since
		 * the results will be bad anyway */
		weights.set_const(1.0/num_kernels);
	}
	else
	{
		SG_DEBUG("one MMD entry is positive, performing optimisation\n")
		/* do optimisation, init vectors */
		for (index_t i=0; i<num_kernels; ++i)
		{
			Q_diag[i]=m_Q(i,i);
			f[i]=0;
			lb[i]=0;
			ub[i]=CMath::INFTY;

			/* initial point has to be feasible, i.e. mmds'*x = b */
			weights[i]=1.0/sum_mmds;
		}

		/* start libqp solver with desired parameters */
		SG_DEBUG("starting libqp optimization\n")
		libqp_state_T qp_exitflag=libqp_gsmo_solver(&get_Q_col, Q_diag.vector,
				f.vector, mmds.vector,
				one_pos ? 1 : -1,
				lb.vector, ub.vector,
				weights.vector, num_kernels, m_opt_max_iterations,
				m_opt_epsilon, &(CMMDKernelSelectionComb::print_state));

		SG_DEBUG("libqp returns: nIts=%d, exit_flag: %d\n", qp_exitflag.nIter,
				qp_exitflag.exitflag);

		/* set really small entries to zero and sum up for normalization */
		float64_t sum_weights=0;
		for (index_t i=0; i<weights.vlen; ++i)
		{
			if (weights[i]<m_opt_low_cut)
			{
				SG_DEBUG("lowcut: weight[%i]=%f<%f setting to zero\n", i, weights[i],
						m_opt_low_cut);
				weights[i]=0;
			}

			sum_weights+=weights[i];
		}

		/* normalize (allowed since problem is scale invariant) */
		for (index_t i=0; i<weights.vlen; ++i)
			weights[i]/=sum_weights;
	}

	return weights;
}
#else
CKernel* CMMDKernelSelectionComb::select_kernel()
{
	SG_ERROR("CMMDKernelSelectionComb::select_kernel(): LAPACK needs to be "
			"installed in order to use weight optimisation for combined "
			"kernels!\n");
	return NULL;
}

SGVector<float64_t> CMMDKernelSelectionComb::compute_measures()
{
	SG_ERROR("CMMDKernelSelectionComb::select_kernel(): LAPACK needs to be "
			"installed in order to use weight optimisation for combined "
			"kernels!\n");
	return SGVector<float64_t>();
}

SGVector<float64_t> CMMDKernelSelectionComb::solve_optimization(
		SGVector<float64_t> mmds)
{
	SG_ERROR("CMMDKernelSelectionComb::solve_optimization(): LAPACK needs to be "
			"installed in order to use weight optimisation for combined "
			"kernels!\n");
	return SGVector<float64_t>();
}
#endif
<commit_msg>fix typo in warning msg<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2012-2013 Heiko Strathmann
 */

#include <shogun/statistics/MMDKernelSelectionComb.h>
#include <shogun/statistics/KernelTwoSampleTestStatistic.h>
#include <shogun/kernel/CombinedKernel.h>

using namespace shogun;

CMMDKernelSelectionComb::CMMDKernelSelectionComb() :
		CMMDKernelSelection()
{
	init();
}

CMMDKernelSelectionComb::CMMDKernelSelectionComb(
		CKernelTwoSampleTestStatistic* mmd) : CMMDKernelSelection(mmd)
{
	init();
}

CMMDKernelSelectionComb::~CMMDKernelSelectionComb()
{
}

void CMMDKernelSelectionComb::init()
{
#ifdef HAVE_LAPACK
	SG_ADD(&m_opt_max_iterations, "opt_max_iterations", "Maximum number of "
			"iterations for qp solver", MS_NOT_AVAILABLE);
	SG_ADD(&m_opt_epsilon, "opt_epsilon", "Stopping criterion for qp solver",
			MS_NOT_AVAILABLE);
	SG_ADD(&m_opt_low_cut, "opt_low_cut", "Low cut value for optimization "
			"kernel weights", MS_NOT_AVAILABLE);

	/* sensible values for optimization */
	m_opt_max_iterations=10000;
	m_opt_epsilon=10E-15;
	m_opt_low_cut=10E-7;
#endif
}

#ifdef HAVE_LAPACK
/* no reference counting, use the static context constructor of SGMatrix */
SGMatrix<float64_t> CMMDKernelSelectionComb::m_Q=SGMatrix<float64_t>(false);

const float64_t* CMMDKernelSelectionComb::get_Q_col(uint32_t i)
{
	return &m_Q[m_Q.num_rows*i];
}

/** helper function that prints current state */
void CMMDKernelSelectionComb::print_state(libqp_state_T state)
{
	SG_SDEBUG("CMMDKernelSelectionComb::print_state: libqp state:"
			" primal=%f\n", state.QP);
}

CKernel* CMMDKernelSelectionComb::select_kernel()
{
	/* cast is safe due to assertion in constructor */
	CCombinedKernel* combined=(CCombinedKernel*)m_mmd->get_kernel();

	/* optimise for kernel weights and set them */
	SGVector<float64_t> weights=compute_measures();
	combined->set_subkernel_weights(weights);

	/* note that kernel is SG_REF'ed from getter above */
	return combined;
}

SGVector<float64_t> CMMDKernelSelectionComb::solve_optimization(
		SGVector<float64_t> mmds)
{
	/* readability */
	index_t num_kernels=mmds.vlen;

	/* compute sum of mmds to generate feasible point for convex program */
	float64_t sum_mmds=0;
	for (index_t i=0; i<mmds.vlen; ++i)
		sum_mmds+=mmds[i];

	/* QP: 0.5*x'*Q*x + f'*x
	 * subject to
	 * mmds'*x = b
	 * LB[i] <= x[i] <= UB[i]   for all i=1..n */
	SGVector<float64_t> Q_diag(num_kernels);
	SGVector<float64_t> f(num_kernels);
	SGVector<float64_t> lb(num_kernels);
	SGVector<float64_t> ub(num_kernels);
	SGVector<float64_t> weights(num_kernels);

	/* init everything, there are two cases possible: i) at least one mmd is
	 * is positive, ii) all mmds are negative */
	bool one_pos;
	for (index_t i=0; i<mmds.vlen; ++i)
	{
		if (mmds[i]>0)
		{
			SG_DEBUG("found at least one positive MMD\n")
			one_pos=true;
			break;
		}
		one_pos=false;
	}

	if (!one_pos)
	{
		SG_WARNING("CMMDKernelSelectionComb::solve_optimization(): all mmd "
				"estimates are negative. This is techically possible, although "
				"extremely rare. Consider using different kernels. "
				"This combination will lead to a bad two-sample test. Since any"
				"combination is bad, will now just return equally distributed "
				"kernel weights\n");

		/* if no element is positive, we can choose arbritary weights since
		 * the results will be bad anyway */
		weights.set_const(1.0/num_kernels);
	}
	else
	{
		SG_DEBUG("one MMD entry is positive, performing optimisation\n")
		/* do optimisation, init vectors */
		for (index_t i=0; i<num_kernels; ++i)
		{
			Q_diag[i]=m_Q(i,i);
			f[i]=0;
			lb[i]=0;
			ub[i]=CMath::INFTY;

			/* initial point has to be feasible, i.e. mmds'*x = b */
			weights[i]=1.0/sum_mmds;
		}

		/* start libqp solver with desired parameters */
		SG_DEBUG("starting libqp optimization\n")
		libqp_state_T qp_exitflag=libqp_gsmo_solver(&get_Q_col, Q_diag.vector,
				f.vector, mmds.vector,
				one_pos ? 1 : -1,
				lb.vector, ub.vector,
				weights.vector, num_kernels, m_opt_max_iterations,
				m_opt_epsilon, &(CMMDKernelSelectionComb::print_state));

		SG_DEBUG("libqp returns: nIts=%d, exit_flag: %d\n", qp_exitflag.nIter,
				qp_exitflag.exitflag);

		/* set really small entries to zero and sum up for normalization */
		float64_t sum_weights=0;
		for (index_t i=0; i<weights.vlen; ++i)
		{
			if (weights[i]<m_opt_low_cut)
			{
				SG_DEBUG("lowcut: weight[%i]=%f<%f setting to zero\n", i, weights[i],
						m_opt_low_cut);
				weights[i]=0;
			}

			sum_weights+=weights[i];
		}

		/* normalize (allowed since problem is scale invariant) */
		for (index_t i=0; i<weights.vlen; ++i)
			weights[i]/=sum_weights;
	}

	return weights;
}
#else
CKernel* CMMDKernelSelectionComb::select_kernel()
{
	SG_ERROR("CMMDKernelSelectionComb::select_kernel(): LAPACK needs to be "
			"installed in order to use weight optimisation for combined "
			"kernels!\n");
	return NULL;
}

SGVector<float64_t> CMMDKernelSelectionComb::compute_measures()
{
	SG_ERROR("CMMDKernelSelectionComb::select_kernel(): LAPACK needs to be "
			"installed in order to use weight optimisation for combined "
			"kernels!\n");
	return SGVector<float64_t>();
}

SGVector<float64_t> CMMDKernelSelectionComb::solve_optimization(
		SGVector<float64_t> mmds)
{
	SG_ERROR("CMMDKernelSelectionComb::solve_optimization(): LAPACK needs to be "
			"installed in order to use weight optimisation for combined "
			"kernels!\n");
	return SGVector<float64_t>();
}
#endif
<|endoftext|>


<commit_before>
#include "msg_types.h"

#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>

bool entity_addr_t::parse(const char *s, const char **end)
{
  memset(this, 0, sizeof(*this));

  const char *p = s;
  bool braces = false;
  bool ipv6 = false;
  if (*p == '{') {
    p++;
    braces = true;
    ipv6 = true;
  }

  char buf[32];
  char *o = buf;

  while (o < buf + sizeof(buf) &&
	 *p && ((*p == '.') ||
		(ipv6 && *p == ':') ||
		(*p >= '0' && *p <= '9') ||
		(*p >= 'a' && *p <= 'f') ||
		(*p >= 'A' && *p <= 'F'))) {
    if (*p == ':')
      ipv6 = true;
    *o++ = *p++;
  }
  *o = 0;
  //cout << "buf is '" << buf << "'" << std::endl;

  // ipv4?
  struct in_addr a4;
  struct in6_addr a6;
  if (inet_pton(AF_INET, buf, &a4)) {
    addr4.sin_addr.s_addr = a4.s_addr;
    addr.ss_family = AF_INET;
  } else if (inet_pton(AF_INET6, buf, &a6)) {
    addr.ss_family = AF_INET6;
    memcpy(&addr6.sin6_addr, &a6, sizeof(a6));
  } else {
    //cout << "couldn't parse '" << buf << "'" << std::endl;
  }

  if (braces) {
    if (*p != '}')
      return false;
    p++;
  }

  //cout << "p is " << *p << std::endl;
  if (*p == ':') {
    // parse a port, too!
    p++;
    int port = atoi(p);
    set_port(port);
    while (*p && *p >= '0' && *p <= '9')
      p++;
  }

  if (end)
    *end = p;
  return true;
}
<commit_msg>msg: fix entity_addr_t::parse() to return false on failure<commit_after>
#include "msg_types.h"

#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>

bool entity_addr_t::parse(const char *s, const char **end)
{
  memset(this, 0, sizeof(*this));

  const char *p = s;
  bool braces = false;
  bool ipv6 = false;
  if (*p == '{') {
    p++;
    braces = true;
    ipv6 = true;
  }

  char buf[32];
  char *o = buf;

  while (o < buf + sizeof(buf) &&
	 *p && ((*p == '.') ||
		(ipv6 && *p == ':') ||
		(*p >= '0' && *p <= '9') ||
		(*p >= 'a' && *p <= 'f') ||
		(*p >= 'A' && *p <= 'F'))) {
    if (*p == ':')
      ipv6 = true;
    *o++ = *p++;
  }
  *o = 0;
  //cout << "buf is '" << buf << "'" << std::endl;

  // ipv4?
  struct in_addr a4;
  struct in6_addr a6;
  if (inet_pton(AF_INET, buf, &a4)) {
    addr4.sin_addr.s_addr = a4.s_addr;
    addr.ss_family = AF_INET;
  } else if (inet_pton(AF_INET6, buf, &a6)) {
    addr.ss_family = AF_INET6;
    memcpy(&addr6.sin6_addr, &a6, sizeof(a6));
  } else {
    //cout << "couldn't parse '" << buf << "'" << std::endl;
    return false;
  }

  if (braces) {
    if (*p != '}')
      return false;
    p++;
  }

  //cout << "p is " << *p << std::endl;
  if (*p == ':') {
    // parse a port, too!
    p++;
    int port = atoi(p);
    set_port(port);
    while (*p && *p >= '0' && *p <= '9')
      p++;
  }

  if (end)
    *end = p;
  return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Max Kellermann <max@duempel.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BIND_METHOD_HXX
#define BIND_METHOD_HXX

#include <type_traits>
#include <utility>

/**
 * This object stores a function pointer wrapping a method, and a
 * reference to an instance of the method's class.  It can be used to
 * wrap instance methods as callback functions.
 *
 * @param S the plain function signature type
 */
template<typename S=void()>
class BoundMethod;

template<typename R, typename... Args>
class BoundMethod<R(Args...)> {
	typedef R (*function_pointer)(void *instance, Args... args);

	void *instance;
	function_pointer function;

public:
	/**
	 * Non-initializing trivial constructor
	 */
	BoundMethod() = default;

	constexpr
	BoundMethod(void *_instance, function_pointer _function)
		:instance(_instance), function(_function) {}

	/**
	 * Construct an "undefined" object.  It must not be called,
	 * and its "bool" operator returns false.
	 */
	BoundMethod(std::nullptr_t):function(nullptr) {}

	/**
	 * Was this object initialized with a valid function pointer?
	 */
	operator bool() const {
		return function != nullptr;
	}

	R operator()(Args... args) const {
		return function(instance, std::forward<Args>(args)...);
	}
};

namespace BindMethodDetail {

/**
 * Helper class which converts a signature type to a method pointer
 * type.
 *
 * @param T the wrapped class
 * @param S the function signature type (plain, without instance
 * pointer)
 */
template<typename T, typename S>
struct MethodWithSignature;

template<typename T, typename R, typename... Args>
struct MethodWithSignature<T, R(Args...)> {
	typedef R (T::*method_pointer)(Args...);
};

/**
 * Helper class which introspects a method pointer type.
 *
 * @param M the method pointer type
 */
template<typename M>
struct MethodSignatureHelper;

template<typename R, typename T, typename... Args>
struct MethodSignatureHelper<R (T::*)(Args...)> {
	/**
	 * The class which contains the given method (signature).
	 */
	typedef T class_type;

	/**
	 * A function type which describes the "plain" function
	 * signature.
	 */
	typedef R plain_signature(Args...);
};

/**
 * Helper class which converts a plain function signature type to a
 * wrapper function pointer type.
 */
template<typename S>
struct MethodWrapperWithSignature;

template<typename R, typename... Args>
struct MethodWrapperWithSignature<R(Args...)> {
	typedef R (*function_pointer)(void *instance, Args...);
};

/**
 * Generate a wrapper function.  Helper class for
 * #BindMethodWrapperGenerator.
 *
 * @param T the containing class
 * @param M the method pointer type
 * @param method the method pointer
 * @param R the return type
 * @param Args the method arguments
 */
template<typename T, typename M, M method, typename R, typename... Args>
struct BindMethodWrapperGenerator2 {
	static R Invoke(void *instance, Args... args) {
		auto &t = *(T *)instance;
		return (t.*method)(std::forward<Args>(args)...);
	}
};

/**
 * Generate a wrapper function.
 *
 * @param T the containing class
 * @param M the method pointer type
 * @param method the method pointer
 * @param S the plain function signature type
 */
template<typename T, typename M, M method, typename S>
struct BindMethodWrapperGenerator;

template<typename T, typename M, M method, typename R, typename... Args>
struct BindMethodWrapperGenerator<T, M, method, R(Args...)>
	: BindMethodWrapperGenerator2<T, M, method, R, Args...> {
};

template<typename T, typename S,
	 typename MethodWithSignature<T, S>::method_pointer method>
typename MethodWrapperWithSignature<S>::function_pointer
MakeBindMethodWrapper()
{
	return BindMethodWrapperGenerator<T, typename MethodWithSignature<T, S>::method_pointer, method, S>::Invoke;
}

} /* namespace BindMethodDetail */

/**
 * Construct a #BoundMethod instance.
 *
 * @param T the containing class
 * @param S the plain function signature type
 * @param method the method pointer
 * @param instance the instance of #T to be bound
 */
template<typename T, typename S,
	 typename BindMethodDetail::MethodWithSignature<T, S>::method_pointer method>
constexpr BoundMethod<S>
BindMethod(T &instance)
{
	return BoundMethod<S>(&instance,
			      BindMethodDetail::MakeBindMethodWrapper<T, S, method>());
}

/**
 * Shortcut macro which takes an instance and a method pointer and
 * constructs a #BoundMethod instance.
 */
#define BIND_METHOD(instance, method) \
	BindMethod<typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::class_type, \
		   typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::plain_signature, \
		   method>(instance)

/**
 * Shortcut wrapper for BIND_METHOD() which assumes "*this" is the
 * instance to be bound.
 */
#define BIND_THIS_METHOD(method) BIND_METHOD(*this, &std::remove_reference<decltype(*this)>::type::method)

#endif
<commit_msg>util/BindMethod: rename "instance" to "instance_" to avoid shadowing<commit_after>/*
 * Copyright (C) 2016 Max Kellermann <max@duempel.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BIND_METHOD_HXX
#define BIND_METHOD_HXX

#include <type_traits>
#include <utility>

/**
 * This object stores a function pointer wrapping a method, and a
 * reference to an instance of the method's class.  It can be used to
 * wrap instance methods as callback functions.
 *
 * @param S the plain function signature type
 */
template<typename S=void()>
class BoundMethod;

template<typename R, typename... Args>
class BoundMethod<R(Args...)> {
	typedef R (*function_pointer)(void *instance, Args... args);

	void *instance_;
	function_pointer function;

public:
	/**
	 * Non-initializing trivial constructor
	 */
	BoundMethod() = default;

	constexpr
	BoundMethod(void *_instance, function_pointer _function)
		:instance_(_instance), function(_function) {}

	/**
	 * Construct an "undefined" object.  It must not be called,
	 * and its "bool" operator returns false.
	 */
	BoundMethod(std::nullptr_t):function(nullptr) {}

	/**
	 * Was this object initialized with a valid function pointer?
	 */
	operator bool() const {
		return function != nullptr;
	}

	R operator()(Args... args) const {
		return function(instance_, std::forward<Args>(args)...);
	}
};

namespace BindMethodDetail {

/**
 * Helper class which converts a signature type to a method pointer
 * type.
 *
 * @param T the wrapped class
 * @param S the function signature type (plain, without instance
 * pointer)
 */
template<typename T, typename S>
struct MethodWithSignature;

template<typename T, typename R, typename... Args>
struct MethodWithSignature<T, R(Args...)> {
	typedef R (T::*method_pointer)(Args...);
};

/**
 * Helper class which introspects a method pointer type.
 *
 * @param M the method pointer type
 */
template<typename M>
struct MethodSignatureHelper;

template<typename R, typename T, typename... Args>
struct MethodSignatureHelper<R (T::*)(Args...)> {
	/**
	 * The class which contains the given method (signature).
	 */
	typedef T class_type;

	/**
	 * A function type which describes the "plain" function
	 * signature.
	 */
	typedef R plain_signature(Args...);
};

/**
 * Helper class which converts a plain function signature type to a
 * wrapper function pointer type.
 */
template<typename S>
struct MethodWrapperWithSignature;

template<typename R, typename... Args>
struct MethodWrapperWithSignature<R(Args...)> {
	typedef R (*function_pointer)(void *instance, Args...);
};

/**
 * Generate a wrapper function.  Helper class for
 * #BindMethodWrapperGenerator.
 *
 * @param T the containing class
 * @param M the method pointer type
 * @param method the method pointer
 * @param R the return type
 * @param Args the method arguments
 */
template<typename T, typename M, M method, typename R, typename... Args>
struct BindMethodWrapperGenerator2 {
	static R Invoke(void *_instance, Args... args) {
		auto &t = *(T *)_instance;
		return (t.*method)(std::forward<Args>(args)...);
	}
};

/**
 * Generate a wrapper function.
 *
 * @param T the containing class
 * @param M the method pointer type
 * @param method the method pointer
 * @param S the plain function signature type
 */
template<typename T, typename M, M method, typename S>
struct BindMethodWrapperGenerator;

template<typename T, typename M, M method, typename R, typename... Args>
struct BindMethodWrapperGenerator<T, M, method, R(Args...)>
	: BindMethodWrapperGenerator2<T, M, method, R, Args...> {
};

template<typename T, typename S,
	 typename MethodWithSignature<T, S>::method_pointer method>
typename MethodWrapperWithSignature<S>::function_pointer
MakeBindMethodWrapper()
{
	return BindMethodWrapperGenerator<T, typename MethodWithSignature<T, S>::method_pointer, method, S>::Invoke;
}

} /* namespace BindMethodDetail */

/**
 * Construct a #BoundMethod instance.
 *
 * @param T the containing class
 * @param S the plain function signature type
 * @param method the method pointer
 * @param instance the instance of #T to be bound
 */
template<typename T, typename S,
	 typename BindMethodDetail::MethodWithSignature<T, S>::method_pointer method>
constexpr BoundMethod<S>
BindMethod(T &_instance)
{
	return BoundMethod<S>(&_instance,
			      BindMethodDetail::MakeBindMethodWrapper<T, S, method>());
}

/**
 * Shortcut macro which takes an instance and a method pointer and
 * constructs a #BoundMethod instance.
 */
#define BIND_METHOD(instance, method) \
	BindMethod<typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::class_type, \
		   typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::plain_signature, \
		   method>(instance)

/**
 * Shortcut wrapper for BIND_METHOD() which assumes "*this" is the
 * instance to be bound.
 */
#define BIND_THIS_METHOD(method) BIND_METHOD(*this, &std::remove_reference<decltype(*this)>::type::method)

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef WIN32
# include <cstdio>
# include <cstring>
#else
# include <windows.h>
# include <strsafe.h>
#endif /* WIN32 */

#include "error_util.h"
#include "stl_util.h"

namespace zorba {
namespace error {

using namespace std;

///////////////////////////////////////////////////////////////////////////////

zstring get_os_err_string( char const *what, os_code code ) {
#ifndef WIN32
  char err[ 512 ];
  if ( what ) {
    snprintf(
      err, sizeof( err ), "%s failed (error %d): %s",
      what, code, ::strerror( code )
    );
  } else {
    snprintf(
      err, sizeof( err ), "error %d: %s",
      code, ::strerror( code )
    );
  }
  return zstring( err );
#else
  LPWSTR wmsg;
  FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER
    | FORMAT_MESSAGE_FROM_SYSTEM
    | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL, code, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
    reinterpret_cast<LPWSTR>( &wmsg ), 0, NULL
  );
  int const werr_size = ::wcslen( wmsg ) + 40;
  ztd::auto_vec<WCHAR> const werr( new WCHAR[ werr_size ] );
  if ( what ) {
    StringCchPrintf(
      werr.get(), werr_size, L"%hs failed (error %d): %ls",
      what, code, wmsg
    );
  } else {
    StringCchPrintf(
      werr.get(), werr_size, L"error %d: %ls", code, wmsg
    );
  }
  LocalFree( wmsg );

  int const err_size = ::wcslen( werr.get() ) * 2;
  ztd::auto_vec<char> const err( new char[ err_size ] );
  WideCharToMultiByte(
    CP_UTF8, 0, werr.get(), -1, err.get(), err_size, NULL, NULL
  );
  return zstring( err.get() );
#endif /* WIN32 */
}

///////////////////////////////////////////////////////////////////////////////

} // namespace error
} // namespace zorba

/*
 * Local variables:
 * mode: c++
 * End:
 */
/* vim:set et sw=2 ts=2: */
<commit_msg>Added && *what for empty strings.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef WIN32
# include <cstdio>
# include <cstring>
#else
# include <windows.h>
# include <strsafe.h>
#endif /* WIN32 */

#include "error_util.h"
#include "stl_util.h"

namespace zorba {
namespace error {

using namespace std;

///////////////////////////////////////////////////////////////////////////////

zstring get_os_err_string( char const *what, os_code code ) {
#ifndef WIN32
  char err[ 512 ];
  if ( what && *what ) {
    snprintf(
      err, sizeof( err ), "%s failed (error %d): %s",
      what, code, ::strerror( code )
    );
  } else {
    snprintf(
      err, sizeof( err ), "error %d: %s",
      code, ::strerror( code )
    );
  }
  return zstring( err );
#else
  LPWSTR wmsg;
  FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER
    | FORMAT_MESSAGE_FROM_SYSTEM
    | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL, code, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
    reinterpret_cast<LPWSTR>( &wmsg ), 0, NULL
  );
  int const werr_size = ::wcslen( wmsg ) + 40;
  ztd::auto_vec<WCHAR> const werr( new WCHAR[ werr_size ] );
  if ( what && *what ) {
    StringCchPrintf(
      werr.get(), werr_size, L"%hs failed (error %d): %ls",
      what, code, wmsg
    );
  } else {
    StringCchPrintf(
      werr.get(), werr_size, L"error %d: %ls", code, wmsg
    );
  }
  LocalFree( wmsg );

  int const err_size = ::wcslen( werr.get() ) * 2;
  ztd::auto_vec<char> const err( new char[ err_size ] );
  WideCharToMultiByte(
    CP_UTF8, 0, werr.get(), -1, err.get(), err_size, NULL, NULL
  );
  return zstring( err.get() );
#endif /* WIN32 */
}

///////////////////////////////////////////////////////////////////////////////

} // namespace error
} // namespace zorba

/*
 * Local variables:
 * mode: c++
 * End:
 */
/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>#include "common.th"

    .global main
main:
    prologue

#define DATA_LEN (.L_data_end - .L_data_start)
#define ELT_LEN  (.L_data_elt_end - .L_data_elt_start)

    c <- rel(data_start)        // data to sort
    d <- (DATA_LEN / ELT_LEN)   // number of elements
    e <- ELT_LEN                // size of each element
    f <- rel(inteq)             // comparator
    call(qsort)

done:
    i <- .L_data_start
print_loop:
    c <- [i - (. + 0) + p]      // get second field of struct
    c <-  c - (. + 1) + p       // and relocate it
    call(puts)
    c <- rel(nl)
    call(puts)
    i <- i + ELT_LEN
    c <- i < .L_data_end
    jnzrel(c,print_loop)

    illegal

#define elem(Dest, Base, Index) \
    Dest <- Index * E         ; \
    Dest <- Dest + Base       ; \
    //

#define swap(i0, i1)            \
    pushall(c,d,e,f,g)        ; \
    f <- c                    ; \
    g <- e                    ; \
    o <- o - e - 1            ; \
    c <- o + 1                ; \
    elem(d,f,i0)              ; \
    /* E is already width */  ; \
    call(memcpy)              ; \
    elem(c,f,i0)              ; \
    elem(d,f,i1)              ; \
    e <- g                    ; \
    call(memcpy)              ; \
    elem(c,f,i1)              ; \
    d <- o + 1                ; \
    e <- g                    ; \
    call(memcpy)              ; \
    o <- o + g + 1            ; \
    popall(c,d,e,f,g)         ; \
    //

// c <- base
// d <- number of elements
// e <- size of element
// f <- comparator
    .global qsort
qsort:
    pushall(h)
    h <- d < 2                  // test for base case
    jnzrel(h,qsort_done)
    h <- d >> 1                 // H is partition index
    i <- d - 1                  // I is last index
    // partitioning
    swap(h,i)
    j <- 0                      // J is store index

    swap(j,i)
qsort_done:
    popall(h)
    ret

// c <- pointer to key
// d <- pointer to element
// b -> < 0, 0, > 0
inteq:
    c <- [c]
    d <- [d]
    b <- c - d
    ret

data_start:
.L_data_start:
.L_data_elt_start:
    .word     21, @L_21
.L_data_elt_end:
    .word     34, @L_34
    .word     55, @L_55
    .word    144, @L_144
    .word      1, @L_1
    .word      2, @L_2
    .word     89, @L_89
    .word      3, @L_3
    .word      5, @L_5
    .word      8, @L_8
    .word     13, @L_13
.L_data_end:
    .word 0

L_1  : .utf32 "one"                    ; .word 0
L_2  : .utf32 "two"                    ; .word 0
L_3  : .utf32 "three"                  ; .word 0
L_5  : .utf32 "five"                   ; .word 0
L_8  : .utf32 "eight"                  ; .word 0
L_13 : .utf32 "thirteen"               ; .word 0
L_21 : .utf32 "twenty-one"             ; .word 0
L_34 : .utf32 "thirty-four"            ; .word 0
L_55 : .utf32 "fifty-five"             ; .word 0
L_89 : .utf32 "eighty-nine"            ; .word 0
L_144: .utf32 "one hundred forty-four" ; .word 0

nl: .word '\n', 0

<commit_msg>Partitioning done in qsort<commit_after>#include "common.th"

    .global main
main:
    prologue

#define DATA_LEN (.L_data_end - .L_data_start)
#define ELT_LEN  (.L_data_elt_end - .L_data_elt_start)

    c <- rel(data_start)        // data to sort
    d <- (DATA_LEN / ELT_LEN)   // number of elements
    e <- ELT_LEN                // size of each element
    f <- rel(inteq)             // comparator
    call(qsort)

done:
    i <- .L_data_start
print_loop:
    c <- [i - (. + 0) + p]      // get second field of struct
    c <-  c - (. + 1) + p       // and relocate it
    call(puts)
    c <- rel(nl)
    call(puts)
    i <- i + ELT_LEN
    c <- i < .L_data_end
    jnzrel(c,print_loop)

    illegal

#define elem(Dest, Base, Index) \
    Dest <- Index * E         ; \
    Dest <- Dest + Base       ; \
    //

#define swap(i0, i1)            \
    pushall(c,d,e,f,g)        ; \
    f <- c                    ; \
    g <- e                    ; \
    o <- o - e - 1            ; \
    c <- o + 1                ; \
    elem(d,f,i0)              ; \
    /* E is already width */  ; \
    call(memcpy)              ; \
    elem(c,f,i0)              ; \
    elem(d,f,i1)              ; \
    e <- g                    ; \
    call(memcpy)              ; \
    elem(c,f,i1)              ; \
    d <- o + 1                ; \
    e <- g                    ; \
    call(memcpy)              ; \
    o <- o + g + 1            ; \
    popall(c,d,e,f,g)         ; \
    //

// c <- base
// d <- number of elements
// e <- size of element
// f <- comparator
    .global qsort
qsort:
    pushall(h,i,j,k,l,m)
    h <- d < 2                  // test for base case
    jnzrel(h,L_qsort_done)
    h <- d >> 1                 // H is partition index
    i <- d - 1                  // I is last index
    // partitioning
    swap(h,i)
    m <- 0                      // M is store index
    j <- 0                      // J is i index

L_qsort_partition:
    elem(k, c, j)
    elem(l, c, j)
    pushall(c,d,e)
    c <- k
    d <- l
    callr(f)
    popall(c,d,e)
    k <- b < 0
    jzrel(k,L_qsort_noswap)
    swap(j,m)
    m <- m + 1
L_qsort_noswap:

    j <- j + 1
    k <- j < i
    jnzrel(k,L_qsort_partition)

    swap(j,i)
L_qsort_done:
    popall(h,i,j,k,l,m)
    ret

// c <- pointer to key
// d <- pointer to element
// b -> < 0, 0, > 0
inteq:
    c <- [c]
    d <- [d]
    b <- c - d
    ret

data_start:
.L_data_start:
.L_data_elt_start:
    .word     21, @L_21
.L_data_elt_end:
    .word     34, @L_34
    .word     55, @L_55
    .word    144, @L_144
    .word      1, @L_1
    .word      2, @L_2
    .word     89, @L_89
    .word      3, @L_3
    .word      5, @L_5
    .word      8, @L_8
    .word     13, @L_13
.L_data_end:
    .word 0

L_1  : .utf32 "one"                    ; .word 0
L_2  : .utf32 "two"                    ; .word 0
L_3  : .utf32 "three"                  ; .word 0
L_5  : .utf32 "five"                   ; .word 0
L_8  : .utf32 "eight"                  ; .word 0
L_13 : .utf32 "thirteen"               ; .word 0
L_21 : .utf32 "twenty-one"             ; .word 0
L_34 : .utf32 "thirty-four"            ; .word 0
L_55 : .utf32 "fifty-five"             ; .word 0
L_89 : .utf32 "eighty-nine"            ; .word 0
L_144: .utf32 "one hundred forty-four" ; .word 0

nl: .word '\n', 0

<|endoftext|>