<commit_before>/*-
 * Copyright (c) 2005-2008 Benjamin Close <Benjamin.Close@clearchain.com>
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <string.h>

#ifdef WIN32
	#include <strstream>
#else /* UNIX */
	#include <iostream>
	#include <unistd.h>
	#include <sys/socket.h>
	#include <fcntl.h>
	#include <errno.h>
	#include <sys/ioctl.h>
#endif

#include "Socket.h"

namespace wcl {

/**
 * For Win32 winsock needs to be initialised before
 * we can use the subsystem. This is done in the first constructor call to
 * Socket. But we need to know if it's been done or not
 */
#ifdef WIN32
static bool win32init = false;
static WORD sockVersion = MAKEWORD(1,1); // We'd like Winsock version 1.1
static WSADATA wsaData;
#endif

/**
 * Constructor, create a socket which has not yet got a file descriptor
 * allocated to it. This can only be called by subclasses to its the sub classes
 * responsibility to create the socket.
 */
Socket::Socket():
    sockfd(-1),blocking(BLOCKING)
{
    memset( &this->address, 0, sizeof( this->address ));

#ifdef WIN32
	if(!win32init){
		WSAStartup(sockVersion, &wsaData);
		win32init=true;
	}
#endif

#if defined(__linux) || defined(MACOSX)
	/* Block the SIGPIPE signal to avoid it being sent when a read on a closed socket happens */
	sigset_t mask;

	/* Initialise the signal mask */
	sigemptyset(&mask);

	/* Add the new signal to the mask */
	sigaddset(&mask, SIGPIPE);

	/* Set the new signal to be blocked */
	sigprocmask(SIG_BLOCK, &mask, NULL);
#endif
}

/**
 * Destructor, this closes the socket if its open
 */
Socket::~Socket()
{
    if ( this->isValid()){
	this->close();
    }
}

/**
 * Close the socket if it is open
 */
void Socket::close()
{
    if ( this->isValid()){
#ifdef WIN32
	::closesocket( this->sockfd );
#else
	::close( this->sockfd );
#endif
	this->sockfd = -1;
    }
}

/**
 * Indicate if the socket object is valid.
 * This is a lightweight call that checks class internals only
 *
 * @return true if the socket object is valid, false if it is not
 */
bool Socket::isValid() const
{
    return (this->sockfd != -1);
}

/**
 * Bind the socket to a given port on any address of the local host
 *
 * @param port The port to bind the socket to
 * @return true if the bind was successful, false if socket was invalid or the bind failed
 */
bool Socket::bind( const unsigned port )
{
    if ( !this->isValid()){
	return false;
    }

    this->address.sin_family = AF_INET;
    this->address.sin_addr.s_addr = INADDR_ANY;
    this->address.sin_port = htons ( port );

    if ( ::bind ( this->sockfd, (struct sockaddr *)&this->address, sizeof(this->address)) == -1 ){
	return false;
    }

    return true;
}

/**
 * Attempt to read data from a socket into a buffer. This method
 * will read data and return as soon as it can. It will not block until
 * the given size has been read. If you want this functionality use readuntil.
 * If the remote socket is closed a SocketException is thrown.
 *
 * @param buffer The buffer to read into
 * @param size The size of the buffer
 * @return The amount of data read if all ok, -1 on a read error, not caused
 *         by the close of a socket, 0 on a graceful close Note, the amount
 *        of data actually read may not match what you requested. This function
 *        will return as soon as some data has been read
 * @throws SocketException if the remote end has forcable closed the socket
 */
ssize_t Socket::read ( void *buffer, size_t size )
{

    if ( !isValid()){
	return -1;
    }

#ifdef WIN32
    ssize_t retval = ::recv(this->sockfd, (char*)buffer, size, 0x0);
    if( retval == SOCKET_ERROR ){
	throw new SocketException(this);
    }
    return retval;
#else
    ssize_t retval = ::read(this->sockfd, buffer, size );
    if ( retval == -1 && errno == ECONNRESET){
	throw new SocketException(this);
    }
    return retval;
#endif
}

/**
 * Attempt to read data from a socket into a buffer. This method
 * will block until the requested size has been read. If you don't want
 * the socket to block, (even if it's nonblocking) use read. Please note
 * if using this on a blocking socket, it will act like a busy loop thrashing.
 *
 * @param buffer The buffer to read into
 * @param size The amount of data to read, the buffer msut be at least this size
 * @throws SocketException if the remote end has forcable closed the socket
 */
void Socket::readUntil ( void *buffer, size_t size )
{
    ssize_t amount;

    while( size > 0 ){
	amount = this->read( buffer, size );

	// We just can't increment a void * pointer as we don't know what it is
	// pointing too. However, we know that ::read returns in bytes so we
	// cast to a type which can be validly incremented
	buffer = amount + (uint8_t *)buffer;
	size-=amount;
    }
}

/**
 * Will attempt to write to a socket form a buffer. This method will block
 * until the requested size has been written.
 *
 * @param buffer The buffer to read from.
 * @param size The amount of data to write, the buffer must be at least this size.
 * @throws SocketException if the remote peer has forced the socket closes.
 */
void Socket::writeUntil ( void *buffer, size_t size )
{
    ssize_t amount;

    while( size > 0 ){
		amount = this->write( buffer, size );

		// We just can't increment a void * pointer as we don't know what it is
		// pointing too. However, we know that ::read returns in bytes so we
		// cast to a type which can be validly incremented
		buffer = amount + (uint8_t *)buffer;
		size-=amount;
    }
}

/**
 * Attempt to write size characters from buffer to the socket.
 * This method throws an exception if the remote end has forcable closed
 * the socket.
 *
 * @param buffer The buffer containing the data to write
 * @param size The amount of characters to write, the buffer must be this big
 * @return The amount of charaters written
 * @throws SockcetException if the remote peer has forced the socket * closed
 */
ssize_t Socket::write( const void *buffer, size_t size )
{
	if ( !isValid()){
		return -1;
	}

#ifdef WIN32
	ssize_t retval = ::send(this->sockfd, (const char *)buffer, size, 0x0);
	if ( retval == SOCKET_ERROR ){
		throw new SocketException(this);
	}
	return retval;
#else
	ssize_t retval =  ::write( this->sockfd, buffer, size );
	if ( retval == -1 ){
		throw new SocketException(this);
	}
	return retval;
#endif
}

/**
 * Write the given string to the socket.
 *
 * @param string The string to write
 * @return -1 if the socket is invalid, or the number of bytes written otherwise
 * @throws SocketException if the write fails.
 */
ssize_t Socket::write( const std::string &string )
{
    return this->write( string.c_str(), string.size());
}

/**
 * Set the blocking mode of this socket.
 * The blocking mode of a socket indicates whether read / accept / write calls will
 * block. Win32 does not support non blocking sockets without a HWND hence this library doesnt
 *
 * @param mode The mode to set this socket too
 * @return true if the call was successful, false otherwise
 */
bool Socket::setBlockingMode( const BlockingMode mode)
{
    int flags;

    if ( !isValid()){
	return false;
    }

#ifdef WIN32
	/**
         * Windows does non blocking very, very differently.
	 * hence we don't support it. We return false to indicate this.
	 */
	return false;

#else /* UNIX */
    // In order to set the blocking flag, we must be careful not
    // to stop on any other flags that have been set. Hence
    // we obtain all the flags and adjust the blocking flag only
    flags = ::fcntl(this->sockfd, F_GETFL, 0 /* ALLFLAGS */);

    switch( mode ) {
	case BLOCKING:
	    flags &=~O_NONBLOCK;
	    if ( ::fcntl( this->sockfd, F_SETFL, flags ) == 0 ){
                this->blocking = mode;
		return true;
	    }
	    break;
	case NONBLOCKING:
	    flags |= O_NONBLOCK;
	    if ( ::fcntl( this->sockfd, F_SETFL, flags ) == 0 ){
                this->blocking = mode;
		return true;
	    }
	    break;
    }

    return false;
#endif
}

/**
 * Obtain whether the socket is set to blocking or non blocking mode.
 * Note: A windows socket will always be blocking
 *
 * @return BLOCKING or NONBLOCKING depending on the socket state, if the socket has not been setup
 *         then it is in the default state of BLOCKING.
 */
Socket::BlockingMode Socket::getBlockingMode() const
{
    return this->blocking;
}

/**
 * Return the file descriptor associated with this socket
 *
 * @return the socket descriptor, -1 if its in error
 */
int Socket::operator *() const
{
    return this->sockfd;
}

/**
 * Obtain the amount of bytes currently available for reading
 *
 * @return The amount of bytes available or 0 if the socket is closed
 * @throws SocketException if the remote has closed the socket
 */
ssize_t Socket::getAvailableCount()
{
    ssize_t bytesAvailable;
    int status = ioctl (this->sockfd, FIONREAD, &bytesAvailable);
    if ( status == -1 && errno == ECONNRESET){
	throw new SocketException(this);
    }
    return bytesAvailable;
}

/*==============================================================================
 *
 *  SocketException Class Methods
 *
 *=============================================================================*/

/**
 * Construct a socket exception with the specified reason
 *
 * @param reason The reason the exception occurred
 */
SocketException::SocketException( const Socket *s )
{
    this->sockid = **s;

#ifdef WIN32
    this->errornumber  = WSAGetLastError();
#else
    this->errornumber  = errno; /* errno defined in errno.h */
#endif
}

SocketException::~SocketException()
{}

int SocketException::getCause() const
{
	return this->errornumber;
}

/**
 * Obtain the reason why the socket exception was
 * thrown
 *
 * @return The reason this socket exception occurred
 */
const std::string SocketException::getReason() const
{
#ifdef WIN32
    std::strstream s;
    s << "Winsock Errno:";
    s << this->errornumber;
    s << std::ends;
    return s.str();
#else
    return strerror( this->errornumber );
#endif
}

} // namespace wcl
<commit_msg>Fixed return type in Socket's getAvailable.<commit_after>/*-
 * Copyright (c) 2005-2008 Benjamin Close <Benjamin.Close@clearchain.com>
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <string.h>

