<commit_before>/*
 * Copyright (C) 2003-2006 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "spds/SyncSourceReport.h"
#include "spds/SyncReport.h"
#include "spds/ItemReport.h"

//--------------------------------------------------- Constructor & Destructor
SyncSourceReport::SyncSourceReport(const char* name) {

    lastErrorCode  = ERR_NONE;
    lastErrorMsg   = NULL;
    sourceName     = NULL;
    state          = SOURCE_ACTIVE;

    if (name) {
        setSourceName(name);
    }

    clientAddItems = new ArrayList();
    clientModItems = new ArrayList();
    clientDelItems = new ArrayList();

    serverAddItems = new ArrayList();
    serverModItems = new ArrayList();
    serverDelItems = new ArrayList();
}

SyncSourceReport::SyncSourceReport(SyncSourceReport& ssr) {
    assign(ssr);
}

SyncSourceReport::~SyncSourceReport() {

    if (lastErrorMsg) {
        delete [] lastErrorMsg;
        lastErrorMsg = NULL;
    }
    if (sourceName) {
        delete [] sourceName;
        sourceName = NULL;
    }

    clientAddItems->clear();
    clientModItems->clear();
    clientDelItems->clear();

    serverAddItems->clear();
    serverModItems->clear();
    serverDelItems->clear();
}

//------------------------------------------------------------- Public Methods

const int SyncSourceReport::getLastErrorCode() const {
    return lastErrorCode;
}
void SyncSourceReport::setLastErrorCode(const int code) {
    lastErrorCode = code;

    if (state == SOURCE_ACTIVE) {
        state = SOURCE_ERROR;
    }
}

const SourceState SyncSourceReport::getState() const {
    return state;
}
void SyncSourceReport::setState(const SourceState s) {
    state = s;
}

const char* SyncSourceReport::getLastErrorMsg() const {
    return lastErrorMsg;
}
void SyncSourceReport::setLastErrorMsg(const char* msg) {
    if (lastErrorMsg) {
        delete [] lastErrorMsg;
        lastErrorMsg = NULL;
    }
    lastErrorMsg = stringdup(msg);
}

const char* SyncSourceReport::getSourceName() const {
    return sourceName;
}
void SyncSourceReport::setSourceName(const char* name) {
    if (sourceName) {
        delete [] sourceName;
        sourceName = NULL;
    }
    sourceName = stringdup(name);
}

bool SyncSourceReport::checkState() {
    if (state == SOURCE_ACTIVE) {
        return true;
    }
    return false;
}

ItemReport* SyncSourceReport::getItemReport(const char* target, const char* command, unsigned int index) {

    ArrayList* list = getList(target, command);
    return (ItemReport*)list->get(index);
}

void SyncSourceReport::addItem(const char* target, const char* command, const WCHAR* ID, const int status) {

    // Create the ItemReport element
    ItemReport element(ID, status);

    // Add element in the corresponding list
    ArrayList* list = getList(target, command);
    list->add(element);
}

int SyncSourceReport::getItemReportCount(const char* target, const char* command) {
    ArrayList* list = getList(target, command);
    return list->size();
}

int SyncSourceReport::getItemReportSuccessfulCount(const char* target, const char* command) {

    ArrayList* list = getList(target, command);
    ItemReport* e;

    // Scan for succesful codes
    int good = 0;
    if (list->size() > 0) {
        e = (ItemReport*)list->front();
        if ( isSuccessful(e->getStatus()) ) good++;
        for (int i=1; i<list->size(); i++) {
            e = (ItemReport*)list->next();
            if ( isSuccessful(e->getStatus()) ) good++;
        }
    }
    return good;
}

int SyncSourceReport::getItemReportFailedCount(const char* target, const char* command) {

    ArrayList* list = getList(target, command);
    if (list->size() == 0) {
        return 0;
    }
    int good = getItemReportSuccessfulCount(target, command);
    return (list->size() - good);
}

ArrayList* SyncSourceReport::getList(const char* target, const char* command) const {
    ArrayList* ret;

    if (!strcmp(target, CLIENT)) {
        if (!strcmp(command, COMMAND_ADD)) {
            ret = clientAddItems;
        }
        else if (!strcmp(command, COMMAND_REPLACE)) {
            ret = clientModItems;
        }
        else if (!strcmp(command, COMMAND_DELETE)) {
            ret = clientDelItems;
        }
        else {
            // error
        }
    }
    else if (!strcmp(target, SERVER)) {
        if (!strcmp(command, COMMAND_ADD)) {
            ret = serverAddItems;
        }
        else if (!strcmp(command, COMMAND_REPLACE)) {
            ret = serverModItems;
        }
        else if (!strcmp(command, COMMAND_DELETE)) {
            ret = serverDelItems;
        }
        else {
            // error
        }
    }
    else {
        // error
    }

    return ret;
}

void SyncSourceReport::assign(const SyncSourceReport& ssr) {

    setLastErrorCode(ssr.getLastErrorCode());
    setLastErrorMsg (ssr.getLastErrorMsg ());
    setSourceName   (ssr.getSourceName   ());
    setState        (ssr.getState        ());

    clientAddItems = ssr.getList(CLIENT, COMMAND_ADD);
    clientModItems = ssr.getList(CLIENT, COMMAND_REPLACE);
    clientDelItems = ssr.getList(CLIENT, COMMAND_DELETE);

    serverAddItems = ssr.getList(SERVER, COMMAND_ADD);
    serverModItems = ssr.getList(SERVER, COMMAND_REPLACE);
    serverDelItems = ssr.getList(SERVER, COMMAND_DELETE);
}

//------------------------------------------------------------- Private Methods

bool SyncSourceReport::isSuccessful(const int status) {
    if (status >= 200 && status <= 299)
        return true;
    else
        return false;
}
<commit_msg>Adapted addItem() to manage multiple status received for the same item id (for example on large object)<commit_after>/*
 * Copyright (C) 2003-2006 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "spds/SyncSourceReport.h"
#include "spds/SyncReport.h"
#include "spds/ItemReport.h"

//--------------------------------------------------- Constructor & Destructor
SyncSourceReport::SyncSourceReport(const char* name) {

    lastErrorCode  = ERR_NONE;
    lastErrorMsg   = NULL;
    sourceName     = NULL;
    state          = SOURCE_ACTIVE;

    if (name) {
        setSourceName(name);
    }

    clientAddItems = new ArrayList();
    clientModItems = new ArrayList();
    clientDelItems = new ArrayList();

    serverAddItems = new ArrayList();
    serverModItems = new ArrayList();
    serverDelItems = new ArrayList();
}

SyncSourceReport::SyncSourceReport(SyncSourceReport& ssr) {
    assign(ssr);
}

SyncSourceReport::~SyncSourceReport() {

    if (lastErrorMsg) {
        delete [] lastErrorMsg;
        lastErrorMsg = NULL;
    }
    if (sourceName) {
        delete [] sourceName;
        sourceName = NULL;
    }

    clientAddItems->clear();
    clientModItems->clear();
    clientDelItems->clear();

    serverAddItems->clear();
    serverModItems->clear();
    serverDelItems->clear();
}

//------------------------------------------------------------- Public Methods

const int SyncSourceReport::getLastErrorCode() const {
    return lastErrorCode;
}
void SyncSourceReport::setLastErrorCode(const int code) {
    lastErrorCode = code;

    if (state == SOURCE_ACTIVE) {
        state = SOURCE_ERROR;
    }
}

const SourceState SyncSourceReport::getState() const {
    return state;
}
void SyncSourceReport::setState(const SourceState s) {
    state = s;
}

const char* SyncSourceReport::getLastErrorMsg() const {
    return lastErrorMsg;
}
void SyncSourceReport::setLastErrorMsg(const char* msg) {
    if (lastErrorMsg) {
        delete [] lastErrorMsg;
        lastErrorMsg = NULL;
    }
    lastErrorMsg = stringdup(msg);
}

const char* SyncSourceReport::getSourceName() const {
    return sourceName;
}
void SyncSourceReport::setSourceName(const char* name) {
    if (sourceName) {
        delete [] sourceName;
        sourceName = NULL;
    }
    sourceName = stringdup(name);
}

bool SyncSourceReport::checkState() {
    if (state == SOURCE_ACTIVE) {
        return true;
    }
    return false;
}

ItemReport* SyncSourceReport::getItemReport(const char* target, const char* command, unsigned int index) {

    ArrayList* list = getList(target, command);

    if (index<0 || index >= list->size()) {
        return NULL;
    }
    return (ItemReport*)list->get(index);
}

void SyncSourceReport::addItem(const char* target, const char* command, const WCHAR* ID, const int status) {

    // Create the ItemReport element
    ItemReport element(ID, status);

    // Add element in the corresponding list
    ArrayList* list = getList(target, command);

    // If the element is already present -> no add, only replace status with the new one.
    ItemReport* ie = NULL;
    for (unsigned int i=0; i<list->size(); i++) {
        ie = getItemReport(target, command, i);
        if ( !wcscmp(element.getId(), ie->getId()) ) {
            ie->setStatus(status);
            return;
        }
    }

    // If here, element is new -> add.
    list->add(element);
}

int SyncSourceReport::getItemReportCount(const char* target, const char* command) {
    ArrayList* list = getList(target, command);
    return list->size();
}

int SyncSourceReport::getItemReportSuccessfulCount(const char* target, const char* command) {

    ArrayList* list = getList(target, command);
    ItemReport* e;

    // Scan for succesful codes
    int good = 0;
    if (list->size() > 0) {
        e = (ItemReport*)list->front();
        if ( isSuccessful(e->getStatus()) ) good++;
        for (int i=1; i<list->size(); i++) {
            e = (ItemReport*)list->next();
            if ( isSuccessful(e->getStatus()) ) good++;
        }
    }
    return good;
}

int SyncSourceReport::getItemReportFailedCount(const char* target, const char* command) {

    ArrayList* list = getList(target, command);
    if (list->size() == 0) {
        return 0;
    }
    int good = getItemReportSuccessfulCount(target, command);
    return (list->size() - good);
}

ArrayList* SyncSourceReport::getList(const char* target, const char* command) const {
    ArrayList* ret;

    if (!strcmp(target, CLIENT)) {
        if (!strcmp(command, COMMAND_ADD)) {
            ret = clientAddItems;
        }
        else if (!strcmp(command, COMMAND_REPLACE)) {
            ret = clientModItems;
        }
        else if (!strcmp(command, COMMAND_DELETE)) {
            ret = clientDelItems;
        }
        else {
            // error
        }
    }
    else if (!strcmp(target, SERVER)) {
        if (!strcmp(command, COMMAND_ADD)) {
            ret = serverAddItems;
        }
        else if (!strcmp(command, COMMAND_REPLACE)) {
            ret = serverModItems;
        }
        else if (!strcmp(command, COMMAND_DELETE)) {
            ret = serverDelItems;
        }
        else {
            // error
        }
    }
    else {
        // error
    }

    return ret;
}

void SyncSourceReport::assign(const SyncSourceReport& ssr) {

    setLastErrorCode(ssr.getLastErrorCode());
    setLastErrorMsg (ssr.getLastErrorMsg ());
    setSourceName   (ssr.getSourceName   ());
    setState        (ssr.getState        ());

    clientAddItems = ssr.getList(CLIENT, COMMAND_ADD);
    clientModItems = ssr.getList(CLIENT, COMMAND_REPLACE);
    clientDelItems = ssr.getList(CLIENT, COMMAND_DELETE);

    serverAddItems = ssr.getList(SERVER, COMMAND_ADD);
    serverModItems = ssr.getList(SERVER, COMMAND_REPLACE);
    serverDelItems = ssr.getList(SERVER, COMMAND_DELETE);
}

//------------------------------------------------------------- Private Methods

bool SyncSourceReport::isSuccessful(const int status) {
    if (status >= 200 && status <= 299)
        return true;
    else
        return false;
}
<|endoftext|>


<commit_before>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "http/MacTransportAgent.h"
#include "http/constants.h"

#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#import <SystemConfiguration/SystemConfiguration.h>

USE_NAMESPACE

MacTransportAgent::MacTransportAgent() : TransportAgent() {}

MacTransportAgent::~MacTransportAgent() {}

/*
 * Constructor.
 * In this implementation newProxy is ignored, since proxy configuration
 * is taken from the WinInet subsystem.
 *
 * @param url the url where messages will be sent with sendMessage()
 * @param proxy proxy information or NULL if no proxy should be used
 */
