<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.6  2001/05/11 13:26:16  tng
 * Copyright update.
 *
 * Revision 1.5  2001/03/21 21:56:04  tng
 * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
 *
 * Revision 1.4  2001/02/26 19:44:14  tng
 * Schema: add utility class QName, by Pei Yong Zhang.
 *
 * Revision 1.3  2000/11/02 01:14:07  andyh
 * SAX bug fix:  Attribute lists were throwing exceptions rather than returning
 * null when an attribute could not be found by name.  Fixed by Tinny Ng.
 *
 * Revision 1.2  2000/08/09 22:11:16  jpolast
 * changes to allow const instances of the sax2
 * Attributes class.
 *
 * Revision 1.1  2000/08/02 18:09:14  jpolast
 * initial checkin: attributes vector needed for
 * Attributes class as defined by sax2 spec
 *
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/Janitor.hpp>
#include <internal/VecAttributesImpl.hpp>

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
VecAttributesImpl::VecAttributesImpl() :

    fAdopt(false)
    , fCount(0)
    , fVector(0)
    , fScanner(0)
{
}

VecAttributesImpl::~VecAttributesImpl()
{
    //
    //  Note that some compilers can't deal with the fact that the pointer
    //  is to a const object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;
}

// ---------------------------------------------------------------------------
//  Implementation of the attribute list interface
// ---------------------------------------------------------------------------
unsigned int VecAttributesImpl::getLength() const
{
    return fCount;
}

const XMLCh* VecAttributesImpl::getURI(const unsigned int index) const
{
    // since this func really needs to be const, like the rest, not sure how we
    // make it const and re-use the fURIBuffer member variable.  we're currently
    // creating a buffer each time you need a URI.  there has to be a better
    // way to do this...

    //XMLBuffer tempBuf;
    if (index >= fCount) {

        return 0;
     }
    //fValidator->getURIText(fVector->elementAt(index)->getURIId(), tempBuf) ;
    //return tempBuf.getRawBuffer() ;
    return fScanner->getURIText(fVector->elementAt(index)->getURIId());
}

const XMLCh* VecAttributesImpl::getLocalName(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return fVector->elementAt(index)->getName();
}

const XMLCh* VecAttributesImpl::getQName(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return fVector->elementAt(index)->getQName();
}

const XMLCh* VecAttributesImpl::getType(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return XMLAttDef::getAttTypeString(fVector->elementAt(index)->getType());
}

const XMLCh* VecAttributesImpl::getValue(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return fVector->elementAt(index)->getValue();
}

int VecAttributesImpl::getIndex(const XMLCh* const uri, const XMLCh* const localPart ) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    XMLBuffer uriBuffer ;
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        fScanner->getURIText(curElem->getURIId(), uriBuffer) ;

        if ( (!XMLString::compareString(curElem->getName(), localPart)) &&
             (!XMLString::compareString(uriBuffer.getRawBuffer(), uri)) )
            return index ;
    }
    return -1;
}

int VecAttributesImpl::getIndex(const XMLCh* const qName ) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getQName(), qName))
            return index ;
    }
    return -1;
}

const XMLCh* VecAttributesImpl::getType(const XMLCh* const uri, const XMLCh* const localPart ) const
{
    return getType(getIndex(uri, localPart)) ;
}

const XMLCh* VecAttributesImpl::getType(const XMLCh* const qName) const
{
    return getType(getIndex(qName)) ;
}

const XMLCh* VecAttributesImpl::getValue(const XMLCh* const uri, const XMLCh* const localPart ) const
{
    return getValue(getIndex(uri, localPart)) ;
}

const XMLCh* VecAttributesImpl::getValue(const XMLCh* const qName) const
{
    return getValue(getIndex(qName)) ;
}

// ---------------------------------------------------------------------------
//  Setter methods
// ---------------------------------------------------------------------------
void VecAttributesImpl::setVector(const   RefVectorOf<XMLAttr>* const srcVec
                                , const unsigned int                count
                                , const XMLScanner * const        scanner
                                , const bool                        adopt)
{
    //
    //  Delete the previous vector (if any) if we are adopting. Note that some
    //  compilers can't deal with the fact that the pointer is to a const
    //  object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;

    fAdopt = adopt;
    fCount = count;
    fVector = srcVec;
    fScanner = scanner ;
}

<commit_msg>[BUG# 3831]: -1 returned from getIndex() needs to be checked<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.7  2001/10/05 17:57:39  peiyongz
 * [BUG# 3831]: -1 returned from getIndex() needs to be checked
 *
 * Revision 1.6  2001/05/11 13:26:16  tng
 * Copyright update.
 *
 * Revision 1.5  2001/03/21 21:56:04  tng
 * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
 *
 * Revision 1.4  2001/02/26 19:44:14  tng
 * Schema: add utility class QName, by Pei Yong Zhang.
 *
 * Revision 1.3  2000/11/02 01:14:07  andyh
 * SAX bug fix:  Attribute lists were throwing exceptions rather than returning
 * null when an attribute could not be found by name.  Fixed by Tinny Ng.
 *
 * Revision 1.2  2000/08/09 22:11:16  jpolast
 * changes to allow const instances of the sax2
 * Attributes class.
 *
 * Revision 1.1  2000/08/02 18:09:14  jpolast
 * initial checkin: attributes vector needed for
 * Attributes class as defined by sax2 spec
 *
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/Janitor.hpp>
#include <internal/VecAttributesImpl.hpp>

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
VecAttributesImpl::VecAttributesImpl() :

    fAdopt(false)
    , fCount(0)
    , fVector(0)
    , fScanner(0)
{
}

VecAttributesImpl::~VecAttributesImpl()
{
    //
    //  Note that some compilers can't deal with the fact that the pointer
    //  is to a const object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;
}

// ---------------------------------------------------------------------------
//  Implementation of the attribute list interface
// ---------------------------------------------------------------------------
unsigned int VecAttributesImpl::getLength() const
{
    return fCount;
}

const XMLCh* VecAttributesImpl::getURI(const unsigned int index) const
{
    // since this func really needs to be const, like the rest, not sure how we
    // make it const and re-use the fURIBuffer member variable.  we're currently
    // creating a buffer each time you need a URI.  there has to be a better
    // way to do this...

    //XMLBuffer tempBuf;
    if (index >= fCount) {

        return 0;
     }
    //fValidator->getURIText(fVector->elementAt(index)->getURIId(), tempBuf) ;
    //return tempBuf.getRawBuffer() ;
    return fScanner->getURIText(fVector->elementAt(index)->getURIId());
}

const XMLCh* VecAttributesImpl::getLocalName(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return fVector->elementAt(index)->getName();
}

const XMLCh* VecAttributesImpl::getQName(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return fVector->elementAt(index)->getQName();
}

const XMLCh* VecAttributesImpl::getType(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return XMLAttDef::getAttTypeString(fVector->elementAt(index)->getType());
}

const XMLCh* VecAttributesImpl::getValue(const unsigned int index) const
{
    if (index >= fCount) {
        return 0;
     }
    return fVector->elementAt(index)->getValue();
}

int VecAttributesImpl::getIndex(const XMLCh* const uri, const XMLCh* const localPart ) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    XMLBuffer uriBuffer ;
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        fScanner->getURIText(curElem->getURIId(), uriBuffer) ;

        if ( (!XMLString::compareString(curElem->getName(), localPart)) &&
             (!XMLString::compareString(uriBuffer.getRawBuffer(), uri)) )
            return index ;
    }
    return -1;
}

int VecAttributesImpl::getIndex(const XMLCh* const qName ) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getQName(), qName))
            return index ;
    }
    return -1;
}

const XMLCh* VecAttributesImpl::getType(const XMLCh* const uri, const XMLCh* const localPart ) const
{
    int retVal = getIndex(uri, localPart);
    return ((retVal < 0) ? 0 : getType(retVal));
}

const XMLCh* VecAttributesImpl::getType(const XMLCh* const qName) const
{
    int retVal = getIndex(qName);
    return ((retVal < 0) ? 0 : getType(retVal));
}

const XMLCh* VecAttributesImpl::getValue(const XMLCh* const uri, const XMLCh* const localPart ) const
{
    int retVal = getIndex(uri, localPart);
    return ((retVal < 0) ? 0 : getValue(retVal));
}

const XMLCh* VecAttributesImpl::getValue(const XMLCh* const qName) const
{
    int retVal = getIndex(qName);
    return ((retVal < 0) ? 0 : getValue(retVal));
}

// ---------------------------------------------------------------------------
//  Setter methods
// ---------------------------------------------------------------------------
void VecAttributesImpl::setVector(const   RefVectorOf<XMLAttr>* const srcVec
                                , const unsigned int                count
                                , const XMLScanner * const        scanner
                                , const bool                        adopt)
{
    //
    //  Delete the previous vector (if any) if we are adopting. Note that some
    //  compilers can't deal with the fact that the pointer is to a const
    //  object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;

    fAdopt = adopt;
    fCount = count;
    fVector = srcVec;
    fScanner = scanner ;
}

<|endoftext|>


<commit_before>#include "convergence/moments/convergence_checker_l1_norm.hpp"

namespace bart::convergence::moments {

ConvergenceCheckerL1Norm::ConvergenceCheckerL1Norm(const double max_delta) {
  max_delta_ = max_delta;
}

bool ConvergenceCheckerL1Norm::IsConverged(const Vector& current_iteration, const Vector& previous_iteration) {
  Vector difference(current_iteration);
  difference -= previous_iteration;
  delta_ = difference.l1_norm()/current_iteration.l1_norm();
  is_converged_ = delta_ <= max_delta_;
  return is_converged_;
}

auto ConvergenceCheckerL1Norm::SetMaxDelta(const double &to_set) -> void {
  AssertThrow(to_set > 0, dealii::ExcMessage("Error in ConvergenceCheckerL1Norm::SetMaxDelta, value to set must be "
                                             "greater than 0"))
  this->SetMaxDelta(to_set);
}

} // namespace bart::convergence::moments<commit_msg>Removed incorrect call to this in ConvergenceCheckerL1Norm::SetMaxDelta.<commit_after>#include "convergence/moments/convergence_checker_l1_norm.hpp"