#ifdef WIN32
	#include <strstream>
#else /* UNIX */
	#include <iostream>
	#include <unistd.h>
	#include <sys/socket.h>
	#include <fcntl.h>
	#include <errno.h>
	#include <sys/ioctl.h>
#endif

#include "Socket.h"

namespace wcl {

/**
 * For Win32 winsock needs to be initialised before
 * we can use the subsystem. This is done in the first constructor call to
 * Socket. But we need to know if it's been done or not
 */
#ifdef WIN32
static bool win32init = false;
static WORD sockVersion = MAKEWORD(1,1); // We'd like Winsock version 1.1
static WSADATA wsaData;
#endif

/**
 * Constructor, create a socket which has not yet got a file descriptor
 * allocated to it. This can only be called by subclasses to its the sub classes
 * responsibility to create the socket.
 */
Socket::Socket():
    sockfd(-1),blocking(BLOCKING)
{
    memset( &this->address, 0, sizeof( this->address ));

#ifdef WIN32
	if(!win32init){
		WSAStartup(sockVersion, &wsaData);
		win32init=true;
	}
#endif

#if defined(__linux) || defined(MACOSX)
	/* Block the SIGPIPE signal to avoid it being sent when a read on a closed socket happens */
	sigset_t mask;

	/* Initialise the signal mask */
	sigemptyset(&mask);

	/* Add the new signal to the mask */
	sigaddset(&mask, SIGPIPE);

	/* Set the new signal to be blocked */
	sigprocmask(SIG_BLOCK, &mask, NULL);
#endif
}

/**
 * Destructor, this closes the socket if its open
 */
Socket::~Socket()
{
    if ( this->isValid()){
	this->close();
    }
}

/**
 * Close the socket if it is open
 */
void Socket::close()
{
    if ( this->isValid()){
#ifdef WIN32
	::closesocket( this->sockfd );
#else
	::close( this->sockfd );
#endif
	this->sockfd = -1;
    }
}

/**
 * Indicate if the socket object is valid.
 * This is a lightweight call that checks class internals only
 *
 * @return true if the socket object is valid, false if it is not
 */
bool Socket::isValid() const
{
    return (this->sockfd != -1);
}

/**
 * Bind the socket to a given port on any address of the local host
 *
 * @param port The port to bind the socket to
 * @return true if the bind was successful, false if socket was invalid or the bind failed
 */
bool Socket::bind( const unsigned port )
{
    if ( !this->isValid()){
	return false;
    }

    this->address.sin_family = AF_INET;
    this->address.sin_addr.s_addr = INADDR_ANY;
    this->address.sin_port = htons ( port );

    if ( ::bind ( this->sockfd, (struct sockaddr *)&this->address, sizeof(this->address)) == -1 ){
	return false;
    }

    return true;
}

/**
 * Attempt to read data from a socket into a buffer. This method
 * will read data and return as soon as it can. It will not block until
 * the given size has been read. If you want this functionality use readuntil.
 * If the remote socket is closed a SocketException is thrown.
 *
 * @param buffer The buffer to read into
 * @param size The size of the buffer
 * @return The amount of data read if all ok, -1 on a read error, not caused
 *         by the close of a socket, 0 on a graceful close Note, the amount
 *        of data actually read may not match what you requested. This function
 *        will return as soon as some data has been read
 * @throws SocketException if the remote end has forcable closed the socket
 */
ssize_t Socket::read ( void *buffer, size_t size )
{

    if ( !isValid()){
	return -1;
    }

#ifdef WIN32
    ssize_t retval = ::recv(this->sockfd, (char*)buffer, size, 0x0);
    if( retval == SOCKET_ERROR ){
	throw new SocketException(this);
    }
    return retval;
#else
    ssize_t retval = ::read(this->sockfd, buffer, size );
    if ( retval == -1 && errno == ECONNRESET){
	throw new SocketException(this);
    }
    return retval;
#endif
}

/**
 * Attempt to read data from a socket into a buffer. This method
 * will block until the requested size has been read. If you don't want
 * the socket to block, (even if it's nonblocking) use read. Please note
 * if using this on a blocking socket, it will act like a busy loop thrashing.
 *
 * @param buffer The buffer to read into
 * @param size The amount of data to read, the buffer msut be at least this size
 * @throws SocketException if the remote end has forcable closed the socket
 */
void Socket::readUntil ( void *buffer, size_t size )
{
    ssize_t amount;

    while( size > 0 ){
	amount = this->read( buffer, size );

	// We just can't increment a void * pointer as we don't know what it is
	// pointing too. However, we know that ::read returns in bytes so we
	// cast to a type which can be validly incremented
	buffer = amount + (uint8_t *)buffer;
	size-=amount;
    }
}

/**
 * Will attempt to write to a socket form a buffer. This method will block
 * until the requested size has been written.
 *
 * @param buffer The buffer to read from.
 * @param size The amount of data to write, the buffer must be at least this size.
 * @throws SocketException if the remote peer has forced the socket closes.
 */
void Socket::writeUntil ( void *buffer, size_t size )
{
    ssize_t amount;

    while( size > 0 ){
		amount = this->write( buffer, size );

		// We just can't increment a void * pointer as we don't know what it is
		// pointing too. However, we know that ::read returns in bytes so we
		// cast to a type which can be validly incremented
		buffer = amount + (uint8_t *)buffer;
		size-=amount;
    }
}

/**
 * Attempt to write size characters from buffer to the socket.
 * This method throws an exception if the remote end has forcable closed
 * the socket.
 *
 * @param buffer The buffer containing the data to write
 * @param size The amount of characters to write, the buffer must be this big
 * @return The amount of charaters written
 * @throws SockcetException if the remote peer has forced the socket * closed
 */
ssize_t Socket::write( const void *buffer, size_t size )
{
	if ( !isValid()){
		return -1;
	}

#ifdef WIN32
	ssize_t retval = ::send(this->sockfd, (const char *)buffer, size, 0x0);
	if ( retval == SOCKET_ERROR ){
		throw new SocketException(this);
	}
	return retval;
#else
	ssize_t retval =  ::write( this->sockfd, buffer, size );
	if ( retval == -1 ){
		throw new SocketException(this);
	}
	return retval;
#endif
}

/**
 * Write the given string to the socket.
 *
 * @param string The string to write
 * @return -1 if the socket is invalid, or the number of bytes written otherwise
 * @throws SocketException if the write fails.
 */
ssize_t Socket::write( const std::string &string )
{
    return this->write( string.c_str(), string.size());
}

/**
 * Set the blocking mode of this socket.
 * The blocking mode of a socket indicates whether read / accept / write calls will
 * block. Win32 does not support non blocking sockets without a HWND hence this library doesnt
 *
 * @param mode The mode to set this socket too
 * @return true if the call was successful, false otherwise
 */
bool Socket::setBlockingMode( const BlockingMode mode)
{
    int flags;

    if ( !isValid()){
	return false;
    }

#ifdef WIN32
	/**
         * Windows does non blocking very, very differently.
	 * hence we don't support it. We return false to indicate this.
	 */
	return false;

#else /* UNIX */
    // In order to set the blocking flag, we must be careful not
    // to stop on any other flags that have been set. Hence
    // we obtain all the flags and adjust the blocking flag only
    flags = ::fcntl(this->sockfd, F_GETFL, 0 /* ALLFLAGS */);

    switch( mode ) {
	case BLOCKING:
	    flags &=~O_NONBLOCK;
	    if ( ::fcntl( this->sockfd, F_SETFL, flags ) == 0 ){
                this->blocking = mode;
		return true;
	    }
	    break;
	case NONBLOCKING:
	    flags |= O_NONBLOCK;
	    if ( ::fcntl( this->sockfd, F_SETFL, flags ) == 0 ){
                this->blocking = mode;
		return true;
	    }
	    break;
    }

    return false;
#endif
}

/**
 * Obtain whether the socket is set to blocking or non blocking mode.
 * Note: A windows socket will always be blocking
 *
 * @return BLOCKING or NONBLOCKING depending on the socket state, if the socket has not been setup
 *         then it is in the default state of BLOCKING.
 */
Socket::BlockingMode Socket::getBlockingMode() const
{
    return this->blocking;
}

/**
 * Return the file descriptor associated with this socket
 *
 * @return the socket descriptor, -1 if its in error
 */
int Socket::operator *() const
{
    return this->sockfd;
}

/**
 * Obtain the amount of bytes currently available for reading
 *
 * @return The amount of bytes available or 0 if the socket is closed
 * @throws SocketException if the remote has closed the socket
 */
ssize_t Socket::getAvailableCount()
{
    int bytesAvailable;
    int status = ioctl (this->sockfd, FIONREAD, &bytesAvailable);
    if ( status == -1 && errno == ECONNRESET){
	throw new SocketException(this);
    }
    return bytesAvailable;
}

/*==============================================================================
 *
 *  SocketException Class Methods
 *
 *=============================================================================*/

/**
 * Construct a socket exception with the specified reason
 *
 * @param reason The reason the exception occurred
 */
SocketException::SocketException( const Socket *s )
{
    this->sockid = **s;

#ifdef WIN32
    this->errornumber  = WSAGetLastError();
#else
    this->errornumber  = errno; /* errno defined in errno.h */
#endif
}

SocketException::~SocketException()
{}

int SocketException::getCause() const
{
	return this->errornumber;
}

/**
 * Obtain the reason why the socket exception was
 * thrown
 *
 * @return The reason this socket exception occurred
 */
const std::string SocketException::getReason() const
{
#ifdef WIN32
    std::strstream s;
    s << "Winsock Errno:";
    s << this->errornumber;
    s << std::ends;
    return s.str();
#else
    return strerror( this->errornumber );
#endif
}

} // namespace wcl
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "modules/notifications/DOMWindowNotifications.h"