MacTransportAgent::MacTransportAgent(URL& newURL, Proxy& newProxy, unsigned int maxResponseTimeout)
: TransportAgent(newURL, newProxy, maxResponseTimeout)
{

}

/*
 * Sends the given SyncML message to the server specified
 * by the instal property 'url'. Returns the response status code or -1
 * if it was not possible initialize the connection.
 *
 * Use getResponse() to get the server response.
 */
char* MacTransportAgent::sendMessage(const char* msg){

    if(!msg) {
        LOG.error("MacTransportAgent::sendMessage error: NULL message.");
        setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: NULL message.");
        return NULL;
    }

    SCNetworkReachabilityFlags        flags;
    SCNetworkReachabilityRef scnReachRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, url.host);

    bool gotflags = SCNetworkReachabilityGetFlags(scnReachRef, &flags);
    bool isReachable = flags & kSCNetworkReachabilityFlagsReachable;
    bool noConnectionRequired = !(flags & kSCNetworkReachabilityFlagsConnectionRequired);
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN)) {
        noConnectionRequired = true;
    }

    if ( gotflags && isReachable && noConnectionRequired ){

        // size_t size = strlen(msg);
        LOG.debug("Requesting resource %s at %s:%d", url.resource, url.host, url.port);

        LOG.debug("Sending HTTP Request: %s", msg);

        // Construct some headers
        CFStringRef headerFieldName = CFSTR("Content-Type");
        CFStringRef headerFieldValue = CFSTR("application/vnd.syncml+xml");

        // Construct URL
        CFStringRef CFurl =  CFStringCreateWithCString(NULL, url.fullURL, kCFStringEncodingUTF8);
        CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, CFurl, NULL);

        CFStringRef requestMethod = CFSTR("POST");

        CFHTTPMessageRef httpRequest =
        CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1);
        CFStringRef useragent = CFStringCreateWithCString(NULL, getUserAgent(), kCFStringEncodingUTF8);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, CFSTR("user-agent"),  useragent);
        if(!httpRequest){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            return NULL;
        }

        CFDataRef bodyData = CFDataCreate(kCFAllocatorDefault, (const UInt8*)msg, strlen(msg));
        if (!bodyData){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            return NULL;
        }
        CFHTTPMessageSetBody(httpRequest, bodyData);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, headerFieldName, headerFieldValue);

        CFReadStreamRef responseStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, httpRequest);
        if (!CFReadStreamOpen(responseStream)) {//Sends request
            LOG.error("Failed to send HTTP request...");
        }

        StringBuffer result;

#define READ_SIZE 1000
        CFIndex bytesRead = 1;
        UInt8   buffer[READ_SIZE];
        while ( (bytesRead = CFReadStreamRead(responseStream, buffer, READ_SIZE-1)) > 0)
        {
            //   Convert what was read to a C-string
            buffer[bytesRead] = 0;
            //   Append it to the reply string
            result.append((const char*)buffer);
        }

        int statusCode = -1;
        CFHTTPMessageRef reply = (CFHTTPMessageRef) CFReadStreamCopyProperty( responseStream, kCFStreamPropertyHTTPResponseHeader);

        // Pull the status code from the headers
        if (reply) {
            statusCode = CFHTTPMessageGetResponseStatusCode(reply);
            CFRelease(reply);
        }

        LOG.debug("Status Code: %d", statusCode);
        LOG.debug("Result: %s", result.c_str());

        char* ret=0;

        switch (statusCode) {
            case 0: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case 200: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case -1: {                    // no connection (TODO: implement retry)
                setErrorF(ERR_SERVER_ERROR, "Network error in server receiving data. ");
                LOG.error("%s", getLastErrorMsg());

                break;
            }
            case 400: {                    // 400 bad request error. TODO: retry to send the message
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());

                break;
            }
            case 500: {     // 500 -> out code 2052
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 404: {         // 404 -> out code 2060
                setErrorF(ERR_HTTP_NOT_FOUND, "HTTP request error: resource not found (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 408: {   // 408 -> out code 2061
                setErrorF(ERR_HTTP_REQUEST_TIMEOUT, "HTTP request error: server timed out waiting for request (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }

            default: {
                setErrorF(statusCode, "HTTP request error: status received = %d", statusCode);
                LOG.error("%s", getLastErrorMsg());
            }
        }

        CFRelease(headerFieldName);
        CFRelease(headerFieldValue);
        CFRelease(CFurl);
        CFRelease(myURL);
        CFRelease(httpRequest);
        CFRelease(bodyData);
        CFRelease(responseStream);
        CFRelease(requestMethod);

        return ret;
    }else{
        setErrorF(ERR_CONNECT, "Network error: the attempt to connect to the server failed -> exit");
        LOG.debug("%s", getLastErrorMsg());

        return NULL;
    }
}

<commit_msg>added ifdef to compile the mac trasport agent under mac os ox<commit_after>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "http/MacTransportAgent.h"
#include "http/constants.h"

#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#import <SystemConfiguration/SystemConfiguration.h>

USE_NAMESPACE

MacTransportAgent::MacTransportAgent() : TransportAgent() {}

MacTransportAgent::~MacTransportAgent() {}

/*
 * Constructor.
 * In this implementation newProxy is ignored, since proxy configuration
 * is taken from the WinInet subsystem.
 *
 * @param url the url where messages will be sent with sendMessage()
 * @param proxy proxy information or NULL if no proxy should be used
 */
MacTransportAgent::MacTransportAgent(URL& newURL, Proxy& newProxy, unsigned int maxResponseTimeout)
: TransportAgent(newURL, newProxy, maxResponseTimeout)
{

}

/*
 * Sends the given SyncML message to the server specified
 * by the instal property 'url'. Returns the response status code or -1
 * if it was not possible initialize the connection.
 *
 * Use getResponse() to get the server response.
 */
char* MacTransportAgent::sendMessage(const char* msg){

    if(!msg) {
        LOG.error("MacTransportAgent::sendMessage error: NULL message.");
        setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: NULL message.");
        return NULL;
    }

    SCNetworkReachabilityFlags        flags;
    SCNetworkReachabilityRef scnReachRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, url.host);

    bool gotflags = SCNetworkReachabilityGetFlags(scnReachRef, &flags);
    bool isReachable = flags & kSCNetworkReachabilityFlagsReachable;
    bool noConnectionRequired = !(flags & kSCNetworkReachabilityFlagsConnectionRequired);
#if defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN)) {
        noConnectionRequired = true;
    }
#endif

    if ( gotflags && isReachable && noConnectionRequired ){

        // size_t size = strlen(msg);
        LOG.debug("Requesting resource %s at %s:%d", url.resource, url.host, url.port);

        LOG.debug("Sending HTTP Request: %s", msg);

        // Construct some headers
        CFStringRef headerFieldName = CFSTR("Content-Type");
        CFStringRef headerFieldValue = CFSTR("application/vnd.syncml+xml");

        // Construct URL
        CFStringRef CFurl =  CFStringCreateWithCString(NULL, url.fullURL, kCFStringEncodingUTF8);
        CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, CFurl, NULL);

        CFStringRef requestMethod = CFSTR("POST");

        CFHTTPMessageRef httpRequest =
        CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1);
        CFStringRef useragent = CFStringCreateWithCString(NULL, getUserAgent(), kCFStringEncodingUTF8);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, CFSTR("user-agent"),  useragent);
        if(!httpRequest){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            return NULL;
        }

        CFDataRef bodyData = CFDataCreate(kCFAllocatorDefault, (const UInt8*)msg, strlen(msg));
        if (!bodyData){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            return NULL;
        }
        CFHTTPMessageSetBody(httpRequest, bodyData);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, headerFieldName, headerFieldValue);

        CFReadStreamRef responseStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, httpRequest);
        if (!CFReadStreamOpen(responseStream)) {//Sends request
            LOG.error("Failed to send HTTP request...");
        }

        StringBuffer result;

