<commit_before>// ConverterMarket.cpp
// Implements the ConverterMarket class

#include <iostream>
#include <cmath>

#include "ConverterMarket.h"

#include "ConverterModel.h"
#include "IsoVector.h"
#include "Logger.h"
#include "CycException.h"
#include "InputXML.h"

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::init(xmlNodePtr cur) {
  MarketModel::init(cur);  /// get facility list
  xmlNodeSetPtr nodes = XMLinput->get_xpath_elements(cur,"model/ConverterMarket/converter");

  // Find out what convertermodel matches the name given
  xmlNodePtr conv_node = nodes->nodeTab[0];
  conv_name_ = XMLinput->get_xpath_content(conv_node,"type");
  Model* converter = Model::getModelByName(conv_name_);

  // make one
  Model* new_converter = Model::create(converter);

  // move XML pointer to current model
  cur = XMLinput->get_xpath_element(cur,"model/ConverterMarket");

  // The commodity initialized as the mktcommodity is the request commodity.
  offer_commod_ = XMLinput->get_xpath_content(cur,"offercommodity");
  req_commod_ = XMLinput->get_xpath_content(cur,"reqcommodity");

}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::copy(ConverterMarket* src)
{
  MarketModel::copy(src);
  offer_commod_ = src->offer_commod_;
  req_commod_ = src->req_commod_;
  conv_name_ = src->conv_name_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::copyFreshModel(Model* src)
{
  copy(dynamic_cast<ConverterMarket*>(src));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string ConverterMarket::str() {
  std::string s = MarketModel::str()
                + "with offer commodity '"
                + offer_commod_
                + "' and request commodity '"
                + req_commod_
                + "'. ";
  return s;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ConverterModel* ConverterMarket::getConverter() {
  Model* converter;
  converter = Model::getModelByName(conv_name_);

  return dynamic_cast<ConverterModel*>(converter);
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::receiveMessage(msg_ptr msg)
{
  messages_.insert(msg);

  if (msg->isOffer()){
    offers_.insert(indexedMsg(msg->resource()->quantity(),msg));
  }
  else if (!msg->isOffer()) {
    requests_.insert(indexedMsg(msg->resource()->quantity(),msg));
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::reject_request(sortedMsgList::iterator request)
{

  // delete the tentative orders
  while ( orders_.size() > firmOrders_) {
    orders_.pop_back();
  }

  // put all matched offers back in the sorted list
  while (matchedOffers_.size() > 0) {
    msg_ptr msg = *(matchedOffers_.begin());
    offers_.insert(indexedMsg(msg->resource()->quantity(),msg));
    matchedOffers_.erase(msg);
  }

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::process_request()
{
  // update pointer to firm orders
  firmOrders_ = orders_.size();

  while (matchedOffers_.size() > 0)
  {
    msg_ptr msg = *(matchedOffers_.begin());
    messages_.erase(msg);
    matchedOffers_.erase(msg);
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ConverterMarket::match_request(sortedMsgList::iterator request)
{
  sortedMsgList::iterator offer;
  double requestAmt,offerAmt;
  msg_ptr offerMsg;
  msg_ptr requestMsg;

  requestAmt = (*request).first;
  requestMsg = (*request).second;

  // if this request is not yet satisfied &&
  // there are more offers_ left
  while ( requestAmt > 0 && offers_.size() > 0)
  {
    // get a new offer
    offer = offers_.end();
    offer--;
    // convert it
    offerMsg = (this->getConverter())->convert((*offer).second, requestMsg);
    offerAmt = offerMsg->resource()->quantity();

    // pop off this offer
    offers_.erase(offer);
    if (requestMsg->resource()->checkQuality(offerMsg->resource())){
      if (requestAmt > offerAmt) {
        // put a new message in the order stack
        // it goes down to supplier
        offerMsg->setRequester(requestMsg->requester());

        // tenatively queue a new order (don't execute yet)
        matchedOffers_.insert(offerMsg);

        orders_.push_back(offerMsg);

        LOG(LEV_DEBUG2, "none!") << "ConverterMarket has resolved a match from "
          << offerMsg->supplier()->ID()
          << " to "
          << offerMsg->requester()->ID()
          << " for the amount:  "
          << offerMsg->resource()->quantity();

        requestAmt -= offerAmt;
      }
      else {
        // split offer

        // queue a new order
        msg_ptr maybe_offer = offerMsg->clone();

        maybe_offer->resource()->setQuantity(requestAmt);
        maybe_offer->setRequester(requestMsg->requester());

        matchedOffers_.insert(offerMsg);

        orders_.push_back(maybe_offer);

        LOG(LEV_DEBUG2, "none!") << "ConverterMarket has resolved a partial match from "
          << maybe_offer->supplier()->ID()
          << " to "
          << maybe_offer->requester()->ID()
          << " for the amount:  "
          << maybe_offer->resource()->quantity();

        // reduce the offer amount
        offerAmt -= requestAmt;

        // if the residual is above threshold,
        // make a new offer with reduced amount

        if(offerAmt > EPS_KG) {
          msg_ptr new_offer = offerMsg->clone();
          new_offer->resource()->setQuantity(offerAmt);
          // call this method for consistency
          receiveMessage(new_offer);
        }

        // zero out request
        requestAmt = 0;
      }
    }
  }

  return (0 == requestAmt);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::resolve()
{
  sortedMsgList::iterator request;

  firmOrders_ = 0;

  /// while requests_ remain and there is at least one offer left
  while (requests_.size() > 0)
  {
    request = requests_.end();
    request--;

    if(match_request(request)) {
      process_request();
    }
    else {
      LOG(LEV_DEBUG2, "none!") << "The request from Requester "<<
          (*request).second->requester()->ID()
          << " for the amount " << (*request).first
          << " rejected by the ConverterMarket. ";
      reject_request(request);
    }
    // remove this request
    messages_.erase((*request).second);
    requests_.erase(request);
  }

  for (int i = 0; i < orders_.size(); i++) {
    msg_ptr msg = orders_.at(i);
    msg->setDir(DOWN_MSG);
    msg->sendOn();
  }
  orders_.clear();
}

/* --------------------
 * all MODEL classes have these members
 * --------------------
 */
extern "C" Model* constructConverterMarket() {
  return new ConverterMarket();
}

/* -------------------- */

<commit_msg>ConverterMarket passes tests<commit_after>// ConverterMarket.cpp
// Implements the ConverterMarket class

#include <iostream>
#include <cmath>

#include "ConverterMarket.h"

#include "ConverterModel.h"
#include "Resource.h"
#include "Logger.h"
#include "CycException.h"
#include "InputXML.h"

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::init(xmlNodePtr cur) {
  MarketModel::init(cur);  /// get facility list
  xmlNodeSetPtr nodes = XMLinput->get_xpath_elements(cur,"model/ConverterMarket/converter");

  // Find out what convertermodel matches the name given
  xmlNodePtr conv_node = nodes->nodeTab[0];
  conv_name_ = XMLinput->get_xpath_content(conv_node,"type");
  Model* converter = Model::getModelByName(conv_name_);

  // make one
  Model* new_converter = Model::create(converter);

  // move XML pointer to current model
  cur = XMLinput->get_xpath_element(cur,"model/ConverterMarket");

  // The commodity initialized as the mktcommodity is the request commodity.
  offer_commod_ = XMLinput->get_xpath_content(cur,"offercommodity");
  req_commod_ = XMLinput->get_xpath_content(cur,"reqcommodity");

}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::copy(ConverterMarket* src)
{
  MarketModel::copy(src);
  offer_commod_ = src->offer_commod_;
  req_commod_ = src->req_commod_;
  conv_name_ = src->conv_name_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::copyFreshModel(Model* src)
{
  copy(dynamic_cast<ConverterMarket*>(src));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string ConverterMarket::str() {
  std::string s = MarketModel::str()
                + "with offer commodity '"
                + offer_commod_
                + "' and request commodity '"
                + req_commod_
                + "'. ";
  return s;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ConverterModel* ConverterMarket::getConverter() {
  Model* converter;
  converter = Model::getModelByName(conv_name_);

  return dynamic_cast<ConverterModel*>(converter);
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::receiveMessage(msg_ptr msg)
{
  messages_.insert(msg);

  if (msg->isOffer()){
    offers_.insert(indexedMsg(msg->resource()->quantity(),msg));
  }
  else if (!msg->isOffer()) {
    requests_.insert(indexedMsg(msg->resource()->quantity(),msg));
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::reject_request(sortedMsgList::iterator request)
{

  // delete the tentative orders
  while ( orders_.size() > firmOrders_) {
    orders_.pop_back();
  }

  // put all matched offers back in the sorted list
  while (matchedOffers_.size() > 0) {
    msg_ptr msg = *(matchedOffers_.begin());
    offers_.insert(indexedMsg(msg->resource()->quantity(),msg));
    matchedOffers_.erase(msg);
  }

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::process_request()
{
  // update pointer to firm orders
  firmOrders_ = orders_.size();

  while (matchedOffers_.size() > 0)
  {
    msg_ptr msg = *(matchedOffers_.begin());
    messages_.erase(msg);
    matchedOffers_.erase(msg);
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ConverterMarket::match_request(sortedMsgList::iterator request)
{
  sortedMsgList::iterator offer;
  double requestAmt,offerAmt;
  msg_ptr offerMsg;
  msg_ptr requestMsg;

  requestAmt = (*request).first;
  requestMsg = (*request).second;

  // if this request is not yet satisfied &&
  // there are more offers_ left
  while ( requestAmt > 0 && offers_.size() > 0)
  {
    // get a new offer
    offer = offers_.end();
    offer--;
    // convert it
    offerMsg = (this->getConverter())->convert((*offer).second, requestMsg);
    offerAmt = offerMsg->resource()->quantity();

    // pop off this offer
    offers_.erase(offer);
    if (requestMsg->resource()->checkQuality(offerMsg->resource())){
      if (requestAmt > offerAmt) {
        // put a new message in the order stack
        // it goes down to supplier
        offerMsg->setRequester(requestMsg->requester());

        // tenatively queue a new order (don't execute yet)
        matchedOffers_.insert(offerMsg);

        orders_.push_back(offerMsg);

        LOG(LEV_DEBUG2, "none!") << "ConverterMarket has resolved a match from "
          << offerMsg->supplier()->ID()
          << " to "
          << offerMsg->requester()->ID()
          << " for the amount:  "
          << offerMsg->resource()->quantity();

        requestAmt -= offerAmt;
      }
      else {
        // split offer

        // queue a new order
        msg_ptr maybe_offer = offerMsg->clone();

        maybe_offer->resource()->setQuantity(requestAmt);
        maybe_offer->setRequester(requestMsg->requester());

        matchedOffers_.insert(offerMsg);

        orders_.push_back(maybe_offer);

        LOG(LEV_DEBUG2, "none!") << "ConverterMarket has resolved a partial match from "
          << maybe_offer->supplier()->ID()
          << " to "
          << maybe_offer->requester()->ID()
          << " for the amount:  "
          << maybe_offer->resource()->quantity();

        // reduce the offer amount
        offerAmt -= requestAmt;

        // if the residual is above threshold,
        // make a new offer with reduced amount

        if(offerAmt > EPS_RSRC) {
          msg_ptr new_offer = offerMsg->clone();
          new_offer->resource()->setQuantity(offerAmt);
          // call this method for consistency
          receiveMessage(new_offer);
        }

        // zero out request
        requestAmt = 0;
      }
    }
  }

  return (0 == requestAmt);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ConverterMarket::resolve()
{
  sortedMsgList::iterator request;

  firmOrders_ = 0;

  /// while requests_ remain and there is at least one offer left
  while (requests_.size() > 0)
  {
    request = requests_.end();
    request--;

    if(match_request(request)) {
      process_request();
    }
    else {
      LOG(LEV_DEBUG2, "none!") << "The request from Requester "<<
          (*request).second->requester()->ID()
          << " for the amount " << (*request).first
          << " rejected by the ConverterMarket. ";
      reject_request(request);
    }
    // remove this request
    messages_.erase((*request).second);
    requests_.erase(request);
  }

  for (int i = 0; i < orders_.size(); i++) {
    msg_ptr msg = orders_.at(i);
    msg->setDir(DOWN_MSG);
    msg->sendOn();
  }
  orders_.clear();
}

/* --------------------
 * all MODEL classes have these members
 * --------------------
 */
extern "C" Model* constructConverterMarket() {
  return new ConverterMarket();
}

/* -------------------- */

<|endoftext|>


<commit_before>/*
 * Copyright 2002,2004 The Apache Software 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.
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/framework/XMLErrorCodes.hpp>
#include <xercesc/framework/XMLValidityCodes.hpp>
#include <xercesc/framework/XMLErrorReporter.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLRegisterCleanup.hpp>
#include <xercesc/util/XMLInitializer.hpp>
#include <xercesc/validators/schema/XSDErrorReporter.hpp>
#include <xercesc/validators/schema/XSDLocator.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local static data
// ---------------------------------------------------------------------------
static XMLMsgLoader*  gErrMsgLoader = 0;
static XMLMsgLoader*  gValidMsgLoader = 0;
static XMLMutex*      sErrRprtrMutex = 0;
static XMLRegisterCleanup errRprtrMutexCleanup;
static XMLRegisterCleanup cleanupErrMsgLoader;
static XMLRegisterCleanup cleanupValidMsgLoader;

// ---------------------------------------------------------------------------
//  Local, static functions
// ---------------------------------------------------------------------------
static void reinitErrRprtrMutex()
{
    delete sErrRprtrMutex;
    sErrRprtrMutex = 0;
}

static XMLMutex& getErrRprtrMutex()
{
    if (!sErrRprtrMutex)
    {
        XMLMutexLock lockInit(XMLPlatformUtils::fgAtomicMutex);

        if (!sErrRprtrMutex)
        {
            sErrRprtrMutex = new XMLMutex(XMLPlatformUtils::fgMemoryManager);
            errRprtrMutexCleanup.registerCleanup(reinitErrRprtrMutex);
        }
    }

    return *sErrRprtrMutex;
}

static void reinitErrMsgLoader()
{
	delete gErrMsgLoader;
	gErrMsgLoader = 0;
}

static void reinitValidMsgLoader()
{
	delete gValidMsgLoader;
	gValidMsgLoader = 0;
}

static XMLMsgLoader* getErrMsgLoader()
{
    if (!gErrMsgLoader)
    {
        XMLMutexLock lock(&getErrRprtrMutex());

        if (!gErrMsgLoader)
        {
            gErrMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);

            if (!gErrMsgLoader)
                XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
            else
                cleanupErrMsgLoader.registerCleanup(reinitErrMsgLoader);
        }
    }

    return gErrMsgLoader;
}

static XMLMsgLoader* getValidMsgLoader()
{
    if (!gValidMsgLoader)
    {
        XMLMutexLock lock(&getErrRprtrMutex());

        if (!gValidMsgLoader)
        {
            gValidMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgValidityDomain);

            if (!gValidMsgLoader)
                XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
            else
                cleanupValidMsgLoader.registerCleanup(reinitValidMsgLoader);
        }
    }
    return gValidMsgLoader;
}

void XMLInitializer::initializeXSDErrReporterMsgLoader()
{
    gErrMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
    if (gErrMsgLoader) {
        cleanupErrMsgLoader.registerCleanup(reinitErrMsgLoader);
    }

    gValidMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgValidityDomain);
    if (gValidMsgLoader) {
        cleanupValidMsgLoader.registerCleanup(reinitValidMsgLoader);
    }
}

// ---------------------------------------------------------------------------
//  XSDErrorReporter: Constructors and Destructor
// ---------------------------------------------------------------------------
XSDErrorReporter::XSDErrorReporter(XMLErrorReporter* const errorReporter) :
    fExitOnFirstFatal(false)
    , fErrorReporter(errorReporter)
{

}

// ---------------------------------------------------------------------------
//  XSDErrorReporter: Error reporting
// ---------------------------------------------------------------------------
void XSDErrorReporter::emitError(const unsigned int toEmit,
                                 const XMLCh* const msgDomain,
                                 const Locator* const aLocator)
{
    // Bump the error count if it is not a warning
//    if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
//        incrementErrorCount();

    //
    //  Load the message into alocal and replace any tokens found in
    //  the text.
    //
    const unsigned int msgSize = 1023;
    XMLCh errText[msgSize + 1];
    XMLMsgLoader* msgLoader = getErrMsgLoader();
    XMLErrorReporter::ErrTypes errType = XMLErrs::errorType((XMLErrs::Codes) toEmit);

    if (XMLString::equals(msgDomain, XMLUni::fgValidityDomain)) {

        errType = XMLValid::errorType((XMLValid::Codes) toEmit);
        msgLoader = getValidMsgLoader();
    }

    if (!msgLoader->loadMsg(toEmit, errText, msgSize))
    {
                // <TBD> Should probably load a default message here
    }

    if (fErrorReporter)
        fErrorReporter->error(toEmit, msgDomain, errType, errText, aLocator->getSystemId(),
                              aLocator->getPublicId(), aLocator->getLineNumber(),
                              aLocator->getColumnNumber());

    // Bail out if its fatal an we are to give up on the first fatal error
    if (errType == XMLErrorReporter::ErrType_Fatal && fExitOnFirstFatal)
        throw (XMLErrs::Codes) toEmit;
}

void XSDErrorReporter::emitError(const unsigned int toEmit,
                                 const XMLCh* const msgDomain,
                                 const Locator* const aLocator,
                                 const XMLCh* const text1,
                                 const XMLCh* const text2,
                                 const XMLCh* const text3,
                                 const XMLCh* const text4,
                                 MemoryManager* const manager)
{
    // Bump the error count if it is not a warning
//    if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
//        incrementErrorCount();

    //
    //  Load the message into alocal and replace any tokens found in
    //  the text.
    //
    const unsigned int maxChars = 2047;
    XMLCh errText[maxChars + 1];
    XMLMsgLoader* msgLoader = getErrMsgLoader();
    XMLErrorReporter::ErrTypes errType = XMLErrs::errorType((XMLErrs::Codes) toEmit);

    if (XMLString::equals(msgDomain, XMLUni::fgValidityDomain)) {

        errType = XMLValid::errorType((XMLValid::Codes) toEmit);
        msgLoader = getValidMsgLoader();
    }

    if (!msgLoader->loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4, manager))
    {
                // <TBD> Should probably load a default message here
    }

    if (fErrorReporter)
        fErrorReporter->error(toEmit, msgDomain, errType, errText, aLocator->getSystemId(),
                              aLocator->getPublicId(), aLocator->getLineNumber(),
                              aLocator->getColumnNumber());

    // Bail out if its fatal an we are to give up on the first fatal error
    if (errType == XMLErrorReporter::ErrType_Fatal && fExitOnFirstFatal)
        throw (XMLErrs::Codes) toEmit;
}

void XSDErrorReporter::emitError(const XMLException&  except,
                                 const Locator* const aLocator)
{
    const XMLCh* const  errText = except.getMessage();
    const unsigned int  toEmit = except.getCode();
    XMLErrorReporter::ErrTypes errType = XMLErrs::errorType((XMLErrs::Codes) toEmit);

    if (fErrorReporter)
        fErrorReporter->error(toEmit, XMLUni::fgExceptDomain, errType, errText, aLocator->getSystemId(),
                              aLocator->getPublicId(), aLocator->getLineNumber(),
                              aLocator->getColumnNumber());

    // Bail out if its fatal an we are to give up on the first fatal error
    if (errType == XMLErrorReporter::ErrType_Fatal && fExitOnFirstFatal)
        throw (XMLErrs::Codes) toEmit;
}

XERCES_CPP_NAMESPACE_END
<commit_msg>Use errType of Error to be consistent with previous behaviour.<commit_after>/*
 * Copyright 2002,2004 The Apache Software 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.
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/framework/XMLErrorCodes.hpp>
#include <xercesc/framework/XMLValidityCodes.hpp>
#include <xercesc/framework/XMLErrorReporter.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLRegisterCleanup.hpp>
#include <xercesc/util/XMLInitializer.hpp>
#include <xercesc/validators/schema/XSDErrorReporter.hpp>
#include <xercesc/validators/schema/XSDLocator.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local static data
// ---------------------------------------------------------------------------
static XMLMsgLoader*  gErrMsgLoader = 0;
static XMLMsgLoader*  gValidMsgLoader = 0;
static XMLMutex*      sErrRprtrMutex = 0;
static XMLRegisterCleanup errRprtrMutexCleanup;
static XMLRegisterCleanup cleanupErrMsgLoader;
static XMLRegisterCleanup cleanupValidMsgLoader;

// ---------------------------------------------------------------------------
//  Local, static functions
// ---------------------------------------------------------------------------
static void reinitErrRprtrMutex()
{
    delete sErrRprtrMutex;
    sErrRprtrMutex = 0;
}

static XMLMutex& getErrRprtrMutex()
{
    if (!sErrRprtrMutex)
    {
        XMLMutexLock lockInit(XMLPlatformUtils::fgAtomicMutex);

        if (!sErrRprtrMutex)
        {
            sErrRprtrMutex = new XMLMutex(XMLPlatformUtils::fgMemoryManager);
            errRprtrMutexCleanup.registerCleanup(reinitErrRprtrMutex);
        }
    }

    return *sErrRprtrMutex;
}

static void reinitErrMsgLoader()
{
	delete gErrMsgLoader;
	gErrMsgLoader = 0;
}

static void reinitValidMsgLoader()
{
	delete gValidMsgLoader;
	gValidMsgLoader = 0;
}

static XMLMsgLoader* getErrMsgLoader()
{
    if (!gErrMsgLoader)
    {
        XMLMutexLock lock(&getErrRprtrMutex());

        if (!gErrMsgLoader)
        {
            gErrMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);

            if (!gErrMsgLoader)
                XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
            else
                cleanupErrMsgLoader.registerCleanup(reinitErrMsgLoader);
        }
    }

    return gErrMsgLoader;
}

static XMLMsgLoader* getValidMsgLoader()
{
    if (!gValidMsgLoader)
    {
        XMLMutexLock lock(&getErrRprtrMutex());

        if (!gValidMsgLoader)
        {
            gValidMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgValidityDomain);

            if (!gValidMsgLoader)
                XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
            else
                cleanupValidMsgLoader.registerCleanup(reinitValidMsgLoader);
        }
    }
    return gValidMsgLoader;
}

void XMLInitializer::initializeXSDErrReporterMsgLoader()
{
    gErrMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
    if (gErrMsgLoader) {
        cleanupErrMsgLoader.registerCleanup(reinitErrMsgLoader);
    }

    gValidMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgValidityDomain);
    if (gValidMsgLoader) {
        cleanupValidMsgLoader.registerCleanup(reinitValidMsgLoader);
    }
}

// ---------------------------------------------------------------------------
//  XSDErrorReporter: Constructors and Destructor
// ---------------------------------------------------------------------------
XSDErrorReporter::XSDErrorReporter(XMLErrorReporter* const errorReporter) :
    fExitOnFirstFatal(false)
    , fErrorReporter(errorReporter)
{

}

// ---------------------------------------------------------------------------
//  XSDErrorReporter: Error reporting
// ---------------------------------------------------------------------------
void XSDErrorReporter::emitError(const unsigned int toEmit,
                                 const XMLCh* const msgDomain,
                                 const Locator* const aLocator)
{
    // Bump the error count if it is not a warning
//    if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
//        incrementErrorCount();

    //
    //  Load the message into alocal and replace any tokens found in
    //  the text.
    //
    const unsigned int msgSize = 1023;
    XMLCh errText[msgSize + 1];
    XMLMsgLoader* msgLoader = getErrMsgLoader();
    XMLErrorReporter::ErrTypes errType = XMLErrs::errorType((XMLErrs::Codes) toEmit);

    if (XMLString::equals(msgDomain, XMLUni::fgValidityDomain)) {

        errType = XMLValid::errorType((XMLValid::Codes) toEmit);
        msgLoader = getValidMsgLoader();
    }

    if (!msgLoader->loadMsg(toEmit, errText, msgSize))
    {
                // <TBD> Should probably load a default message here
    }

    if (fErrorReporter)
        fErrorReporter->error(toEmit, msgDomain, errType, errText, aLocator->getSystemId(),
                              aLocator->getPublicId(), aLocator->getLineNumber(),
                              aLocator->getColumnNumber());

    // Bail out if its fatal an we are to give up on the first fatal error
    if (errType == XMLErrorReporter::ErrType_Fatal && fExitOnFirstFatal)
        throw (XMLErrs::Codes) toEmit;
}

void XSDErrorReporter::emitError(const unsigned int toEmit,
                                 const XMLCh* const msgDomain,
                                 const Locator* const aLocator,
                                 const XMLCh* const text1,
                                 const XMLCh* const text2,
                                 const XMLCh* const text3,
                                 const XMLCh* const text4,
                                 MemoryManager* const manager)
{
    // Bump the error count if it is not a warning
//    if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
//        incrementErrorCount();

    //
    //  Load the message into alocal and replace any tokens found in
    //  the text.
    //
    const unsigned int maxChars = 2047;
    XMLCh errText[maxChars + 1];
    XMLMsgLoader* msgLoader = getErrMsgLoader();
    XMLErrorReporter::ErrTypes errType = XMLErrs::errorType((XMLErrs::Codes) toEmit);

    if (XMLString::equals(msgDomain, XMLUni::fgValidityDomain)) {

        errType = XMLValid::errorType((XMLValid::Codes) toEmit);
        msgLoader = getValidMsgLoader();
    }

    if (!msgLoader->loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4, manager))
    {
                // <TBD> Should probably load a default message here
    }

    if (fErrorReporter)
        fErrorReporter->error(toEmit, msgDomain, errType, errText, aLocator->getSystemId(),
                              aLocator->getPublicId(), aLocator->getLineNumber(),
                              aLocator->getColumnNumber());

    // Bail out if its fatal an we are to give up on the first fatal error
    if (errType == XMLErrorReporter::ErrType_Fatal && fExitOnFirstFatal)
        throw (XMLErrs::Codes) toEmit;
}

void XSDErrorReporter::emitError(const XMLException&  except,
                                 const Locator* const aLocator)
{
    const XMLCh* const  errText = except.getMessage();
    const unsigned int  toEmit = except.getCode();
    //Before the code was modified to call this routine it used to use
    //the XMLErrs::DisplayErrorMessage error message, which is just {'0'}
    //and that error message has errType of Error.  So to be consistent
    //with previous behaviour set the errType to be Error instead of
    //getting the error type off of the exception.
    //XMLErrorReporter::ErrTypes errType = XMLErrs::errorType((XMLErrs::Codes) toEmit);
    XMLErrorReporter::ErrTypes errType = XMLErrorReporter::ErrType_Error;

    if (fErrorReporter)
        fErrorReporter->error(toEmit, XMLUni::fgExceptDomain, errType, errText, aLocator->getSystemId(),
                              aLocator->getPublicId(), aLocator->getLineNumber(),
                              aLocator->getColumnNumber());

    // Bail out if its fatal an we are to give up on the first fatal error
    //if (errType == XMLErrorReporter::ErrType_Fatal && fExitOnFirstFatal)
    //    throw (XMLErrs::Codes) toEmit;
}

XERCES_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: iso8601_converter.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 01:46:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_shell.hxx"

#ifndef ISO8601_CONVERTER_HXX_INCLUDED
#include "internal/iso8601_converter.hxx"
#endif

#ifndef UTILITIES_HXX_INCLUDED
#include "internal/utilities.hxx"
#endif

#include <sstream>
#include <iomanip>

//-----------------------------------
/* Converts ISO 8601 conform date/time
   represenation to the representation
   conforming to the current locale
*/
std::wstring iso8601_date_to_local_date(const std::wstring& isoDate )
{
    const std::wstring CONST_SPACE(L" ");
    ::std::wstring ws8601DateTime(isoDate);

    if ( ws8601DateTime.length() == 19 )
    {
        //fill in the SYSTEMTIME structure;
        std::string asDateTime = WStringToString( ws8601DateTime );
        SYSTEMTIME DateTime;
        DateTime.wYear         = ( unsigned short )strtol( asDateTime.substr( 0, 4 ).c_str(), NULL, 10 );
        DateTime.wMonth        = ( unsigned short )strtol( asDateTime.substr( 5, 2 ).c_str(), NULL, 10 );
        DateTime.wDayOfWeek    =  0;
        DateTime.wDay          = ( unsigned short )strtol( asDateTime.substr( 8, 2 ).c_str(), NULL, 10 );
        DateTime.wHour         = ( unsigned short )strtol( asDateTime.substr( 11,2 ).c_str(), NULL, 10 );
        DateTime.wMinute       = ( unsigned short )strtol( asDateTime.substr( 14,2 ).c_str(), NULL, 10 );
        DateTime.wSecond       = ( unsigned short )strtol( asDateTime.substr( 17,2 ).c_str(), NULL, 10 );
        DateTime.wMilliseconds =  0;

        //get Date info from structure
        WCHAR DateBuffer[ MAX_PATH ];
        int DateSize = GetDateFormatW(
            LOCALE_SYSTEM_DEFAULT,
            0,
            &DateTime,
            NULL,
            DateBuffer,
            MAX_PATH );

        if ( DateSize )
            ws8601DateTime.assign(DateBuffer);
        else
            ws8601DateTime = StringToWString( asDateTime );

        //get Time info from structure
        WCHAR TimeBuffer[ MAX_PATH ];

        int TimeSize =  GetTimeFormatW(
            LOCALE_SYSTEM_DEFAULT,
            0,
            &DateTime,
            NULL,
            TimeBuffer,
            MAX_PATH );

        if ( TimeSize )
        {
            ws8601DateTime.append(L" ");
            ws8601DateTime.append(TimeBuffer);
        }
        else
            ws8601DateTime = StringToWString( asDateTime );
    }

    return ws8601DateTime;
}

//------------------------------------
/* Converts ISO 8601 conform duration
   representation to the representation
   conforming to the current locale

   Expect format PTnHnMnS according to
   ISO 8601 where n is abitrary number
   of digits
*/

std::wstring iso8601_duration_to_local_duration(const std::wstring& iso8601duration)
{
    std::wstring days;
    std::wstring hours;
    std::wstring minutes;
    std::wstring seconds;

    std::wstring::const_iterator iter     = iso8601duration.begin();
    std::wstring::const_iterator iter_end = iso8601duration.end();

    std::wstring num;

    for (/**/; iter != iter_end; ++iter)
    {
        if (isdigit(*iter))
        {
            num += *iter;
        }
        else
        {
            if (*iter == L'D' || *iter == L'd')
                days = num;
            else if (*iter == L'H' || *iter == L'h')
                hours = num;
            else if (*iter == L'M' || *iter == L'm')
                minutes = num;
            else if (*iter == L'S' || *iter == L's')
                seconds = num;

            num.clear();
        }
    }

    if (days.length() > 0)
    {
        int h = ((_wtoi(days.c_str()) * 24) + _wtoi(hours.c_str()));
        wchar_t buff[10];
        _itow(h, buff, 10);
        hours = buff;
    }

    std::wostringstream oss;

    oss << std::setw(2) << std::setfill('0') << hours   << L":" <<
           std::setw(2) << std::setfill('0') << minutes << L":" <<
           std::setw(2) << std::setfill('0') << seconds;

    return oss.str();
}

<commit_msg>INTEGRATION: CWS obo24 (1.5.120); FILE MERGED 2008/03/13 15:26:36 obo 1.5.120.1: #i75046# additional build for 64 bit shell extension (Windows Vista)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: iso8601_converter.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-02 09:45:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_shell.hxx"

#ifndef ISO8601_CONVERTER_HXX_INCLUDED
#include "internal/iso8601_converter.hxx"
#endif

#ifndef UTILITIES_HXX_INCLUDED
#include "internal/utilities.hxx"
#endif

#include <sstream>
#include <iomanip>

//-----------------------------------
/* Converts ISO 8601 conform date/time
   represenation to the representation
   conforming to the current locale
*/
std::wstring iso8601_date_to_local_date(const std::wstring& isoDate )
{
    const std::wstring CONST_SPACE(L" ");
    ::std::wstring ws8601DateTime(isoDate);

    if ( ws8601DateTime.length() == 19 )
    {
        //fill in the SYSTEMTIME structure;
        std::string asDateTime = WStringToString( ws8601DateTime );
        SYSTEMTIME DateTime;
        DateTime.wYear         = ( unsigned short )strtol( asDateTime.substr( 0, 4 ).c_str(), NULL, 10 );
        DateTime.wMonth        = ( unsigned short )strtol( asDateTime.substr( 5, 2 ).c_str(), NULL, 10 );
        DateTime.wDayOfWeek    =  0;
        DateTime.wDay          = ( unsigned short )strtol( asDateTime.substr( 8, 2 ).c_str(), NULL, 10 );
        DateTime.wHour         = ( unsigned short )strtol( asDateTime.substr( 11,2 ).c_str(), NULL, 10 );
        DateTime.wMinute       = ( unsigned short )strtol( asDateTime.substr( 14,2 ).c_str(), NULL, 10 );
        DateTime.wSecond       = ( unsigned short )strtol( asDateTime.substr( 17,2 ).c_str(), NULL, 10 );
        DateTime.wMilliseconds =  0;

        //get Date info from structure
        WCHAR DateBuffer[ MAX_PATH ];
        int DateSize = GetDateFormatW(
            LOCALE_SYSTEM_DEFAULT,
            0,
            &DateTime,
            NULL,
            DateBuffer,
            MAX_PATH );

        if ( DateSize )
            ws8601DateTime.assign(DateBuffer);
        else
            ws8601DateTime = StringToWString( asDateTime );

        //get Time info from structure
        WCHAR TimeBuffer[ MAX_PATH ];

        int TimeSize =  GetTimeFormatW(
            LOCALE_SYSTEM_DEFAULT,
            0,
            &DateTime,
            NULL,
            TimeBuffer,
            MAX_PATH );

        if ( TimeSize )
        {
            ws8601DateTime.append(L" ");
            ws8601DateTime.append(TimeBuffer);
        }
        else
            ws8601DateTime = StringToWString( asDateTime );
    }

    return ws8601DateTime;
}

//------------------------------------
/* Converts ISO 8601 conform duration
   representation to the representation
   conforming to the current locale

   Expect format PTnHnMnS according to
   ISO 8601 where n is abitrary number
   of digits
*/

std::wstring iso8601_duration_to_local_duration(const std::wstring& iso8601duration)
{
    std::wstring days;
    std::wstring hours;
    std::wstring minutes;
    std::wstring seconds;

    std::wstring::const_iterator iter     = iso8601duration.begin();
    std::wstring::const_iterator iter_end = iso8601duration.end();

    std::wstring num;

    for (/**/; iter != iter_end; ++iter)
    {
        if (isdigit(*iter))
        {
            num += *iter;
        }
        else
        {
            if (*iter == L'D' || *iter == L'd')
                days = num;
            else if (*iter == L'H' || *iter == L'h')
                hours = num;
            else if (*iter == L'M' || *iter == L'm')
                minutes = num;
            else if (*iter == L'S' || *iter == L's')
                seconds = num;

            num.clear();
        }
    }

    if (days.length() > 0)
    {
        int h = ((_wtoi(days.c_str()) * 24) + _wtoi(hours.c_str()));
        wchar_t buff[10];
        _itow(h, buff, 10);
        hours = buff;
    }

    std::wostringstream oss;

#if defined(_MSC_VER) && defined(_M_X64)
    oss << std::setw(2) << std::setfill(wchar_t('0')) << hours   << L":" <<
           std::setw(2) << std::setfill(wchar_t('0')) << minutes << L":" <<
           std::setw(2) << std::setfill(wchar_t('0')) << seconds;
#else
    oss << std::setw(2) << std::setfill('0') << hours   << L":" <<
           std::setw(2) << std::setfill('0') << minutes << L":" <<
           std::setw(2) << std::setfill('0') << seconds;
#endif
    return oss.str();
}

<|endoftext|>


<commit_before>/*******************************
Copyright (c) 2016-2019 Grégoire Angerand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**********************************/

#include "componentwidgets.h"

#include <editor/context/EditorContext.h>

#include <editor/components/EditorComponent.h>
#include <yave/components/PointLightComponent.h>
#include <yave/components/DirectionalLightComponent.h>
#include <yave/components/SkyComponent.h>
#include <yave/components/StaticMeshComponent.h>
#include <yave/components/TransformableComponent.h>

#include <yave/utils/color.h>
#include <editor/utils/ui.h>
#include <editor/widgets/AssetSelector.h>

#include <imgui/yave_imgui.h>

#include <mutex>

namespace editor {
namespace detail {

static ComponentWidgetData* first_component = nullptr;

void register_component_widget(ComponentWidgetData* data) {
	data->next = first_component;
	first_component = data;
}

}

void draw_component_widgets(ContextPtr ctx, ecs::EntityId id) {
	for(detail::ComponentWidgetData* data = detail::first_component; data; data = data->next) {
		y_debug_assert(data->func);
		data->func(ctx, id);
	}
}

/**************************************************************************
*								Lights
**************************************************************************/

template<typename T>
static void light_widget(T* light) {
	const int color_flags = ImGuiColorEditFlags_NoSidePreview |
					  // ImGuiColorEditFlags_NoSmallPreview |
					  ImGuiColorEditFlags_NoAlpha |
					  ImGuiColorEditFlags_Float |
					  ImGuiColorEditFlags_InputRGB;

	const math::Vec4 color(light->color(), 1.0f);
	if(ImGui::ColorButton("Color", color, color_flags)) {
		ImGui::OpenPopup("Color");
	}
	ImGui::SameLine();
	ImGui::Text("Light color");

	if(ImGui::BeginPopup("Color")) {
		ImGui::ColorPicker3("##lightpicker", light->color().begin(), color_flags);

		float kelvin = std::clamp(rgb_to_k(light->color()), 1000.0f, 12000.0f);
		if(ImGui::SliderFloat("", &kelvin, 1000.0f, 12000.0f, "%.0f°K")) {
			light->color() = k_to_rbg(kelvin);
		}

		ImGui::EndPopup();
	}

	ImGui::DragFloat("Intensity", &light->intensity(), 1.0f, 0.0f, std::numeric_limits<float>::max());
}

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	PointLightComponent* light = ctx->world().component<PointLightComponent>(id);
	if(!light) {
		return;
	}

	if(!ImGui::CollapsingHeader("Point light", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	light_widget(light);

	ImGui::DragFloat("Radius", &light->radius(), 1.0f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
	ImGui::DragFloat("Falloff", &light->falloff(), 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f", 2.0f);
}

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	DirectionalLightComponent* light = ctx->world().component<DirectionalLightComponent>(id);
	if(!light) {
		return;
	}

	if(!ImGui::CollapsingHeader("Directional light", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	light_widget(light);

	ImGui::InputFloat3("Direction", light->direction().data(), "%.2f");
}

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	SkyComponent* sky = ctx->world().component<SkyComponent>(id);
	if(!sky) {
		return;
	}

	if(!ImGui::CollapsingHeader("Sky", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	light_widget(&sky->sun());

	math::Vec3 beta = sky->beta_rayleight() * 1e6f;
	if(ImGui::InputFloat3("Beta", beta.data(), "%.2f")) {
		sky->beta_rayleight() = beta * 1e-6f;
	}

	ImGui::SameLine();

	if(ImGui::Button(ICON_FA_GLOBE_AFRICA)) {
		sky->beta_rayleight() = SkyComponent::earth_beta;
	}
}

/**************************************************************************
*								Meshes
**************************************************************************/

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	if(!ctx->world().component<StaticMeshComponent>(id)) {
		return;
	}
	if(!ImGui::CollapsingHeader("Static mesh")) {
		return;
	}

	const auto static_mesh = [ctx, id]() -> StaticMeshComponent* { return ctx->world().component<StaticMeshComponent>(id); };
	{
		// material
		if(imgui::asset_selector(ctx, static_mesh()->material().id(), AssetType::Material, "Material")) {
			ctx->ui().add<AssetSelector>(AssetType::Material)->set_selected_callback(
				[=](AssetId asset) {
					if(const auto material = ctx->loader().load<Material>(asset)) {
						if(StaticMeshComponent* comp = static_mesh()) {
							comp->material() = material.unwrap();
						}
					}
					return true;
				});
		}

		// mesh
		if(imgui::asset_selector(ctx, static_mesh()->mesh().id(), AssetType::Mesh, "Mesh")) {
			ctx->ui().add<AssetSelector>(AssetType::Mesh)->set_selected_callback(
				[=](AssetId asset) {
					if(const auto mesh = ctx->loader().load<StaticMesh>(asset)) {
						if(StaticMeshComponent* comp = static_mesh()) {
							comp->mesh() = mesh.unwrap();
						}
					}
					return true;
				});
		}
	}
}

/**************************************************************************
*								Editor
**************************************************************************/

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	EditorComponent* component = ctx->world().component<EditorComponent>(id);
	if(!component) {
		return;
	}

	if(!ImGui::CollapsingHeader("Entity")) {
		return;
	}

	const core::String& name = component->name();

	std::array<char, 1024> name_buffer;
	std::fill(name_buffer.begin(), name_buffer.end(), 0);
	std::copy(name.begin(), name.end(), name_buffer.begin());

	if(ImGui::InputText("Name", name_buffer.begin(), name_buffer.size())) {
		component->set_name(name_buffer.begin());
	}
}

}
<commit_msg>Added transformable editor back<commit_after>/*******************************
Copyright (c) 2016-2019 Grégoire Angerand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**********************************/

#include "componentwidgets.h"

#include <editor/context/EditorContext.h>

#include <editor/components/EditorComponent.h>
#include <yave/components/PointLightComponent.h>
#include <yave/components/DirectionalLightComponent.h>
#include <yave/components/SkyComponent.h>
#include <yave/components/StaticMeshComponent.h>
#include <yave/components/TransformableComponent.h>

#include <yave/utils/color.h>
#include <editor/utils/ui.h>
#include <editor/widgets/AssetSelector.h>

#include <imgui/yave_imgui.h>

#include <mutex>

namespace editor {
namespace detail {

static ComponentWidgetData* first_component = nullptr;

void register_component_widget(ComponentWidgetData* data) {
	data->next = first_component;
	first_component = data;
}

}

void draw_component_widgets(ContextPtr ctx, ecs::EntityId id) {
	for(detail::ComponentWidgetData* data = detail::first_component; data; data = data->next) {
		y_debug_assert(data->func);
		data->func(ctx, id);
	}
}

/**************************************************************************
*								Lights
**************************************************************************/

template<typename T>
static void light_widget(T* light) {
	const int color_flags = ImGuiColorEditFlags_NoSidePreview |
					  // ImGuiColorEditFlags_NoSmallPreview |
					  ImGuiColorEditFlags_NoAlpha |
					  ImGuiColorEditFlags_Float |
					  ImGuiColorEditFlags_InputRGB;

	const math::Vec4 color(light->color(), 1.0f);
	if(ImGui::ColorButton("Color", color, color_flags)) {
		ImGui::OpenPopup("Color");
	}
	ImGui::SameLine();
	ImGui::Text("Light color");

	if(ImGui::BeginPopup("Color")) {
		ImGui::ColorPicker3("##lightpicker", light->color().begin(), color_flags);

		float kelvin = std::clamp(rgb_to_k(light->color()), 1000.0f, 12000.0f);
		if(ImGui::SliderFloat("", &kelvin, 1000.0f, 12000.0f, "%.0f°K")) {
			light->color() = k_to_rbg(kelvin);
		}

		ImGui::EndPopup();
	}

	ImGui::DragFloat("Intensity", &light->intensity(), 1.0f, 0.0f, std::numeric_limits<float>::max());
}

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	PointLightComponent* light = ctx->world().component<PointLightComponent>(id);
	if(!light) {
		return;
	}

	if(!ImGui::CollapsingHeader("Point light", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	light_widget(light);

	ImGui::DragFloat("Radius", &light->radius(), 1.0f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
	ImGui::DragFloat("Falloff", &light->falloff(), 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f", 2.0f);
}

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	DirectionalLightComponent* light = ctx->world().component<DirectionalLightComponent>(id);
	if(!light) {
		return;
	}

	if(!ImGui::CollapsingHeader("Directional light", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	light_widget(light);

	ImGui::InputFloat3("Direction", light->direction().data(), "%.2f");
}

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	SkyComponent* sky = ctx->world().component<SkyComponent>(id);
	if(!sky) {
		return;
	}

	if(!ImGui::CollapsingHeader("Sky", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	light_widget(&sky->sun());

	ImGui::InputFloat3("Direction", sky->sun().direction().data(), "%.2f");

	math::Vec3 beta = sky->beta_rayleight() * 1e6f;
	if(ImGui::InputFloat3("Beta", beta.data(), "%.2f")) {
		sky->beta_rayleight() = beta * 1e-6f;
	}

	ImGui::SameLine();

	if(ImGui::Button(ICON_FA_GLOBE_AFRICA)) {
		sky->beta_rayleight() = SkyComponent::earth_beta;
	}
}

/**************************************************************************
*								Meshes
**************************************************************************/

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	if(!ctx->world().component<StaticMeshComponent>(id)) {
		return;
	}
	if(!ImGui::CollapsingHeader("Static mesh")) {
		return;
	}

	const auto static_mesh = [ctx, id]() -> StaticMeshComponent* { return ctx->world().component<StaticMeshComponent>(id); };
	{
		// material
		if(imgui::asset_selector(ctx, static_mesh()->material().id(), AssetType::Material, "Material")) {
			ctx->ui().add<AssetSelector>(AssetType::Material)->set_selected_callback(
				[=](AssetId asset) {
					if(const auto material = ctx->loader().load<Material>(asset)) {
						if(StaticMeshComponent* comp = static_mesh()) {
							comp->material() = material.unwrap();
						}
					}
					return true;
				});
		}

		// mesh
		if(imgui::asset_selector(ctx, static_mesh()->mesh().id(), AssetType::Mesh, "Mesh")) {
			ctx->ui().add<AssetSelector>(AssetType::Mesh)->set_selected_callback(
				[=](AssetId asset) {
					if(const auto mesh = ctx->loader().load<StaticMesh>(asset)) {
						if(StaticMeshComponent* comp = static_mesh()) {
							comp->mesh() = mesh.unwrap();
						}
					}
					return true;
				});
		}
	}
}

/**************************************************************************
*								Transformable
**************************************************************************/

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	TransformableComponent* component = ctx->world().component<TransformableComponent>(id);
	if(!component) {
		return;
	}

	if(!ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) {
		return;
	}

	{
		math::Vec3 prev_euler; // this should be stable
		auto [pos, rot, scale] = component->transform().decompose();

		// position
		{
			ImGui::BeginGroup();
			ImGui::InputFloat3("Position", pos.data(), "%.2f");
			ImGui::EndGroup();
		}

		// rotation
		{
			auto dedouble_quat = [](math::Quaternion<> q) {
				return q.x() < 0.0f ? -q.as_vec() : q.as_vec();
			};
			auto is_same_angle = [&](math::Vec3 a, math::Vec3 b) {
				auto qa = math::Quaternion<>::from_euler(a * math::to_rad(1.0f));
				auto qb = math::Quaternion<>::from_euler(b * math::to_rad(1.0f));
				return (dedouble_quat(qa) - dedouble_quat(qb)).length2() < 0.0001f;
			};

			math::Vec3 euler = rot.to_euler() * math::to_deg(1.0f);
			if(is_same_angle(euler, prev_euler)) {
				euler = prev_euler;
			}

			float speed = 1.0f;
			ImGui::BeginGroup();
			ImGui::DragFloat("Yaw", &euler[math::Quaternion<>::YawIndex], speed, -180.0f, 180.0f, "%.2f");
			ImGui::DragFloat("Pitch", &euler[math::Quaternion<>::PitchIndex], speed, -180.0f, 180.0f, "%.2f");
			ImGui::DragFloat("Roll", &euler[math::Quaternion<>::RollIndex], speed, -180.0f, 180.0f, "%.2f");
			ImGui::EndGroup();

			if(!is_same_angle(euler, prev_euler)) {
				prev_euler = euler;
				rot = math::Quaternion<>::from_euler(euler * math::to_rad(1.0f));
			}
		}

		component->transform() = math::Transform<>(pos, rot, scale);
	}
}

/**************************************************************************
*								Editor
**************************************************************************/

editor_widget_draw_func(ContextPtr ctx, ecs::EntityId id) {
	EditorComponent* component = ctx->world().component<EditorComponent>(id);
	if(!component) {
		return;
	}

	if(!ImGui::CollapsingHeader("Entity")) {
		return;
	}

	const core::String& name = component->name();

	std::array<char, 1024> name_buffer;
	std::fill(name_buffer.begin(), name_buffer.end(), 0);
	std::copy(name.begin(), name.end(), name_buffer.begin());

	if(ImGui::InputText("Name", name_buffer.begin(), name_buffer.size())) {
		component->set_name(name_buffer.begin());
	}
}

}
<|endoftext|>


<commit_before>// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
// By default (allocator_may_return_null=0) the process shoudl crash.
// With allocator_may_return_null=1 the allocator should return 0.
//
// RUN: %clangxx_asan -O0 %s -o %t
// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL

#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <limits>
int main(int argc, char **argv) {
  volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
  assert(argc == 2);
  char *x = 0;
  if (!strcmp(argv[1], "malloc")) {
    fprintf(stderr, "malloc:\n");
    x = (char*)malloc(size);
  }
  if (!strcmp(argv[1], "calloc")) {
    fprintf(stderr, "calloc:\n");
    x = (char*)calloc(size / 4, 4);
  }

  if (!strcmp(argv[1], "calloc-overflow")) {
    fprintf(stderr, "calloc-overflow:\n");
    volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
    size_t kArraySize = 4096;
    volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
    x = (char*)calloc(kArraySize, kArraySize2);
  }

  if (!strcmp(argv[1], "realloc")) {
    fprintf(stderr, "realloc:\n");
    x = (char*)realloc(0, size);
  }
  if (!strcmp(argv[1], "realloc-after-malloc")) {
    fprintf(stderr, "realloc-after-malloc:\n");
    char *t = (char*)malloc(100);
    *t = 42;
    x = (char*)realloc(t, size);
    assert(*t == 42);
  }
  fprintf(stderr, "x: %p\n", x);
  return x != 0;
}
// CHECK-mCRASH: malloc:
// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-cCRASH: calloc:
// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-coCRASH: calloc-overflow:
// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-rCRASH: realloc:
// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-mrCRASH: realloc-after-malloc:
// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process

// CHECK-mNULL: malloc:
// CHECK-mNULL: x: (nil)
// CHECK-cNULL: calloc:
// CHECK-cNULL: x: (nil)
// CHECK-coNULL: calloc-overflow:
// CHECK-coNULL: x: (nil)
// CHECK-rNULL: realloc:
// CHECK-rNULL: x: (nil)
// CHECK-mrNULL: realloc-after-malloc:
// CHECK-mrNULL: x: (nil)
<commit_msg>[ASan] make the check for NULL more portable.<commit_after>// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
// By default (allocator_may_return_null=0) the process shoudl crash.
// With allocator_may_return_null=1 the allocator should return 0.
//
// RUN: %clangxx_asan -O0 %s -o %t
// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
// RUN: ASAN_OPTIONS=allocator_may_return_null=1     %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL

#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <limits>
int main(int argc, char **argv) {
  volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
  assert(argc == 2);
  char *x = 0;
  if (!strcmp(argv[1], "malloc")) {
    fprintf(stderr, "malloc:\n");
    x = (char*)malloc(size);
  }
  if (!strcmp(argv[1], "calloc")) {
    fprintf(stderr, "calloc:\n");
    x = (char*)calloc(size / 4, 4);
  }

  if (!strcmp(argv[1], "calloc-overflow")) {
    fprintf(stderr, "calloc-overflow:\n");
    volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
    size_t kArraySize = 4096;
    volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
    x = (char*)calloc(kArraySize, kArraySize2);
  }

  if (!strcmp(argv[1], "realloc")) {
    fprintf(stderr, "realloc:\n");
    x = (char*)realloc(0, size);
  }
  if (!strcmp(argv[1], "realloc-after-malloc")) {
    fprintf(stderr, "realloc-after-malloc:\n");
    char *t = (char*)malloc(100);
    *t = 42;
    x = (char*)realloc(t, size);
    assert(*t == 42);
  }
  // The NULL pointer is printed differently on different systems, while (long)0
  // is always the same.
  fprintf(stderr, "x: %lx\n", (long)x);
  return x != 0;
}
// CHECK-mCRASH: malloc:
// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-cCRASH: calloc:
// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-coCRASH: calloc-overflow:
// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-rCRASH: realloc:
// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
// CHECK-mrCRASH: realloc-after-malloc:
// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process

// CHECK-mNULL: malloc:
// CHECK-mNULL: x: 0
// CHECK-cNULL: calloc:
// CHECK-cNULL: x: 0
// CHECK-coNULL: calloc-overflow:
// CHECK-coNULL: x: 0
// CHECK-rNULL: realloc:
// CHECK-rNULL: x: 0
// CHECK-mrNULL: realloc-after-malloc:
// CHECK-mrNULL: x: 0
<|endoftext|>


<commit_before>#include "common/RhodesApp.h"
#include "common/RhoStd.h"
#include "common/RhoConf.h"
#include "common/RhoFile.h"
#include "common/RhoDefs.h"
#include "common/Tokenizer.h"
#include "logging/RhoLogConf.h"
#include "generated/cpp/LogCaptureBase.h"

namespace rho {

    using namespace apiGenerator;
    using namespace common;

    class CLogCaptureImpl: public CLogCaptureSingletonBase, public ILogSink
    {
    public:

        CLogCaptureImpl(): CLogCaptureSingletonBase(), mMaxLines(1024), mTotalSize(0) {}

        // ILogSink
        virtual void writeLogMessage( String& strMsg )
        {
            if ( mMaxLines > 0 )
            {
                if (mCapturedLog.size() > mMaxLines)
                {
                    mCapturedLog.clear();
                    mTotalSize = 0;
                }

                if (mExcludeCategories.size()>0)
                {
                    for(Vector<String>::const_iterator it = mExcludeCategories.begin(); it != mExcludeCategories.end(); ++it)
                    {
                        if (strMsg.find(*it)!=String::npos)
                        {
                            return;
                        }
                    }
                }
                mCapturedLog.push_back(strMsg);
                mTotalSize += strMsg.size() + 2;
            }
        }

        virtual int getCurPos()
        {
            return mCapturedLog.size();
        }

        virtual void clear()
        {

        }

        // ILogCaptureSingleto
        virtual void getExcludeCategories(rho::apiGenerator::CMethodResult& oResult)
        {
            const Vector<rho::String>& log_attr = mExcludeCategories;

            size_t len = 0;
            for(Vector<rho::String>::const_iterator iter = log_attr.begin(); iter != log_attr.end(); iter++)
            {
                len += (*iter).length() + 1; // including separator
            }

            rho::String str;
            str.reserve(len);

            for(Vector<rho::String>::const_iterator iter = log_attr.begin(); iter != log_attr.end(); iter++)
            {
                if (iter != log_attr.begin())
                {
                    str += ",";
                }
                str += *iter;
            }

            oResult.set( str );
        }

        virtual void setExcludeCategories( const rho::String& excludeCategories, rho::apiGenerator::CMethodResult& oResult)
        {
            if ( excludeCategories.length() > 0 )
            {
                rho::common::CTokenizer oTokenizer( excludeCategories, "," );
                while (oTokenizer.hasMoreTokens())
                {
                    String tok = rho::String_trim(oTokenizer.nextToken());
                    if (tok.length() == 0)
                        continue;

                    mExcludeCategories.addElement( tok );
                }
            }
            else
                mExcludeCategories.removeAllElements();
        }

        virtual void getMaxLines(rho::apiGenerator::CMethodResult& oResult)
        {
            oResult.set(mMaxLines);
        }

        virtual void setMaxLines( int maxLines, rho::apiGenerator::CMethodResult& oResult)
        {
            mMaxLines = maxLines;
        }

        virtual void start(rho::apiGenerator::CMethodResult& oResult)
        {
            LOGCONF().addAuxSink(this);
        }

        virtual void stop(rho::apiGenerator::CMethodResult& oResult)
        {
            LOGCONF().removeAuxSink(this);
        }

        virtual void clear(rho::apiGenerator::CMethodResult& oResult)
        {
            mCapturedLog.clear();
            mTotalSize = 0;
        }

        virtual void numLines(rho::apiGenerator::CMethodResult& oResult)
        {
            oResult.set( static_cast<int>(mCapturedLog.size()) );
        }

        virtual void read(rho::apiGenerator::CMethodResult& oResult)
        {
            String str;

            str.reserve(mTotalSize);
            for (Vector<String>::iterator it = mCapturedLog.begin(); it != mCapturedLog.end(); ++it )
            {
                str += *it;
                str += '\n';
            }

            oResult.set(str);
        }

    private:
        Vector<String> mCapturedLog;
        Vector<String> mExcludeCategories;
        int mMaxLines;
        size_t mTotalSize;
    };

    class CLogCaptureFactory: public CLogCaptureFactoryBase
    {
    public:
        ~CLogCaptureFactory(){}

        ILogCaptureSingleton* createModuleSingleton()
        {
            return new CLogCaptureImpl();
        }
    };
}

extern "C" void Init_LogCapture_extension()
{
    rho::CLogCaptureFactory::setInstance( new rho::CLogCaptureFactory() );
    rho::Init_LogCapture_API();
}
<commit_msg>Add proper LogCapture destructor<commit_after>#include "common/RhodesApp.h"
#include "common/RhoStd.h"
#include "common/RhoConf.h"
#include "common/RhoFile.h"
#include "common/RhoDefs.h"
#include "common/Tokenizer.h"
#include "logging/RhoLogConf.h"
#include "generated/cpp/LogCaptureBase.h"

namespace rho {

    using namespace apiGenerator;
    using namespace common;

    class CLogCaptureImpl: public CLogCaptureSingletonBase, public ILogSink
    {
    public:

        CLogCaptureImpl(): CLogCaptureSingletonBase(), mMaxLines(1024), mTotalSize(0) {}
        virtual ~CLogCaptureImpl()
        {
            LOGCONF().removeAuxSink(this);
        }

        // ILogSink
        virtual void writeLogMessage( String& strMsg )
        {
            if ( mMaxLines > 0 )
            {
                if (mCapturedLog.size() > mMaxLines)
                {
                    mCapturedLog.clear();
                    mTotalSize = 0;
                }

                if (mExcludeCategories.size()>0)
                {
                    for(Vector<String>::const_iterator it = mExcludeCategories.begin(); it != mExcludeCategories.end(); ++it)
                    {
                        if (strMsg.find(*it)!=String::npos)
                        {
                            return;
                        }
                    }
                }
                mCapturedLog.push_back(strMsg);
                mTotalSize += strMsg.size() + 2;
            }
        }

        virtual int getCurPos()
        {
            return mCapturedLog.size();
        }

        virtual void clear()
        {

        }

        // ILogCaptureSingleto
        virtual void getExcludeCategories(rho::apiGenerator::CMethodResult& oResult)
        {
            const Vector<rho::String>& log_attr = mExcludeCategories;

            size_t len = 0;
            for(Vector<rho::String>::const_iterator iter = log_attr.begin(); iter != log_attr.end(); iter++)
            {
                len += (*iter).length() + 1; // including separator
            }

            rho::String str;
            str.reserve(len);

            for(Vector<rho::String>::const_iterator iter = log_attr.begin(); iter != log_attr.end(); iter++)
            {
                if (iter != log_attr.begin())
                {
                    str += ",";
                }
                str += *iter;
            }

            oResult.set( str );
        }

        virtual void setExcludeCategories( const rho::String& excludeCategories, rho::apiGenerator::CMethodResult& oResult)
        {
            if ( excludeCategories.length() > 0 )
            {
                rho::common::CTokenizer oTokenizer( excludeCategories, "," );
                while (oTokenizer.hasMoreTokens())
                {
                    String tok = rho::String_trim(oTokenizer.nextToken());
                    if (tok.length() == 0)
                        continue;

                    mExcludeCategories.addElement( tok );
                }
            }
            else
                mExcludeCategories.removeAllElements();
        }

        virtual void getMaxLines(rho::apiGenerator::CMethodResult& oResult)
        {
            oResult.set(mMaxLines);
        }

        virtual void setMaxLines( int maxLines, rho::apiGenerator::CMethodResult& oResult)
        {
            mMaxLines = maxLines;
        }

        virtual void start(rho::apiGenerator::CMethodResult& oResult)
        {
            LOGCONF().addAuxSink(this);
        }

        virtual void stop(rho::apiGenerator::CMethodResult& oResult)
        {
            LOGCONF().removeAuxSink(this);
        }

        virtual void clear(rho::apiGenerator::CMethodResult& oResult)
        {
            mCapturedLog.clear();
            mTotalSize = 0;
        }

        virtual void numLines(rho::apiGenerator::CMethodResult& oResult)
        {
            oResult.set( static_cast<int>(mCapturedLog.size()) );
        }

        virtual void read(rho::apiGenerator::CMethodResult& oResult)
        {
            String str;

            str.reserve(mTotalSize);
            for (Vector<String>::iterator it = mCapturedLog.begin(); it != mCapturedLog.end(); ++it )
            {
                str += *it;
                str += '\n';
            }

            oResult.set(str);
        }

    private:
        Vector<String> mCapturedLog;
        Vector<String> mExcludeCategories;
        int mMaxLines;
        size_t mTotalSize;
    };

    class CLogCaptureFactory: public CLogCaptureFactoryBase
    {
    public:
        ~CLogCaptureFactory(){}

        ILogCaptureSingleton* createModuleSingleton()
        {
            return new CLogCaptureImpl();
        }
    };
}

extern "C" void Init_LogCapture_extension()
{
    rho::CLogCaptureFactory::setInstance( new rho::CLogCaptureFactory() );
    rho::Init_LogCapture_API();
}
<|endoftext|>


<commit_before>#include <general/nmspc_tensor_extra.h>
// -- (textra first)
#include "ceres_subspace_functor.h"
#include <algorithms/class_algorithm_status.h>
#include <config/nmspc_settings.h>
#include <iostream>
#include <math/rnd.h>
#include <tensors/class_tensors_finite.h>
#include <tensors/model/class_model_finite.h>
#include <tensors/state/class_state_finite.h>
#include <tools/common/log.h>
#include <tools/common/prof.h>
#include <tools/finite/measure.h>
#include <tools/finite/opt_tensor.h>
using namespace tools::finite::opt;
using namespace tools::finite::opt::internal;

void tools::finite::opt::internal::subspace::filter_candidates(std::vector<opt_tensor> &candidate_list, double maximum_subspace_error, size_t max_accept) {
    // Sort the candidate list in order of descending overlaps. If the overlaps are the same, compare instead the distance in energy to the
    // current energy
    std::sort(candidate_list.begin(),candidate_list.end(), std::greater<>());
    size_t initial_size = candidate_list.size();
    size_t min_accept   = std::min(std::min(max_accept,32ul), candidate_list.size());
    max_accept          = std::min(max_accept, candidate_list.size());
    double subspace_error = subspace::get_subspace_error(candidate_list); // This number is as low as it gets now, and will start growing
    while(true){
        if(candidate_list.size() <= max_accept){
            if(candidate_list.size() <= min_accept) break;
            subspace_error = subspace::get_subspace_error(candidate_list);
            if(subspace_error >= maximum_subspace_error) break;
        }
       candidate_list.pop_back();
    }
    size_t idx = 0;
    for(auto & candidate : candidate_list){
        candidate.set_name(fmt::format("eigenvector {}", idx++));
//        tools::log->trace("Filtered {:<16}: overlap {:.16f} | energy {:>20.16f}", candidate.get_name(), candidate.get_overlap(),
//                          candidate.get_energy_per_site());
    }

    tools::log->trace("Filtered from {} down to {} states", initial_size, candidate_list.size());
    tools::log->trace("Subspace error after filter = {}", std::log10(subspace_error));
    if(candidate_list.size() < min_accept) throw std::runtime_error("Filtered too many candidates");
}

std::optional<size_t> tools::finite::opt::internal::subspace::get_idx_to_candidate_with_highest_overlap(const std::vector<opt_tensor> &candidate_list,
                                                                                double energy_llim_per_site, double energy_ulim_per_site) {
    if(candidate_list.empty()) return std::nullopt;
    auto   overlaps = get_overlaps(candidate_list);
    long idx      = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        if(candidate.get_energy_per_site() > energy_ulim_per_site) overlaps(idx) = 0.0;
        if(candidate.get_energy_per_site() < energy_llim_per_site) overlaps(idx) = 0.0;
        idx++;
    }
    // Now we have a list of overlaps where nonzero elements correspond do candidates inside the energy window
    // Get the index to the highest overlapping element
    double max_overlap_val = overlaps.maxCoeff(&idx);
    if(max_overlap_val == 0.0) {
        tools::log->debug("No overlapping eigenstates in given energy window {} to {}.", energy_llim_per_site, energy_ulim_per_site);
        return std::nullopt;
    }
    return idx;
}

std::vector<size_t> tools::finite::opt::internal::subspace::get_idx_to_candidates_with_highest_overlap(const std::vector<opt_tensor> &candidate_list, size_t max_candidates, double energy_llim_per_site,
                                                               double energy_ulim_per_site) {
    if(candidate_list.empty()) return std::vector<size_t>();
    auto   overlaps = get_overlaps(candidate_list);
    long idx      = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        if(candidate.get_energy_per_site() > energy_ulim_per_site) overlaps(idx) = 0.0;
        if(candidate.get_energy_per_site() < energy_llim_per_site) overlaps(idx) = 0.0;
        idx++;
    }
    // Now we have a list of overlaps where nonzero elements correspond do candidates inside the energy window
    // Get the index to the highest overlapping element
    double max_overlap_val = overlaps.maxCoeff();
    if(max_overlap_val == 0.0) {
        tools::log->debug("No overlapping eigenstates in given energy window {} to {}.", energy_llim_per_site, energy_ulim_per_site);
        return std::vector<size_t>();
    }

    std::vector<size_t> best_idx;
    std::vector<double> best_val;
    // We collect the best candidates from this list until the squared sum of their overlaps goes above a certain threshold.
    // Note that the squared sum overlap = 1 if the states in the list form a complete basis for the current state.
    while(true) {
        max_overlap_val = overlaps.maxCoeff(&idx);
        if(max_overlap_val == 0.0) break;
        best_idx.emplace_back(idx);
        const auto &candidate = *std::next(candidate_list.begin(), static_cast<long>(idx));
        if(candidate.is_basis_vector) best_val.emplace_back(max_overlap_val);
        if(best_idx.size() > max_candidates) break;
        double sq_sum_overlap = overlaps.cwiseAbs2().sum();
        if(sq_sum_overlap > 0.6) break;  // Half means cat state.
        overlaps(idx) = 0.0; // Zero out the current best so the next-best is found in the next iteration
    }
    tools::log->debug("Found {} candidates with good overlap in energy window", best_idx.size());
    return best_idx;
}

Eigen::MatrixXcd tools::finite::opt::internal::subspace::get_eigvecs(const std::vector<opt_tensor> &candidate_list) {
    long             rows = candidate_list.front().get_tensor().size();
    long             cols = static_cast<long>(candidate_list.size());
    Eigen::MatrixXcd eigvecs(rows, cols);
    long             idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        eigvecs.col(idx++) = Eigen::Map<const Eigen::VectorXcd>(candidate.get_tensor().data(), rows);
    }
    eigvecs.conservativeResize(rows, idx);
    return eigvecs;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_eigvals(const std::vector<opt_tensor> &candidate_list) {
    long            size = static_cast<long>(candidate_list.size());
    Eigen::VectorXd eigvals(size);
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        eigvals(idx++) = candidate.get_eigval();
    }
    eigvals.conservativeResize(idx);
    return eigvals;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_energies(const std::vector<opt_tensor> &candidate_list) {
    Eigen::VectorXd energies(static_cast<long>(candidate_list.size()));
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        energies(idx++) = candidate.get_energy();
    }
    energies.conservativeResize(idx);
    return energies;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_energies_per_site(const std::vector<opt_tensor> &candidate_list) {
    Eigen::VectorXd energies(static_cast<long>(candidate_list.size()));
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        energies(idx++) = candidate.get_energy_per_site();
    }
    energies.conservativeResize(idx);
    return energies;
}

double tools::finite::opt::internal::subspace::get_subspace_error(const std::vector<opt_tensor> &candidate_list) {
    double eps = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        eps += std::pow(candidate.get_overlap(), 2);
    }
    return 1.0 - eps;
}

double tools::finite::opt::internal::subspace::get_subspace_error(const std::vector<double> &overlaps) {
    double eps = 0;
    for(const auto &overlap : overlaps) {
        eps += std::pow(overlap, 2);
    }
    return 1.0 - eps;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_overlaps(const std::vector<opt_tensor> &candidate_list) {
    Eigen::VectorXd overlaps(static_cast<long>(candidate_list.size()));
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        overlaps(idx++) = candidate.get_overlap();
    }
    overlaps.conservativeResize(idx);
    return overlaps;
}

std::pair<double, size_t> find_max_overlap(const std::vector<double> &overlaps) {
    auto max_it  = max_element(overlaps.begin(), overlaps.end());
    auto max_val = *max_it;
    auto max_idx = std::distance(overlaps.begin(), max_it);
    return {max_val, static_cast<size_t>(max_idx)};
}

Eigen::VectorXcd tools::finite::opt::internal::subspace::get_vector_in_subspace(const std::vector<opt_tensor> &candidate_list, size_t idx) {
    // In this function we project a vector to the subspace spanned by a small set of eigenvectors
    // Essentially this old computation
    //      Eigen::VectorXcd subspace_vector = (eigvecs.adjoint() * fullspace_vector).normalized();

    auto             fullspace_vector = std::next(candidate_list.begin(), static_cast<long>(idx))->get_vector();
    long             subspace_size    = static_cast<long>(candidate_list.size());
    Eigen::VectorXcd subspace_vector(subspace_size);
    long             subspace_idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        subspace_vector(subspace_idx++) = candidate.get_vector().dot(fullspace_vector);
    }
    subspace_vector.conservativeResize(subspace_idx);
    return subspace_vector.normalized();
}

Eigen::VectorXcd tools::finite::opt::internal::subspace::get_vector_in_subspace(const std::vector<opt_tensor> &candidate_list, const Eigen::VectorXcd & fullspace_vector) {
    // In this function we project a vector to the subspace spanned by a small set of eigenvectors
    // Essentially this old computation
    //      Eigen::VectorXcd subspace_vector = (eigvecs.adjoint() * fullspace_vector).normalized();
    long             subspace_size    = static_cast<long>(candidate_list.size());
    Eigen::VectorXcd subspace_vector(subspace_size);
    long             subspace_idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        subspace_vector(subspace_idx++) = candidate.get_vector().adjoint() * fullspace_vector;
    }
    subspace_vector.conservativeResize(subspace_idx);
    return subspace_vector.normalized();
}

Eigen::VectorXcd tools::finite::opt::internal::subspace::get_vector_in_fullspace(const std::vector<opt_tensor> &candidate_list,
                                                                                const Eigen::VectorXcd & subspace_vector) {
    // In this function we project a subspace vector back to the full space
    // Essentially this old computation
    //     Eigen::VectorXcd fullspace_vector = (eigvecs * subspace_vector.asDiagonal()).rowwise().sum().normalized();
    //
    // The subspace_vector is a list of weights corresponding to each eigenvector that we use to form a linear combination.
    // Therefore all we need to do to obtain the fullspace vector is to actually add up the linear combination with those weights.

    long             fullspace_size = candidate_list.front().get_vector().size();
    Eigen::VectorXcd fullspace_vector(fullspace_size);
    fullspace_vector.setZero();
    long subspace_idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        fullspace_vector += candidate.get_vector() * subspace_vector(subspace_idx++);
    }
    return fullspace_vector.normalized();
}
<commit_msg>Use dot product instead of adjoint. Some compilers don't seem to like the implicit conversion to double when using adjoint()<commit_after>#include <general/nmspc_tensor_extra.h>
// -- (textra first)
#include "ceres_subspace_functor.h"
#include <algorithms/class_algorithm_status.h>
#include <config/nmspc_settings.h>
#include <iostream>
#include <math/rnd.h>
#include <tensors/class_tensors_finite.h>
#include <tensors/model/class_model_finite.h>
#include <tensors/state/class_state_finite.h>
#include <tools/common/log.h>
#include <tools/common/prof.h>
#include <tools/finite/measure.h>
#include <tools/finite/opt_tensor.h>
using namespace tools::finite::opt;
using namespace tools::finite::opt::internal;

void tools::finite::opt::internal::subspace::filter_candidates(std::vector<opt_tensor> &candidate_list, double maximum_subspace_error, size_t max_accept) {
    // Sort the candidate list in order of descending overlaps. If the overlaps are the same, compare instead the distance in energy to the
    // current energy
    std::sort(candidate_list.begin(),candidate_list.end(), std::greater<>());
    size_t initial_size = candidate_list.size();
    size_t min_accept   = std::min(std::min(max_accept,32ul), candidate_list.size());
    max_accept          = std::min(max_accept, candidate_list.size());
    double subspace_error = subspace::get_subspace_error(candidate_list); // This number is as low as it gets now, and will start growing
    while(true){
        if(candidate_list.size() <= max_accept){
            if(candidate_list.size() <= min_accept) break;
            subspace_error = subspace::get_subspace_error(candidate_list);
            if(subspace_error >= maximum_subspace_error) break;
        }
       candidate_list.pop_back();
    }
    size_t idx = 0;
    for(auto & candidate : candidate_list){
        candidate.set_name(fmt::format("eigenvector {}", idx++));
//        tools::log->trace("Filtered {:<16}: overlap {:.16f} | energy {:>20.16f}", candidate.get_name(), candidate.get_overlap(),
//                          candidate.get_energy_per_site());
    }

    tools::log->trace("Filtered from {} down to {} states", initial_size, candidate_list.size());
    tools::log->trace("Subspace error after filter = {}", std::log10(subspace_error));
    if(candidate_list.size() < min_accept) throw std::runtime_error("Filtered too many candidates");
}

std::optional<size_t> tools::finite::opt::internal::subspace::get_idx_to_candidate_with_highest_overlap(const std::vector<opt_tensor> &candidate_list,
                                                                                double energy_llim_per_site, double energy_ulim_per_site) {
    if(candidate_list.empty()) return std::nullopt;
    auto   overlaps = get_overlaps(candidate_list);
    long idx      = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        if(candidate.get_energy_per_site() > energy_ulim_per_site) overlaps(idx) = 0.0;
        if(candidate.get_energy_per_site() < energy_llim_per_site) overlaps(idx) = 0.0;
        idx++;
    }
    // Now we have a list of overlaps where nonzero elements correspond do candidates inside the energy window
    // Get the index to the highest overlapping element
    double max_overlap_val = overlaps.maxCoeff(&idx);
    if(max_overlap_val == 0.0) {
        tools::log->debug("No overlapping eigenstates in given energy window {} to {}.", energy_llim_per_site, energy_ulim_per_site);
        return std::nullopt;
    }
    return idx;
}

std::vector<size_t> tools::finite::opt::internal::subspace::get_idx_to_candidates_with_highest_overlap(const std::vector<opt_tensor> &candidate_list, size_t max_candidates, double energy_llim_per_site,
                                                               double energy_ulim_per_site) {
    if(candidate_list.empty()) return std::vector<size_t>();
    auto   overlaps = get_overlaps(candidate_list);
    long idx      = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        if(candidate.get_energy_per_site() > energy_ulim_per_site) overlaps(idx) = 0.0;
        if(candidate.get_energy_per_site() < energy_llim_per_site) overlaps(idx) = 0.0;
        idx++;
    }
    // Now we have a list of overlaps where nonzero elements correspond do candidates inside the energy window
    // Get the index to the highest overlapping element
    double max_overlap_val = overlaps.maxCoeff();
    if(max_overlap_val == 0.0) {
        tools::log->debug("No overlapping eigenstates in given energy window {} to {}.", energy_llim_per_site, energy_ulim_per_site);
        return std::vector<size_t>();
    }

    std::vector<size_t> best_idx;
    std::vector<double> best_val;
    // We collect the best candidates from this list until the squared sum of their overlaps goes above a certain threshold.
    // Note that the squared sum overlap = 1 if the states in the list form a complete basis for the current state.
    while(true) {
        max_overlap_val = overlaps.maxCoeff(&idx);
        if(max_overlap_val == 0.0) break;
        best_idx.emplace_back(idx);
        const auto &candidate = *std::next(candidate_list.begin(), static_cast<long>(idx));
        if(candidate.is_basis_vector) best_val.emplace_back(max_overlap_val);
        if(best_idx.size() > max_candidates) break;
        double sq_sum_overlap = overlaps.cwiseAbs2().sum();
        if(sq_sum_overlap > 0.6) break;  // Half means cat state.
        overlaps(idx) = 0.0; // Zero out the current best so the next-best is found in the next iteration
    }
    tools::log->debug("Found {} candidates with good overlap in energy window", best_idx.size());
    return best_idx;
}

Eigen::MatrixXcd tools::finite::opt::internal::subspace::get_eigvecs(const std::vector<opt_tensor> &candidate_list) {
    long             rows = candidate_list.front().get_tensor().size();
    long             cols = static_cast<long>(candidate_list.size());
    Eigen::MatrixXcd eigvecs(rows, cols);
    long             idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        eigvecs.col(idx++) = Eigen::Map<const Eigen::VectorXcd>(candidate.get_tensor().data(), rows);
    }
    eigvecs.conservativeResize(rows, idx);
    return eigvecs;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_eigvals(const std::vector<opt_tensor> &candidate_list) {
    long            size = static_cast<long>(candidate_list.size());
    Eigen::VectorXd eigvals(size);
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        eigvals(idx++) = candidate.get_eigval();
    }
    eigvals.conservativeResize(idx);
    return eigvals;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_energies(const std::vector<opt_tensor> &candidate_list) {
    Eigen::VectorXd energies(static_cast<long>(candidate_list.size()));
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        energies(idx++) = candidate.get_energy();
    }
    energies.conservativeResize(idx);
    return energies;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_energies_per_site(const std::vector<opt_tensor> &candidate_list) {
    Eigen::VectorXd energies(static_cast<long>(candidate_list.size()));
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        energies(idx++) = candidate.get_energy_per_site();
    }
    energies.conservativeResize(idx);
    return energies;
}

double tools::finite::opt::internal::subspace::get_subspace_error(const std::vector<opt_tensor> &candidate_list) {
    double eps = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        eps += std::pow(candidate.get_overlap(), 2);
    }
    return 1.0 - eps;
}

double tools::finite::opt::internal::subspace::get_subspace_error(const std::vector<double> &overlaps) {
    double eps = 0;
    for(const auto &overlap : overlaps) {
        eps += std::pow(overlap, 2);
    }
    return 1.0 - eps;
}

Eigen::VectorXd tools::finite::opt::internal::subspace::get_overlaps(const std::vector<opt_tensor> &candidate_list) {
    Eigen::VectorXd overlaps(static_cast<long>(candidate_list.size()));
    long            idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        overlaps(idx++) = candidate.get_overlap();
    }
    overlaps.conservativeResize(idx);
    return overlaps;
}

std::pair<double, size_t> find_max_overlap(const std::vector<double> &overlaps) {
    auto max_it  = max_element(overlaps.begin(), overlaps.end());
    auto max_val = *max_it;
    auto max_idx = std::distance(overlaps.begin(), max_it);
    return {max_val, static_cast<size_t>(max_idx)};
}

Eigen::VectorXcd tools::finite::opt::internal::subspace::get_vector_in_subspace(const std::vector<opt_tensor> &candidate_list, size_t idx) {
    // In this function we project a vector to the subspace spanned by a small set of eigenvectors
    // Essentially this old computation
    //      Eigen::VectorXcd subspace_vector = (eigvecs.adjoint() * fullspace_vector).normalized();

    auto             fullspace_vector = std::next(candidate_list.begin(), static_cast<long>(idx))->get_vector();
    long             subspace_size    = static_cast<long>(candidate_list.size());
    Eigen::VectorXcd subspace_vector(subspace_size);
    long             subspace_idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        subspace_vector(subspace_idx++) = candidate.get_vector().dot(fullspace_vector);
    }
    subspace_vector.conservativeResize(subspace_idx);
    return subspace_vector.normalized();
}

Eigen::VectorXcd tools::finite::opt::internal::subspace::get_vector_in_subspace(const std::vector<opt_tensor> &candidate_list, const Eigen::VectorXcd & fullspace_vector) {
    // In this function we project a vector to the subspace spanned by a small set of eigenvectors
    // Essentially this old computation
    //      Eigen::VectorXcd subspace_vector = (eigvecs.adjoint() * fullspace_vector).normalized();
    long             subspace_size    = static_cast<long>(candidate_list.size());
    Eigen::VectorXcd subspace_vector(subspace_size);
    long             subspace_idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        subspace_vector(subspace_idx++) = candidate.get_vector().dot(fullspace_vector);
    }
    subspace_vector.conservativeResize(subspace_idx);
    return subspace_vector.normalized();
}

Eigen::VectorXcd tools::finite::opt::internal::subspace::get_vector_in_fullspace(const std::vector<opt_tensor> &candidate_list,
                                                                                const Eigen::VectorXcd & subspace_vector) {
    // In this function we project a subspace vector back to the full space
    // Essentially this old computation
    //     Eigen::VectorXcd fullspace_vector = (eigvecs * subspace_vector.asDiagonal()).rowwise().sum().normalized();
    //
    // The subspace_vector is a list of weights corresponding to each eigenvector that we use to form a linear combination.
    // Therefore all we need to do to obtain the fullspace vector is to actually add up the linear combination with those weights.

    long             fullspace_size = candidate_list.front().get_vector().size();
    Eigen::VectorXcd fullspace_vector(fullspace_size);
    fullspace_vector.setZero();
    long subspace_idx = 0;
    for(const auto &candidate : candidate_list) {
        if(not candidate.is_basis_vector) continue;
        fullspace_vector += candidate.get_vector() * subspace_vector(subspace_idx++);
    }
    return fullspace_vector.normalized();
}
<|endoftext|>