namespace bart::convergence::moments {

ConvergenceCheckerL1Norm::ConvergenceCheckerL1Norm(const double max_delta) {
  max_delta_ = max_delta;
}

bool ConvergenceCheckerL1Norm::IsConverged(const Vector& current_iteration, const Vector& previous_iteration) {
  Vector difference(current_iteration);
  difference -= previous_iteration;
  delta_ = difference.l1_norm()/current_iteration.l1_norm();
  is_converged_ = delta_ <= max_delta_;
  return is_converged_;
}

auto ConvergenceCheckerL1Norm::SetMaxDelta(const double &to_set) -> void {
  AssertThrow(to_set > 0, dealii::ExcMessage("Error in ConvergenceCheckerL1Norm::SetMaxDelta, value to set must be "
                                             "greater than 0"))
  this->max_delta_ = to_set;
}

} // namespace bart::convergence::moments<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"
#include "dynamic_string.h"
#include "lua_resource.h"
#include "os.h"
#include "temp_allocator.h"
#include "array.h"
#include "compile_options.h"

#if CROWN_DEBUG
	#define LUAJIT_FLAGS "-bg" // Keep debug info
#else
	#define LUAJIT_FLAGS "-b"
#endif // CROWN_DEBUG

namespace crown
{
namespace lua_resource
{
	void compile(const char* path, CompileOptions& opts)
	{
		TempAllocator1024 alloc;
		DynamicString res_abs_path(alloc);
		TempAllocator1024 alloc2;
		DynamicString bc_abs_path(alloc2);
		opts.get_absolute_path(path, res_abs_path);
		opts.get_absolute_path("bc.tmp", bc_abs_path);

		const char* luajit[] =
		{
#if CROWN_PLATFORM_LINUX
			"./luajit",
#else
			"luajit.exe",
#endif // CROWN_PLATFORM_LINUX
			LUAJIT_FLAGS,
			res_abs_path.c_str(),
			bc_abs_path.c_str(),
			NULL
		};

		int exitcode = os::execute_process(luajit);
		CE_ASSERT(exitcode == 0, "Failed to compile lua");

		Buffer blob = opts.read(bc_abs_path.c_str());
		opts.delete_file(bc_abs_path.c_str());

		LuaResource lr;
		lr.version = SCRIPT_VERSION;
		lr.size = array::size(blob);

		opts.write(lr.version);
		opts.write(lr.size);
		opts.write(blob);
	}

	void* load(File& file, Allocator& a)
	{
		const uint32_t file_size = file.size();
		void* res = a.allocate(file_size);
		file.read(res, file_size);
		CE_ASSERT(*(uint32_t*)res == SCRIPT_VERSION, "Wrong version");
		return res;
	}

	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
	{
	}

	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
	{
	}

	void unload(Allocator& allocator, void* resource)
	{
		allocator.deallocate(resource);
	}

	uint32_t size(const LuaResource* lr)
	{
		return lr->size;
	}

	const char* program(const LuaResource* lr)
	{
		return (char*)lr + sizeof(LuaResource);
	}
} // namespace lua_resource
} // namespace crown
<commit_msg>Cleanup<commit_after>/*
 * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"
#include "dynamic_string.h"
#include "lua_resource.h"
#include "os.h"
#include "temp_allocator.h"
#include "array.h"
#include "compile_options.h"

#define LUAJIT_NAME "luajit"

#if CROWN_PLATFORM_WINDOWS
	#define EXE ".exe"
#else
 	#define EXE ""
#endif // CROWN_PLATFORM_WINDOWS

#define LUAJIT_EXE LUAJIT_NAME EXE

#if CROWN_DEBUG
	#define LUAJIT_FLAGS "-bg" // Keep debug info
#else
	#define LUAJIT_FLAGS "-b"
#endif // CROWN_DEBUG

namespace crown
{
namespace lua_resource
{
	void compile(const char* path, CompileOptions& opts)
	{
		TempAllocator1024 alloc;
		DynamicString res_abs_path(alloc);
		TempAllocator1024 alloc2;
		DynamicString bc_abs_path(alloc2);
		opts.get_absolute_path(path, res_abs_path);
		opts.get_absolute_path("bc.tmp", bc_abs_path);

		const char* luajit[] =
		{
			LUAJIT_EXE,
			LUAJIT_FLAGS,
			res_abs_path.c_str(),
			bc_abs_path.c_str(),
			NULL
		};

		int exitcode = os::execute_process(luajit);
		CE_ASSERT(exitcode == 0, "Failed to compile lua");

		Buffer blob = opts.read(bc_abs_path.c_str());
		opts.delete_file(bc_abs_path.c_str());

		LuaResource lr;
		lr.version = SCRIPT_VERSION;
		lr.size = array::size(blob);

		opts.write(lr.version);
		opts.write(lr.size);
		opts.write(blob);
	}

	void* load(File& file, Allocator& a)
	{
		const uint32_t file_size = file.size();
		void* res = a.allocate(file_size);
		file.read(res, file_size);
		CE_ASSERT(*(uint32_t*)res == SCRIPT_VERSION, "Wrong version");
		return res;
	}

	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
	{
	}

	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
	{
	}

	void unload(Allocator& allocator, void* resource)
	{
		allocator.deallocate(resource);
	}

	uint32_t size(const LuaResource* lr)
	{
		return lr->size;
	}

	const char* program(const LuaResource* lr)
	{
		return (char*)lr + sizeof(LuaResource);
	}
} // namespace lua_resource
} // namespace crown
<|endoftext|>


<commit_before>/*************************************************
* HMAC_RNG Source File                           *
* (C) 2008 Jack Lloyd                            *
*************************************************/

#include <botan/hmac_rng.h>
#include <botan/entropy.h>
#include <botan/loadstor.h>
#include <botan/xor_buf.h>
#include <botan/util.h>
#include <botan/bit_ops.h>
#include <botan/stl_util.h>
#include <algorithm>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode* prf,
            MemoryRegion<byte>& K,
            u32bit& counter,
            const std::string& label)
   {
   prf->update(K, K.size());
   prf->update(label);
   for(u32bit i = 0; i != 4; ++i)
      prf->update(get_byte(i, counter));
   prf->final(K);

   ++counter;
   }

}

/*************************************************
* Generate a buffer of random bytes              *
*************************************************/
void HMAC_RNG::randomize(byte out[], u32bit length)
   {
   /* Attempt to seed if we are either unseeded or have generated
      enouch counters that it seems wise to roll over keys */
   if(!is_seeded() || counter >= 16 * 1024)
      {
      reseed();

      if(!is_seeded())
         throw PRNG_Unseeded(name() + " seeding attempt failed");
      }

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(prf, K, counter, "rng");

      const u32bit copied = std::min(K.size(), length);

      copy_mem(out, K.begin(), copied);
      out += copied;
      length -= copied;
      }

   hmac_prf(prf, K, counter, "rng");

   /* Every once in a while do a fast poll of a entropy source */
   if(entropy_sources.size() && (counter % 1024 == 0))
      {
      u32bit got = entropy_sources.at(source_index)->fast_poll(io_buffer, io_buffer.size());
      source_index = (source_index + 1) % entropy_sources.size();
      extractor->update(io_buffer, got);
      }
   }

/**
* Reseed the internal state, also accepting user input to include
*/
void HMAC_RNG::reseed_with_input(const byte input[], u32bit input_length)
   {
   Entropy_Estimator estimate;

   if(entropy_sources.size())
      {
      /**
      Using the terminology of E-t-E, XTR is the MAC function (normally
      HMAC) seeded with XTS (below) and we form SKM, the key material, by
      fast polling each source, and then slow polling as many as we think
      we need (in the following loop), and feeding all of the poll
      results, along with any optional user input, along with, finally,
      feedback of the current PRK value, into the extractor function.
      */

      for(u32bit j = 0; j < entropy_sources.size(); ++j)
         {
         u32bit got = entropy_sources[j]->fast_poll(io_buffer, io_buffer.size());
         extractor->update(io_buffer, got);
         estimate.update(io_buffer, got, 96);
         }

      /* Limit assumed entropy from fast polls (to ensure we do at
         least a few slow polls) */
      estimate.set_upper_bound(256);

      /* Then do a slow poll, until we think we have got enough entropy
      */
      for(u32bit j = 0; j != entropy_sources.size(); ++j)
         {
         u32bit got = entropy_sources[j]->slow_poll(io_buffer, io_buffer.size());

         extractor->update(io_buffer, got);
         estimate.update(io_buffer, got, 256);

         if(estimate.value() > 8 * extractor->OUTPUT_LENGTH)
            break;
         }
      }

   /*
   And now add the user-provided input, if any
   */
   if(input_length)
      {
      extractor->update(input, input_length);
      estimate.update(input, input_length);
      }

   /*
   It is necessary to feed forward poll data. Otherwise, a good
   poll (collecting a large amount of conditional entropy) followed
   by a bad one (collecting little) would be unsafe. Do this by
   generating new PRF outputs using the previous key and feeding them
   into the extractor function.

   Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output
   using the CTXinfo "reseed". Provide these values as input to the
   extractor function.
   */
   hmac_prf(prf, K, counter, "rng");
   extractor->update(K); // K is the CTXinfo=rng PRF output

   hmac_prf(prf, K, counter, "reseed");
   extractor->update(K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into the extractor,
      and set the PRF key to that*/
   prf->set_key(extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(prf, K, counter, "xts");
   extractor->set_key(K, K.size());

   // Reset state
   K.clear();
   counter = 0;

   // Increase entropy estimate (for is_seeded)
   entropy = std::min<u32bit>(entropy + estimate.value(),
                              8 * extractor->OUTPUT_LENGTH);
   }

/**
* Reseed the internal state
*/
void HMAC_RNG::reseed()
   {
   reseed_with_input(0, 0);
   }

/**
Add user-supplied entropy by reseeding and including this
input among the poll data
*/
void HMAC_RNG::add_entropy(const byte input[], u32bit length)
   {
   reseed_with_input(input, length);
   }

/*************************************************
* Add another entropy source to the list         *
*************************************************/
void HMAC_RNG::add_entropy_source(EntropySource* src)
   {
   entropy_sources.push_back(src);
   }

/*************************************************
* Check if the the pool is seeded                *
*************************************************/
bool HMAC_RNG::is_seeded() const
   {
   return (entropy >= 8 * prf->OUTPUT_LENGTH);
   }

 /*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void HMAC_RNG::clear() throw()
   {
   extractor->clear();
   prf->clear();
   K.clear();
   entropy = 0;
   counter = 0;
   source_index = 0;
   }

/*************************************************
* Return the name of this type                   *
*************************************************/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")";
   }

/*************************************************
* HMAC_RNG Constructor                           *
*************************************************/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac,
                   MessageAuthenticationCode* prf_mac) :
   extractor(extractor_mac), prf(prf_mac), io_buffer(128)
   {
   entropy = 0;

   // First PRF inputs are all zero, as specified in section 2
   K.create(prf->OUTPUT_LENGTH);
   counter = 0;
   source_index = 0;

   /*
   Normally we want to feedback PRF output into the input to the
   extractor function to ensure a single bad poll does not damage the
   RNG, but obviously that is meaningless to do on the first poll.

   We will want to use the PRF before we set the first key (in
   reseed_with_input), and it is a pain to keep track if it is set or
   not. Since the first time it doesn't matter anyway, just set it to
   a constant: randomize() will not produce output unless is_seeded()
   returns true, and that will only be the case if the estimated
   entropy counter is high enough. That variable is only set when a
   reseeding is performed.
   */
   std::string prf_key = "Botan HMAC_RNG PRF";
   prf->set_key(reinterpret_cast<const byte*>(prf_key.c_str()),
                prf_key.length());

   /*
   This will be used as the first XTS value when extracting input.
   XTS values after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   std::string xts = "Botan HMAC_RNG XTS";
   extractor->set_key(reinterpret_cast<const byte*>(xts.c_str()),
                      xts.length());
   }

/*************************************************
* HMAC_RNG Destructor                            *
*************************************************/
HMAC_RNG::~HMAC_RNG()
   {
   delete extractor;
   delete prf;

   std::for_each(entropy_sources.begin(), entropy_sources.end(),
                 del_fun<EntropySource>());

   entropy = 0;
   counter = 0;
   }

}
<commit_msg>Several changes to HMAC_RNG, many on the basis of the paper<commit_after>/*************************************************
* HMAC_RNG Source File                           *
* (C) 2008 Jack Lloyd                            *
*************************************************/