#if ENABLE(LEGACY_NOTIFICATIONS)

#include "core/dom/Document.h"
#include "core/frame/DOMWindow.h"
#include "core/page/Page.h"
#include "modules/notifications/NotificationCenter.h"
#include "modules/notifications/NotificationController.h"

namespace WebCore {

DOMWindowNotifications::DOMWindowNotifications(DOMWindow* window)
    : DOMWindowProperty(window->frame())
    , m_window(window)
{
}

DOMWindowNotifications::~DOMWindowNotifications()
{
}

const char* DOMWindowNotifications::supplementName()
{
    return "DOMWindowNotifications";
}

DOMWindowNotifications* DOMWindowNotifications::from(DOMWindow* window)
{
    DOMWindowNotifications* supplement = static_cast<DOMWindowNotifications*>(Supplement<DOMWindow>::from(window, supplementName()));
    if (!supplement) {
        supplement = new DOMWindowNotifications(window);
        Supplement<DOMWindow>::provideTo(window, supplementName(), adoptPtr(supplement));
    }
    return supplement;
}

NotificationCenter* DOMWindowNotifications::webkitNotifications(DOMWindow* window)
{
    return DOMWindowNotifications::from(window)->webkitNotifications();
}

void DOMWindowNotifications::willDestroyGlobalObjectInFrame()
{
    m_notificationCenter = nullptr;
    DOMWindowProperty::willDestroyGlobalObjectInFrame();
}

void DOMWindowNotifications::willDetachGlobalObjectFromFrame()
{
    m_notificationCenter = nullptr;
    DOMWindowProperty::willDetachGlobalObjectFromFrame();
}

NotificationCenter* DOMWindowNotifications::webkitNotifications()
{
    if (!m_window->isCurrentlyDisplayedInFrame())
        return 0;

    if (m_notificationCenter)
        return m_notificationCenter.get();

    Document* document = m_window->document();
    if (!document)
        return 0;

    Page* page = document->page();
    if (!page)
        return 0;

    NotificationClient* provider = NotificationController::clientFrom(page);
    if (provider)
        m_notificationCenter = NotificationCenter::create(document, provider);

    return m_notificationCenter.get();
}

} // namespace WebCore

#endif // ENABLE(LEGACY_NOTIFICATIONS)
<commit_msg>Fix oilpan build after r167256<commit_after>/*
 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "modules/notifications/DOMWindowNotifications.h"

#if ENABLE(LEGACY_NOTIFICATIONS)

#include "core/dom/Document.h"
#include "core/frame/DOMWindow.h"
#include "core/page/Page.h"
#include "modules/notifications/NotificationCenter.h"
#include "modules/notifications/NotificationController.h"

namespace WebCore {

DOMWindowNotifications::DOMWindowNotifications(DOMWindow* window)
    : DOMWindowProperty(window->frame())
    , m_window(window)
{
}

DOMWindowNotifications::~DOMWindowNotifications()
{
}

const char* DOMWindowNotifications::supplementName()
{
    return "DOMWindowNotifications";
}

DOMWindowNotifications* DOMWindowNotifications::from(DOMWindow* window)
{
    DOMWindowNotifications* supplement = static_cast<DOMWindowNotifications*>(Supplement<DOMWindow>::from(window, supplementName()));
    if (!supplement) {
        supplement = new DOMWindowNotifications(window);
        Supplement<DOMWindow>::provideTo(window, supplementName(), adoptPtr(supplement));
    }
    return supplement;
}

NotificationCenter* DOMWindowNotifications::webkitNotifications(DOMWindow* window)
{
    return DOMWindowNotifications::from(window)->webkitNotifications();
}

void DOMWindowNotifications::willDestroyGlobalObjectInFrame()
{
    m_notificationCenter = 0;
    DOMWindowProperty::willDestroyGlobalObjectInFrame();
}

void DOMWindowNotifications::willDetachGlobalObjectFromFrame()
{
    m_notificationCenter = 0;
    DOMWindowProperty::willDetachGlobalObjectFromFrame();
}

NotificationCenter* DOMWindowNotifications::webkitNotifications()
{
    if (!m_window->isCurrentlyDisplayedInFrame())
        return 0;

    if (m_notificationCenter)
        return m_notificationCenter.get();

    Document* document = m_window->document();
    if (!document)
        return 0;

    Page* page = document->page();
    if (!page)
        return 0;

    NotificationClient* provider = NotificationController::clientFrom(page);
    if (provider)
        m_notificationCenter = NotificationCenter::create(document, provider);

    return m_notificationCenter.get();
}

} // namespace WebCore

#endif // ENABLE(LEGACY_NOTIFICATIONS)
<|endoftext|>


<commit_before>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.03
 * @brief Contains the NetworkGeraet class
 */