#define READ_SIZE 1000
        CFIndex bytesRead = 1;
        UInt8   buffer[READ_SIZE];
        while ( (bytesRead = CFReadStreamRead(responseStream, buffer, READ_SIZE-1)) > 0)
        {
            //   Convert what was read to a C-string
            buffer[bytesRead] = 0;
            //   Append it to the reply string
            result.append((const char*)buffer);
        }

        int statusCode = -1;
        CFHTTPMessageRef reply = (CFHTTPMessageRef) CFReadStreamCopyProperty( responseStream, kCFStreamPropertyHTTPResponseHeader);

        // Pull the status code from the headers
        if (reply) {
            statusCode = CFHTTPMessageGetResponseStatusCode(reply);
            CFRelease(reply);
        }

        LOG.debug("Status Code: %d", statusCode);
        LOG.debug("Result: %s", result.c_str());

        char* ret=0;

        switch (statusCode) {
            case 0: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case 200: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case -1: {                    // no connection (TODO: implement retry)
                setErrorF(ERR_SERVER_ERROR, "Network error in server receiving data. ");
                LOG.error("%s", getLastErrorMsg());

                break;
            }
            case 400: {                    // 400 bad request error. TODO: retry to send the message
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());

                break;
            }
            case 500: {     // 500 -> out code 2052
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 404: {         // 404 -> out code 2060
                setErrorF(ERR_HTTP_NOT_FOUND, "HTTP request error: resource not found (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 408: {   // 408 -> out code 2061
                setErrorF(ERR_HTTP_REQUEST_TIMEOUT, "HTTP request error: server timed out waiting for request (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }

            default: {
                setErrorF(statusCode, "HTTP request error: status received = %d", statusCode);
                LOG.error("%s", getLastErrorMsg());
            }
        }

        CFRelease(headerFieldName);
        CFRelease(headerFieldValue);
        CFRelease(CFurl);
        CFRelease(myURL);
        CFRelease(httpRequest);
        CFRelease(bodyData);
        CFRelease(responseStream);
        CFRelease(requestMethod);

        return ret;
    }else{
        setErrorF(ERR_CONNECT, "Network error: the attempt to connect to the server failed -> exit");
        LOG.debug("%s", getLastErrorMsg());

        return NULL;
    }
}

<|endoftext|>


<commit_before>#include "Matrix.hpp"
#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <cstdio>
//#include <omp.h>

  // LAPACK/BLAS functions
  extern"C"{

    /*!
     * SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR,
     *               LDVR, WORK, LWORK, INFO )
     *   for info, see: http://www.netlib.org/lapack/double/dgeev.f
     */
    void dgeev_(char* jobvl, char *jobvr, int *n, double *a, int *lda,
        double *wr, double *wi, double *vl, int *ldvl, double *vr,
        int *ldvr, double *work, int *lwork, int *info);

  /*!
   * SUBROUTINE DGEMM(TRANSA,TRANSB,M,N,K,ALPHA,A,LDA,B,LDB,BETA,C,LDC)
   *   for info, see: http://www.netlib.org/blas/dgemm.f
   */
  void dgemm_(char *transa, char* transb, int *m, int *n, int *k, double *alpha,
      double *a, int *lda, double *b, int *ldb, double *beta, double *c,
      int *ldc);

  /*!
   *  SUBROUTINE DGETRI( N, A, LDA, IPIV, WORK, LWORK, INFO )
   *  for info, see http://www.netlib.org/lapack/double/dgetri.f
   */
  void dgetri_(int *n, double *a, int *lda, int *ipiv, double *work, int *lwork, int *info);

  /*!
   * SUBROUTINE DGETRF( M, N, A, LDA, IPIV, INFO )
   * for info, see http://www.netlib.org/lapack/double/dgetrf.f
   */
  void dgetrf_(int *m, int *n, double *a, int *lda, int *ipiv, int *info);
}
/*!
 *  Default constructor, constructs a matrix with size (0,0)
 */
Matrix::Matrix(): nr_rows(0), nr_cols(0), m_data(0){
}
/*!
 *  Constructs a square matrix, filled with 0
 *  @param size The side of the square matrix
 */
Matrix::Matrix(std::size_t size): nr_rows(size), nr_cols(size), m_data(size*size, 0){
}

/*!
 *  Constructs a matrix with size (rows, cols), filled with 0
 *  @param rows Amount of rows
 *  @param cols Amount of columns
 */
Matrix::Matrix(std::size_t rows, std::size_t cols): nr_rows(rows), nr_cols(cols), m_data(cols*rows, 0){
}

/*!
 *  Constructs a matrix with size (rows, cols) and fills it with elements from
 *  an array. The array needs to be of size rows*cols
 *  @param array[] The elements in row-major order
 *  @param rows The amount of rows
 *  @param cols The amount of cols
 */
Matrix::Matrix(const double array[], std::size_t rows, std::size_t cols): m_data(rows*cols, 0), nr_rows(rows), nr_cols(cols){
  for (int i=0; i<cols; i++) {
    for (int j=0; j<rows; j++) {
      m_data[i*rows + j] = array[j*cols + i];
    }
  }
}
/*! Constructs a diagonal matrix from a vector
 *  @param d A reference to a vector containing the diagonal elements
 */
Matrix::Matrix(const std::vector<double> &d): nr_rows(d.size()), nr_cols(d.size()), m_data(d.size()*d.size()){
  for (int i=0; i<d.size(); i++)
    m_data[i*d.size()+i] = d[i];
}

/*! Creates a copy of a matrix
 * @param m The matrix to be copied
 */
Matrix::Matrix(const Matrix &m) : nr_rows(m.get_rows()), nr_cols(m.get_cols()), m_data(m.m_data){
}
/*! Assignment operator
 *  @param m The matrix to be
 *  */
Matrix &Matrix::operator=(const Matrix &m){
  if (&m != this){
    nr_rows = m.get_rows();
    nr_cols = m.get_cols();
    m_data.clear();
    m_data.reserve(m.get_rows()*m.get_cols());
    for (int i=0; i<m.get_rows()*m.get_cols(); i++)
      m_data.push_back(m(i));
  }
  return *this;
}
/*! Function that multiplies two matrices and returns a copy of the product
 *  @param lhv The left matrix
 *  @param rhv The right matrix
 *  @return a const copy with the product of lhv*rhv
 */
Matrix Matrix::mult(const Matrix &lhv,const Matrix &rhv) {
  return mult(lhv, rhv, false, false);
}

/*!
 *  Static function that multiplies to matrices and possiby transposes them,
 *  returns a copy of the product
 *  @param lhv The left matrix
 *  @param rhv The right matrix
 *  @param tr_left true if the left matrix should be transposed, false otherwise
 *  @param tr_right true if the right matrix should be transposed, false otherwise
 *  @return A const copy with the product lhv*rhv
 */
Matrix Matrix::mult(const Matrix &lhv, const Matrix &rhv, bool tr_left, bool tr_right) {
    if (lhv.get_cols() != rhv.get_rows())
      throw std::out_of_range("Matrix dimensions doesn't agree");

    char transl, transr;
    int left_op_rows = lhv.get_rows();
    int right_op_cols = rhv.get_cols();
    int left_op_cols = lhv.get_cols();
    double dummy_one = 1;
    double dummy_zero = 0;
    // Matrix to store the result
    Matrix result(left_op_rows, right_op_cols);

    // T - the matrix should be transposed
    // N - the matrix should not be transposed
    tr_left ? transl = 'T' : transl = 'N';
    tr_right ? transr = 'T' : transr = 'N';

    // dgemm_ is a BLAS subroutine that multiplies two matrices
    // const_cast<double*> because dgemm_ will not change those arguments
    dgemm_(&transl, &transr, &left_op_rows, &right_op_cols, &left_op_cols,
        &dummy_one, const_cast<double *>(&lhv.m_data[0]), &left_op_cols,
        const_cast<double *>(&rhv.m_data[0]), &right_op_cols,
        &dummy_zero, &result.m_data[0], &left_op_rows);
    return result;
  }

//Should this function be turned into a non-member too?
/*!
 *
 * @return A copy of the product
 */
Matrix Matrix::diag_mult(const std::vector<double> &diag) const{
  Matrix temp(*this);

  for (int i=0; i<get_cols(); i++)
    for (int j=0; j<get_rows(); j++)
      temp(i,j) = (*this)(i*get_rows()+j)*diag[i];

  return temp;
}
/*!
 * A function that applies ln() on every element in the matrix.
 */
void Matrix::mlog(){
  int size = get_rows()*get_cols();
  for (int i=0; i<size; i++)
    (*this)(i) = log((*this)(i));
}

/*!
 *  A const function that calculates the matrix exponential and returns a copy.
 *  The exponential is calculated by finding the eigenvalues and eigenvectors
 *  of the matrix, exponentiating the eigenvalues. The eigenvalues is stored in
 *  a matrix V, eigenvectors is stored in a matrix A, inv(A) is calculated.
 *  The product A*V*inv(A) is returned.
 *  @return A copy of the exponentiated matrix
 */
Matrix Matrix::expm() const{
  return expm(DblVec(1,1))[0];
}

/*!
 *  A const function that for every value in a vector calculates the matrix
 *  exponential of the matrix multiplied with that value
 *  The exponential is calculated by finding the eigenvalues and eigenvectors
 *  of the matrix, exponentiating the eigenvalues. The eigenvalues is stored in
 *  a matrix V, eigenvectors is stored in a matrix A, inv(A) is calculated.
 *  The product A*V*inv(A) is returned.
 *  @param s A vector with values to be multiplied with the matrix before
 *            the exponent is calculated.
 *  @return A vector with the exponential of the matrix multiplied with every
 *            value in s
 */
MatVec Matrix::expm(const DblVec &s) const {

  // Can only calculate eigenvalues and vectors of square matrices
  if (get_rows() != get_cols())
    throw std::out_of_range("Matrix needs to be square");

  int size = get_rows();
  DblVec eg_val_real(size, 0); // Real part of eigenvalues
  DblVec eg_val_im(size, 0);   // Imaginary part of eigenvalues
                               // should be zero
  double dummy[1];
  int dummy_size = 1;
  double dummy_one = 1;
  int info[1];
  char n = 'N';   // Do not want to use this argument
  char v = 'V';   // Want to use this argument
  double workspace_size[1];
  int w_query = -1;

  // Need to make a copy of the data in Q to send into dgeev_ because
  // the data sent in is overwritten
  int data_size = get_rows()*get_cols();
  DblVec data(m_data);

  // Matrix for the eigenvectors
  Matrix t_mat = Matrix(size, size);

  //workspace-query
  // SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR,
  //               LDVR, WORK, LWORK, INFO )
  dgeev_(&n, &v, &size, &data[0], &size, &eg_val_real[0], &eg_val_im[0], dummy,
      &dummy_size, &t_mat.m_data[0], &size, workspace_size, &w_query, info);

  DblVec workspace_vec(static_cast<int>(workspace_size[0]), 0);
  int w_size = static_cast<int>(workspace_size[0]);

  // Real calculation of eigenvalues and eigenvectors for Q
  dgeev_(&n, &v, &size, &data[0], &size, &eg_val_real[0], &eg_val_im[0], dummy,
      &dummy_size, &t_mat.m_data[0], &size, &workspace_vec[0], &w_size, info);

  // Calculating inverse of matrix with eigenvectors
  Matrix t_mat_inv(t_mat);
  int ipiv[size];

  // LU factorization, t_mat_inv.m_data is overwritten with the LU factorization
  dgetrf_(&size, &size, &t_mat_inv.m_data[0], &size, ipiv, info);

  //workspace-query, nothing happens with t_mat_inv.m_data
  dgetri_(&size, &t_mat_inv.m_data[0], &size, ipiv, workspace_size, &w_query, info);

  double workspace_vec2[static_cast<int>(workspace_size[0])];
  w_size = static_cast<int>(workspace_size[0]);

  // Inverse calculation from LU values, the inverse is stored in t_mat_inv.m_data
  dgetri_(&size, &t_mat_inv.m_data[0], &size, ipiv, workspace_vec2, &w_size, info);

  MatVec result;
  result.reserve(s.size());

  // e^(this) = T*D*T^-1
  // T = matrix with eigenvectors (t_mat), D = matrix with exponentiated eigenvalues
  // Calculate for every value in incoming vector s
  DblVec eg_val_exp;
  eg_val_exp.reserve(size);
  for (DblVec::const_iterator it=s.begin(); it != s.end(); it++){
    for (int i=0; i<size; i++)
      eg_val_exp.push_back(exp(eg_val_real[i]*(*it)));
    Matrix left = Matrix::mult(t_mat, Matrix(eg_val_exp));
    Matrix res = Matrix::mult( left, t_mat_inv);
    result.push_back(res);
    eg_val_exp.clear();
  }
  return result;
}

/*!
 *  A function for printing the matrix
 */
void Matrix::printm() const{
  for (int i=0; i<get_rows(); i++) {
    for (int j=0; j<get_cols(); j++)
      printf(" %.20e ", (*this)(i,j));
    std::cout << std::endl;
  }
}
void Matrix::printmi() const{
  for (int i=0; i<get_rows(); i++) {
    for (int j=0; j<get_cols(); j++)
      printf(" %.3d ", (*this)(i,j));
    std::cout << std::endl;
  }
}
/*!
 *  A const function that sums all the elements in the matrix.
 *  @return The sum of all the elements in the matrix
 */
double Matrix::sum() const{
  return std::accumulate(m_data.begin(), m_data.end(), 0.0);
}

/*!
 *  A const function that sums all the elements on the diagonal of the matrix
 *  @return The sum of all the diagonal elements of the matrix
 */
double Matrix::sum_diag() const{
  double sum=0.0;
  if (get_rows() != get_cols())
    throw std::out_of_range("Matrix needs to be square");

  for (int i=0;i<get_rows();i++)
    sum += (*this)(i,i);

  return sum;
}
//--------------------------------------------------------------
// Non-member functions

/*!
 *  Non-member function that multiplies two matrices elementwise. The product is
 *  C(i,j) = A(i,j)*B(i,j). The matrices must have the same dimensions.
 *  @param lhv The matrix to the right
 *  @param rhv The matrix to the right
 *  @param A copy of the product
 */
  Matrix elem_mult(const Matrix &lhv, const Matrix &rhv){
    if (lhv.get_rows() != rhv.get_rows() || lhv.get_cols() != rhv.get_cols())
      throw std::out_of_range("Matrix dimensions must agree");

    Matrix temp(lhv.get_rows(), rhv.get_cols());

    for (int i=0; i<lhv.get_rows()*lhv.get_cols(); i++)
      temp(i) = lhv(i)*rhv(i);

    return temp;

  }

/*!
 *  Non-member function that divides a matrix with another elementwise. A copy
 *  of the quotient C(i,j) = A(i,j)/B(i,j) is returned.
 *  @param lhv The dividend
 *  @param rhv The divisor
 *  @return The quotient
 */
  Matrix elem_div(const Matrix &lhv, const Matrix &rhv){
    if (lhv.get_rows() != rhv.get_rows() || lhv.get_cols() != rhv.get_cols())
      throw std::out_of_range("Matrix dimensions must agree");

    Matrix temp(lhv.get_rows(), lhv.get_cols());

    for (int i=0; i<lhv.get_rows()*lhv.get_cols(); i++)
      temp(i) = lhv(i)/rhv(i);

    return temp;
  }
<commit_msg>Piping now working for xml, phylip and binary cases. Efficient Memory functionality is added<commit_after>#include "Matrix.hpp"
#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <cstdio>
#include <omp.h>

  // LAPACK/BLAS functions
  extern"C"{

    /*!
     * SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR,
     *               LDVR, WORK, LWORK, INFO )
     *   for info, see: http://www.netlib.org/lapack/double/dgeev.f
     */
    void dgeev_(char* jobvl, char *jobvr, int *n, double *a, int *lda,
        double *wr, double *wi, double *vl, int *ldvl, double *vr,
        int *ldvr, double *work, int *lwork, int *info);

  /*!
   * SUBROUTINE DGEMM(TRANSA,TRANSB,M,N,K,ALPHA,A,LDA,B,LDB,BETA,C,LDC)
   *   for info, see: http://www.netlib.org/blas/dgemm.f
   */
  void dgemm_(char *transa, char* transb, int *m, int *n, int *k, double *alpha,
      double *a, int *lda, double *b, int *ldb, double *beta, double *c,
      int *ldc);

  /*!
   *  SUBROUTINE DGETRI( N, A, LDA, IPIV, WORK, LWORK, INFO )
   *  for info, see http://www.netlib.org/lapack/double/dgetri.f
   */
  void dgetri_(int *n, double *a, int *lda, int *ipiv, double *work, int *lwork, int *info);

  /*!
   * SUBROUTINE DGETRF( M, N, A, LDA, IPIV, INFO )
   * for info, see http://www.netlib.org/lapack/double/dgetrf.f
   */
  void dgetrf_(int *m, int *n, double *a, int *lda, int *ipiv, int *info);
}
/*!
 *  Default constructor, constructs a matrix with size (0,0)
 */
Matrix::Matrix(): nr_rows(0), nr_cols(0), m_data(0){
}
/*!
 *  Constructs a square matrix, filled with 0
 *  @param size The side of the square matrix
 */
Matrix::Matrix(std::size_t size): nr_rows(size), nr_cols(size), m_data(size*size, 0){
}

/*!
 *  Constructs a matrix with size (rows, cols), filled with 0
 *  @param rows Amount of rows
 *  @param cols Amount of columns
 */
Matrix::Matrix(std::size_t rows, std::size_t cols): nr_rows(rows), nr_cols(cols), m_data(cols*rows, 0){
}

/*!
 *  Constructs a matrix with size (rows, cols) and fills it with elements from
 *  an array. The array needs to be of size rows*cols
 *  @param array[] The elements in row-major order
 *  @param rows The amount of rows
 *  @param cols The amount of cols
 */
Matrix::Matrix(const double array[], std::size_t rows, std::size_t cols): m_data(rows*cols, 0), nr_rows(rows), nr_cols(cols){
  for (int i=0; i<cols; i++) {
    for (int j=0; j<rows; j++) {
      m_data[i*rows + j] = array[j*cols + i];
    }
  }
}
/*! Constructs a diagonal matrix from a vector
 *  @param d A reference to a vector containing the diagonal elements
 */
Matrix::Matrix(const std::vector<double> &d): nr_rows(d.size()), nr_cols(d.size()), m_data(d.size()*d.size()){
  for (int i=0; i<d.size(); i++)
    m_data[i*d.size()+i] = d[i];
}

/*! Creates a copy of a matrix
 * @param m The matrix to be copied
 */
Matrix::Matrix(const Matrix &m) : nr_rows(m.get_rows()), nr_cols(m.get_cols()), m_data(m.m_data){
}
/*! Assignment operator
 *  @param m The matrix to be
 *  */
Matrix &Matrix::operator=(const Matrix &m){
  if (&m != this){
    nr_rows = m.get_rows();
    nr_cols = m.get_cols();
    m_data.clear();
    m_data.reserve(m.get_rows()*m.get_cols());
    for (int i=0; i<m.get_rows()*m.get_cols(); i++)
      m_data.push_back(m(i));
  }
  return *this;
}
/*! Function that multiplies two matrices and returns a copy of the product
 *  @param lhv The left matrix
 *  @param rhv The right matrix
 *  @return a const copy with the product of lhv*rhv
 */
Matrix Matrix::mult(const Matrix &lhv,const Matrix &rhv) {
  return mult(lhv, rhv, false, false);
}

/*!
 *  Static function that multiplies to matrices and possiby transposes them,
 *  returns a copy of the product
 *  @param lhv The left matrix
 *  @param rhv The right matrix
 *  @param tr_left true if the left matrix should be transposed, false otherwise
 *  @param tr_right true if the right matrix should be transposed, false otherwise
 *  @return A const copy with the product lhv*rhv
 */
Matrix Matrix::mult(const Matrix &lhv, const Matrix &rhv, bool tr_left, bool tr_right) {
    if (lhv.get_cols() != rhv.get_rows())
      throw std::out_of_range("Matrix dimensions doesn't agree");

    char transl, transr;
    int left_op_rows = lhv.get_rows();
    int right_op_cols = rhv.get_cols();
    int left_op_cols = lhv.get_cols();
    double dummy_one = 1;
    double dummy_zero = 0;
    // Matrix to store the result
    Matrix result(left_op_rows, right_op_cols);

    // T - the matrix should be transposed
    // N - the matrix should not be transposed
    tr_left ? transl = 'T' : transl = 'N';
    tr_right ? transr = 'T' : transr = 'N';

    // dgemm_ is a BLAS subroutine that multiplies two matrices
    // const_cast<double*> because dgemm_ will not change those arguments
    dgemm_(&transl, &transr, &left_op_rows, &right_op_cols, &left_op_cols,
        &dummy_one, const_cast<double *>(&lhv.m_data[0]), &left_op_cols,
        const_cast<double *>(&rhv.m_data[0]), &right_op_cols,
        &dummy_zero, &result.m_data[0], &left_op_rows);
    return result;
  }

//Should this function be turned into a non-member too?
/*!
 *
 * @return A copy of the product
 */
Matrix Matrix::diag_mult(const std::vector<double> &diag) const{
  Matrix temp(*this);

  for (int i=0; i<get_cols(); i++)
    for (int j=0; j<get_rows(); j++)
      temp(i,j) = (*this)(i*get_rows()+j)*diag[i];

  return temp;
}
/*!
 * A function that applies ln() on every element in the matrix.
 */
void Matrix::mlog(){
  int size = get_rows()*get_cols();
  for (int i=0; i<size; i++)
    (*this)(i) = log((*this)(i));
}

/*!
 *  A const function that calculates the matrix exponential and returns a copy.
 *  The exponential is calculated by finding the eigenvalues and eigenvectors
 *  of the matrix, exponentiating the eigenvalues. The eigenvalues is stored in
 *  a matrix V, eigenvectors is stored in a matrix A, inv(A) is calculated.
 *  The product A*V*inv(A) is returned.
 *  @return A copy of the exponentiated matrix
 */
Matrix Matrix::expm() const{
  return expm(DblVec(1,1))[0];
}

/*!
 *  A const function that for every value in a vector calculates the matrix
 *  exponential of the matrix multiplied with that value
 *  The exponential is calculated by finding the eigenvalues and eigenvectors
 *  of the matrix, exponentiating the eigenvalues. The eigenvalues is stored in
 *  a matrix V, eigenvectors is stored in a matrix A, inv(A) is calculated.
 *  The product A*V*inv(A) is returned.
 *  @param s A vector with values to be multiplied with the matrix before
 *            the exponent is calculated.
 *  @return A vector with the exponential of the matrix multiplied with every
 *            value in s
 */
MatVec Matrix::expm(const DblVec &s) const {

  // Can only calculate eigenvalues and vectors of square matrices
  if (get_rows() != get_cols())
    throw std::out_of_range("Matrix needs to be square");

  int size = get_rows();
  DblVec eg_val_real(size, 0); // Real part of eigenvalues
  DblVec eg_val_im(size, 0);   // Imaginary part of eigenvalues
                               // should be zero
  double dummy[1];
  int dummy_size = 1;
  double dummy_one = 1;
  int info[1];
  char n = 'N';   // Do not want to use this argument
  char v = 'V';   // Want to use this argument
  double workspace_size[1];
  int w_query = -1;

  // Need to make a copy of the data in Q to send into dgeev_ because
  // the data sent in is overwritten
  int data_size = get_rows()*get_cols();
  DblVec data(m_data);

  // Matrix for the eigenvectors
  Matrix t_mat = Matrix(size, size);

  //workspace-query
  // SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR,
  //               LDVR, WORK, LWORK, INFO )
  dgeev_(&n, &v, &size, &data[0], &size, &eg_val_real[0], &eg_val_im[0], dummy,
      &dummy_size, &t_mat.m_data[0], &size, workspace_size, &w_query, info);

  DblVec workspace_vec(static_cast<int>(workspace_size[0]), 0);
  int w_size = static_cast<int>(workspace_size[0]);

  // Real calculation of eigenvalues and eigenvectors for Q
  dgeev_(&n, &v, &size, &data[0], &size, &eg_val_real[0], &eg_val_im[0], dummy,
      &dummy_size, &t_mat.m_data[0], &size, &workspace_vec[0], &w_size, info);

  // Calculating inverse of matrix with eigenvectors
  Matrix t_mat_inv(t_mat);
  int ipiv[size];

  // LU factorization, t_mat_inv.m_data is overwritten with the LU factorization
  dgetrf_(&size, &size, &t_mat_inv.m_data[0], &size, ipiv, info);

  //workspace-query, nothing happens with t_mat_inv.m_data
  dgetri_(&size, &t_mat_inv.m_data[0], &size, ipiv, workspace_size, &w_query, info);

  double workspace_vec2[static_cast<int>(workspace_size[0])];
  w_size = static_cast<int>(workspace_size[0]);

  // Inverse calculation from LU values, the inverse is stored in t_mat_inv.m_data
  dgetri_(&size, &t_mat_inv.m_data[0], &size, ipiv, workspace_vec2, &w_size, info);

  MatVec result;
  result.reserve(s.size());

  // e^(this) = T*D*T^-1
  // T = matrix with eigenvectors (t_mat), D = matrix with exponentiated eigenvalues
  // Calculate for every value in incoming vector s
  DblVec eg_val_exp;
  eg_val_exp.reserve(size);
  for (DblVec::const_iterator it=s.begin(); it != s.end(); it++){
    for (int i=0; i<size; i++)
      eg_val_exp.push_back(exp(eg_val_real[i]*(*it)));
    Matrix left = Matrix::mult(t_mat, Matrix(eg_val_exp));
    Matrix res = Matrix::mult( left, t_mat_inv);
    result.push_back(res);
    eg_val_exp.clear();
  }
  return result;
}

/*!
 *  A function for printing the matrix
 */
void Matrix::printm() const{
  for (int i=0; i<get_rows(); i++) {
    for (int j=0; j<get_cols(); j++)
      printf(" %.20e ", (*this)(i,j));
    std::cout << std::endl;
  }
}
void Matrix::printmi() const{
  for (int i=0; i<get_rows(); i++) {
    for (int j=0; j<get_cols(); j++)
      printf(" %.3d ", (*this)(i,j));
    std::cout << std::endl;
  }
}
/*!
 *  A const function that sums all the elements in the matrix.
 *  @return The sum of all the elements in the matrix
 */
double Matrix::sum() const{
  return std::accumulate(m_data.begin(), m_data.end(), 0.0);
}

/*!
 *  A const function that sums all the elements on the diagonal of the matrix
 *  @return The sum of all the diagonal elements of the matrix
 */
double Matrix::sum_diag() const{
  double sum=0.0;
  if (get_rows() != get_cols())
    throw std::out_of_range("Matrix needs to be square");

  for (int i=0;i<get_rows();i++)
    sum += (*this)(i,i);

  return sum;
}
//--------------------------------------------------------------
// Non-member functions

/*!
 *  Non-member function that multiplies two matrices elementwise. The product is
 *  C(i,j) = A(i,j)*B(i,j). The matrices must have the same dimensions.
 *  @param lhv The matrix to the right
 *  @param rhv The matrix to the right
 *  @param A copy of the product
 */
  Matrix elem_mult(const Matrix &lhv, const Matrix &rhv){
    if (lhv.get_rows() != rhv.get_rows() || lhv.get_cols() != rhv.get_cols())
      throw std::out_of_range("Matrix dimensions must agree");

    Matrix temp(lhv.get_rows(), rhv.get_cols());

    for (int i=0; i<lhv.get_rows()*lhv.get_cols(); i++)
      temp(i) = lhv(i)*rhv(i);

    return temp;

  }

/*!
 *  Non-member function that divides a matrix with another elementwise. A copy
 *  of the quotient C(i,j) = A(i,j)/B(i,j) is returned.
 *  @param lhv The dividend
 *  @param rhv The divisor
 *  @return The quotient
 */
  Matrix elem_div(const Matrix &lhv, const Matrix &rhv){
    if (lhv.get_rows() != rhv.get_rows() || lhv.get_cols() != rhv.get_cols())
      throw std::out_of_range("Matrix dimensions must agree");

    Matrix temp(lhv.get_rows(), lhv.get_cols());

    for (int i=0; i<lhv.get_rows()*lhv.get_cols(); i++)
      temp(i) = lhv(i)/rhv(i);

    return temp;
  }
<|endoftext|>


<commit_before>/*
 * uptest.cpp
 *
 *  Created on: Dec 12, 2011
 *      Author: joe
 */

#define BOOST_TEST_MODULE UPTest
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/shared_ptr.hpp>
#include <list>
#include <algorithm>
#include "logic/unit_prop.h"
#include "testutilities.h"
#include "siset.h"
#include "spaninterval.h"
#include "interval.h"
#include "logic/el_syntax.h"

BOOST_AUTO_TEST_CASE( qconstraints ) {
    boost::shared_ptr<Sentence> s = getAsSentence("<>{m} P(a)");
    boost::shared_ptr<DiamondOp> dia = boost::dynamic_pointer_cast<DiamondOp>(s);

    TQConstraints constraints;
    constraints.mustBeIn.add(SpanInterval(1,2,1,2));
    constraints.mustNotBeIn.add(SpanInterval(1,1,1,1));

    boost::shared_ptr<DiamondOp> diaCopy(new DiamondOp(dia->sentence(),dia->relations().begin(), dia->relations().end(), &constraints));
    BOOST_CHECK_EQUAL(diaCopy->toString(), "<>{m:&{[1:2]},\\{[1:1]}} P(a)");
}

BOOST_AUTO_TEST_CASE( simple_lit ) {
    std::string facts = "video(a) @ [1:20]";
    std::string formulas = "P(a) @ [1:3]\n"
            "!P(a) @ [8:11]\n"
            "Q(a) @ [1:10]\n"
            "P(a) v Q(a) v R(a) @ [1:20]";

    Domain d = loadDomainWithStreams(facts, formulas);

    FormulaList flist = d.formulas();
    QCNFClauseList clauseList = convertToQCNFClauseList(flist);

    QUnitsFormulasPair result = performUnitPropagation(clauseList);

    for(QCNFLiteralList::const_iterator it = result.first.begin(); it != result.first.end(); it++) {
        QCNFLiteral lit = *it;
        ELSentence s = convertFromQCNFClause(lit);
        std::cout << "unit clause: " << s.toString() << std::endl;
    }

    for(QCNFClauseList::const_iterator it = result.second.begin(); it != result.second.end(); it++) {
        QCNFClause c = *it;
        ELSentence s = convertFromQCNFClause(c);
        std::cout << "formula: " << s.toString() << std::endl;
    }
    BOOST_REQUIRE_EQUAL(result.first.size(), 3);
    // TODO: write test
}

BOOST_AUTO_TEST_CASE( dia_lit ) {
    std::string facts = "video(a) @ [1:20]";
    std::string formulas = "P(a) @ [1:3]\n"
            "<>{d} P(a) v Q(a) @ [1:4]\n";

    Domain d = loadDomainWithStreams(facts, formulas);

    FormulaList flist = d.formulas();
    QCNFClauseList clauseList = convertToQCNFClauseList(flist);

    QUnitsFormulasPair result = performUnitPropagation(clauseList);

    for(QCNFLiteralList::const_iterator it = result.first.begin(); it != result.first.end(); it++) {
        QCNFLiteral lit = *it;
        ELSentence s = convertFromQCNFClause(lit);
        std::cout << "unit clause: " << s.toString() << std::endl;
    }

    for(QCNFClauseList::const_iterator it = result.second.begin(); it != result.second.end(); it++) {
        QCNFClause c = *it;
        ELSentence s = convertFromQCNFClause(c);
        std::cout << "formula: " << s.toString() << std::endl;
    }
}

BOOST_AUTO_TEST_CASE( simple_lit_directly ) {

    std::string facts = "video(a) @ [1:20]";
    std::string formulas = "P(a) @ [1:10]\n"
            "Q(a) @ [1:10]\n"
            "P(a) v Q(a) @ [1:20]";

    Domain d = loadDomainWithStreams(facts, formulas);

    FormulaList flist = d.formulas();
    ELSentence s1 = flist[0];
    ELSentence s2 = flist[1];
    ELSentence s3 = flist[2];

    QCNFClause qs1 = convertToQCNFClause(s1);
    QCNFClause qs2 = convertToQCNFClause(s2);
    QCNFClause qs3 = convertToQCNFClause(s3);

    QCNFLiteral l1;
    l1.first = qs1.first.front();
    l1.second = qs1.second;

    QCNFClauseList list = propagateLiteral(l1, qs3);
    BOOST_REQUIRE_EQUAL(list.size(), 1);
    BOOST_CHECK_EQUAL(list.front().second.toString(), "{[(1, 10), (11, 20)], [11:20]}");

    // try wrapping l1 in a negation and propagating
    boost::shared_ptr<Sentence> negl1(new Negation(l1.first));
    l1.first = negl1;

    list = propagateLiteral(l1, qs3);
    BOOST_REQUIRE_EQUAL(list.size(), 2);
    QCNFClauseList::const_iterator it = list.begin();
    ELSentence first = convertFromQCNFClause(*it);
    it++;
    ELSentence second = convertFromQCNFClause(*it);
    BOOST_CHECK_EQUAL(first.sentence()->toString(), "Q(a)");
    BOOST_CHECK_EQUAL(first.quantification().toString(), "{[1:10]}");

    BOOST_CHECK_EQUAL(second.sentence()->toString(), "P(a) v Q(a)");
    BOOST_CHECK_EQUAL(second.quantification().toString(), "{[(1, 10), (11, 20)], [11:20]}");
}

BOOST_AUTO_TEST_CASE( cnfConvertBasic ) {

    boost::shared_ptr<Sentence> a = getAsSentence("P(a) v Q(a) v !R(a) v S(a)");
    CNFClause c = convertToCNFClause(a);

    BOOST_REQUIRE_EQUAL(c.size(), 4);
    boost::shared_ptr<Sentence> pa = getAsSentence("P(a)");
    boost::shared_ptr<Sentence> qa = getAsSentence("Q(a)");
    boost::shared_ptr<Sentence> nra = getAsSentence("!R(a)");
    boost::shared_ptr<Sentence> sa = getAsSentence("S(a)");
    /* TODO: why doesn't the below work?
    BOOST_CHECK(std::find(c.begin(), c.end(), pa) != c.end());
    BOOST_CHECK(std::find(c.begin(), c.end(), qa) != c.end());
    BOOST_CHECK(std::find(c.begin(), c.end(), nra) != c.end());
    BOOST_CHECK(std::find(c.begin(), c.end(), sa) != c.end());
     */

}
<commit_msg>added unit test for the liquid op case<commit_after>/*
 * uptest.cpp
 *
 *  Created on: Dec 12, 2011
 *      Author: joe
 */

#define BOOST_TEST_MODULE UPTest
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/shared_ptr.hpp>
#include <list>
#include <algorithm>
#include "logic/unit_prop.h"
#include "testutilities.h"
#include "siset.h"
#include "spaninterval.h"
#include "interval.h"
#include "logic/el_syntax.h"

BOOST_AUTO_TEST_CASE( qconstraints ) {
    boost::shared_ptr<Sentence> s = getAsSentence("<>{m} P(a)");
    boost::shared_ptr<DiamondOp> dia = boost::dynamic_pointer_cast<DiamondOp>(s);

    TQConstraints constraints;
    constraints.mustBeIn.add(SpanInterval(1,2,1,2));
    constraints.mustNotBeIn.add(SpanInterval(1,1,1,1));

    boost::shared_ptr<DiamondOp> diaCopy(new DiamondOp(dia->sentence(),dia->relations().begin(), dia->relations().end(), &constraints));
    BOOST_CHECK_EQUAL(diaCopy->toString(), "<>{m:&{[1:2]},\\{[1:1]}} P(a)");
}

BOOST_AUTO_TEST_CASE( simple_lit ) {
    std::string facts = "video(a) @ [1:20]";
    std::string formulas = "P(a) @ [1:3]\n"
            "!P(a) @ [8:11]\n"
            "Q(a) @ [1:10]\n"
            "P(a) v Q(a) v R(a) @ [1:20]";

    Domain d = loadDomainWithStreams(facts, formulas);

    FormulaList flist = d.formulas();
    QCNFClauseList clauseList = convertToQCNFClauseList(flist);

    QUnitsFormulasPair result = performUnitPropagation(clauseList);

    for(QCNFLiteralList::const_iterator it = result.first.begin(); it != result.first.end(); it++) {
        QCNFLiteral lit = *it;
        ELSentence s = convertFromQCNFClause(lit);
        std::cout << "unit clause: " << s.toString() << std::endl;
    }

    for(QCNFClauseList::const_iterator it = result.second.begin(); it != result.second.end(); it++) {
        QCNFClause c = *it;
        ELSentence s = convertFromQCNFClause(c);
        std::cout << "formula: " << s.toString() << std::endl;
    }
    BOOST_REQUIRE_EQUAL(result.first.size(), 3);
    // TODO: write test
}

BOOST_AUTO_TEST_CASE( dia_lit ) {
    std::string facts = "video(a) @ [1:20]";
    std::string formulas = "P(a) @ [1:3]\n"
            "<>{d} P(a) v Q(a) @ [1:4]\n";

    Domain d = loadDomainWithStreams(facts, formulas);

    FormulaList flist = d.formulas();
    QCNFClauseList clauseList = convertToQCNFClauseList(flist);

    QUnitsFormulasPair result = performUnitPropagation(clauseList);

    for(QCNFLiteralList::const_iterator it = result.first.begin(); it != result.first.end(); it++) {
        QCNFLiteral lit = *it;
        ELSentence s = convertFromQCNFClause(lit);
        std::cout << "unit clause: " << s.toString() << std::endl;
    }

    for(QCNFClauseList::const_iterator it = result.second.begin(); it != result.second.end(); it++) {
        QCNFClause c = *it;
        ELSentence s = convertFromQCNFClause(c);
        std::cout << "formula: " << s.toString() << std::endl;
    }
}

BOOST_AUTO_TEST_CASE( simple_lit_directly ) {

    std::string facts = "video(a) @ [1:20]";
    std::string formulas = "P(a) @ [1:10]\n"
            "Q(a) @ [1:10]\n"
            "P(a) v Q(a) @ [1:20]";

    Domain d = loadDomainWithStreams(facts, formulas);

    FormulaList flist = d.formulas();
    ELSentence s1 = flist[0];
    ELSentence s2 = flist[1];
    ELSentence s3 = flist[2];

    QCNFClause qs1 = convertToQCNFClause(s1);
    QCNFClause qs2 = convertToQCNFClause(s2);
    QCNFClause qs3 = convertToQCNFClause(s3);

    QCNFLiteral l1;
    l1.first = qs1.first.front();
    l1.second = qs1.second;

    QCNFClauseList list = propagateLiteral(l1, qs3);
    BOOST_REQUIRE_EQUAL(list.size(), 1);
    BOOST_CHECK_EQUAL(list.front().second.toString(), "{[(1, 10), (11, 20)], [11:20]}");

    // try wrapping l1 in a negation and propagating
    boost::shared_ptr<Sentence> negl1(new Negation(l1.first));
    l1.first = negl1;

    list = propagateLiteral(l1, qs3);
    BOOST_REQUIRE_EQUAL(list.size(), 2);
    QCNFClauseList::const_iterator it = list.begin();
    ELSentence first = convertFromQCNFClause(*it);
    it++;
    ELSentence second = convertFromQCNFClause(*it);
    BOOST_CHECK_EQUAL(first.sentence()->toString(), "Q(a)");
    BOOST_CHECK_EQUAL(first.quantification().toString(), "{[1:10]}");

    BOOST_CHECK_EQUAL(second.sentence()->toString(), "P(a) v Q(a)");
    BOOST_CHECK_EQUAL(second.quantification().toString(), "{[(1, 10), (11, 20)], [11:20]}");
}

BOOST_AUTO_TEST_CASE( simpleLitToLiq) {
    std::string facts = "P(a) @ [1:20]\n";
    std::string formulas = "[ P(a) ] v Q(a) @ [1:30]\n";

    Domain d = loadDomainWithStreams(facts, formulas);
    QUnitsFormulasPair pair = performUnitPropagation(d);
    std::ostringstream str;
    std::copy(pair.second.begin(), pair.second.end(), std::ostream_iterator<QCNFClause>(str, ", "));
    BOOST_CHECK_EQUAL(str.str(), "[ P(a) ], Q(a) @ {[(1, 20), (21, 30)], [21:30]}, ");
}

BOOST_AUTO_TEST_CASE( cnfConvertBasic ) {

    boost::shared_ptr<Sentence> a = getAsSentence("P(a) v Q(a) v !R(a) v S(a)");
    CNFClause c = convertToCNFClause(a);

    BOOST_REQUIRE_EQUAL(c.size(), 4);
    boost::shared_ptr<Sentence> pa = getAsSentence("P(a)");
    boost::shared_ptr<Sentence> qa = getAsSentence("Q(a)");
    boost::shared_ptr<Sentence> nra = getAsSentence("!R(a)");
    boost::shared_ptr<Sentence> sa = getAsSentence("S(a)");
    /* TODO: why doesn't the below work?
    BOOST_CHECK(std::find(c.begin(), c.end(), pa) != c.end());
    BOOST_CHECK(std::find(c.begin(), c.end(), qa) != c.end());
    BOOST_CHECK(std::find(c.begin(), c.end(), nra) != c.end());
    BOOST_CHECK(std::find(c.begin(), c.end(), sa) != c.end());
     */

}
<|endoftext|>


<commit_before>#include <RGBLed.h>
#include <Backlight.h>
#include <AdapterBoard.h>
#include <Arduino.h>
#include "usb_commands.h"

AdapterBoard::AdapterBoard()
{
}

void AdapterBoard::init()
{
  //Initialize the led, set to 'standby'
  led.init(LED_R, LED_G, LED_B);
  led.set(STANDBY_COLOUR);

  //Setup backlight, restore previous brightness, but don't enable
  backlight.init(BACKLIGHT_PIN, SUPPLY_EN);
  backlight.setLast();

  //Initialize the switches on board
  initSwitches();
}

void AdapterBoard::poll()
{
  //Check the switches, execute action if necessary
  pollSwitches();

  //Handle any USB commands waiting
  handleUSB();
}

void AdapterBoard::initSwitches()
{
  pinMode(SW_ON, INPUT);
  pinMode(SW_UP, INPUT);
  pinMode(SW_DOWN, INPUT);

  swOn = Bounce();
  swOn.attach(SW_ON);
  swOn.interval(20);
  swUp = Bounce();
  swUp.attach(SW_UP);
  swUp.interval(20);
  swDown = Bounce();
  swDown.attach(SW_DOWN);
  swDown.interval(20);
}

void AdapterBoard::pollSwitches()
{
  swOn.update();
  swUp.update();
  swDown.update();

  if(swOn.read() == LOW)
    togglePower();

  //When both pressed, backlight up button has priority
  if(swUp.read() == LOW)
    backlight.up();
  if(swDown.read() == LOW)
    backlight.down();
}

void AdapterBoard::togglePower()
{
  if(backlight.isOn())
  {
    backlight.off();
    led.set(STANDBY_COLOUR);
  }
  else
  {
    led.set(ON_COLOUR);
    backlight.setLast();
    backlight.on();
  }
}

char buf[EP_LEN];

void AdapterBoard::handleUSB()
{
  if(usb.isEnumerated())
  {
    if(usb.hasData())
    {
      char resp[EP_LEN];
      bool unknown = false;
      bool needsAck = true;
      usb.read(buf, EP_LEN);

      //Command type specifier stored in byte 0
      switch(buf[0])
      {
        case CMD_BL_ON:
          backlight.on();
          break;
        case CMD_BL_OFF:
          backlight.off();
          break;
        case CMD_BL_LEVEL:
          backlight.set(buf[1]);
          break;
        case CMD_BL_UP:
          backlight.up();
          break;
        case CMD_BL_DOWN:
          backlight.down();
          break;
        case CMD_BL_GET_STATE:
          needsAck = false;
          //Send state response
          resp[0] = CMD_RESP;
          resp[1] = CMD_BL_GET_STATE;
          resp[2] = backlight.isOn();
          resp[3] = backlight.get();
          while(!usb.canSend());
          usb.write(resp, EP_LEN);
          break;

        case CMD_RGB_SET:
          led.set(buf[1], buf[2], buf[3]);
          break;
        case CMD_RGB_GET:
          needsAck = false;
          //Send response
          resp[0] = CMD_RESP;
          resp[1] = CMD_RGB_GET;
          resp[2] = led.r;
          resp[2] = led.g;
          resp[3] = led.b;
          while(!usb.canSend());
          usb.write(resp, EP_LEN);
          break;

        default:
          unknown = true;
          break;
      }

      if(!unknown && needsAck)
      {
        //Send ACK back to PC
        resp[0] = CMD_ACK;
        resp[1] = buf[0];
        while(!usb.canSend());
        usb.write(resp, EP_LEN);
      }
    }
  }
}
<commit_msg>Increase debounce delay notably<commit_after>#include <RGBLed.h>
#include <Backlight.h>
#include <AdapterBoard.h>
#include <Arduino.h>
#include "usb_commands.h"

AdapterBoard::AdapterBoard()
{
}

void AdapterBoard::init()
{
  //Initialize the led, set to 'standby'
  led.init(LED_R, LED_G, LED_B);
  led.set(STANDBY_COLOUR);

  //Setup backlight, restore previous brightness, but don't enable
  backlight.init(BACKLIGHT_PIN, SUPPLY_EN);
  backlight.setLast();

  //Initialize the switches on board
  initSwitches();
}

void AdapterBoard::poll()
{
  //Check the switches, execute action if necessary
  pollSwitches();

  //Handle any USB commands waiting
  handleUSB();
}

void AdapterBoard::initSwitches()
{
  pinMode(SW_ON, INPUT);
  pinMode(SW_UP, INPUT);
  pinMode(SW_DOWN, INPUT);

  swOn = Bounce();
  swOn.attach(SW_ON);
  swOn.interval(200);
  swUp = Bounce();
  swUp.attach(SW_UP);
  swUp.interval(200);
  swDown = Bounce();
  swDown.attach(SW_DOWN);
  swDown.interval(200);
}

void AdapterBoard::pollSwitches()
{
  swOn.update();
  swUp.update();
  swDown.update();

  if(swOn.read() == LOW)
    togglePower();

  //When both pressed, backlight up button has priority
  if(swUp.read() == LOW)
    backlight.up();
  if(swDown.read() == LOW)
    backlight.down();
}

void AdapterBoard::togglePower()
{
  if(backlight.isOn())
  {
    backlight.off();
    led.set(STANDBY_COLOUR);
  }
  else
  {
    led.set(ON_COLOUR);
    backlight.setLast();
    backlight.on();
  }
}

char buf[EP_LEN];

void AdapterBoard::handleUSB()
{
  if(usb.isEnumerated())
  {
    if(usb.hasData())
    {
      char resp[EP_LEN];
      bool unknown = false;
      bool needsAck = true;
      usb.read(buf, EP_LEN);

      //Command type specifier stored in byte 0
      switch(buf[0])
      {
        case CMD_BL_ON:
          backlight.on();
          break;
        case CMD_BL_OFF:
          backlight.off();
          break;
        case CMD_BL_LEVEL:
          backlight.set(buf[1]);
          break;
        case CMD_BL_UP:
          backlight.up();
          break;
        case CMD_BL_DOWN:
          backlight.down();
          break;
        case CMD_BL_GET_STATE:
          needsAck = false;
          //Send state response
          resp[0] = CMD_RESP;
          resp[1] = CMD_BL_GET_STATE;
          resp[2] = backlight.isOn();
          resp[3] = backlight.get();
          while(!usb.canSend());
          usb.write(resp, EP_LEN);
          break;

        case CMD_RGB_SET:
          led.set(buf[1], buf[2], buf[3]);
          break;
        case CMD_RGB_GET:
          needsAck = false;
          //Send response
          resp[0] = CMD_RESP;
          resp[1] = CMD_RGB_GET;
          resp[2] = led.r;
          resp[2] = led.g;
          resp[3] = led.b;
          while(!usb.canSend());
          usb.write(resp, EP_LEN);
          break;

        default:
          unknown = true;
          break;
      }

      if(!unknown && needsAck)
      {
        //Send ACK back to PC
        resp[0] = CMD_ACK;
        resp[1] = buf[0];
        while(!usb.canSend());
        usb.write(resp, EP_LEN);
      }
    }
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <functional>

#include "core/image.h"
#include "core/random.h"
#include "core/io.h"
#include "core/vec2.h"
#include "core/palette.h"
#include "core/closestpoint.h"

#include "core/palette_tableu.h"

using namespace euphoria::core;

float
i2f(int i)
{
    return static_cast<float>(i);
}

int
main(int argc, char* argv[])
{
    const auto size = 512;
    const auto number_of_points = 30;

    Random rand;

    using DistFunc = std::function<float(const vec2f&, const vec2f&)>;

    DistFunc euclidian_distance = [](const vec2f& lhs, const vec2f& rhs)
    {
        return (lhs-rhs).GetLengthSquared();
    };

    DistFunc manhattan_distance = [](const vec2f& lhs, const vec2f& rhs)
    {
        const auto d = (lhs-rhs);
        return Abs(d.x) + Abs(d.y);
    };

    // auto pal = Palette::Rainbow(number_of_points);
    auto pal = palette::ColorBlind_10();
    Image image;
    image.SetupNoAlphaSupport(size, size);

    ClosestPoint<vec2f, int, DistFunc, float> points(euclidian_distance);
    for(int index=0; index<number_of_points; index+=1)
    {
        const auto x = rand.NextRange(image.GetWidth());
        const auto y = rand.NextRange(image.GetHeight());
        points.Add(vec2f{i2f(x), i2f(y)}, index);
    }

    image.SetAllBottomTop([&](int x, int y) {
        const auto index = points.FindClosest(vec2f{i2f(x), i2f(y)});
        return pal.GetSafeIndex(index);
    });

    io::ChunkToFile(image.Write(ImageWriteFormat::PNG), "voronoi.png");
}
<commit_msg>updated voronoi test to use custom center points<commit_after>#include <iostream>
#include <functional>

#include "core/image.h"
#include "core/random.h"
#include "core/io.h"
#include "core/vec2.h"
#include "core/palette.h"
#include "core/closestpoint.h"
#include "core/rect.h"

#include "core/palette_tableu.h"

using namespace euphoria::core;

float
i2f(int i)
{
    return static_cast<float>(i);
}

std::vector<vec2f> GenerateRandomPoints(int count, const Rectf& size, Random* random)
{
    std::vector<vec2f> r;
    for(int i=0; i<count; i+=1)
    {
        r.emplace_back( size.RandomPoint(random) );
    }
    return r;
}

int
main(int argc, char* argv[])
{
    const auto size = 512;
    // const auto number_of_points = 30;

    Random rand;

    const auto random_points = GenerateRandomPoints(30, Rectf::FromWidthHeight(size, size), &rand);

    using DistFunc = std::function<float(const vec2f&, const vec2f&)>;

    DistFunc euclidian_distance = [](const vec2f& lhs, const vec2f& rhs)
    {
        return (lhs-rhs).GetLengthSquared();
    };

    DistFunc manhattan_distance = [](const vec2f& lhs, const vec2f& rhs)
    {
        const auto d = (lhs-rhs);
        return Abs(d.x) + Abs(d.y);
    };

    auto pal = Palette::Rainbow(random_points.size());
    // auto pal = palette::ColorBlind_10();
    Image image;
    image.SetupNoAlphaSupport(size, size);

    ClosestPoint<vec2f, int, DistFunc, float> points(euclidian_distance);
    {
        int index = 0;
        for(auto p: random_points)
        {
            points.Add(p, index);
            index += 1;
        }
    }

    image.SetAllBottomTop([&](int x, int y) {
        const auto index = points.FindClosest(vec2f{i2f(x), i2f(y)});
        return pal.GetSafeIndex(index);
    });

    io::ChunkToFile(image.Write(ImageWriteFormat::PNG), "voronoi.png");
}
<|endoftext|>


<commit_before>#include <iostream>
using namespace std;
#include "EasyCL.h"
#include "util/StatefulTimer.h"
#include "util/easycl_stringhelper.h"

static const char *kernelSource = R"DELIM(
  kernel void test(int offset, int totalN, global float*out) {
    int linearId = get_global_id(0) + offset;
    if(linearId < totalN) {
      out[linearId] = out[linearId] {{operation}} 2.0f;
    }
  }
)DELIM";

void test(EasyCL *cl, int numLaunches, int vectorSize, string operation = "+") {
  string arrayType = "float";
  if(vectorSize > 1) {
    arrayType += easycl::toString(vectorSize);
  }
  int totalN = 128 * 1024 * 1024;
//  int numLaunches = 1;
  int N = totalN / numLaunches;
  string templatedSource = easycl::replace(kernelSource, "float", arrayType);
  templatedSource = easycl::replace(templatedSource, "{{operation}}", operation);
//  cout << templatedSource << endl;
  CLKernel *kernel = cl->buildKernelFromString(templatedSource, "test", "");
  const int workgroupSize = 64;
  int numWorkgroups = (N / vectorSize + workgroupSize - 1) / workgroupSize;

  float *in = new float[totalN];
  float *inOut = new float[totalN];
  for( int i = 0; i < totalN; i++ ) {
      in[i] = inOut[i] = (i + 4) % 1000000;
  }
  CLWrapper *wrapper = cl->wrap(totalN, inOut);
  wrapper->copyToDevice();

  cl->finish();

  for(int it = 0; it < 3; it++) {
    double start = StatefulTimer::instance()->getSystemMilliseconds();
    for( int i = 0; i < numLaunches; i++ ) {
      kernel->in(N * i / vectorSize);
      kernel->in(totalN / vectorSize);
      kernel->inout(wrapper);
      kernel->run_1d(numWorkgroups * workgroupSize, workgroupSize);
    }
    cl->finish();
    double end = StatefulTimer::instance()->getSystemMilliseconds();
    cl->dumpProfiling();
  //  cout << "in[10]" << in[10] << endl;
  //  cout << "Time, " << numLaunches << " launches: " << (end - start) << "ms" << endl;
    cout << "it=" << it << " launches " << numLaunches << " N per launch " << N << " vectorsize=" << vectorSize << " op=" << operation << " time=" << (end - start) << "ms" << endl;
    wrapper->copyToHost();
    cl->finish();
    int errorCount = 0;
    if( operation == "+" ) {
      for( int i = 0; i < totalN; i++ ) {
        float targetValue = in[i] + 2.0f * (it + 1);
        if(inOut[i] != targetValue ) {
          errorCount++;
          if( errorCount < 20 ) {
            cout << inOut[i] << " != " << targetValue << endl;
          }
        }
      }
    }
  //  cout << endl;
    if( errorCount > 0 ) {
      cout << "errors: " << errorCount << " out of totalN=" << totalN << endl;
    } else {
  //    cout << "No errors detected" << endl;
    }
  }

  delete wrapper;
  delete[] in;
  delete[] inOut;
  delete kernel;
}

void testVectorSize(EasyCL *cl) {
  for( int p = 0; p < 16; p += 8 ) {
    int numLaunches = 1 << p;
    test(cl, numLaunches, 1);
    test(cl, numLaunches, 4);
  }
}

void testOperations(EasyCL *cl) {
  test(cl, 256, 4, "+");
  cl->dumpProfiling();
  test(cl, 256, 4, "*");
  cl->dumpProfiling();
  test(cl, 256, 4, "/");
  cl->dumpProfiling();
  test(cl, 256, 1, "+");
  cl->dumpProfiling();
  test(cl, 256, 1, "*");
  cl->dumpProfiling();
  test(cl, 256, 1, "/");
  cl->dumpProfiling();
//  test(cl, 256, 1, "%");
}

int main(int argc, char *argv[]) {
  int gpu = 0;
  if( argc == 2 ) {
    gpu = atoi(argv[1]);
  }
  cout << "using gpu " << gpu << endl;
  EasyCL *cl = EasyCL::createForIndexedGpu(gpu);
  cl->setProfiling(true);
//  testVectorSize(cl);
  testOperations(cl);
  cl->dumpProfiling();
  delete cl;
  return 0;
}

<commit_msg>fix apply1 a bit, so doesnt show errors, and * not shortcutted<commit_after>#include <iostream>
using namespace std;
#include "EasyCL.h"
#include "util/StatefulTimer.h"
#include "util/easycl_stringhelper.h"

static const char *kernelSource = R"DELIM(
  kernel void test(int offset, int totalN, global float*out) {
    int linearId = get_global_id(0) + offset;
    if(linearId < totalN) {
      out[linearId] = out[linearId] {{operation}} 3.3f;
    }
  }
)DELIM";

void test(EasyCL *cl, int numLaunches, int vectorSize, string operation = "+") {
  string arrayType = "float";
  if(vectorSize > 1) {
    arrayType += easycl::toString(vectorSize);
  }
  int totalN = 128 * 1024 * 1024;
//  int numLaunches = 1;
  int N = totalN / numLaunches;
  string templatedSource = easycl::replace(kernelSource, "float", arrayType);
  templatedSource = easycl::replace(templatedSource, "{{operation}}", operation);
//  cout << templatedSource << endl;
  CLKernel *kernel = cl->buildKernelFromString(templatedSource, "test", "");
  const int workgroupSize = 64;
  int numWorkgroups = (N / vectorSize + workgroupSize - 1) / workgroupSize;

  float *in = new float[totalN];
  float *inOut = new float[totalN];
  for( int i = 0; i < totalN; i++ ) {
      in[i] = inOut[i] = (i + 4) % 1000000;
  }
  CLWrapper *wrapper = cl->wrap(totalN, inOut);
  wrapper->copyToDevice();

  cl->finish();

  for(int it = 0; it < 3; it++) {
    double start = StatefulTimer::instance()->getSystemMilliseconds();
    for( int i = 0; i < numLaunches; i++ ) {
      kernel->in(N * i / vectorSize);
      kernel->in(totalN / vectorSize);
      kernel->inout(wrapper);
      kernel->run_1d(numWorkgroups * workgroupSize, workgroupSize);
    }
    cl->finish();
    double end = StatefulTimer::instance()->getSystemMilliseconds();
    cl->dumpProfiling();
  //  cout << "in[10]" << in[10] << endl;
  //  cout << "Time, " << numLaunches << " launches: " << (end - start) << "ms" << endl;
    cout << "it=" << it << " launches " << numLaunches << " N per launch " << N << " vectorsize=" << vectorSize << " op=" << operation << " time=" << (end - start) << "ms" << endl;
    wrapper->copyToHost();
    cl->finish();
    int errorCount = 0;
    if( operation == "+" ) {
      for( int i = 0; i < totalN; i++ ) {
        float targetValue = in[i] + 3.3f * (it + 1);
        if(abs(inOut[i] - targetValue)> 0.1f) {
          errorCount++;
          if( errorCount < 20 ) {
            cout << inOut[i] << " != " << targetValue << endl;
            cout << abs(inOut[i] - targetValue) << endl;
          }
        }
      }
    }
  //  cout << endl;
    if( errorCount > 0 ) {
      cout << "errors: " << errorCount << " out of totalN=" << totalN << endl;
    } else {
  //    cout << "No errors detected" << endl;
    }
  }

  delete wrapper;
  delete[] in;
  delete[] inOut;
  delete kernel;
}

void testVectorSize(EasyCL *cl) {
  for( int p = 0; p < 16; p += 8 ) {
    int numLaunches = 1 << p;
    test(cl, numLaunches, 1);
    test(cl, numLaunches, 4);
  }
}

void testOperations(EasyCL *cl) {
  test(cl, 256, 4, "+");
  cl->dumpProfiling();
  test(cl, 256, 4, "*");
  cl->dumpProfiling();
  test(cl, 256, 4, "/");
  cl->dumpProfiling();
  test(cl, 256, 1, "+");
  cl->dumpProfiling();
  test(cl, 256, 1, "*");
  cl->dumpProfiling();
  test(cl, 256, 1, "/");
  cl->dumpProfiling();
//  test(cl, 256, 1, "%");
}

int main(int argc, char *argv[]) {
  int gpu = 0;
  if( argc == 2 ) {
    gpu = atoi(argv[1]);
  }
  cout << "using gpu " << gpu << endl;
  EasyCL *cl = EasyCL::createForIndexedGpu(gpu);
  cl->setProfiling(true);
//  testVectorSize(cl);
  testOperations(cl);
  cl->dumpProfiling();
  delete cl;
  return 0;
}

<|endoftext|>


<commit_before>#include <osg/Notify>

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>

#include "OSGA_Archive.h"

class ReaderWriterOSGA : public osgDB::ReaderWriter
{
public:
    ReaderWriterOSGA() { }

    virtual const char* className() const { return "OpenSceneGraph Archive Reader/Writer"; }
    virtual bool acceptsExtension(const std::string& extension) const
    {
        return osgDB::equalCaseInsensitive(extension,"osga");
    }

    virtual ReadResult openArchive(const std::string& file,ArchiveStatus status, unsigned int indexBlockSize = 4096, const Options* options=NULL) const
    {

        std::string ext = osgDB::getLowerCaseFileExtension(file);
        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

        std::string fileName = osgDB::findDataFile( file, options );
        if (fileName.empty())
        {
            if (status==READ) return ReadResult::FILE_NOT_FOUND;
            fileName = file;
        }

        osg::ref_ptr<OSGA_Archive> archive = new OSGA_Archive;
        if (!archive->open(fileName, status, indexBlockSize))
        {
            return ReadResult(ReadResult::FILE_NOT_HANDLED);
        }

        return archive.get();
    }

    /** open an archive for reading.*/
    virtual ReadResult openArchive(std::istream& fin,const Options*) const
    {
        osg::ref_ptr<OSGA_Archive> archive = new OSGA_Archive;
        if (!archive->open(fin))
        {
            return ReadResult(ReadResult::FILE_NOT_HANDLED);
        }

        return archive.get();
    }

    virtual ReadResult readImage(const std::string& file,const Options* options) const
    {
        ReadResult result = openArchive(file,osgDB::Archive::READ);

        if (!result.validArchive()) return result;

        osg::ref_ptr<osgDB::ReaderWriter::Options> local_options = new osgDB::ReaderWriter::Options;
        local_options->setDatabasePath(file);

        ReadResult result_2 = result.getArchive()->readImage(result.getArchive()->getMasterFileName(),local_options.get());

        if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES))
        {
            // register the archive so that it is cached for future use.
            osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive());
        }

        return result_2;
    }

    virtual ReadResult readNode(const std::string& file,const Options* options) const
    {
        ReadResult result = openArchive(file,osgDB::Archive::READ);

        if (!result.validArchive()) return result;

        osg::ref_ptr<osgDB::ReaderWriter::Options> local_options = new osgDB::ReaderWriter::Options;
        local_options->setDatabasePath(file);

        ReadResult result_2 = result.getArchive()->readNode(result.getArchive()->getMasterFileName(),local_options.get());

        if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES))
        {
            // register the archive so that it is cached for future use.
            osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive());
        }

        return result_2;
    }