#include <botan/hmac_rng.h>
#include <botan/entropy.h>
#include <botan/loadstor.h>
#include <botan/xor_buf.h>
#include <botan/util.h>
#include <botan/bit_ops.h>
#include <botan/stl_util.h>
#include <algorithm>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode* prf,
            MemoryRegion<byte>& K,
            u32bit& counter,
            const std::string& label)
   {
   prf->update(K, K.size());
   prf->update(label);
   for(u32bit i = 0; i != 4; ++i)
      prf->update(get_byte(i, counter));
   prf->final(K);

   ++counter;
   }

}

/*************************************************
* Generate a buffer of random bytes              *
*************************************************/
void HMAC_RNG::randomize(byte out[], u32bit length)
   {
   /* Attempt to seed if we are currently not seeded, or if the
      counter is greater than 2^20

      If HMAC_RNG is wrapped in an X9.31/AES PRNG (the default), this
      means a reseed will be kicked off every 16 MiB of RNG output.
   */
   if(!is_seeded() || counter >= 0x100000)
      {
      reseed();

      if(!is_seeded())
         throw PRNG_Unseeded(name() + " seeding attempt failed");
      }

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(prf, K, counter, "rng");

      const u32bit copied = std::min(K.size(), length);

      copy_mem(out, K.begin(), copied);
      out += copied;
      length -= copied;
      }

   /* Every once in a while do a fast poll of a entropy source */
   if(entropy_sources.size() && (counter % 65536 == 0))
      {
      u32bit got = entropy_sources.at(source_index)->fast_poll(io_buffer, io_buffer.size());
      source_index = (source_index + 1) % entropy_sources.size();
      extractor->update(io_buffer, got);
      }
   }

/**
* Reseed the internal state, also accepting user input to include
*/
void HMAC_RNG::reseed_with_input(const byte input[], u32bit input_length)
   {
   if(entropy_sources.size())
      {
      /**
      Using the terminology of E-t-E, XTR is the MAC function (normally
      HMAC) seeded with XTS (below) and we form SKM, the key material, by
      fast polling each source, and then slow polling as many as we think
      we need (in the following loop), and feeding all of the poll
      results, along with any optional user input, along with, finally,
      feedback of the current PRK value, into the extractor function.
      */

      /*
      Previously this function did entropy estimation. However the paper

      "Boaz Barak, Shai Halevi: A model and architecture for
       pseudo-random generation with applications to /dev/random. ACM
       Conference on Computer and Communications Security 2005."

      provides a pretty strong case to not even try, since what we are
      really interested in is the *conditional* entropy from the point
      of view of an unknown attacker, which is impossible to
      calculate. They recommend, if an entropy estimate of some kind
      is needed, to use a low static estimate instead. We use here an
      estimate of 1 bit per byte.

      One thing I had been concerned about initially was that people
      without any randomness source enabled (much more likely in the
      days when you had to enable them manually) would find the RNG
      was unseeded and then pull the manuever some OpenSSL users did
      and seed the RNG with a constant string. However, upon further
      thought, I've decided that people who do that deserve to lose
      anyway.
      */

      for(u32bit j = 0; j < entropy_sources.size(); ++j)
         {
         const u32bit got =
            entropy_sources[j]->fast_poll(io_buffer, io_buffer.size());

         entropy += got;
         extractor->update(io_buffer, got);
         }

      for(u32bit j = 0; j != entropy_sources.size(); ++j)
         {
         const u32bit got =
            entropy_sources[j]->slow_poll(io_buffer, io_buffer.size());

         entropy += got;
         extractor->update(io_buffer, got);
         }
      }

   /*
   And now add the user-provided input, if any
   */
   if(input_length)
      {
      extractor->update(input, input_length);
      entropy += input_length;
      }

   /*
   It is necessary to feed forward poll data. Otherwise, a good
   poll (collecting a large amount of conditional entropy) followed
   by a bad one (collecting little) would be unsafe. Do this by
   generating new PRF outputs using the previous key and feeding them
   into the extractor function.

   Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output
   using the CTXinfo "reseed". Provide these values as input to the
   extractor function.
   */
   hmac_prf(prf, K, counter, "rng");
   extractor->update(K); // K is the CTXinfo=rng PRF output

   hmac_prf(prf, K, counter, "reseed");
   extractor->update(K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into
      the extractor, and set the PRF key to that */
   prf->set_key(extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(prf, K, counter, "xts");
   extractor->set_key(K, K.size());

   // Reset state
   K.clear();
   counter = 0;

   // Upper bound entropy estimate at the extractor output size
   entropy = std::min<u32bit>(entropy, 8 * extractor->OUTPUT_LENGTH);
   }

/**
* Reseed the internal state
*/
void HMAC_RNG::reseed()
   {
   reseed_with_input(0, 0);
   }

/**
Add user-supplied entropy by reseeding and including this
input among the poll data
*/
void HMAC_RNG::add_entropy(const byte input[], u32bit length)
   {
   reseed_with_input(input, length);
   }

/*************************************************
* Add another entropy source to the list         *
*************************************************/
void HMAC_RNG::add_entropy_source(EntropySource* src)
   {
   entropy_sources.push_back(src);
   }

/*************************************************
* Check if the the pool is seeded                *
*************************************************/
bool HMAC_RNG::is_seeded() const
   {
   return (entropy >= 8 * prf->OUTPUT_LENGTH);
   }

 /*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void HMAC_RNG::clear() throw()
   {
   extractor->clear();
   prf->clear();
   K.clear();
   entropy = 0;
   counter = 0;
   source_index = 0;
   }

/*************************************************
* Return the name of this type                   *
*************************************************/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")";
   }

/*************************************************
* HMAC_RNG Constructor                           *
*************************************************/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac,
                   MessageAuthenticationCode* prf_mac) :
   extractor(extractor_mac), prf(prf_mac), io_buffer(128)
   {
   entropy = 0;

   // First PRF inputs are all zero, as specified in section 2
   K.create(prf->OUTPUT_LENGTH);
   counter = 0;
   source_index = 0;

   /*
   Normally we want to feedback PRF output into the input to the
   extractor function to ensure a single bad poll does not damage the
   RNG, but obviously that is meaningless to do on the first poll.

   We will want to use the PRF before we set the first key (in
   reseed_with_input), and it is a pain to keep track if it is set or
   not. Since the first time it doesn't matter anyway, just set it to
   a constant: randomize() will not produce output unless is_seeded()
   returns true, and that will only be the case if the estimated
   entropy counter is high enough. That variable is only set when a
   reseeding is performed.
   */
   std::string prf_key = "Botan HMAC_RNG PRF";
   prf->set_key(reinterpret_cast<const byte*>(prf_key.c_str()),
                prf_key.length());

   /*
   This will be used as the first XTS value when extracting input.
   XTS values after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   std::string xts = "Botan HMAC_RNG XTS";
   extractor->set_key(reinterpret_cast<const byte*>(xts.c_str()),
                      xts.length());
   }

/*************************************************
* HMAC_RNG Destructor                            *
*************************************************/
HMAC_RNG::~HMAC_RNG()
   {
   delete extractor;
   delete prf;

   std::for_each(entropy_sources.begin(), entropy_sources.end(),
                 del_fun<EntropySource>());

   entropy = 0;
   counter = 0;
   }

}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "VelocitySmoothing.hpp"

#include <cstdio>
#include <float.h>
#include <mathlib/mathlib.h>