#ifndef NETWORK_GERAET_HXX_
#define NETWORK_GERAET_HXX_

#include "antenna.hxx"

/**
 * Defines the interface common to all input network Geräte.
 */
class InputNetworkGeraet: public AObject {
public:
  /**
   * Notifies the InputNetworkGeraet that it has received a packet.
   * @param seq the sequence number of the packet
   * @param data the payload of the packet, excluding sequence and channel
   * numbers
   * @param len the length of the payload
   */
  virtual void receive(unsigned short seq, const byte* data, unsigned len)
  throw() = 0;

  /**
   * Updates the InputNetworkGeraet based on elapsed time.
   *
   * The default does nothing.
   * @param et the time, in milliseconds, since the previous call to update()
   */
  virtual void update(unsigned et) throw() { }
};

/**
 * Defines the interface common to all output network Geräte.
 */
class OutputNetworkGeraet: public AObject {
public:
  /**
   * Updates the OutputNetworkGeraet based on elapsed time.
   *
   * The default does nothing.
   * @param et the time, in milliseconds, since the previous call to update()
   */
  virtual void update(unsigned et) throw() { }
};
#endif /* NETWORK_GERAET_HXX_ */
<commit_msg>Add channel field to OutputNetworkGeraet.<commit_after>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.03
 * @brief Contains the NetworkGeraet class
 */
#ifndef NETWORK_GERAET_HXX_
#define NETWORK_GERAET_HXX_

#include "antenna.hxx"
#include "network_connection.hxx"

/**
 * Defines the interface common to all input network Geräte.
 */
class InputNetworkGeraet: public AObject {
public:
  /**
   * Notifies the InputNetworkGeraet that it has received a packet.
   * @param seq the sequence number of the packet
   * @param data the payload of the packet, excluding sequence and channel
   * numbers
   * @param len the length of the payload
   */
  virtual void receive(unsigned short seq, const byte* data, unsigned len)
  throw() = 0;

  /**
   * Updates the InputNetworkGeraet based on elapsed time.
   *
   * The default does nothing.
   * @param et the time, in milliseconds, since the previous call to update()
   */
  virtual void update(unsigned et) throw() { }
};

/**
 * Defines the interface common to all output network Geräte.
 */
class OutputNetworkGeraet: public AObject {
protected:
  /**
   * The output channel to write to.
   */
  NetworkConnection::channel channel;
public:
  /**
   * Updates the OutputNetworkGeraet based on elapsed time.
   *
   * The default does nothing.
   * @param et the time, in milliseconds, since the previous call to update()
   */
  virtual void update(unsigned et) throw() { }
};
#endif /* NETWORK_GERAET_HXX_ */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: XMLReplacementImageContext.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2004-11-29 13:16:23 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLREPLACEMENTIMAGECONTEXT_HXX
#define _XMLOFF_XMLREPLACEMENTIMAGECONTEXT_HXX

#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP_
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#endif

#ifndef _XMLOFF_XMLICTXT_HXX
#include "xmlictxt.hxx"
#endif

namespace com { namespace sun { namespace star {
    namespace beans { class XPropertySet; }
    namespace io { class XOutputStream; } } } }

class XMLReplacementImageContext : public SvXMLImportContext
{
    ::com::sun::star::uno::Reference <
        ::com::sun::star::io::XOutputStream > m_xBase64Stream;
::com::sun::star::uno::Reference <
        ::com::sun::star::beans::XPropertySet > m_xPropSet;

    ::rtl::OUString m_sHRef;
    const ::rtl::OUString m_sGraphicURL;

public:

    TYPEINFO();

    XMLReplacementImageContext( SvXMLImport& rImport,
            sal_uInt16 nPrfx,
            const ::rtl::OUString& rLName,
            const ::com::sun::star::uno::Reference<
                ::com::sun::star::xml::sax::XAttributeList > & rAttrList,
            const ::com::sun::star::uno::Reference <
                ::com::sun::star::beans::XPropertySet >& rPropSet );
    virtual ~XMLReplacementImageContext();

    virtual void EndElement();

    SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
                const ::rtl::OUString& rLocalName,
                 const ::com::sun::star::uno::Reference<
                    ::com::sun::star::xml::sax::XAttributeList > & xAttrList );

};

#endif  //  _XMLOFF_XMLREPLACEMENTIMAGECONTEXT_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.202); FILE MERGED 2005/09/05 14:37:58 rt 1.3.202.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: XMLReplacementImageContext.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 12:54:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLREPLACEMENTIMAGECONTEXT_HXX
#define _XMLOFF_XMLREPLACEMENTIMAGECONTEXT_HXX

#ifndef _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HPP_
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#endif

#ifndef _XMLOFF_XMLICTXT_HXX
#include "xmlictxt.hxx"
#endif

namespace com { namespace sun { namespace star {
    namespace beans { class XPropertySet; }
    namespace io { class XOutputStream; } } } }

class XMLReplacementImageContext : public SvXMLImportContext
{
    ::com::sun::star::uno::Reference <
        ::com::sun::star::io::XOutputStream > m_xBase64Stream;
::com::sun::star::uno::Reference <
        ::com::sun::star::beans::XPropertySet > m_xPropSet;

    ::rtl::OUString m_sHRef;
    const ::rtl::OUString m_sGraphicURL;

public:

    TYPEINFO();

    XMLReplacementImageContext( SvXMLImport& rImport,
            sal_uInt16 nPrfx,
            const ::rtl::OUString& rLName,
            const ::com::sun::star::uno::Reference<
                ::com::sun::star::xml::sax::XAttributeList > & rAttrList,
            const ::com::sun::star::uno::Reference <
                ::com::sun::star::beans::XPropertySet >& rPropSet );
    virtual ~XMLReplacementImageContext();

    virtual void EndElement();

    SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
                const ::rtl::OUString& rLocalName,
                 const ::com::sun::star::uno::Reference<
                    ::com::sun::star::xml::sax::XAttributeList > & xAttrList );

};

#endif  //  _XMLOFF_XMLREPLACEMENTIMAGECONTEXT_HXX

<|endoftext|>


<commit_before>#include "MacauPrior.h"

#include <SmurffCpp/IO/MatrixIO.h>
#include <SmurffCpp/IO/GenericIO.h>

#include <SmurffCpp/Utils/Distribution.h>
#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/counters.h>

#include <SmurffCpp/Utils/linop.h>

#include <ios>

using namespace smurff;

MacauPrior::MacauPrior()
   : NormalPrior()
{
}

MacauPrior::MacauPrior(std::shared_ptr<Session> session, uint32_t mode)
   : NormalPrior(session, mode, "MacauPrior")
{
   beta_precision = SideInfoConfig::BETA_PRECISION_DEFAULT_VALUE;
   tol = SideInfoConfig::TOL_DEFAULT_VALUE;

   enable_beta_precision_sampling = Config::ENABLE_BETA_PRECISION_SAMPLING_DEFAULT_VALUE;
}

MacauPrior::~MacauPrior()
{
}

void MacauPrior::init()
{
   NormalPrior::init();

   THROWERROR_ASSERT_MSG(Features->rows() == num_cols(), "Number of rows in train must be equal to number of rows in features");

   if (use_FtF)
   {
      std::uint64_t dim = Features->cols();
      FtF_plus_beta.resize(dim, dim);
      Features->At_mul_A(FtF_plus_beta);
      FtF_plus_beta.diagonal().array() += beta_precision;
   }

   Uhat.resize(this->num_latent(), Features->rows());
   Uhat.setZero();

   m_beta = std::make_shared<Eigen::MatrixXd>(this->num_latent(), Features->cols());
   m_beta->setZero();

   m_session->model().setLinkMatrix(m_mode, m_beta);
}

void MacauPrior::update_prior()
{
    COUNTER("update_prior");
    // residual (Uhat is later overwritten):
    Uhat.noalias() = U() - Uhat;
    Eigen::MatrixXd BBt = smurff::linop::A_mul_At_combo(*m_beta);

    // sampling Gaussian
    std::tie(this->mu, this->Lambda) = CondNormalWishart(Uhat, this->mu0, this->b0, this->WI + beta_precision * BBt, this->df + m_beta->cols());
    sample_beta();
    Features->compute_uhat(Uhat, *m_beta);

    if (enable_beta_precision_sampling)
    {
        double old_beta = beta_precision;
        beta_precision = sample_beta_precision(*m_beta, this->Lambda, beta_precision_nu0, beta_precision_mu0);
        FtF_plus_beta.diagonal().array() += beta_precision - old_beta;
   }
}