protected:

};

// register with Registry to instantiate the above reader/writer.
REGISTER_OSGPLUGIN(osga, ReaderWriterOSGA)
<commit_msg>From Glen Waldon, "This change patches ReaderWriterOSGA.cpp so that it passes along the ReaderWriter::Options to files loaded from inside the archive. Previously it was discarding them.<commit_after>#include <osg/Notify>

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>

#include "OSGA_Archive.h"

class ReaderWriterOSGA : public osgDB::ReaderWriter
{
public:
    ReaderWriterOSGA() { }

    virtual const char* className() const { return "OpenSceneGraph Archive Reader/Writer"; }
    virtual bool acceptsExtension(const std::string& extension) const
    {
        return osgDB::equalCaseInsensitive(extension,"osga");
    }

    virtual ReadResult openArchive(const std::string& file,ArchiveStatus status, unsigned int indexBlockSize = 4096, const Options* options=NULL) const
    {

        std::string ext = osgDB::getLowerCaseFileExtension(file);
        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

        std::string fileName = osgDB::findDataFile( file, options );
        if (fileName.empty())
        {
            if (status==READ) return ReadResult::FILE_NOT_FOUND;
            fileName = file;
        }

        osg::ref_ptr<OSGA_Archive> archive = new OSGA_Archive;
        if (!archive->open(fileName, status, indexBlockSize))
        {
            return ReadResult(ReadResult::FILE_NOT_HANDLED);
        }

        return archive.get();
    }