VelocitySmoothing::VelocitySmoothing(float initial_accel, float initial_vel, float initial_pos)
{
	reset(initial_accel, initial_vel, initial_pos);
}

void VelocitySmoothing::reset(float accel, float vel, float pos)
{
	_state.j = 0.f;
	_state.a = accel;
	_state.v = vel;
	_state.x = pos;

	_state_init = _state;
}

float VelocitySmoothing::saturateT1ForAccel(float a0, float j_max, float T1, float a_max)
{
	/* Check maximum acceleration, saturate and recompute T1 if needed */
	float accel_T1 = a0 + j_max * T1;
	float T1_new = T1;

	if (accel_T1 > a_max) {
		T1_new = (a_max - a0) / j_max;

	} else if (accel_T1 < -a_max) {
		T1_new = (-a_max - a0) / j_max;
	}

	return T1_new;
}

float VelocitySmoothing::computeT1(float a0, float v3, float j_max, float a_max)
{
	float delta = 2.f * a0 * a0 + 4.f * j_max * v3;

	if (delta < 0.f) {
		// Solution is not real
		return 0.f;
	}

	float sqrt_delta = sqrtf(delta);
	float T1_plus = (-a0 + 0.5f * sqrt_delta) / j_max;
	float T1_minus = (-a0 - 0.5f * sqrt_delta) / j_max;

	float T3_plus = a0 / j_max + T1_plus;
	float T3_minus = a0 / j_max + T1_minus;

	float T1 = 0.f;

	if (T1_plus >= 0.f && T3_plus >= 0.f) {
		T1 = T1_plus;

	} else if (T1_minus >= 0.f && T3_minus >= 0.f) {
		T1 = T1_minus;
	}

	T1 = saturateT1ForAccel(a0, j_max, T1, a_max);

	return math::max(T1, 0.f);
}

float VelocitySmoothing::computeT1(float T123, float a0, float v3, float j_max, float a_max)
{
	float a = -j_max;
	float b = j_max * T123 - a0;
	float delta = T123 * T123 * j_max * j_max + 2.f * T123 * a0 * j_max - a0 * a0 - 4.f * j_max * v3;

	if (delta < 0.f) {
		// Solution is not real
		return 0.f;
	}

	float sqrt_delta = sqrtf(delta);
	float denominator_inv = 1.f / (2.f * a);
	float T1_plus = math::max((-b + sqrt_delta) * denominator_inv, 0.f);
	float T1_minus = math::max((-b - sqrt_delta) * denominator_inv, 0.f);

	float T3_plus = a0 / j_max + T1_plus;
	float T3_minus = a0 / j_max + T1_minus;

	float T13_plus = T1_plus + T3_plus;
	float T13_minus = T1_minus + T3_minus;

	float T1 = 0.f;

	if (T13_plus > T123) {
		T1 = T1_minus;

	} else if (T13_minus > T123) {
		T1 = T1_plus;
	}

	T1 = saturateT1ForAccel(a0, j_max, T1, a_max);

	return T1;
}

float VelocitySmoothing::computeT2(float T1, float T3, float a0, float v3, float j_max)
{
	float T2 = 0.f;

	float den = a0 + j_max * T1;

	if (math::abs_t(den) > FLT_EPSILON) {
		T2 = (-0.5f * T1 * T1 * j_max - T1 * T3 * j_max - T1 * a0 + 0.5f * T3 * T3 * j_max - T3 * a0 + v3) / den;
	}

	return math::max(T2, 0.f);
}

float VelocitySmoothing::computeT2(float T123, float T1, float T3)
{
	float T2 = T123 - T1 - T3;
	return math::max(T2, 0.f);
}

float VelocitySmoothing::computeT3(float T1, float a0, float j_max)
{
	float T3 = a0 / j_max + T1;
	return math::max(T3, 0.f);
}

void VelocitySmoothing::updateDurations(float vel_setpoint)
{
	_vel_sp = math::constrain(vel_setpoint, -_max_vel, _max_vel);
	_local_time = 0.f;
	_state_init = _state;

	_direction = computeDirection();

	if (_direction != 0) {
		updateDurationsMinimizeTotalTime();

	} else {
		_T1 = _T2 = _T3 = 0.f;
	}
}

int VelocitySmoothing::computeDirection()
{
	// Compute the velocity at which the trajectory will be
	// when the acceleration will be zero
	float vel_zero_acc = computeVelAtZeroAcc();

	/* Depending of the direction, start accelerating positively or negatively */
	int direction = math::sign(_vel_sp - vel_zero_acc);

	if (direction == 0) {
		// If by braking immediately the velocity is exactly
		// the require one with zero acceleration, then brake
		direction = math::sign(_state.a);
	}

	return direction;
}

float VelocitySmoothing::computeVelAtZeroAcc()
{
	float vel_zero_acc = _state.v;

	if (fabsf(_state.a) > FLT_EPSILON) {
		float j_zero_acc = -math::sign(_state.a) * _max_jerk; // Required jerk to reduce the acceleration
		float t_zero_acc = -_state.a / j_zero_acc; // Required time to cancel the current acceleration
		vel_zero_acc = _state.v + _state.a * t_zero_acc + 0.5f * j_zero_acc * t_zero_acc * t_zero_acc;
	}

	return vel_zero_acc;
}

void VelocitySmoothing::updateDurationsMinimizeTotalTime()
{
	float jerk_max_T1 = _direction * _max_jerk;
	float delta_v = _vel_sp - _state.v;

	// compute increasing acceleration time
	_T1 = computeT1(_state.a, delta_v, jerk_max_T1, _max_accel);

	// compute decreasing acceleration time
	_T3 = computeT3(_T1, _state.a, jerk_max_T1);

	// compute constant acceleration time
	_T2 = computeT2(_T1, _T3, _state.a, delta_v, jerk_max_T1);
}

Trajectory VelocitySmoothing::evaluatePoly(float j, float a0, float v0, float x0, float t, int d)
{
	Trajectory traj;
	float jt = d * j;
	float t2 = t * t;
	float t3 = t2 * t;

	traj.j = jt;
	traj.a = a0 + jt * t;
	traj.v = v0 + a0 * t + 0.5f * jt * t2;
	traj.x = x0 + v0 * t + 0.5f * a0 * t2 + 1.f / 6.f * jt * t3;

	return traj;
}

void VelocitySmoothing::updateTraj(float dt, float time_stretch)
{
	_local_time += dt * time_stretch;
	const float t = _local_time;
	float t1 = 0.f;
	float t2 = 0.f;
	float t3 = 0.f;
	float t4 = 0.f;

	if (t <= _T1) {
		t1 = t;

	} else if (t <= _T1 + _T2) {
		t1 = _T1;
		t2 = t - _T1;

	} else if (t <= _T1 + _T2 + _T3) {
		t1 = _T1;
		t2 = _T2;
		t3 = t - _T1 - _T2;

	} else {
		t1 = _T1;
		t2 = _T2;
		t3 = _T3;
		t4 = t - _T1 - _T2 - _T3;
	}

	if (t > 0.f) {
		_state = evaluatePoly(_max_jerk, _state_init.a, _state_init.v, _state_init.x, t1, _direction);
	}

	if (t >= _T1) {
		_state = evaluatePoly(0.f, _state.a, _state.v, _state.x, t2, 0.f);
	}

	if (t >= _T1 + _T2) {
		_state = evaluatePoly(_max_jerk, _state.a, _state.v, _state.x, t3, -_direction);
	}

	if (t >= _T1 + _T2 + _T3) {
		_state = evaluatePoly(0.f, 0.f, _state.v, _state.x, t4, 0.f);
	}
}

void VelocitySmoothing::timeSynchronization(VelocitySmoothing *traj, int n_traj)
{
	float desired_time = 0.f;
	int longest_traj_index = 0;

	for (int i = 0; i < n_traj; i++) {
		const float T123 = traj[i].getTotalTime();

		if (T123 > desired_time) {
			desired_time = T123;
			longest_traj_index = i;
		}
	}

	if (desired_time > FLT_EPSILON) {
		for (int i = 0; i < n_traj; i++) {
			if (i != longest_traj_index) {
				traj[i].updateDurationsGivenTotalTime(desired_time);
			}
		}
	}
}

void VelocitySmoothing::updateDurationsGivenTotalTime(float T123)
{
	float jerk_max_T1 = _direction * _max_jerk;
	float delta_v = _vel_sp - _state.v;

	// compute increasing acceleration time
	_T1 = computeT1(T123, _state.a, delta_v, jerk_max_T1, _max_accel);

	// compute decreasing acceleration time
	_T3 = computeT3(_T1, _state.a, jerk_max_T1);

	// compute constant acceleration time
	_T2 = computeT2(T123, _T1, _T3);
}
<commit_msg>VelocitySmoothing - Clean up updateTraj function based on Matthias' comments<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "VelocitySmoothing.hpp"

#include <cstdio>
#include <float.h>
#include <mathlib/mathlib.h>

VelocitySmoothing::VelocitySmoothing(float initial_accel, float initial_vel, float initial_pos)
{
	reset(initial_accel, initial_vel, initial_pos);
}

void VelocitySmoothing::reset(float accel, float vel, float pos)
{
	_state.j = 0.f;
	_state.a = accel;
	_state.v = vel;
	_state.x = pos;

	_state_init = _state;
}

float VelocitySmoothing::saturateT1ForAccel(float a0, float j_max, float T1, float a_max)
{
	/* Check maximum acceleration, saturate and recompute T1 if needed */
	float accel_T1 = a0 + j_max * T1;
	float T1_new = T1;

	if (accel_T1 > a_max) {
		T1_new = (a_max - a0) / j_max;

	} else if (accel_T1 < -a_max) {
		T1_new = (-a_max - a0) / j_max;
	}

	return T1_new;
}