const Eigen::VectorXd MacauPrior::getMu(int n) const
{
   return this->mu + Uhat.col(n);
}

void MacauPrior::compute_Ft_y_omp(Eigen::MatrixXd& Ft_y)
{
   const int num_feat = m_beta->cols();

   // Ft_y = (U .- mu + Normal(0, Lambda^-1)) * F + std::sqrt(beta_precision) * Normal(0, Lambda^-1)
   // Ft_y is [ D x F ] matrix
   HyperU = (U() + MvNormal_prec(Lambda, num_cols())).colwise() - mu;

   Ft_y = Features->A_mul_B(HyperU);
   HyperU2 = MvNormal_prec(Lambda, num_feat);

   #pragma omp parallel for schedule(static)
   for (int f = 0; f < num_feat; f++)
   {
      for (int d = 0; d < num_latent(); d++)
      {
         Ft_y(d, f) += std::sqrt(beta_precision) * HyperU2(d, f);
      }
   }
}

void MacauPrior::sample_beta()
{
   COUNTER("sample_beta");
   if (use_FtF)
      sample_beta_direct();
   else
      sample_beta_cg();
}

void MacauPrior::addSideInfo(const std::shared_ptr<ISideInfo>& side_info_a, double beta_precision_a, double tolerance_a, bool direct_a, bool enable_beta_precision_sampling_a, bool throw_on_cholesky_error_a)
{
   //FIXME: remove old code

   // old code

   // side information
   Features = side_info_a;
   beta_precision = beta_precision_a;
   tol = tolerance_a;
   use_FtF = direct_a;
   enable_beta_precision_sampling = enable_beta_precision_sampling_a;
   throw_on_cholesky_error = throw_on_cholesky_error_a;

   // new code

   // side information
   side_info_values.push_back(side_info_a);
   beta_precision_values.push_back(beta_precision_a);
   tol_values.push_back(tolerance_a);
   direct_values.push_back(direct_a);
   enable_beta_precision_sampling_values.push_back(enable_beta_precision_sampling_a);
   throw_on_cholesky_error_values.push_back(throw_on_cholesky_error_a);

   // other code

   // Hyper-prior for beta_precision (mean 1.0, var of 1e+3):
   beta_precision_mu0 = 1.0;
   beta_precision_nu0 = 1e-3;
}

bool MacauPrior::save(std::shared_ptr<const StepFile> sf) const
{
   NormalPrior::save(sf);

   std::string path = sf->getLinkMatrixFileName(m_mode);
   smurff::matrix_io::eigen::write_matrix(path, *m_beta);

   return true;
}

void MacauPrior::restore(std::shared_ptr<const StepFile> sf)
{
   NormalPrior::restore(sf);

   std::string path = sf->getLinkMatrixFileName(m_mode);

   THROWERROR_FILE_NOT_EXIST(path);

   smurff::matrix_io::eigen::read_matrix(path, *m_beta);
}

std::ostream& MacauPrior::info(std::ostream &os, std::string indent)
{
   NormalPrior::info(os, indent);
   os << indent << " SideInfo: ";
   Features->print(os);
   os << indent << " Method: ";
   if (use_FtF)
   {
      os << "Cholesky Decomposition";
      double needs_gb = (double)Features->cols() / 1024. * (double)Features->cols() / 1024. / 1024.;
      if (needs_gb > 1.0) os << " (needing " << needs_gb << " GB of memory)";
      os << std::endl;
   } else {
      os << "CG Solver with tolerance: " << std::scientific << tol << std::fixed << std::endl;
   }
   os << indent << " BetaPrecision: " << beta_precision << std::endl;
   return os;
}

std::ostream& MacauPrior::status(std::ostream &os, std::string indent) const
{
   os << indent << m_name << ": " << std::endl;
   indent += "  ";
   os << indent << "blockcg iter = " << blockcg_iter << std::endl;
   os << indent << "FtF_plus_beta= " << FtF_plus_beta.norm() << std::endl;
   os << indent << "HyperU       = " << HyperU.norm() << std::endl;
   os << indent << "HyperU2      = " << HyperU2.norm() << std::endl;
   os << indent << "Beta         = " << m_beta->norm() << std::endl;
   os << indent << "beta_precision  = " << beta_precision << std::endl;
   os << indent << "Ft_y         = " << Ft_y.norm() << std::endl;
   return os;
}

// direct method
void MacauPrior::sample_beta_direct()
{
    this->compute_Ft_y_omp(Ft_y);
    *m_beta = FtF_plus_beta.llt().solve(Ft_y.transpose()).transpose();
}

std::pair<double, double> MacauPrior::posterior_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   const int D = beta.rows();
   Eigen::MatrixXd BB(D, D);
   smurff::linop::A_mul_At_combo(BB, beta);
   double nux = nu + beta.rows() * beta.cols();
   double mux = mu * nux / (nu + mu * (BB.selfadjointView<Eigen::Lower>() * Lambda_u).trace());
   double b = nux / 2;
   double c = 2 * mux / nux;
   return std::make_pair(b, c);
}

double MacauPrior::sample_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   auto gamma_post = posterior_beta_precision(beta, Lambda_u, nu, mu);
   return rgamma(gamma_post.first, gamma_post.second);
}

void MacauPrior::sample_beta_cg()
{
    Eigen::MatrixXd Ft_y;
    this->compute_Ft_y_omp(Ft_y);

    blockcg_iter = Features->solve_blockcg(*m_beta, beta_precision, Ft_y, tol, 32, 8, throw_on_cholesky_error);
}
<commit_msg>ENH: Print if beta_precision is sampled or not<commit_after>#include "MacauPrior.h"

#include <SmurffCpp/IO/MatrixIO.h>
#include <SmurffCpp/IO/GenericIO.h>

#include <SmurffCpp/Utils/Distribution.h>
#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/counters.h>

#include <SmurffCpp/Utils/linop.h>

#include <ios>

using namespace smurff;

MacauPrior::MacauPrior()
   : NormalPrior()
{
}

MacauPrior::MacauPrior(std::shared_ptr<Session> session, uint32_t mode)
   : NormalPrior(session, mode, "MacauPrior")
{
   beta_precision = SideInfoConfig::BETA_PRECISION_DEFAULT_VALUE;
   tol = SideInfoConfig::TOL_DEFAULT_VALUE;

   enable_beta_precision_sampling = Config::ENABLE_BETA_PRECISION_SAMPLING_DEFAULT_VALUE;
}

MacauPrior::~MacauPrior()
{
}

void MacauPrior::init()
{
   NormalPrior::init();

   THROWERROR_ASSERT_MSG(Features->rows() == num_cols(), "Number of rows in train must be equal to number of rows in features");

   if (use_FtF)
   {
      std::uint64_t dim = Features->cols();
      FtF_plus_beta.resize(dim, dim);
      Features->At_mul_A(FtF_plus_beta);
      FtF_plus_beta.diagonal().array() += beta_precision;
   }

   Uhat.resize(this->num_latent(), Features->rows());
   Uhat.setZero();

   m_beta = std::make_shared<Eigen::MatrixXd>(this->num_latent(), Features->cols());
   m_beta->setZero();

   m_session->model().setLinkMatrix(m_mode, m_beta);
}

void MacauPrior::update_prior()
{
    COUNTER("update_prior");
    // residual (Uhat is later overwritten):
    Uhat.noalias() = U() - Uhat;
    Eigen::MatrixXd BBt = smurff::linop::A_mul_At_combo(*m_beta);

    // sampling Gaussian
    std::tie(this->mu, this->Lambda) = CondNormalWishart(Uhat, this->mu0, this->b0, this->WI + beta_precision * BBt, this->df + m_beta->cols());
    sample_beta();
    Features->compute_uhat(Uhat, *m_beta);

    if (enable_beta_precision_sampling)
    {
        double old_beta = beta_precision;
        beta_precision = sample_beta_precision(*m_beta, this->Lambda, beta_precision_nu0, beta_precision_mu0);
        FtF_plus_beta.diagonal().array() += beta_precision - old_beta;
   }
}