    /** open an archive for reading.*/
    virtual ReadResult openArchive(std::istream& fin,const Options*) const
    {
        osg::ref_ptr<OSGA_Archive> archive = new OSGA_Archive;
        if (!archive->open(fin))
        {
            return ReadResult(ReadResult::FILE_NOT_HANDLED);
        }

        return archive.get();
    }

    virtual ReadResult readImage(const std::string& file,const Options* options) const
    {
        ReadResult result = openArchive(file,osgDB::Archive::READ);

        if (!result.validArchive()) return result;

        // copy the incoming options if possible so that plugin options can be applied to files
        // inside the archive
        osg::ref_ptr<osgDB::ReaderWriter::Options> local_options =
            options?
            new osgDB::ReaderWriter::Options( *options ) :
            new osgDB::ReaderWriter::Options;

        local_options->setDatabasePath(file);

        ReadResult result_2 = result.getArchive()->readImage(result.getArchive()->getMasterFileName(),local_options.get());

        if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES))
        {
            // register the archive so that it is cached for future use.
            osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive());
        }

        return result_2;
    }

    virtual ReadResult readNode(const std::string& file,const Options* options) const
    {
        ReadResult result = openArchive(file,osgDB::Archive::READ);

        if (!result.validArchive()) return result;

        // copy the incoming options if possible so that plugin options can be applied to files
        // inside the archive
        osg::ref_ptr<osgDB::ReaderWriter::Options> local_options =
            options?
            new osgDB::ReaderWriter::Options( *options ) :
            new osgDB::ReaderWriter::Options;

        local_options->setDatabasePath(file);

        ReadResult result_2 = result.getArchive()->readNode(result.getArchive()->getMasterFileName(),local_options.get());

        if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES))
        {
            // register the archive so that it is cached for future use.
            osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive());
        }

        return result_2;
    }