float VelocitySmoothing::computeT1(float a0, float v3, float j_max, float a_max)
{
	float delta = 2.f * a0 * a0 + 4.f * j_max * v3;

	if (delta < 0.f) {
		// Solution is not real
		return 0.f;
	}

	float sqrt_delta = sqrtf(delta);
	float T1_plus = (-a0 + 0.5f * sqrt_delta) / j_max;
	float T1_minus = (-a0 - 0.5f * sqrt_delta) / j_max;

	float T3_plus = a0 / j_max + T1_plus;
	float T3_minus = a0 / j_max + T1_minus;

	float T1 = 0.f;

	if (T1_plus >= 0.f && T3_plus >= 0.f) {
		T1 = T1_plus;

	} else if (T1_minus >= 0.f && T3_minus >= 0.f) {
		T1 = T1_minus;
	}

	T1 = saturateT1ForAccel(a0, j_max, T1, a_max);

	return math::max(T1, 0.f);
}

float VelocitySmoothing::computeT1(float T123, float a0, float v3, float j_max, float a_max)
{
	float a = -j_max;
	float b = j_max * T123 - a0;
	float delta = T123 * T123 * j_max * j_max + 2.f * T123 * a0 * j_max - a0 * a0 - 4.f * j_max * v3;

	if (delta < 0.f) {
		// Solution is not real
		return 0.f;
	}

	float sqrt_delta = sqrtf(delta);
	float denominator_inv = 1.f / (2.f * a);
	float T1_plus = math::max((-b + sqrt_delta) * denominator_inv, 0.f);
	float T1_minus = math::max((-b - sqrt_delta) * denominator_inv, 0.f);

	float T3_plus = a0 / j_max + T1_plus;
	float T3_minus = a0 / j_max + T1_minus;

	float T13_plus = T1_plus + T3_plus;
	float T13_minus = T1_minus + T3_minus;

	float T1 = 0.f;

	if (T13_plus > T123) {
		T1 = T1_minus;

	} else if (T13_minus > T123) {
		T1 = T1_plus;
	}

	T1 = saturateT1ForAccel(a0, j_max, T1, a_max);

	return T1;
}

float VelocitySmoothing::computeT2(float T1, float T3, float a0, float v3, float j_max)
{
	float T2 = 0.f;

	float den = a0 + j_max * T1;

	if (math::abs_t(den) > FLT_EPSILON) {
		T2 = (-0.5f * T1 * T1 * j_max - T1 * T3 * j_max - T1 * a0 + 0.5f * T3 * T3 * j_max - T3 * a0 + v3) / den;
	}

	return math::max(T2, 0.f);
}

float VelocitySmoothing::computeT2(float T123, float T1, float T3)
{
	float T2 = T123 - T1 - T3;
	return math::max(T2, 0.f);
}

float VelocitySmoothing::computeT3(float T1, float a0, float j_max)
{
	float T3 = a0 / j_max + T1;
	return math::max(T3, 0.f);
}

void VelocitySmoothing::updateDurations(float vel_setpoint)
{
	_vel_sp = math::constrain(vel_setpoint, -_max_vel, _max_vel);
	_local_time = 0.f;
	_state_init = _state;

	_direction = computeDirection();

	if (_direction != 0) {
		updateDurationsMinimizeTotalTime();

	} else {
		_T1 = _T2 = _T3 = 0.f;
	}
}

int VelocitySmoothing::computeDirection()
{
	// Compute the velocity at which the trajectory will be
	// when the acceleration will be zero
	float vel_zero_acc = computeVelAtZeroAcc();

	/* Depending of the direction, start accelerating positively or negatively */
	int direction = math::sign(_vel_sp - vel_zero_acc);

	if (direction == 0) {
		// If by braking immediately the velocity is exactly
		// the require one with zero acceleration, then brake
		direction = math::sign(_state.a);
	}

	return direction;
}

float VelocitySmoothing::computeVelAtZeroAcc()
{
	float vel_zero_acc = _state.v;

	if (fabsf(_state.a) > FLT_EPSILON) {
		float j_zero_acc = -math::sign(_state.a) * _max_jerk; // Required jerk to reduce the acceleration
		float t_zero_acc = -_state.a / j_zero_acc; // Required time to cancel the current acceleration
		vel_zero_acc = _state.v + _state.a * t_zero_acc + 0.5f * j_zero_acc * t_zero_acc * t_zero_acc;
	}

	return vel_zero_acc;
}

void VelocitySmoothing::updateDurationsMinimizeTotalTime()
{
	float jerk_max_T1 = _direction * _max_jerk;
	float delta_v = _vel_sp - _state.v;

	// compute increasing acceleration time
	_T1 = computeT1(_state.a, delta_v, jerk_max_T1, _max_accel);

	// compute decreasing acceleration time
	_T3 = computeT3(_T1, _state.a, jerk_max_T1);

	// compute constant acceleration time
	_T2 = computeT2(_T1, _T3, _state.a, delta_v, jerk_max_T1);
}

Trajectory VelocitySmoothing::evaluatePoly(float j, float a0, float v0, float x0, float t, int d)
{
	Trajectory traj;
	float jt = d * j;
	float t2 = t * t;
	float t3 = t2 * t;

	traj.j = jt;
	traj.a = a0 + jt * t;
	traj.v = v0 + a0 * t + 0.5f * jt * t2;
	traj.x = x0 + v0 * t + 0.5f * a0 * t2 + 1.f / 6.f * jt * t3;

	return traj;
}

void VelocitySmoothing::updateTraj(float dt, float time_stretch)
{
	_local_time += dt * time_stretch;
	float t_remain = _local_time;
	float t[3];

	t[0] = math::min(t_remain, _T1);
	_state = evaluatePoly(_max_jerk, _state_init.a, _state_init.v, _state_init.x, t[0], _direction);
	t_remain -= t[0];

	if (t_remain > 0.f) {
		t[1] = math::min(t_remain, _T2);
		_state = evaluatePoly(0.f, _state.a, _state.v, _state.x, t[1], 0.f);
		t_remain -= t[1];
	}

	if (t_remain > 0.f) {
		t[2] = math::min(t_remain, _T3);
		_state = evaluatePoly(_max_jerk, _state.a, _state.v, _state.x, t[2], -_direction);
		t_remain -= t[2];
	}

	if (t_remain > 0.f) {
		_state = evaluatePoly(0.f, 0.f, _state.v, _state.x, t_remain, 0.f);
	}
}

void VelocitySmoothing::timeSynchronization(VelocitySmoothing *traj, int n_traj)
{
	float desired_time = 0.f;
	int longest_traj_index = 0;

	for (int i = 0; i < n_traj; i++) {
		const float T123 = traj[i].getTotalTime();

		if (T123 > desired_time) {
			desired_time = T123;
			longest_traj_index = i;
		}
	}

	if (desired_time > FLT_EPSILON) {
		for (int i = 0; i < n_traj; i++) {
			if (i != longest_traj_index) {
				traj[i].updateDurationsGivenTotalTime(desired_time);
			}
		}
	}
}

void VelocitySmoothing::updateDurationsGivenTotalTime(float T123)
{
	float jerk_max_T1 = _direction * _max_jerk;
	float delta_v = _vel_sp - _state.v;

	// compute increasing acceleration time
	_T1 = computeT1(T123, _state.a, delta_v, jerk_max_T1, _max_accel);

	// compute decreasing acceleration time
	_T3 = computeT3(_T1, _state.a, jerk_max_T1);

	// compute constant acceleration time
	_T2 = computeT2(T123, _T1, _T3);
}
<|endoftext|>


<commit_before>/**
 * @file sparse_coding_impl.hpp
 * @author Nishant Mehta
 *
 * Implementation of Sparse Coding with Dictionary Learning using l1 (LASSO) or
 * l1+l2 (Elastic Net) regularization.
 */
#ifndef __MLPACK_METHODS_SPARSE_CODING_SPARSE_CODING_IMPL_HPP
#define __MLPACK_METHODS_SPARSE_CODING_SPARSE_CODING_IMPL_HPP

// In case it hasn't already been included.
#include "sparse_coding.hpp"