const Eigen::VectorXd MacauPrior::getMu(int n) const
{
   return this->mu + Uhat.col(n);
}

void MacauPrior::compute_Ft_y_omp(Eigen::MatrixXd& Ft_y)
{
   const int num_feat = m_beta->cols();

   // Ft_y = (U .- mu + Normal(0, Lambda^-1)) * F + std::sqrt(beta_precision) * Normal(0, Lambda^-1)
   // Ft_y is [ D x F ] matrix
   HyperU = (U() + MvNormal_prec(Lambda, num_cols())).colwise() - mu;

   Ft_y = Features->A_mul_B(HyperU);
   HyperU2 = MvNormal_prec(Lambda, num_feat);

   #pragma omp parallel for schedule(static)
   for (int f = 0; f < num_feat; f++)
   {
      for (int d = 0; d < num_latent(); d++)
      {
         Ft_y(d, f) += std::sqrt(beta_precision) * HyperU2(d, f);
      }
   }
}

void MacauPrior::sample_beta()
{
   COUNTER("sample_beta");
   if (use_FtF)
      sample_beta_direct();
   else
      sample_beta_cg();
}

void MacauPrior::addSideInfo(const std::shared_ptr<ISideInfo>& side_info_a, double beta_precision_a, double tolerance_a, bool direct_a, bool enable_beta_precision_sampling_a, bool throw_on_cholesky_error_a)
{
   //FIXME: remove old code

   // old code

   // side information
   Features = side_info_a;
   beta_precision = beta_precision_a;
   tol = tolerance_a;
   use_FtF = direct_a;
   enable_beta_precision_sampling = enable_beta_precision_sampling_a;
   throw_on_cholesky_error = throw_on_cholesky_error_a;

   // new code

   // side information
   side_info_values.push_back(side_info_a);
   beta_precision_values.push_back(beta_precision_a);
   tol_values.push_back(tolerance_a);
   direct_values.push_back(direct_a);
   enable_beta_precision_sampling_values.push_back(enable_beta_precision_sampling_a);
   throw_on_cholesky_error_values.push_back(throw_on_cholesky_error_a);

   // other code

   // Hyper-prior for beta_precision (mean 1.0, var of 1e+3):
   beta_precision_mu0 = 1.0;
   beta_precision_nu0 = 1e-3;
}

bool MacauPrior::save(std::shared_ptr<const StepFile> sf) const
{
   NormalPrior::save(sf);

   std::string path = sf->getLinkMatrixFileName(m_mode);
   smurff::matrix_io::eigen::write_matrix(path, *m_beta);

   return true;
}

void MacauPrior::restore(std::shared_ptr<const StepFile> sf)
{
   NormalPrior::restore(sf);

   std::string path = sf->getLinkMatrixFileName(m_mode);

   THROWERROR_FILE_NOT_EXIST(path);

   smurff::matrix_io::eigen::read_matrix(path, *m_beta);
}

std::ostream& MacauPrior::info(std::ostream &os, std::string indent)
{
   NormalPrior::info(os, indent);
   os << indent << " SideInfo: ";
   Features->print(os);
   os << indent << " Method: ";
   if (use_FtF)
   {
      os << "Cholesky Decomposition";
      double needs_gb = (double)Features->cols() / 1024. * (double)Features->cols() / 1024. / 1024.;
      if (needs_gb > 1.0) os << " (needing " << needs_gb << " GB of memory)";
      os << std::endl;
   } else {
      os << "CG Solver with tolerance: " << std::scientific << tol << std::fixed << std::endl;
   }
   os << indent << " BetaPrecision: ";
   if (enable_beta_precision_sampling)
   {
       os << "sampled around ";
   }
   else
   {
       os << "fixed at ";
   }
   os << beta_precision << std::endl;
   return os;
}

std::ostream& MacauPrior::status(std::ostream &os, std::string indent) const
{
   os << indent << m_name << ": " << std::endl;
   indent += "  ";
   os << indent << "blockcg iter = " << blockcg_iter << std::endl;
   os << indent << "FtF_plus_beta= " << FtF_plus_beta.norm() << std::endl;
   os << indent << "HyperU       = " << HyperU.norm() << std::endl;
   os << indent << "HyperU2      = " << HyperU2.norm() << std::endl;
   os << indent << "Beta         = " << m_beta->norm() << std::endl;
   os << indent << "beta_precision  = " << beta_precision << std::endl;
   os << indent << "Ft_y         = " << Ft_y.norm() << std::endl;
   return os;
}

// direct method
void MacauPrior::sample_beta_direct()
{
    this->compute_Ft_y_omp(Ft_y);
    *m_beta = FtF_plus_beta.llt().solve(Ft_y.transpose()).transpose();
}

std::pair<double, double> MacauPrior::posterior_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   const int D = beta.rows();
   Eigen::MatrixXd BB(D, D);
   smurff::linop::A_mul_At_combo(BB, beta);
   double nux = nu + beta.rows() * beta.cols();
   double mux = mu * nux / (nu + mu * (BB.selfadjointView<Eigen::Lower>() * Lambda_u).trace());
   double b = nux / 2;
   double c = 2 * mux / nux;
   return std::make_pair(b, c);
}

double MacauPrior::sample_beta_precision(Eigen::MatrixXd & beta, Eigen::MatrixXd & Lambda_u, double nu, double mu)
{
   auto gamma_post = posterior_beta_precision(beta, Lambda_u, nu, mu);
   return rgamma(gamma_post.first, gamma_post.second);
}

void MacauPrior::sample_beta_cg()
{
    Eigen::MatrixXd Ft_y;
    this->compute_Ft_y_omp(Ft_y);

    blockcg_iter = Features->solve_blockcg(*m_beta, beta_precision, Ft_y, tol, 32, 8, throw_on_cholesky_error);
}
<|endoftext|>


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

#include <gtest/gtest.h>

#include <memory>
#include <array>

#include "SurgSim/Math/GaussLegendreQuadrature.h"
#include "SurgSim/Math/Matrix.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Physics/DeformableRepresentationState.h"
#include "SurgSim/Physics/FemElement2DTriangle.h"

using SurgSim::Math::Matrix;
using SurgSim::Math::Matrix33d;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::Vector;
using SurgSim::Math::Vector3d;
using SurgSim::Physics::DeformableRepresentationState;
using SurgSim::Physics::FemElement2DTriangle;

namespace
{
const double epsilon = 1e-9;
};

class MockFemElement2D : public FemElement2DTriangle
{
public:
	MockFemElement2D(std::array<unsigned int, 3> nodeIds)
		: FemElement2DTriangle(nodeIds)
	{
	}

	const Eigen::Matrix<double, 18, 18, Eigen::DontAlign>& getInitialRotation() const
	{
		return m_R0;
	}

	double getRestArea() const
	{
		return m_restArea;
	}
};

class FemElement2DTriangleTests : public ::testing::Test
{
public:
	static const int m_numberNodes = 6;

	std::array<unsigned int, 3> m_nodeIds;
	DeformableRepresentationState m_restState;
	double m_expectedVolume;
	double m_rho, m_E, m_nu;
	double m_A;         // area
	double m_thickness; // thickness
	Quaterniond m_expectedRotation;

	virtual void SetUp() override
	{
		using SurgSim::Math::getSubVector;

		m_rho = 1000.0;
		m_E = 1e6;
		m_nu = 0.45;
		m_thickness = 1e-2;
		m_A = 1.0 / 2.0;
		m_expectedVolume = m_A * m_thickness;

		// Triangle is made of node 3, 1 and 5 in a bigger system containing m_numberNodes nodes (at least 6)
		m_nodeIds[0] = 3;
		m_nodeIds[1] = 1;
		m_nodeIds[2] = 5;

		m_restState.setNumDof(6, m_numberNodes);

		m_expectedRotation.coeffs().setRandom();
		m_expectedRotation.normalize();

		Vector3d A(0.0, 0.0, 0.0);
		Vector3d B(1.0, 0.0, 0.0);
		Vector3d C(0.0, 1.0, 0.0);
		// The initial rotation of ABC is defined by (i=AB, j=AC, k=ABxAC) = Identity
		// Therefore, by applying m_expectedRotation to the points, the initial rotation of the
		// element should be m_expectedRotation

		Vector& x = m_restState.getPositions();
		getSubVector(x, m_nodeIds[0], 6).segment<3>(0) = m_expectedRotation._transformVector(A);
		getSubVector(x, m_nodeIds[1], 6).segment<3>(0) = m_expectedRotation._transformVector(B);
		getSubVector(x, m_nodeIds[2], 6).segment<3>(0) = m_expectedRotation._transformVector(C);
	}