protected:

};

// register with Registry to instantiate the above reader/writer.
REGISTER_OSGPLUGIN(osga, ReaderWriterOSGA)
<|endoftext|>


<commit_before>/*
 * Louvain.cpp
 *
 *  Created on: 25.02.2013
 *      Author: Matthias Stumpp
 */

#include "KERNIGHANLIN_Stumpp.h"

namespace NetworKit {

cluster CL0 = 0;
cluster CL1 = 1;

KERNIGHAN_LIN::KERNIGHAN_LIN() {
}

KERNIGHAN_LIN::~KERNIGHAN_LIN() {
}

// compute initial gain for all nodes in graph
void KERNIGHAN_LIN::computeGainAllNodes(Graph& g, Clustering& c, NodeMap<double>& gain) {
	g.forNodes([&](node u) {
		this->computeGainForNode(g, u, c, gain);
	});
}

// compute initial gain for a certain node
void KERNIGHAN_LIN::computeGainForNode(Graph& g, node u, Clustering& c, NodeMap<double>& gain) {
	double samePart = 0.0, otherPart = 0.0;
	g.forWeightedNeighborsOf(u, [&](node v, edgeweight w) {
		if (c.inSameCluster(u, v)) {
			samePart += w;
		} else {
			otherPart += w;
		}
	});
	gain[u] = otherPart-samePart;
}

Clustering KERNIGHAN_LIN::partition(Graph& g, Clustering& c) {

	EdgeCut edgeCut;
	double cut = edgeCut.getQuality(c, g);
	DEBUG("KL start with edge cut " << cut);

	// unmark all nodes
	// false -> not visited, true otherwise
	NodeMap<char> marker(g.numberOfNodes(), 'f');
	// keeps the gain
	NodeMap<double> gain(g.numberOfNodes(), 0.0);
	// compute initial gain for all nodes
	TRACE("KL: start computing initial gains");
	this->computeGainAllNodes(g, c, gain);
	TRACE("KL: have computed initial gains");

	bool improved = false;
	std::vector<count> numCl = c.clusterSizes();
	count min = *min_element(std::begin(numCl), std::end(numCl));
	for (count n=0; n<min; n++) {
		TRACE("KL iteration " << n);

		double currentBest = 0.0;
		node best_u = none;
		node best_v = none;
		auto computeBestGain = [&](node u, node v, edgeweight w) {
			// continue if nodes in same cluster
			// or u or v have been vistited already
			if (c.inSameCluster(u, v) || marker[u] == 't' || marker[v] == 't')
				return;

			// compute edge gain
			double runningGain = gain[u]+gain[v]-2*w;
			if (runningGain > currentBest) {
				improved = true;
				currentBest = runningGain;
				best_u = u;
				best_v = v;
			}
		};
		g.forNodePairs(computeBestGain);

		// no more improvements
		if (currentBest == 0.0)
			break;

		// otherwise, move nodes to other cluster
		if (c.clusterOf(best_u) == CL0) {
			c.moveToCluster(CL1, best_u);
			c.moveToCluster(CL0, best_v);
		} else {
			c.moveToCluster(CL0, best_u);
			c.moveToCluster(CL1, best_v);
		}
		// set marker to true, meaning node has been visited
		marker[best_u] = 't';
		marker[best_v] = 't';
		// recompute gain of nodes in neighbourhood of best two nodes
		// FIXME: iterate over neighbors of best_u and best_v
		this->computeGainForNode(g, best_u, c, gain);
		this->computeGainForNode(g, best_v, c, gain);
	}

	// either recursibely call or return
	if (improved)
		return this->partition(g, c);
	return c;
}

Clustering KERNIGHAN_LIN::run(Graph& graph) {
	Graph g = graph;

	// initialization
	// initial random partitioning
	ClusteringGenerator clusteringGenerator;
	TRACE("KL: start computing initial partition");
	Clustering clustering = clusteringGenerator.makeRandomClustering(g, 2);
	TRACE("KL: have computed initial partition, start KL pass");
	return this->partition(g, clustering);
}

std::string KERNIGHAN_LIN::toString() const {
	return "KERNIGHAN_LIN implementation by M. Stumpp";
}

} /* namespace NetworKit */
<commit_msg>KL did not compile, fixed<commit_after>/*
 * Louvain.cpp
 *
 *  Created on: 25.02.2013
 *      Author: Matthias Stumpp
 */