namespace mlpack {
namespace sparse_coding {

template<typename DictionaryInitializer>
SparseCoding<DictionaryInitializer>::SparseCoding(const arma::mat& data,
                                                  const size_t atoms,
                                                  const double lambda1,
                                                  const double lambda2) :
    atoms(atoms),
    data(data),
    codes(atoms, data.n_cols),
    lambda1(lambda1),
    lambda2(lambda2)
{
  // Initialize the dictionary.
  DictionaryInitializer::Initialize(data, atoms, dictionary);
}

template<typename DictionaryInitializer>
void SparseCoding<DictionaryInitializer>::Encode(const size_t maxIterations,
                                                 const double objTolerance,
                                                 const double newtonTolerance)
{
  Timer::Start("sparse_coding");

  double lastObjVal = DBL_MAX;

  // Take the initial coding step, which has to happen before entering the main
  // optimization loop.
  Log::Info << "Initial Coding Step." << std::endl;

  OptimizeCode();
  arma::uvec adjacencies = find(codes);

  Log::Info << "  Sparsity level: " << 100.0 * ((double) (adjacencies.n_elem))
      / ((double) (atoms * data.n_cols)) << "%." << std::endl;
  Log::Info << "  Objective value: " << Objective() << "." << std::endl;

  for (size_t t = 1; t != maxIterations; ++t)
  {
    // Print current iteration, and maximum number of iterations (if it isn't
    // 0).
    Log::Info << "Iteration " << t;
    if (maxIterations != 0)
      Log::Info << " of " << maxIterations;
    Log::Info << "." << std::endl;

    // First step: optimize the dictionary.
    Log::Info << "Performing dictionary step... " << std::endl;
    OptimizeDictionary(adjacencies, newtonTolerance);
    Log::Info << "  Objective value: " << Objective() << "." << std::endl;

    // Second step: perform the coding.
    Log::Info << "Performing coding step..." << std::endl;
    OptimizeCode();
    // Get the indices of all the nonzero elements in the codes.
    adjacencies = find(codes);
    Log::Info << "  Sparsity level: " << 100.0 * ((double) (adjacencies.n_elem))
        / ((double) (atoms * data.n_cols)) << "%." << std::endl;

    // Find the new objective value and improvement so we can check for
    // convergence.
    double curObjVal = Objective();
    double improvement = lastObjVal - curObjVal;
    Log::Info << "  Objective value: " << curObjVal << " (improvement "
        << std::scientific << improvement << ")." << std::endl;

    // Have we converged?
    if (improvement < objTolerance)
    {
      Log::Info << "Converged within tolerance " << objTolerance << ".\n";
      break;
    }

    lastObjVal = curObjVal;
  }

  Timer::Stop("sparse_coding");
}

template<typename DictionaryInitializer>
void SparseCoding<DictionaryInitializer>::OptimizeCode()
{
  // When using the Cholesky version of LARS, this is correct even if
  // lambda2 > 0.
  arma::mat matGram = trans(dictionary) * dictionary;

  for (size_t i = 0; i < data.n_cols; ++i)
  {
    // Report progress.
    if ((i % 100) == 0)
      Log::Debug << "Optimization at point " << i << "." << std::endl;

    bool useCholesky = true;
    regression::LARS lars(useCholesky, matGram, lambda1, lambda2);

    // Create an alias of the code (using the same memory), and then LARS will
    // place the result directly into that; then we will not need to have an
    // extra copy.
    arma::vec code = codes.unsafe_col(i);
    lars.Regress(dictionary, data.unsafe_col(i), code, false);
  }
}

// Dictionary step for optimization.
template<typename DictionaryInitializer>
double SparseCoding<DictionaryInitializer>::OptimizeDictionary(
    const arma::uvec& adjacencies,
    const double newtonTolerance,
    const size_t maxIterations)
{
  // Count the number of atomic neighbors for each point x^i.
  arma::uvec neighborCounts = arma::zeros<arma::uvec>(data.n_cols, 1);

  if (adjacencies.n_elem > 0)
  {
    // This gets the column index.  Intentional integer division.
    size_t curPointInd = (size_t) (adjacencies(0) / atoms);

    size_t nextColIndex = (curPointInd + 1) * atoms;
    for (size_t l = 1; l < adjacencies.n_elem; ++l)
    {
      // If l no longer refers to an element in this column, advance the column
      // number accordingly.
      if (adjacencies(l) >= nextColIndex)
      {
        curPointInd = (size_t) (adjacencies(l) / atoms);
        nextColIndex = (curPointInd + 1) * atoms;
      }

      ++neighborCounts(curPointInd);
    }
  }

  // Handle the case of inactive atoms (atoms not used in the given coding).
  std::vector<size_t> inactiveAtoms;

  for (size_t j = 0; j < atoms; ++j)
  {
    if (arma::accu(codes.row(j) != 0) == 0)
      inactiveAtoms.push_back(j);
  }

  const size_t nInactiveAtoms = inactiveAtoms.size();
  const size_t nActiveAtoms = atoms - nInactiveAtoms;

  // Efficient construction of Z restricted to active atoms.
  arma::mat matActiveZ;
  if (nInactiveAtoms > 0)
  {
    math::RemoveRows(codes, inactiveAtoms, matActiveZ);
  }

  if (nInactiveAtoms > 0)
  {
    Log::Warn << "There are " << nInactiveAtoms
        << " inactive atoms. They will be re-initialized randomly.\n";
  }

  Log::Debug << "Solving Dual via Newton's Method.\n";

  // Solve using Newton's method in the dual - note that the final dot
  // multiplication with inv(A) seems to be unavoidable. Although more
  // expensive, the code written this way (we use solve()) should be more
  // numerically stable than just using inv(A) for everything.
  arma::vec dualVars = arma::zeros<arma::vec>(nActiveAtoms);

  //vec dualVars = 1e-14 * ones<vec>(nActiveAtoms);

  // Method used by feature sign code - fails miserably here.  Perhaps the
  // MATLAB optimizer fmincon does something clever?
  //vec dualVars = 10.0 * randu(nActiveAtoms, 1);

  //vec dualVars = diagvec(solve(dictionary, data * trans(codes))
  //    - codes * trans(codes));
  //for (size_t i = 0; i < dualVars.n_elem; i++)
  //  if (dualVars(i) < 0)
  //    dualVars(i) = 0;

  bool converged = false;

  // If we have any inactive atoms, we must construct these differently.
  arma::mat codesXT;
  arma::mat codesZT;

  if (inactiveAtoms.empty())
  {
    codesXT = codes * trans(data);
    codesZT = codes * trans(codes);
  }
  else
  {
    codesXT = matActiveZ * trans(data);
    codesZT = matActiveZ * trans(matActiveZ);
  }

  double normGradient;
  double improvement = 0;
  for (size_t t = 1; !converged; ++t)
  {
    arma::mat A = codesZT + diagmat(dualVars);

    arma::mat matAInvZXT = solve(A, codesXT);

    arma::vec gradient = -arma::sum(arma::square(matAInvZXT), 1);
    gradient += 1;

    arma::mat hessian = -(-2 * (matAInvZXT * trans(matAInvZXT)) % inv(A));

    arma::vec searchDirection = -solve(hessian, gradient);
    //printf("%e\n", norm(searchDirection, 2));

    // Armijo line search.
    const double c = 1e-4;
    double alpha = 1.0;
    const double rho = 0.9;
    double sufficientDecrease = c * dot(gradient, searchDirection);

    for (size_t t = 1; t != maxIterations; ++t)
    {
      // Calculate objective.
      double sumDualVars = arma::sum(dualVars);
      double fOld = -(-trace(trans(codesXT) * matAInvZXT) - sumDualVars);
      double fNew = -(-trace(trans(codesXT) * solve(codesZT +
          diagmat(dualVars + alpha * searchDirection), codesXT)) -
          (sumDualVars + alpha * arma::sum(searchDirection)));

      if (fNew <= fOld + alpha * sufficientDecrease)
      {
        searchDirection = alpha * searchDirection;
        improvement = fOld - fNew;
        break;
      }

      alpha *= rho;
    }

    // Take step and print useful information.
    dualVars += searchDirection;
    normGradient = arma::norm(gradient, 2);
    Log::Debug << "Newton Method iteration " << t << ":" << std::endl;
    Log::Debug << "  Gradient norm: " << std::scientific << normGradient
        << "." << std::endl;
    Log::Debug << "  Improvement: " << std::scientific << improvement << ".\n";

    if (normGradient < newtonTolerance)
      converged = true;
  }

  if (inactiveAtoms.empty())
  {
    // Directly update dictionary.
    dictionary = trans(solve(codesZT + diagmat(dualVars), codesXT));
  }
  else
  {
    arma::mat activeDictionary = trans(solve(codesZT +
        diagmat(dualVars), codesXT));

    // Update all atoms.
    size_t currentInactiveIndex = 0;
    for (size_t i = 0; i < atoms; ++i)
    {
      if (inactiveAtoms[currentInactiveIndex] == i)
      {
        // This atom is inactive.  Reinitialize it randomly.
        dictionary.col(i) = (data.col(math::RandInt(data.n_cols)) +
                             data.col(math::RandInt(data.n_cols)) +
                             data.col(math::RandInt(data.n_cols)));

        dictionary.col(i) /= arma::norm(dictionary.col(i), 2);

        // Increment inactive index counter.
        ++currentInactiveIndex;
      }
      else
      {
        // Update estimate.
        dictionary.col(i) = activeDictionary.col(i - currentInactiveIndex);
      }
    }
  }

  return normGradient;
}

// Project each atom of the dictionary back into the unit ball (if necessary).
template<typename DictionaryInitializer>
void SparseCoding<DictionaryInitializer>::ProjectDictionary()
{
  for (size_t j = 0; j < atoms; j++)
  {
    double atomNorm = arma::norm(dictionary.col(j), 2);
    if (atomNorm > 1)
    {
      Log::Info << "Norm of atom " << j << " exceeds 1 (" << std::scientific
          << atomNorm << ").  Shrinking...\n";
      dictionary.col(j) /= atomNorm;
    }
  }
}

// Compute the objective function.
template<typename DictionaryInitializer>
double SparseCoding<DictionaryInitializer>::Objective() const
{
  double l11NormZ = arma::sum(arma::sum(arma::abs(codes)));
  double froNormResidual = arma::norm(data - (dictionary * codes), "fro");

  if (lambda2 > 0)
  {
    double froNormZ = arma::norm(codes, "fro");
    return 0.5 * (std::pow(froNormResidual, 2.0) + (lambda2 *
        std::pow(froNormZ, 2.0))) + (lambda1 * l11NormZ);
  }
  else // It can be simpler.
  {
    return 0.5 * std::pow(froNormResidual, 2.0) + lambda1 * l11NormZ;
  }
}

template<typename DictionaryInitializer>
std::string SparseCoding<DictionaryInitializer>::ToString() const
{
  std::ostringstream convert;
  convert << "Sparse Coding  [" << this << "]" << std::endl;
  convert << "  Data: " << data.n_rows << "x" ;
  convert <<  data.n_cols << std::endl;
  convert << "  Atoms: " << atoms << std::endl;
  convert << "  Lambda 1: " << lambda1 << std::endl;
  convert << "  Lambda 2: " << lambda2 << std::endl;
  return convert.str();
}

}; // namespace sparse_coding
}; // namespace mlpack

#endif
<commit_msg>Use maxIterations for Newton method loop instead of nested Armijo line search.<commit_after>/**
 * @file sparse_coding_impl.hpp
 * @author Nishant Mehta
 *
 * Implementation of Sparse Coding with Dictionary Learning using l1 (LASSO) or
 * l1+l2 (Elastic Net) regularization.
 */
#ifndef __MLPACK_METHODS_SPARSE_CODING_SPARSE_CODING_IMPL_HPP
#define __MLPACK_METHODS_SPARSE_CODING_SPARSE_CODING_IMPL_HPP

// In case it hasn't already been included.
#include "sparse_coding.hpp"