	void getExpectedMassMatrix(Eigen::Ref<SurgSim::Math::Matrix> mass)
	{
		// XXX TO DO
	}

	void getExpectedStiffnessMatrix(Eigen::Ref<SurgSim::Math::Matrix> stiffness)
	{
		// XXX TO DO
	}

	std::shared_ptr<MockFemElement2D> getElement()
	{
		auto element = std::make_shared<MockFemElement2D>(m_nodeIds);
		element->setThickness(m_thickness);
		element->setMassDensity(m_rho);
		element->setPoissonRatio(m_nu);
		element->setYoungModulus(m_E);
		element->initialize(m_restState);
		return element;
	}
};

TEST_F(FemElement2DTriangleTests, ConstructorTest)
{
	ASSERT_NO_THROW({ MockFemElement2D triangle(m_nodeIds); });
}

TEST_F(FemElement2DTriangleTests, NodeIdsTest)
{
	FemElement2DTriangle element(m_nodeIds);
	EXPECT_EQ(3u, element.getNumNodes());
	EXPECT_EQ(3u, element.getNodeIds().size());
	for (int i = 0; i < 3; i++)
	{
		EXPECT_EQ(m_nodeIds[i], element.getNodeId(i));
		EXPECT_EQ(m_nodeIds[i], element.getNodeIds()[i]);
	}
}

TEST_F(FemElement2DTriangleTests, setGetThicknessTest)
{
	FemElement2DTriangle element(m_nodeIds);

	// Default thickness = 0.0
	EXPECT_DOUBLE_EQ(0.0, element.getThickness());
	// Set to a valid thickness
	element.setThickness(1.54);
	EXPECT_DOUBLE_EQ(1.54, element.getThickness());
	// Set to an invalid thickness
	EXPECT_ANY_THROW(element.setThickness(0.0));
	EXPECT_ANY_THROW(element.setThickness(-9.4));
}

TEST_F(FemElement2DTriangleTests, MaterialParameterTest)
{
	FemElement2DTriangle element(m_nodeIds);
	element.setThickness(m_thickness);

	// Test the various mode of failure related to the physical parameters
	// This has been already tested in FemElementTests, but this is to make sure this method is called properly
	// So the same behavior should be expected
	{
		// Mass density not set
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Poisson Ratio not set
		element.setMassDensity(-1234.56);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Young modulus not set
		element.setPoissonRatio(0.55);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Invalid mass density
		element.setYoungModulus(-4321.33);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Invalid Poisson ratio
		element.setMassDensity(m_rho);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Invalid Young modulus
		element.setPoissonRatio(m_nu);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		element.setYoungModulus(m_E);
		ASSERT_NO_THROW(element.initialize(m_restState));
	}
}

TEST_F(FemElement2DTriangleTests, VolumeTest)
{
	std::shared_ptr<MockFemElement2D> element = getElement();
	EXPECT_NEAR(element->getVolume(m_restState), m_expectedVolume, 1e-10);
}

TEST_F(FemElement2DTriangleTests, RestAreaTest)
{
	std::shared_ptr<MockFemElement2D> element = getElement();
	EXPECT_NEAR(element->getRestArea(), m_A, 1e-10);
}