#include "KERNIGHANLIN_Stumpp.h"

namespace NetworKit {

cluster CL0 = 0;
cluster CL1 = 1;

KERNIGHAN_LIN::KERNIGHAN_LIN() {
}

KERNIGHAN_LIN::~KERNIGHAN_LIN() {
}

// compute initial gain for all nodes in graph
void KERNIGHAN_LIN::computeGainAllNodes(Graph& g, Clustering& c, NodeMap<double>& gain) {
	g.forNodes([&](node u) {
		this->computeGainForNode(g, u, c, gain);
	});
}

// compute initial gain for a certain node
void KERNIGHAN_LIN::computeGainForNode(Graph& g, node u, Clustering& c, NodeMap<double>& gain) {
	double samePart = 0.0, otherPart = 0.0;
	g.forWeightedNeighborsOf(u, [&](node v, edgeweight w) {
		if (c.inSameCluster(u, v)) {
			samePart += w;
		} else {
			otherPart += w;
		}
	});
	gain[u] = otherPart-samePart;
}

Clustering KERNIGHAN_LIN::partition(Graph& g, Clustering& c) {

	EdgeCut edgeCut;
	double cut = edgeCut.getQuality(c, g);
	DEBUG("KL start with edge cut " << cut);

	// unmark all nodes
	// false -> not visited, true otherwise
	NodeMap<char> marker(g.numberOfNodes(), 'f');
	// keeps the gain
	NodeMap<double> gain(g.numberOfNodes(), 0.0);
	// compute initial gain for all nodes
	TRACE("KL: start computing initial gains");
	this->computeGainAllNodes(g, c, gain);
	TRACE("KL: have computed initial gains");

	bool improved = false;
	std::vector<count> numCl = c.clusterSizes();
	count min = *min_element(std::begin(numCl), std::end(numCl));
	for (count n=0; n<min; n++) {
		TRACE("KL iteration " << n);

		double currentBest = 0.0;
		node best_u = none;
		node best_v = none;
		auto computeBestGain = [&](node u, node v, edgeweight w) {
			// continue if nodes in same cluster
			// or u or v have been vistited already
			if (c.inSameCluster(u, v) || marker[u] == 't' || marker[v] == 't')
				return;

			// compute edge gain
			double runningGain = gain[u]+gain[v]-2*w;
			if (runningGain > currentBest) {
				improved = true;
				currentBest = runningGain;
				best_u = u;
				best_v = v;
			}
		};
		// FIXME: all node pairs from different blocks
		g.forWeightedEdges(computeBestGain);

		// no more improvements
		if (currentBest == 0.0)
			break;

		// otherwise, move nodes to other cluster
		if (c.clusterOf(best_u) == CL0) {
			c.moveToCluster(CL1, best_u);
			c.moveToCluster(CL0, best_v);
		} else {
			c.moveToCluster(CL0, best_u);
			c.moveToCluster(CL1, best_v);
		}
		// set marker to true, meaning node has been visited
		marker[best_u] = 't';
		marker[best_v] = 't';
		// recompute gain of nodes in neighbourhood of best two nodes
		// FIXME: iterate over neighbors of best_u and best_v
		this->computeGainForNode(g, best_u, c, gain);
		this->computeGainForNode(g, best_v, c, gain);
	}

	// either recursibely call or return
	if (improved)
		return this->partition(g, c);
	return c;
}

Clustering KERNIGHAN_LIN::run(Graph& graph) {
	Graph g = graph;

	// initialization
	// initial random partitioning
	ClusteringGenerator clusteringGenerator;
	TRACE("KL: start computing initial partition");
	Clustering clustering = clusteringGenerator.makeRandomClustering(g, 2);
	TRACE("KL: have computed initial partition, start KL pass");
	return this->partition(g, clustering);
}

std::string KERNIGHAN_LIN::toString() const {
	return "KERNIGHAN_LIN implementation by M. Stumpp";
}

} /* namespace NetworKit */
<|endoftext|>