namespace mlpack {
namespace sparse_coding {

template<typename DictionaryInitializer>
SparseCoding<DictionaryInitializer>::SparseCoding(const arma::mat& data,
                                                  const size_t atoms,
                                                  const double lambda1,
                                                  const double lambda2) :
    atoms(atoms),
    data(data),
    codes(atoms, data.n_cols),
    lambda1(lambda1),
    lambda2(lambda2)
{
  // Initialize the dictionary.
  DictionaryInitializer::Initialize(data, atoms, dictionary);
}

template<typename DictionaryInitializer>
void SparseCoding<DictionaryInitializer>::Encode(const size_t maxIterations,
                                                 const double objTolerance,
                                                 const double newtonTolerance)
{
  Timer::Start("sparse_coding");

  double lastObjVal = DBL_MAX;

  // Take the initial coding step, which has to happen before entering the main
  // optimization loop.
  Log::Info << "Initial Coding Step." << std::endl;

  OptimizeCode();
  arma::uvec adjacencies = find(codes);

  Log::Info << "  Sparsity level: " << 100.0 * ((double) (adjacencies.n_elem))
      / ((double) (atoms * data.n_cols)) << "%." << std::endl;
  Log::Info << "  Objective value: " << Objective() << "." << std::endl;

  for (size_t t = 1; t != maxIterations; ++t)
  {
    // Print current iteration, and maximum number of iterations (if it isn't
    // 0).
    Log::Info << "Iteration " << t;
    if (maxIterations != 0)
      Log::Info << " of " << maxIterations;
    Log::Info << "." << std::endl;

    // First step: optimize the dictionary.
    Log::Info << "Performing dictionary step... " << std::endl;
    OptimizeDictionary(adjacencies, newtonTolerance);
    Log::Info << "  Objective value: " << Objective() << "." << std::endl;

    // Second step: perform the coding.
    Log::Info << "Performing coding step..." << std::endl;
    OptimizeCode();
    // Get the indices of all the nonzero elements in the codes.
    adjacencies = find(codes);
    Log::Info << "  Sparsity level: " << 100.0 * ((double) (adjacencies.n_elem))
        / ((double) (atoms * data.n_cols)) << "%." << std::endl;

    // Find the new objective value and improvement so we can check for
    // convergence.
    double curObjVal = Objective();
    double improvement = lastObjVal - curObjVal;
    Log::Info << "  Objective value: " << curObjVal << " (improvement "
        << std::scientific << improvement << ")." << std::endl;

    // Have we converged?
    if (improvement < objTolerance)
    {
      Log::Info << "Converged within tolerance " << objTolerance << ".\n";
      break;
    }

    lastObjVal = curObjVal;
  }

  Timer::Stop("sparse_coding");
}

template<typename DictionaryInitializer>
void SparseCoding<DictionaryInitializer>::OptimizeCode()
{
  // When using the Cholesky version of LARS, this is correct even if
  // lambda2 > 0.
  arma::mat matGram = trans(dictionary) * dictionary;

  for (size_t i = 0; i < data.n_cols; ++i)
  {
    // Report progress.
    if ((i % 100) == 0)
      Log::Debug << "Optimization at point " << i << "." << std::endl;

    bool useCholesky = true;
    regression::LARS lars(useCholesky, matGram, lambda1, lambda2);

    // Create an alias of the code (using the same memory), and then LARS will
    // place the result directly into that; then we will not need to have an
    // extra copy.
    arma::vec code = codes.unsafe_col(i);
    lars.Regress(dictionary, data.unsafe_col(i), code, false);
  }
}

// Dictionary step for optimization.
template<typename DictionaryInitializer>
double SparseCoding<DictionaryInitializer>::OptimizeDictionary(
    const arma::uvec& adjacencies,
    const double newtonTolerance,
    const size_t maxIterations)
{
  // Count the number of atomic neighbors for each point x^i.
  arma::uvec neighborCounts = arma::zeros<arma::uvec>(data.n_cols, 1);

  if (adjacencies.n_elem > 0)
  {
    // This gets the column index.  Intentional integer division.
    size_t curPointInd = (size_t) (adjacencies(0) / atoms);

    size_t nextColIndex = (curPointInd + 1) * atoms;
    for (size_t l = 1; l < adjacencies.n_elem; ++l)
    {
      // If l no longer refers to an element in this column, advance the column
      // number accordingly.
      if (adjacencies(l) >= nextColIndex)
      {
        curPointInd = (size_t) (adjacencies(l) / atoms);
        nextColIndex = (curPointInd + 1) * atoms;
      }

      ++neighborCounts(curPointInd);
    }
  }

  // Handle the case of inactive atoms (atoms not used in the given coding).
  std::vector<size_t> inactiveAtoms;

  for (size_t j = 0; j < atoms; ++j)
  {
    if (arma::accu(codes.row(j) != 0) == 0)
      inactiveAtoms.push_back(j);
  }

  const size_t nInactiveAtoms = inactiveAtoms.size();
  const size_t nActiveAtoms = atoms - nInactiveAtoms;

  // Efficient construction of Z restricted to active atoms.
  arma::mat matActiveZ;
  if (nInactiveAtoms > 0)
  {
    math::RemoveRows(codes, inactiveAtoms, matActiveZ);
  }

  if (nInactiveAtoms > 0)
  {
    Log::Warn << "There are " << nInactiveAtoms
        << " inactive atoms. They will be re-initialized randomly.\n";
  }

  Log::Debug << "Solving Dual via Newton's Method.\n";

  // Solve using Newton's method in the dual - note that the final dot
  // multiplication with inv(A) seems to be unavoidable. Although more
  // expensive, the code written this way (we use solve()) should be more
  // numerically stable than just using inv(A) for everything.
  arma::vec dualVars = arma::zeros<arma::vec>(nActiveAtoms);

  //vec dualVars = 1e-14 * ones<vec>(nActiveAtoms);

  // Method used by feature sign code - fails miserably here.  Perhaps the
  // MATLAB optimizer fmincon does something clever?
  //vec dualVars = 10.0 * randu(nActiveAtoms, 1);

  //vec dualVars = diagvec(solve(dictionary, data * trans(codes))
  //    - codes * trans(codes));
  //for (size_t i = 0; i < dualVars.n_elem; i++)
  //  if (dualVars(i) < 0)
  //    dualVars(i) = 0;

  bool converged = false;

  // If we have any inactive atoms, we must construct these differently.
  arma::mat codesXT;
  arma::mat codesZT;

  if (inactiveAtoms.empty())
  {
    codesXT = codes * trans(data);
    codesZT = codes * trans(codes);
  }
  else
  {
    codesXT = matActiveZ * trans(data);
    codesZT = matActiveZ * trans(matActiveZ);
  }

  double normGradient;
  double improvement = 0;
  for (size_t t = 1; (t != maxIterations) && !converged; ++t)
  {
    arma::mat A = codesZT + diagmat(dualVars);

    arma::mat matAInvZXT = solve(A, codesXT);

    arma::vec gradient = -arma::sum(arma::square(matAInvZXT), 1);
    gradient += 1;

    arma::mat hessian = -(-2 * (matAInvZXT * trans(matAInvZXT)) % inv(A));

    arma::vec searchDirection = -solve(hessian, gradient);
    //printf("%e\n", norm(searchDirection, 2));

    // Armijo line search.
    const double c = 1e-4;
    double alpha = 1.0;
    const double rho = 0.9;
    double sufficientDecrease = c * dot(gradient, searchDirection);

    // A maxIterations parameter for the Armijo line search may be a good idea,
    // but it doesn't seem to be causing any problems for now.
    while (true)
    {
      // Calculate objective.
      double sumDualVars = arma::sum(dualVars);
      double fOld = -(-trace(trans(codesXT) * matAInvZXT) - sumDualVars);
      double fNew = -(-trace(trans(codesXT) * solve(codesZT +
          diagmat(dualVars + alpha * searchDirection), codesXT)) -
          (sumDualVars + alpha * arma::sum(searchDirection)));

      if (fNew <= fOld + alpha * sufficientDecrease)
      {
        searchDirection = alpha * searchDirection;
        improvement = fOld - fNew;
        break;
      }

      alpha *= rho;
    }

    // Take step and print useful information.
    dualVars += searchDirection;
    normGradient = arma::norm(gradient, 2);
    Log::Debug << "Newton Method iteration " << t << ":" << std::endl;
    Log::Debug << "  Gradient norm: " << std::scientific << normGradient
        << "." << std::endl;
    Log::Debug << "  Improvement: " << std::scientific << improvement << ".\n";

    if (normGradient < newtonTolerance)
      converged = true;
  }

  if (inactiveAtoms.empty())
  {
    // Directly update dictionary.
    dictionary = trans(solve(codesZT + diagmat(dualVars), codesXT));
  }
  else
  {
    arma::mat activeDictionary = trans(solve(codesZT +
        diagmat(dualVars), codesXT));

    // Update all atoms.
    size_t currentInactiveIndex = 0;
    for (size_t i = 0; i < atoms; ++i)
    {
      if (inactiveAtoms[currentInactiveIndex] == i)
      {
        // This atom is inactive.  Reinitialize it randomly.
        dictionary.col(i) = (data.col(math::RandInt(data.n_cols)) +
                             data.col(math::RandInt(data.n_cols)) +
                             data.col(math::RandInt(data.n_cols)));

        dictionary.col(i) /= arma::norm(dictionary.col(i), 2);

        // Increment inactive index counter.
        ++currentInactiveIndex;
      }
      else
      {
        // Update estimate.
        dictionary.col(i) = activeDictionary.col(i - currentInactiveIndex);
      }
    }
  }

  return normGradient;
}

// Project each atom of the dictionary back into the unit ball (if necessary).
template<typename DictionaryInitializer>
void SparseCoding<DictionaryInitializer>::ProjectDictionary()
{
  for (size_t j = 0; j < atoms; j++)
  {
    double atomNorm = arma::norm(dictionary.col(j), 2);
    if (atomNorm > 1)
    {
      Log::Info << "Norm of atom " << j << " exceeds 1 (" << std::scientific
          << atomNorm << ").  Shrinking...\n";
      dictionary.col(j) /= atomNorm;
    }
  }
}

// Compute the objective function.
template<typename DictionaryInitializer>
double SparseCoding<DictionaryInitializer>::Objective() const
{
  double l11NormZ = arma::sum(arma::sum(arma::abs(codes)));
  double froNormResidual = arma::norm(data - (dictionary * codes), "fro");

  if (lambda2 > 0)
  {
    double froNormZ = arma::norm(codes, "fro");
    return 0.5 * (std::pow(froNormResidual, 2.0) + (lambda2 *
        std::pow(froNormZ, 2.0))) + (lambda1 * l11NormZ);
  }
  else // It can be simpler.
  {
    return 0.5 * std::pow(froNormResidual, 2.0) + lambda1 * l11NormZ;
  }
}

template<typename DictionaryInitializer>
std::string SparseCoding<DictionaryInitializer>::ToString() const
{
  std::ostringstream convert;
  convert << "Sparse Coding  [" << this << "]" << std::endl;
  convert << "  Data: " << data.n_rows << "x" ;
  convert <<  data.n_cols << std::endl;
  convert << "  Atoms: " << atoms << std::endl;
  convert << "  Lambda 1: " << lambda1 << std::endl;
  convert << "  Lambda 2: " << lambda2 << std::endl;
  return convert.str();
}

}; // namespace sparse_coding
}; // namespace mlpack