TEST_F(FemElement2DTriangleTests, InitialRotationTest)
{
	std::shared_ptr<MockFemElement2D> element = getElement();

	// Use a mask to test the structure of the rotation matrix R0 (6 digonal block 3x3 matrix and 0 elsewhere)
	Eigen::Matrix<double, 18, 18> mask;
	mask.setOnes();
	mask.block<3, 3>(0, 0).setZero();
	mask.block<3, 3>(3, 3).setZero();
	mask.block<3, 3>(6, 6).setZero();
	mask.block<3, 3>(9, 9).setZero();
	mask.block<3, 3>(12, 12).setZero();
	mask.block<3, 3>(15, 15).setZero();
	EXPECT_TRUE(element->getInitialRotation().cwiseProduct(mask).isZero());

	EXPECT_TRUE(element->getInitialRotation().block(0, 0, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(3, 3, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(6, 6, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(9, 9, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(12, 12, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(15, 15, 3, 3).isApprox(m_expectedRotation.matrix()));
}

TEST_F(FemElement2DTriangleTests, ForceAndMatricesTest)
{
	// XXX TO DO
}
<commit_msg>Add Unit Test for FemElement2DTri isValidCoordinate/computeCartesianCoordinate<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <memory>
#include <array>

#include "SurgSim/Math/GaussLegendreQuadrature.h"
#include "SurgSim/Math/Matrix.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Physics/DeformableRepresentationState.h"
#include "SurgSim/Physics/FemElement2DTriangle.h"

using SurgSim::Math::Matrix;
using SurgSim::Math::Matrix33d;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::Vector;
using SurgSim::Math::Vector3d;
using SurgSim::Physics::DeformableRepresentationState;
using SurgSim::Physics::FemElement2DTriangle;

namespace
{
const double epsilon = 1e-9;
};

class MockFemElement2D : public FemElement2DTriangle
{
public:
	MockFemElement2D(std::array<unsigned int, 3> nodeIds)
		: FemElement2DTriangle(nodeIds)
	{
	}

	const Eigen::Matrix<double, 18, 18, Eigen::DontAlign>& getInitialRotation() const
	{
		return m_R0;
	}

	double getRestArea() const
	{
		return m_restArea;
	}
};

class FemElement2DTriangleTests : public ::testing::Test
{
public:
	static const int m_numberNodes = 6;

	std::array<unsigned int, 3> m_nodeIds;
	DeformableRepresentationState m_restState;
	double m_expectedVolume;
	double m_rho, m_E, m_nu;
	double m_A;         // area
	double m_thickness; // thickness
	Quaterniond m_expectedRotation;

	virtual void SetUp() override
	{
		using SurgSim::Math::getSubVector;

		m_rho = 1000.0;
		m_E = 1e6;
		m_nu = 0.45;
		m_thickness = 1e-2;
		m_A = 1.0 / 2.0;
		m_expectedVolume = m_A * m_thickness;

		// Triangle is made of node 3, 1 and 5 in a bigger system containing m_numberNodes nodes (at least 6)
		m_nodeIds[0] = 3;
		m_nodeIds[1] = 1;
		m_nodeIds[2] = 5;

		m_restState.setNumDof(6, m_numberNodes);

		m_expectedRotation.coeffs().setRandom();
		m_expectedRotation.normalize();

		Vector3d A(0.0, 0.0, 0.0);
		Vector3d B(1.0, 0.0, 0.0);
		Vector3d C(0.0, 1.0, 0.0);
		// The initial rotation of ABC is defined by (i=AB, j=AC, k=ABxAC) = Identity
		// Therefore, by applying m_expectedRotation to the points, the initial rotation of the
		// element should be m_expectedRotation

		Vector& x = m_restState.getPositions();
		getSubVector(x, m_nodeIds[0], 6).segment<3>(0) = m_expectedRotation._transformVector(A);
		getSubVector(x, m_nodeIds[1], 6).segment<3>(0) = m_expectedRotation._transformVector(B);
		getSubVector(x, m_nodeIds[2], 6).segment<3>(0) = m_expectedRotation._transformVector(C);
	}

	void getExpectedMassMatrix(Eigen::Ref<SurgSim::Math::Matrix> mass)
	{
		// XXX TO DO
	}

	void getExpectedStiffnessMatrix(Eigen::Ref<SurgSim::Math::Matrix> stiffness)
	{
		// XXX TO DO
	}

	std::shared_ptr<MockFemElement2D> getElement()
	{
		auto element = std::make_shared<MockFemElement2D>(m_nodeIds);
		element->setThickness(m_thickness);
		element->setMassDensity(m_rho);
		element->setPoissonRatio(m_nu);
		element->setYoungModulus(m_E);
		element->initialize(m_restState);
		return element;
	}
};

TEST_F(FemElement2DTriangleTests, ConstructorTest)
{
	ASSERT_NO_THROW({ MockFemElement2D triangle(m_nodeIds); });
}

TEST_F(FemElement2DTriangleTests, NodeIdsTest)
{
	FemElement2DTriangle element(m_nodeIds);
	EXPECT_EQ(3u, element.getNumNodes());
	EXPECT_EQ(3u, element.getNodeIds().size());
	for (int i = 0; i < 3; i++)
	{
		EXPECT_EQ(m_nodeIds[i], element.getNodeId(i));
		EXPECT_EQ(m_nodeIds[i], element.getNodeIds()[i]);
	}
}

TEST_F(FemElement2DTriangleTests, setGetThicknessTest)
{
	FemElement2DTriangle element(m_nodeIds);

	// Default thickness = 0.0
	EXPECT_DOUBLE_EQ(0.0, element.getThickness());
	// Set to a valid thickness
	element.setThickness(1.54);
	EXPECT_DOUBLE_EQ(1.54, element.getThickness());
	// Set to an invalid thickness
	EXPECT_ANY_THROW(element.setThickness(0.0));
	EXPECT_ANY_THROW(element.setThickness(-9.4));
}

TEST_F(FemElement2DTriangleTests, MaterialParameterTest)
{
	FemElement2DTriangle element(m_nodeIds);
	element.setThickness(m_thickness);

	// Test the various mode of failure related to the physical parameters
	// This has been already tested in FemElementTests, but this is to make sure this method is called properly
	// So the same behavior should be expected
	{
		// Mass density not set
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Poisson Ratio not set
		element.setMassDensity(-1234.56);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Young modulus not set
		element.setPoissonRatio(0.55);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Invalid mass density
		element.setYoungModulus(-4321.33);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Invalid Poisson ratio
		element.setMassDensity(m_rho);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		// Invalid Young modulus
		element.setPoissonRatio(m_nu);
		ASSERT_ANY_THROW(element.initialize(m_restState));

		element.setYoungModulus(m_E);
		ASSERT_NO_THROW(element.initialize(m_restState));
	}
}

TEST_F(FemElement2DTriangleTests, VolumeTest)
{
	std::shared_ptr<MockFemElement2D> element = getElement();
	EXPECT_NEAR(element->getVolume(m_restState), m_expectedVolume, 1e-10);
}

TEST_F(FemElement2DTriangleTests, CoordinateTests)
{
	FemElement2DTriangle element(m_nodeIds);

	Vector validNaturalCoordinate(3);
	Vector invalidNaturalCoordinateSumNot1(3);
	Vector invalidNaturalCoordinateNegativeValue(3);
	Vector invalidNaturalCoordinateBiggerThan1Value(3);
	Vector invalidNaturalCoordinateSize2(2), invalidNaturalCoordinateSize4(4);

	validNaturalCoordinate << 0.4, 0.5, 0.1;
	invalidNaturalCoordinateSumNot1 << 0.4, 0.5, 0.3;
	invalidNaturalCoordinateNegativeValue << 0.7, 0.7, -0.4;
	invalidNaturalCoordinateBiggerThan1Value << 1.4, 0.6, -1.0;
	invalidNaturalCoordinateSize2 << 0.4, 0.6;
	invalidNaturalCoordinateSize4 << 0.2, 0.2, 0.2, 0.4;
	EXPECT_TRUE(element.isValidCoordinate(validNaturalCoordinate));
	EXPECT_FALSE(element.isValidCoordinate(invalidNaturalCoordinateSumNot1));
	EXPECT_FALSE(element.isValidCoordinate(invalidNaturalCoordinateNegativeValue));
	EXPECT_FALSE(element.isValidCoordinate(invalidNaturalCoordinateBiggerThan1Value));
	EXPECT_FALSE(element.isValidCoordinate(invalidNaturalCoordinateSize2));
	EXPECT_FALSE(element.isValidCoordinate(invalidNaturalCoordinateSize4));

	Vector naturalCoordinateA(3), naturalCoordinateB(3), naturalCoordinateC(3), naturalCoordinateMiddle(3);
	Vector3d ptA, ptB, ptC, ptMiddle;
	naturalCoordinateA << 1.0, 0.0, 0.0;
	naturalCoordinateB << 0.0, 1.0, 0.0;
	naturalCoordinateC << 0.0, 0.0, 1.0;
	naturalCoordinateMiddle << 1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0;
	EXPECT_THROW(ptA = element.computeCartesianCoordinate(m_restState, invalidNaturalCoordinateBiggerThan1Value), SurgSim::Framework::AssertionFailure);
	EXPECT_THROW(ptA = element.computeCartesianCoordinate(m_restState, invalidNaturalCoordinateNegativeValue), SurgSim::Framework::AssertionFailure);
	EXPECT_THROW(ptA = element.computeCartesianCoordinate(m_restState, invalidNaturalCoordinateSize2), SurgSim::Framework::AssertionFailure);
	EXPECT_THROW(ptA = element.computeCartesianCoordinate(m_restState, invalidNaturalCoordinateSize4), SurgSim::Framework::AssertionFailure);
	EXPECT_THROW(ptA = element.computeCartesianCoordinate(m_restState, invalidNaturalCoordinateSumNot1), SurgSim::Framework::AssertionFailure);
	EXPECT_NO_THROW(ptA = element.computeCartesianCoordinate(m_restState, naturalCoordinateA));
	EXPECT_NO_THROW(ptB = element.computeCartesianCoordinate(m_restState, naturalCoordinateB));
	EXPECT_NO_THROW(ptC = element.computeCartesianCoordinate(m_restState, naturalCoordinateC));
	EXPECT_NO_THROW(ptMiddle = element.computeCartesianCoordinate(m_restState, naturalCoordinateMiddle));
	EXPECT_TRUE(ptA.isApprox(m_expectedRotation._transformVector(Vector3d(0.0, 0.0, 0.0))));
	EXPECT_TRUE(ptB.isApprox(m_expectedRotation._transformVector(Vector3d(1.0, 0.0, 0.0))));
	EXPECT_TRUE(ptC.isApprox(m_expectedRotation._transformVector(Vector3d(0.0, 1.0, 0.0))));
	EXPECT_TRUE(ptMiddle.isApprox(m_expectedRotation._transformVector(Vector3d(1.0 / 3.0, 1.0 / 3.0, 0.0))));
}

TEST_F(FemElement2DTriangleTests, RestAreaTest)
{
	std::shared_ptr<MockFemElement2D> element = getElement();
	EXPECT_NEAR(element->getRestArea(), m_A, 1e-10);
}

TEST_F(FemElement2DTriangleTests, InitialRotationTest)
{
	std::shared_ptr<MockFemElement2D> element = getElement();

	// Use a mask to test the structure of the rotation matrix R0 (6 digonal block 3x3 matrix and 0 elsewhere)
	Eigen::Matrix<double, 18, 18> mask;
	mask.setOnes();
	mask.block<3, 3>(0, 0).setZero();
	mask.block<3, 3>(3, 3).setZero();
	mask.block<3, 3>(6, 6).setZero();
	mask.block<3, 3>(9, 9).setZero();
	mask.block<3, 3>(12, 12).setZero();
	mask.block<3, 3>(15, 15).setZero();
	EXPECT_TRUE(element->getInitialRotation().cwiseProduct(mask).isZero());

	EXPECT_TRUE(element->getInitialRotation().block(0, 0, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(3, 3, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(6, 6, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(9, 9, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(12, 12, 3, 3).isApprox(m_expectedRotation.matrix()));
	EXPECT_TRUE(element->getInitialRotation().block(15, 15, 3, 3).isApprox(m_expectedRotation.matrix()));
}

TEST_F(FemElement2DTriangleTests, ForceAndMatricesTest)
{
	// XXX TO DO
}
<|endoftext|>