#endif
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qtquickplugin.h"
#include <widgetplugin_helper.h>
#include <QtCore/QtPlugin>
#include <private/qdeclarativerectangle_p.h>
#include <private/qdeclarativescalegrid_p_p.h>
#include <MComponentData>

namespace QmlDesigner {

QtQuickPlugin::QtQuickPlugin()
{
    qApp->setProperty("NoMStyle", true);
    if(!MComponentData::instance()) {
        // This is a workaround because we can't use a default
        // constructor for MComponentData
        int argc = 1;
        char *argv0 = "meegotouch";
        (void) new MComponentData(argc, &argv0);
    }

    qmlRegisterType<QDeclarativePen>("Qt", 4, 7, "Pen");
    qmlRegisterType<QDeclarativeScaleGrid>("Qt", 4, 7, "ScaleGrid");
}

QString QtQuickPlugin::pluginName()
{
    return ("QtQuickPlugin");
}

QString QtQuickPlugin::metaInfo()
{
    return QString(":/qtquickplugin/quick.metainfo");
}

}

Q_EXPORT_PLUGIN(QmlDesigner::QtQuickPlugin)

<commit_msg>QmlDesigner: compile fix<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qtquickplugin.h"
#include <widgetplugin_helper.h>
#include <QtCore/QtPlugin>
#include <private/qdeclarativerectangle_p.h>
#include <private/qdeclarativescalegrid_p_p.h>

namespace QmlDesigner {

QtQuickPlugin::QtQuickPlugin()
{

    qmlRegisterType<QDeclarativePen>("Qt", 4, 7, "Pen");
    qmlRegisterType<QDeclarativeScaleGrid>("Qt", 4, 7, "ScaleGrid");
}

QString QtQuickPlugin::pluginName()
{
    return ("QtQuickPlugin");
}

QString QtQuickPlugin::metaInfo()
{
    return QString(":/qtquickplugin/quick.metainfo");
}

}

Q_EXPORT_PLUGIN(QmlDesigner::QtQuickPlugin)

<|endoftext|>


<commit_before>/****************************************************************************
**
** This file is part of QtCompositor**
**
** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
**
** Contact:  Nokia Corporation qt-info@nokia.com
**
** You may use this file under the terms of the BSD license as follows:
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
****************************************************************************/

#include "waylandsurfaceitem.h"
#include "waylandsurface.h"

#include <qsgengine.h>
#include <private/qsgitem_p.h>

#include <QKeyEvent>

#include <qsgsimpletexturenode.h>
#include <qsgsimplerectnode.h>

void WaylandSurfaceItem::surfaceDamaged(const QRect &)
{
    if (m_texture)
        delete m_texture;

    if (m_surface->type() == WaylandSurface::Texture) {
        m_texture = canvas()->sceneGraphEngine()->createTextureFromId(m_surface->texture(),
                                                                      m_surface->geometry().size());
    } else {
        m_texture = canvas()->sceneGraphEngine()->createTextureFromImage(m_surface->image());
    }

    emit textureChanged();
}

WaylandSurfaceItem::WaylandSurfaceItem(QSGItem *parent)
    : QSGItem(parent)
    , m_surface(0)
    , m_texture(0)
{
}

WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QSGItem *parent)
    : QSGItem(parent)
    , m_surface(0)
    , m_texture(0)
{
    init(surface);
}

void WaylandSurfaceItem::init(WaylandSurface *surface)
{
    if (!surface)
        return;

    m_surface = surface;

    setWidth(surface->geometry().width());
    setHeight(surface->geometry().height());

    setSmooth(true);
    setFlag(ItemHasContents);
    setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
    connect(surface, SIGNAL(mapped(const QRect &)), this, SLOT(surfaceMapped(const QRect &)));
    connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
    connect(this, SIGNAL(textureChanged()), this, SLOT(update()));
    connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
}

WaylandSurfaceItem::~WaylandSurfaceItem()
{
    delete m_texture;
}

void WaylandSurfaceItem::setSurface(WaylandSurface *surface)
{
    init(surface);
}

QSGTexture *WaylandSurfaceItem::texture() const
{
    if (m_texture)
        m_texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
    return m_texture;
}

void WaylandSurfaceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_surface)
        m_surface->sendMousePressEvent(toSurface(event->pos()), event->button());
}

void WaylandSurfaceItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_surface)
        m_surface->sendMouseMoveEvent(toSurface(event->pos()));
}

void WaylandSurfaceItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_surface)
        m_surface->sendMouseReleaseEvent(toSurface(event->pos()), event->button());
}

void WaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus())
        m_surface->sendKeyPressEvent(event->nativeScanCode());
}

void WaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus())
        m_surface->sendKeyReleaseEvent(event->nativeScanCode());
}

void WaylandSurfaceItem::takeFocus()
{
    setFocus(true);

    if (m_surface)
        m_surface->setInputFocus();
}

QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const
{
    return pos.toPoint();
}

void WaylandSurfaceItem::surfaceMapped(const QRect &rect)
{
    setWidth(rect.width());
    setHeight(rect.height());
}

void WaylandSurfaceItem::surfaceDestroyed(QObject *)
{
    m_surface = 0;
}

QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);

    if (!m_texture) {
        delete oldNode;
        return 0;
    }

    if (!node) {
        node = new QSGSimpleTextureNode();
        node->setTexture(m_texture);
    }

    node->setRect(QRectF(0, height(), width(), -height()));
    node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);

    return node;
}
<commit_msg>Avoid crash when texture changes.<commit_after>/****************************************************************************
**
** This file is part of QtCompositor**
**
** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
**
** Contact:  Nokia Corporation qt-info@nokia.com
**
** You may use this file under the terms of the BSD license as follows:
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
**
** Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
****************************************************************************/

#include "waylandsurfaceitem.h"
#include "waylandsurface.h"

#include <qsgengine.h>
#include <private/qsgitem_p.h>

#include <QKeyEvent>

#include <qsgsimpletexturenode.h>
#include <qsgsimplerectnode.h>

void WaylandSurfaceItem::surfaceDamaged(const QRect &)
{
    if (m_texture)
        delete m_texture;

    if (m_surface->type() == WaylandSurface::Texture) {
        //qDebug() << "createTextureFromId" << m_surface->texture() << m_surface->geometry().size();
        m_texture = canvas()->sceneGraphEngine()->createTextureFromId(m_surface->texture(),
                                                                      m_surface->geometry().size());
    } else {
        m_texture = canvas()->sceneGraphEngine()->createTextureFromImage(m_surface->image());
    }

    emit textureChanged();
}

WaylandSurfaceItem::WaylandSurfaceItem(QSGItem *parent)
    : QSGItem(parent)
    , m_surface(0)
    , m_texture(0)
{
}

WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QSGItem *parent)
    : QSGItem(parent)
    , m_surface(0)
    , m_texture(0)
{
    init(surface);
}

void WaylandSurfaceItem::init(WaylandSurface *surface)
{
    if (!surface)
        return;

    m_surface = surface;

    setWidth(surface->geometry().width());
    setHeight(surface->geometry().height());

    setSmooth(true);
    setFlag(ItemHasContents);
    setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
    connect(surface, SIGNAL(mapped(const QRect &)), this, SLOT(surfaceMapped(const QRect &)));
    connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
    connect(this, SIGNAL(textureChanged()), this, SLOT(update()));
    connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
}

WaylandSurfaceItem::~WaylandSurfaceItem()
{
    delete m_texture;
}

void WaylandSurfaceItem::setSurface(WaylandSurface *surface)
{
    init(surface);
}

QSGTexture *WaylandSurfaceItem::texture() const
{
    if (m_texture)
        m_texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
    return m_texture;
}

void WaylandSurfaceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_surface)
        m_surface->sendMousePressEvent(toSurface(event->pos()), event->button());
}

void WaylandSurfaceItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_surface)
        m_surface->sendMouseMoveEvent(toSurface(event->pos()));
}

void WaylandSurfaceItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_surface)
        m_surface->sendMouseReleaseEvent(toSurface(event->pos()), event->button());
}

void WaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus())
        m_surface->sendKeyPressEvent(event->nativeScanCode());
}

void WaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus())
        m_surface->sendKeyReleaseEvent(event->nativeScanCode());
}

void WaylandSurfaceItem::takeFocus()
{
    setFocus(true);

    if (m_surface)
        m_surface->setInputFocus();
}

QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const
{
    return pos.toPoint();
}

void WaylandSurfaceItem::surfaceMapped(const QRect &rect)
{
    setWidth(rect.width());
    setHeight(rect.height());
}

void WaylandSurfaceItem::surfaceDestroyed(QObject *)
{
    m_surface = 0;
}

QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);

    if (!m_texture) {
        delete oldNode;
        return 0;
    }

    if (!node) {
        node = new QSGSimpleTextureNode();
    }
    node->setTexture(m_texture);

    node->setRect(QRectF(0, height(), width(), -height()));
    node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);

    return node;
}
<|endoftext|>