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

/**
 * @file px4_posix_tasks.c
 * Implementation of existing task API for Linux
 */

#include <px4_log.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>

#if !defined(__PX4_QURT)
#include <signal.h>
#endif

#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <string>

#include <px4_tasks.h>

#define MAX_CMD_LEN 100

#define PX4_MAX_TASKS 50
#define SHELL_TASK_ID (PX4_MAX_TASKS+1)

pthread_t _shell_task_id = 0;

struct task_entry {
	pthread_t pid;
	std::string name;
	bool isused;
	task_entry() : isused(false) {}
};

static task_entry taskmap[PX4_MAX_TASKS];

typedef struct {
	px4_main_t entry;
	int argc;
	char *argv[];
	// strings are allocated after the
} pthdata_t;

static void *entry_adapter(void *ptr)
{
	pthdata_t *data;
	data = (pthdata_t *) ptr;

	data->entry(data->argc, data->argv);
	PX4_WARN("Before waiting infinte busy loop");
	//for( ;; )
	//{
	//   volatile int x = 0;
	//   ++x;
	// }
	free(ptr);
	px4_task_exit(0);

	return NULL;
}

void
px4_systemreset(bool to_bootloader)
{
	PX4_WARN("Called px4_system_reset");
}

px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int stack_size, px4_main_t entry,
			      char *const argv[])
{
	int rv;
	int argc = 0;
	int i;
	unsigned int len = 0;
	unsigned long offset;
	unsigned long structsize;
	char *p = (char *)argv;

	PX4_DEBUG("Creating %s\n", name);
	pthread_t task;
	pthread_attr_t attr;
	struct sched_param param;

	// Calculate argc
	while (p != (char *)0) {
		p = argv[argc];

		if (p == (char *)0) {
			break;
		}

		++argc;
		len += strlen(p) + 1;
	}

	structsize = sizeof(pthdata_t) + (argc + 1) * sizeof(char *);
	pthdata_t *taskdata;

	// not safe to pass stack data to the thread creation
	taskdata = (pthdata_t *)malloc(structsize + len);
	offset = ((unsigned long)taskdata) + structsize;

	taskdata->entry = entry;
	taskdata->argc = argc;

	for (i = 0; i < argc; i++) {
		PX4_DEBUG("arg %d %s\n", i, argv[i]);
		taskdata->argv[i] = (char *)offset;
		strcpy((char *)offset, argv[i]);
		offset += strlen(argv[i]) + 1;
	}

	// Must add NULL at end of argv
	taskdata->argv[argc] = (char *)0;

	rv = pthread_attr_init(&attr);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to init thread attrs");
		return (rv < 0) ? rv : -rv;
	}

#if 0
	rv = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set inherit sched");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_attr_setschedpolicy(&attr, scheduler);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set sched policy");
		return (rv < 0) ? rv : -rv;
	}

#endif
	size_t fixed_stacksize = -1;
	pthread_attr_getstacksize(&attr, &fixed_stacksize);
	PX4_WARN("stack size: %d passed stacksize(%d)", fixed_stacksize, stack_size);
	fixed_stacksize = 8 * 1024;
	fixed_stacksize = (fixed_stacksize < (size_t)stack_size) ? (size_t)stack_size : fixed_stacksize;

	PX4_WARN("setting the thread[%s] stack size to[%d]", name, fixed_stacksize);
	pthread_attr_setstacksize(&attr, fixed_stacksize);
	//pthread_attr_setstacksize(&attr, stack_size);

	param.sched_priority = priority;

	rv = pthread_attr_setschedparam(&attr, &param);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set sched param");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_create(&task, &attr, &entry_adapter, (void *) taskdata);

	if (rv != 0) {

		return (rv < 0) ? rv : -rv;
	}

	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused == false) {
			taskmap[i].pid = task;
			taskmap[i].name = name;
			taskmap[i].isused = true;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS) {
		return -ENOSPC;
	}

	return i;
}

int px4_task_delete(px4_task_t id)
{
	int rv = 0;
	pthread_t pid;
	PX4_WARN("Called px4_task_delete");

	if (id < PX4_MAX_TASKS && taskmap[id].isused) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	if (pthread_self() == pid) {
		taskmap[id].isused = false;
		pthread_exit(0);

	} else {
		rv = pthread_cancel(pid);
	}

	taskmap[id].isused = false;

	return rv;
}

void px4_task_exit(int ret)
{
	int i;
	pthread_t pid = pthread_self();

	// Get pthread ID from the opaque ID
	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].pid == pid) {
			taskmap[i].isused = false;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS)  {
		PX4_ERR("px4_task_exit: self task not found!");

	} else {
		PX4_DEBUG("px4_task_exit: %s", taskmap[i].name.c_str());
	}

	//pthread_exit((void *)(unsigned long)ret);
}

int px4_task_kill(px4_task_t id, int sig)
{
	int rv = 0;
	pthread_t pid;
	PX4_DEBUG("Called px4_task_kill %d, taskname %s", sig, taskmap[id].name.c_str());

	if (id < PX4_MAX_TASKS && taskmap[id].pid != 0) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	rv = pthread_kill(pid, sig);

	return rv;
}

void px4_show_tasks()
{
	int idx;
	int count = 0;

	PX4_INFO("Active Tasks:");

	for (idx = 0; idx < PX4_MAX_TASKS; idx++) {
		if (taskmap[idx].isused) {
			PX4_INFO("   %-10s %d", taskmap[idx].name.c_str(), taskmap[idx].pid);
			count++;
		}
	}

	if (count == 0) {
		PX4_INFO("   No running tasks");
	}

}

__BEGIN_DECLS

int px4_getpid()
{
	pthread_t pid = pthread_self();
//
//	if (pid == _shell_task_id)
//		return SHELL_TASK_ID;

	// Get pthread ID from the opaque ID
	for (int i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return i;
		}
	}

	PX4_ERR("px4_getpid() called from unknown thread context!");
	return -EINVAL;
}

const char *getprogname();
const char *getprogname()
{
	pthread_t pid = pthread_self();

	for (int i = 0; i < PX4_MAX_TASKS; i++) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return taskmap[i].name.c_str();
		}
	}

	return "Unknown App";
}
__END_DECLS

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

/**
 * @file px4_posix_tasks.c
 * Implementation of existing task API for Linux
 */

#include <px4_log.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>

#if !defined(__PX4_QURT)
#include <signal.h>
#endif

#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <string>

#include <px4_tasks.h>

#define MAX_CMD_LEN 100

#define PX4_MAX_TASKS 50
#define SHELL_TASK_ID (PX4_MAX_TASKS+1)

pthread_t _shell_task_id = 0;

struct task_entry {
	pthread_t pid;
	std::string name;
	bool isused;
	task_entry() : isused(false) {}
};

static task_entry taskmap[PX4_MAX_TASKS];

typedef struct {
	px4_main_t entry;
	int argc;
	char *argv[];
	// strings are allocated after the
} pthdata_t;

static void *entry_adapter(void *ptr)
{
	pthdata_t *data;
	data = (pthdata_t *) ptr;

	data->entry(data->argc, data->argv);
	PX4_WARN("Before waiting infinte busy loop");
	//for( ;; )
	//{
	//   volatile int x = 0;
	//   ++x;
	// }
	free(ptr);
	px4_task_exit(0);

	return NULL;
}

void
px4_systemreset(bool to_bootloader)
{
	PX4_WARN("Called px4_system_reset");
}

px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int stack_size, px4_main_t entry,
			      char *const argv[])
{
	int rv;
	int argc = 0;
	int i;
	unsigned int len = 0;
	unsigned long offset;
	unsigned long structsize;
	char *p = (char *)argv;

	PX4_DEBUG("Creating %s\n", name);
	pthread_t task;
	pthread_attr_t attr;
	struct sched_param param;

	// Calculate argc
	while (p != (char *)0) {
		p = argv[argc];

		if (p == (char *)0) {
			break;
		}

		++argc;
		len += strlen(p) + 1;
	}

	structsize = sizeof(pthdata_t) + (argc + 1) * sizeof(char *);
	pthdata_t *taskdata;

	// not safe to pass stack data to the thread creation
	taskdata = (pthdata_t *)malloc(structsize + len);
	offset = ((unsigned long)taskdata) + structsize;

	taskdata->entry = entry;
	taskdata->argc = argc;

	for (i = 0; i < argc; i++) {
		PX4_DEBUG("arg %d %s\n", i, argv[i]);
		taskdata->argv[i] = (char *)offset;
		strcpy((char *)offset, argv[i]);
		offset += strlen(argv[i]) + 1;
	}

	// Must add NULL at end of argv
	taskdata->argv[argc] = (char *)0;

	rv = pthread_attr_init(&attr);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to init thread attrs");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_attr_getschedparam(&attr, &param);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to get thread sched param");
		return (rv < 0) ? rv : -rv;
	}

#if 0
	rv = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set inherit sched");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_attr_setschedpolicy(&attr, scheduler);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set sched policy");
		return (rv < 0) ? rv : -rv;
	}

#endif
	size_t fixed_stacksize = -1;
	pthread_attr_getstacksize(&attr, &fixed_stacksize);
	PX4_WARN("stack size: %d passed stacksize(%d)", fixed_stacksize, stack_size);
	fixed_stacksize = 8 * 1024;
	fixed_stacksize = (fixed_stacksize < (size_t)stack_size) ? (size_t)stack_size : fixed_stacksize;

	PX4_WARN("setting the thread[%s] stack size to[%d]", name, fixed_stacksize);
	pthread_attr_setstacksize(&attr, fixed_stacksize);
	//pthread_attr_setstacksize(&attr, stack_size);

	param.sched_priority = priority;

	rv = pthread_attr_setschedparam(&attr, &param);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set sched param");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_create(&task, &attr, &entry_adapter, (void *) taskdata);

	if (rv != 0) {

		return (rv < 0) ? rv : -rv;
	}

	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused == false) {
			taskmap[i].pid = task;
			taskmap[i].name = name;
			taskmap[i].isused = true;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS) {
		return -ENOSPC;
	}

	return i;
}

int px4_task_delete(px4_task_t id)
{
	int rv = 0;
	pthread_t pid;
	PX4_WARN("Called px4_task_delete");

	if (id < PX4_MAX_TASKS && taskmap[id].isused) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	if (pthread_self() == pid) {
		taskmap[id].isused = false;
		pthread_exit(0);

	} else {
		rv = pthread_cancel(pid);
	}

	taskmap[id].isused = false;

	return rv;
}

void px4_task_exit(int ret)
{
	int i;
	pthread_t pid = pthread_self();

	// Get pthread ID from the opaque ID
	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].pid == pid) {
			taskmap[i].isused = false;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS)  {
		PX4_ERR("px4_task_exit: self task not found!");

	} else {
		PX4_DEBUG("px4_task_exit: %s", taskmap[i].name.c_str());
	}

	//pthread_exit((void *)(unsigned long)ret);
}

int px4_task_kill(px4_task_t id, int sig)
{
	int rv = 0;
	pthread_t pid;
	PX4_DEBUG("Called px4_task_kill %d, taskname %s", sig, taskmap[id].name.c_str());

	if (id < PX4_MAX_TASKS && taskmap[id].pid != 0) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	rv = pthread_kill(pid, sig);

	return rv;
}

void px4_show_tasks()
{
	int idx;
	int count = 0;

	PX4_INFO("Active Tasks:");

	for (idx = 0; idx < PX4_MAX_TASKS; idx++) {
		if (taskmap[idx].isused) {
			PX4_INFO("   %-10s %d", taskmap[idx].name.c_str(), taskmap[idx].pid);
			count++;
		}
	}

	if (count == 0) {
		PX4_INFO("   No running tasks");
	}

}

__BEGIN_DECLS

int px4_getpid()
{
	pthread_t pid = pthread_self();
//
//	if (pid == _shell_task_id)
//		return SHELL_TASK_ID;

	// Get pthread ID from the opaque ID
	for (int i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return i;
		}
	}

	PX4_ERR("px4_getpid() called from unknown thread context!");
	return -EINVAL;
}

const char *getprogname();
const char *getprogname()
{
	pthread_t pid = pthread_self();

	for (int i = 0; i < PX4_MAX_TASKS; i++) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return taskmap[i].name.c_str();
		}
	}

	return "Unknown App";
}
__END_DECLS

<|endoftext|>


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

#include "config.h"
#include "ConstructData.h"

#include "JSFunction.h"

#ifdef QT_BUILD_SCRIPT_LIB
#include "Debugger.h"
#include "DebuggerCallFrame.h"
#endif

namespace JSC {

#ifdef QT_BUILD_SCRIPT_LIB
JSObject* JSC::NativeConstrWrapper::operator() (ExecState* exec, JSObject* jsobj, const ArgList& argList) const
{
    Debugger* debugger = exec->lexicalGlobalObject()->debugger();
    if (debugger)
        debugger->callEvent(DebuggerCallFrame(exec), -1, -1);

    JSObject* returnValue = ptr(exec, jsobj, argList);

    if ((debugger) && (callDebuggerFunctionExit))
        debugger->functionExit(JSValue(returnValue), -1);

    return returnValue;
}
#endif

JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
{
    if (constructType == ConstructTypeHost)
        return constructData.native.function(exec, asObject(callee), args);
    ASSERT(constructType == ConstructTypeJS);
    // FIXME: Can this be done more efficiently using the constructData?
    return asFunction(callee)->construct(exec, args);
}

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

#include "config.h"
#include "ConstructData.h"

#include "JSFunction.h"

#ifdef QT_BUILD_SCRIPT_LIB
#include "Debugger.h"
#include "DebuggerCallFrame.h"
#include "JSGlobalObject.h"
#endif

namespace JSC {

#ifdef QT_BUILD_SCRIPT_LIB
JSObject* JSC::NativeConstrWrapper::operator() (ExecState* exec, JSObject* jsobj, const ArgList& argList) const
{
    Debugger* debugger = exec->lexicalGlobalObject()->debugger();
    if (debugger)
        debugger->callEvent(DebuggerCallFrame(exec), -1, -1);

    JSObject* returnValue = ptr(exec, jsobj, argList);

    if ((debugger) && (callDebuggerFunctionExit))
        debugger->functionExit(JSValue(returnValue), -1);

    return returnValue;
}
#endif

JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
{
    if (constructType == ConstructTypeHost)
        return constructData.native.function(exec, asObject(callee), args);
    ASSERT(constructType == ConstructTypeJS);
    // FIXME: Can this be done more efficiently using the constructData?
    return asFunction(callee)->construct(exec, args);
}

} // namespace JSC
<|endoftext|>


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

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

#include <canvas/debug.hxx>
#include <canvas/verbosetrace.hxx>

#include <rtl/logfile.hxx>
#include <rtl/math.hxx>

#include <canvas/canvastools.hxx>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx>
#include <basegfx/polygon/b2dpolygontriangulator.hxx>
#include <basegfx/polygon/b2dpolygoncutandtouch.hxx>

#include "cairo_canvascustomsprite.hxx"
#include "cairo_spritehelper.hxx"

#include <memory>

using namespace ::cairo;
using namespace ::com::sun::star;

namespace cairocanvas
{
    SpriteHelper::SpriteHelper() :
        mpSpriteCanvas(),
        mbTextureDirty( true ),
    mpBufferSurface( NULL )
    {
    }

    void SpriteHelper::init( const geometry::RealSize2D&    rSpriteSize,
                             const SpriteCanvasRef&         rSpriteCanvas)
    {
        ENSURE_AND_THROW( rSpriteCanvas.get(),
                          "SpriteHelper::init(): Invalid device, sprite canvas or surface" );

        mpSpriteCanvas     = rSpriteCanvas;
        mbTextureDirty     = true;

        // also init base class
        CanvasCustomSpriteHelper::init( rSpriteSize,
                                        rSpriteCanvas.get() );
    }

    void SpriteHelper::setSurface( Surface* pBufferSurface )
    {
        if( mpBufferSurface )
            mpBufferSurface->Unref();

        mpBufferSurface = pBufferSurface;
        mpBufferSurface->Ref();
    }

    void SpriteHelper::disposing()
    {
        mpSpriteCanvas.clear();

        // forward to parent
        CanvasCustomSpriteHelper::disposing();

        if( mpBufferSurface ) {
            mpBufferSurface->Unref();
            mpBufferSurface = NULL;
        }
    }

    void SpriteHelper::redraw( Cairo*                     pCairo,
                               const ::basegfx::B2DPoint& rPos,
                               bool&                      /*io_bSurfacesDirty*/,
                               bool                       /*bBufferedUpdate*/ ) const
    {
    #ifdef CAIRO_CANVAS_PERF_TRACE
    struct timespec aTimer;
    mxDevice->startPerfTrace( &aTimer );
        #endif

        const double fAlpha( getAlpha() );
    const ::basegfx::B2DHomMatrix aTransform( getTransformation() );

    if( isActive() && !::basegfx::fTools::equalZero( fAlpha ) ) {
        OSL_TRACE ("CanvasCustomSprite::redraw called");
        if( pCairo ) {
        basegfx::B2DVector aSize = getSizePixel();
        cairo_save( pCairo );

        double fX, fY;

        fX = rPos.getX();
        fY = rPos.getY();

         if( !aTransform.isIdentity() ) {
             cairo_matrix_t aMatrix, aInverseMatrix;
             cairo_matrix_init( &aMatrix,
                        aTransform.get( 0, 0 ), aTransform.get( 1, 0 ), aTransform.get( 0, 1 ),
                        aTransform.get( 1, 1 ), aTransform.get( 0, 2 ), aTransform.get( 1, 2 ) );

             aMatrix.x0 = round( aMatrix.x0 );
             aMatrix.y0 = round( aMatrix.y0 );

            cairo_matrix_init( &aInverseMatrix, aMatrix.xx, aMatrix.yx, aMatrix.xy, aMatrix.yy, aMatrix.x0, aMatrix.y0 );
            cairo_matrix_invert( &aInverseMatrix );
            cairo_matrix_transform_distance( &aInverseMatrix, &fX, &fY );

             cairo_set_matrix( pCairo, &aMatrix );
         }

         fX = round( fX );
         fY = round( fY );

        cairo_matrix_t aOrigMatrix;
        cairo_get_matrix( pCairo, &aOrigMatrix );
        cairo_translate( pCairo, fX, fY );

                if( getClip().is() )
                {
                    ::basegfx::B2DPolyPolygon aClipPoly(
                        ::canvas::tools::polyPolygonFromXPolyPolygon2D(
                            getClip() ));

            //cairo_reset_clip( pCairo );
            doPolyPolygonImplementation( aClipPoly, Clip, pCairo );
        }

        OSL_TRACE ("aSize %f x %f position: %f,%f", aSize.getX(), aSize.getY(), fX, fY );
        cairo_rectangle( pCairo, 0, 0, floor( aSize.getX() ), floor( aSize.getY() ) );
        cairo_clip( pCairo );
        cairo_set_matrix( pCairo, &aOrigMatrix );

        if( isContentFullyOpaque() )
             cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
        cairo_set_source_surface( pCairo, mpBufferSurface->mpSurface, fX, fY );
                if( ::rtl::math::approxEqual( fAlpha, 1.0 ) )
            cairo_paint( pCairo );
        else
            cairo_paint_with_alpha( pCairo, fAlpha );

        cairo_restore( pCairo );
        }
    }

    #ifdef CAIRO_CANVAS_PERF_TRACE
    mxDevice->stopPerfTrace( &aTimer, "sprite redraw" );
        #endif
    }

    ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const
    {
        return ::canvas::tools::polyPolygonFromXPolyPolygon2D( xPoly );
    }
}
<commit_msg>INTEGRATION: CWS cairoquartz01 (1.4.22); FILE MERGED 2007/12/10 17:45:38 mox 1.4.22.3: RESYNC: (1.5-1.6); FILE MERGED 2007/07/28 15:31:00 mox 1.4.22.2: RESYNC: (1.4-1.5); FILE MERGED 2007/06/02 23:05:33 thb 1.4.22.1: #i70519# Merged in tml's fixes for WinCairo; made code compile warning-free under Linux; added prex/postx.h (which where already referenced); cleaned up a bit; replaces plain round() call with basegfx::fround; asserting unexpected/unimplemented case at selected places<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cairo_spritehelper.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-02 09:44:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

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

#include <canvas/debug.hxx>
#include <canvas/verbosetrace.hxx>

#include <rtl/logfile.hxx>
#include <rtl/math.hxx>

#include <canvas/canvastools.hxx>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx>
#include <basegfx/polygon/b2dpolygontriangulator.hxx>
#include <basegfx/polygon/b2dpolygoncutandtouch.hxx>

#include "cairo_canvascustomsprite.hxx"
#include "cairo_spritehelper.hxx"

#include <memory>

using namespace ::cairo;
using namespace ::com::sun::star;

namespace cairocanvas
{
    SpriteHelper::SpriteHelper() :
        mpSpriteCanvas(),
        mbTextureDirty( true ),
    mpBufferSurface( NULL )
    {
    }

    void SpriteHelper::init( const geometry::RealSize2D&    rSpriteSize,
                             const SpriteCanvasRef&         rSpriteCanvas)
    {
        ENSURE_AND_THROW( rSpriteCanvas.get(),
                          "SpriteHelper::init(): Invalid device, sprite canvas or surface" );

        mpSpriteCanvas     = rSpriteCanvas;
        mbTextureDirty     = true;

        // also init base class
        CanvasCustomSpriteHelper::init( rSpriteSize,
                                        rSpriteCanvas.get() );
    }

    void SpriteHelper::setSurface( Surface* pBufferSurface )
    {
        if( mpBufferSurface )
            mpBufferSurface->Unref();

        mpBufferSurface = pBufferSurface;
        mpBufferSurface->Ref();
    }

    void SpriteHelper::disposing()
    {
        mpSpriteCanvas.clear();

        // forward to parent
        CanvasCustomSpriteHelper::disposing();

        if( mpBufferSurface ) {
            mpBufferSurface->Unref();
            mpBufferSurface = NULL;
        }
    }

    void SpriteHelper::redraw( Cairo*                     pCairo,
                               const ::basegfx::B2DPoint& rPos,
                               bool&                      /*io_bSurfacesDirty*/,
                               bool                       /*bBufferedUpdate*/ ) const
    {
    #ifdef CAIRO_CANVAS_PERF_TRACE
    struct timespec aTimer;
    mxDevice->startPerfTrace( &aTimer );
        #endif

        const double fAlpha( getAlpha() );
    const ::basegfx::B2DHomMatrix aTransform( getTransformation() );

    if( isActive() && !::basegfx::fTools::equalZero( fAlpha ) ) {
        OSL_TRACE ("CanvasCustomSprite::redraw called");
        if( pCairo ) {
        basegfx::B2DVector aSize = getSizePixel();
        cairo_save( pCairo );

        double fX, fY;

        fX = rPos.getX();
        fY = rPos.getY();

         if( !aTransform.isIdentity() ) {
             cairo_matrix_t aMatrix, aInverseMatrix;
             cairo_matrix_init( &aMatrix,
                        aTransform.get( 0, 0 ), aTransform.get( 1, 0 ), aTransform.get( 0, 1 ),
                        aTransform.get( 1, 1 ), aTransform.get( 0, 2 ), aTransform.get( 1, 2 ) );

             aMatrix.x0 = basegfx::fround( aMatrix.x0 );
             aMatrix.y0 = basegfx::fround( aMatrix.y0 );

            cairo_matrix_init( &aInverseMatrix, aMatrix.xx, aMatrix.yx, aMatrix.xy, aMatrix.yy, aMatrix.x0, aMatrix.y0 );
            cairo_matrix_invert( &aInverseMatrix );
            cairo_matrix_transform_distance( &aInverseMatrix, &fX, &fY );

             cairo_set_matrix( pCairo, &aMatrix );
         }

         fX = basegfx::fround( fX );
         fY = basegfx::fround( fY );

        cairo_matrix_t aOrigMatrix;
        cairo_get_matrix( pCairo, &aOrigMatrix );
        cairo_translate( pCairo, fX, fY );

                if( getClip().is() )
                {
                    ::basegfx::B2DPolyPolygon aClipPoly(
                        ::canvas::tools::polyPolygonFromXPolyPolygon2D(
                            getClip() ));

            //cairo_reset_clip( pCairo );
            doPolyPolygonImplementation( aClipPoly, Clip, pCairo );
        }

        OSL_TRACE ("aSize %f x %f position: %f,%f", aSize.getX(), aSize.getY(), fX, fY );
        cairo_rectangle( pCairo, 0, 0, floor( aSize.getX() ), floor( aSize.getY() ) );
        cairo_clip( pCairo );
        cairo_set_matrix( pCairo, &aOrigMatrix );

        if( isContentFullyOpaque() )
             cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
        cairo_set_source_surface( pCairo, mpBufferSurface->mpSurface, fX, fY );
                if( ::rtl::math::approxEqual( fAlpha, 1.0 ) )
            cairo_paint( pCairo );
        else
            cairo_paint_with_alpha( pCairo, fAlpha );

        cairo_restore( pCairo );
        }
    }

    #ifdef CAIRO_CANVAS_PERF_TRACE
    mxDevice->stopPerfTrace( &aTimer, "sprite redraw" );
        #endif
    }

    ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const
    {
        return ::canvas::tools::polyPolygonFromXPolyPolygon2D( xPoly );
    }
}
<|endoftext|>


<commit_before>/*

This file is part of VROOM.

Copyright (c) 2015-2022, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include "problems/cvrp/operators/reverse_two_opt.h"

namespace vroom {
namespace cvrp {

ReverseTwoOpt::ReverseTwoOpt(const Input& input,
                             const utils::SolutionState& sol_state,
                             RawRoute& s_route,
                             Index s_vehicle,
                             Index s_rank,
                             RawRoute& t_route,
                             Index t_vehicle,
                             Index t_rank)
  : Operator(OperatorName::ReverseTwoOpt,
             input,
             sol_state,
             s_route,
             s_vehicle,
             s_rank,
             t_route,
             t_vehicle,
             t_rank) {
  assert(s_vehicle != t_vehicle);
  assert(s_route.size() >= 1);
  assert(t_route.size() >= 1);
  assert(s_rank < s_route.size());
  assert(t_rank < t_route.size());

  assert(_sol_state.bwd_skill_rank[s_vehicle][t_vehicle] <= s_rank + 1);
  assert(t_rank < _sol_state.fwd_skill_rank[t_vehicle][s_vehicle]);
}

void ReverseTwoOpt::compute_gain() {
  const auto& s_v = _input.vehicles[s_vehicle];
  const auto& t_v = _input.vehicles[t_vehicle];

  Index s_index = _input.jobs[s_route[s_rank]].index();
  Index t_index = _input.jobs[t_route[t_rank]].index();
  Index last_s = _input.jobs[s_route.back()].index();
  Index first_t = _input.jobs[t_route.front()].index();

  bool last_in_source = (s_rank == s_route.size() - 1);
  bool last_in_target = (t_rank == t_route.size() - 1);

  // Cost of swapping route for vehicle s_vehicle after step
  // s_rank with route for vehicle t_vehicle up to step
  // t_rank, but reversed.

  // Add new source -> target edge.
  s_gain -= s_v.eval(s_index, t_index);

  // Cost of reversing target route portion. First remove forward cost
  // for beginning of target route as seen from target vehicle. Then
  // add backward cost for beginning of target route as seen from
  // source vehicle since it's the new source route end.
  t_gain += _sol_state.fwd_costs[t_vehicle][t_vehicle][t_rank];
  s_gain -= _sol_state.bwd_costs[t_vehicle][s_vehicle][t_rank];

  if (!last_in_target) {
    // Spare next edge in target route.
    Index next_index = _input.jobs[t_route[t_rank + 1]].index();
    t_gain += t_v.eval(t_index, next_index);
  }

  if (!last_in_source) {
    // Spare next edge in source route.
    Index next_index = _input.jobs[s_route[s_rank + 1]].index();
    s_gain += s_v.eval(s_index, next_index);

    // Part of source route is moved to target route.
    Index next_s_index = _input.jobs[s_route[s_rank + 1]].index();

    // Cost or reverting source route portion. First remove forward
    // cost for end of source route as seen from source vehicle
    // (subtracting intermediate cost to overall cost). Then add
    // backward cost for end of source route as seen from target
    // vehicle since it's the new target route start.
    s_gain += _sol_state.fwd_costs[s_vehicle][s_vehicle].back();
    s_gain -= _sol_state.fwd_costs[s_vehicle][s_vehicle][s_rank + 1];
    t_gain -= _sol_state.bwd_costs[s_vehicle][t_vehicle].back();
    t_gain += _sol_state.bwd_costs[s_vehicle][t_vehicle][s_rank + 1];

    if (last_in_target) {
      if (t_v.has_end()) {
        // Handle target route new end.
        auto end_t = t_v.end.value().index();
        t_gain += t_v.eval(t_index, end_t);
        t_gain -= t_v.eval(next_s_index, end_t);
      }
    } else {
      // Add new target -> source edge.
      Index next_t_index = _input.jobs[t_route[t_rank + 1]].index();
      t_gain -= t_v.eval(next_s_index, next_t_index);
    }
  }

  if (s_v.has_end()) {
    // Update cost to source end because last job changed.
    auto end_s = s_v.end.value().index();
    s_gain += s_v.eval(last_s, end_s);
    s_gain -= s_v.eval(first_t, end_s);
  }

  if (t_v.has_start()) {
    // Spare cost from target start because first job changed.
    auto start_t = t_v.start.value().index();
    t_gain += t_v.eval(start_t, first_t);
    if (!last_in_source) {
      t_gain -= t_v.eval(start_t, last_s);
    } else {
      // No job from source route actually swapped to target route.
      if (!last_in_target) {
        // Going straight from start to next job in target route.
        Index next_index = _input.jobs[t_route[t_rank + 1]].index();
        t_gain -= t_v.eval(start_t, next_index);
      } else {
        // Emptying the whole target route here, so also gaining cost
        // to end if it exists.
        if (t_v.has_end()) {
          auto end_t = t_v.end.value().index();
          t_gain += t_v.eval(t_index, end_t);
        }
      }
    }
  }

  stored_gain = s_gain + t_gain;
  gain_computed = true;
}

bool ReverseTwoOpt::is_valid() {
  const auto& t_delivery = target.fwd_deliveries(t_rank);
  const auto& t_pickup = target.fwd_pickups(t_rank);

  bool valid = source.is_valid_addition_for_capacity_margins(_input,
                                                             t_pickup,
                                                             t_delivery,
                                                             s_rank + 1,
                                                             s_route.size());

  const auto& s_delivery = source.bwd_deliveries(s_rank);
  const auto& s_pickup = source.bwd_pickups(s_rank);

  valid = valid && target.is_valid_addition_for_capacity_margins(_input,
                                                                 s_pickup,
                                                                 s_delivery,
                                                                 0,
                                                                 t_rank + 1);

  valid =
    valid && source.is_valid_addition_for_capacity_inclusion(_input,
                                                             t_delivery,
                                                             t_route.rbegin() +
                                                               t_route.size() -
                                                               1 - t_rank,
                                                             t_route.rend(),
                                                             s_rank + 1,
                                                             s_route.size());

  valid =
    valid && target.is_valid_addition_for_capacity_inclusion(_input,
                                                             s_delivery,
                                                             s_route.rbegin(),
                                                             s_route.rbegin() +
                                                               s_route.size() -
                                                               1 - s_rank,
                                                             0,
                                                             t_rank + 1);

  return valid;
}

void ReverseTwoOpt::apply() {
  auto nb_source = s_route.size() - 1 - s_rank;

  t_route.insert(t_route.begin(),
                 s_route.rbegin(),
                 s_route.rbegin() + nb_source);
  s_route.erase(s_route.begin() + s_rank + 1, s_route.end());
  s_route.insert(s_route.end(),
                 t_route.rend() - t_rank - nb_source - 1,
                 t_route.rend() - nb_source);
  t_route.erase(t_route.begin() + nb_source,
                t_route.begin() + nb_source + t_rank + 1);

  source.update_amounts(_input);
  target.update_amounts(_input);
}

std::vector<Index> ReverseTwoOpt::addition_candidates() const {
  return {s_vehicle, t_vehicle};
}

std::vector<Index> ReverseTwoOpt::update_candidates() const {
  return {s_vehicle, t_vehicle};
}

} // namespace cvrp
} // namespace vroom
<commit_msg>Check max_travel_time validity in ReverseTwoOpt.<commit_after>/*

This file is part of VROOM.

Copyright (c) 2015-2022, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include "problems/cvrp/operators/reverse_two_opt.h"

namespace vroom {
namespace cvrp {

ReverseTwoOpt::ReverseTwoOpt(const Input& input,
                             const utils::SolutionState& sol_state,
                             RawRoute& s_route,
                             Index s_vehicle,
                             Index s_rank,
                             RawRoute& t_route,
                             Index t_vehicle,
                             Index t_rank)
  : Operator(OperatorName::ReverseTwoOpt,
             input,
             sol_state,
             s_route,
             s_vehicle,
             s_rank,
             t_route,
             t_vehicle,
             t_rank) {
  assert(s_vehicle != t_vehicle);
  assert(s_route.size() >= 1);
  assert(t_route.size() >= 1);
  assert(s_rank < s_route.size());
  assert(t_rank < t_route.size());

  assert(_sol_state.bwd_skill_rank[s_vehicle][t_vehicle] <= s_rank + 1);
  assert(t_rank < _sol_state.fwd_skill_rank[t_vehicle][s_vehicle]);
}

void ReverseTwoOpt::compute_gain() {
  const auto& s_v = _input.vehicles[s_vehicle];
  const auto& t_v = _input.vehicles[t_vehicle];

  Index s_index = _input.jobs[s_route[s_rank]].index();
  Index t_index = _input.jobs[t_route[t_rank]].index();
  Index last_s = _input.jobs[s_route.back()].index();
  Index first_t = _input.jobs[t_route.front()].index();

  bool last_in_source = (s_rank == s_route.size() - 1);
  bool last_in_target = (t_rank == t_route.size() - 1);

  // Cost of swapping route for vehicle s_vehicle after step
  // s_rank with route for vehicle t_vehicle up to step
  // t_rank, but reversed.

  // Add new source -> target edge.
  s_gain -= s_v.eval(s_index, t_index);

  // Cost of reversing target route portion. First remove forward cost
  // for beginning of target route as seen from target vehicle. Then
  // add backward cost for beginning of target route as seen from
  // source vehicle since it's the new source route end.
  t_gain += _sol_state.fwd_costs[t_vehicle][t_vehicle][t_rank];
  s_gain -= _sol_state.bwd_costs[t_vehicle][s_vehicle][t_rank];

  if (!last_in_target) {
    // Spare next edge in target route.
    Index next_index = _input.jobs[t_route[t_rank + 1]].index();
    t_gain += t_v.eval(t_index, next_index);
  }

  if (!last_in_source) {
    // Spare next edge in source route.
    Index next_index = _input.jobs[s_route[s_rank + 1]].index();
    s_gain += s_v.eval(s_index, next_index);

    // Part of source route is moved to target route.
    Index next_s_index = _input.jobs[s_route[s_rank + 1]].index();

    // Cost or reverting source route portion. First remove forward
    // cost for end of source route as seen from source vehicle
    // (subtracting intermediate cost to overall cost). Then add
    // backward cost for end of source route as seen from target
    // vehicle since it's the new target route start.
    s_gain += _sol_state.fwd_costs[s_vehicle][s_vehicle].back();
    s_gain -= _sol_state.fwd_costs[s_vehicle][s_vehicle][s_rank + 1];
    t_gain -= _sol_state.bwd_costs[s_vehicle][t_vehicle].back();
    t_gain += _sol_state.bwd_costs[s_vehicle][t_vehicle][s_rank + 1];

    if (last_in_target) {
      if (t_v.has_end()) {
        // Handle target route new end.
        auto end_t = t_v.end.value().index();
        t_gain += t_v.eval(t_index, end_t);
        t_gain -= t_v.eval(next_s_index, end_t);
      }
    } else {
      // Add new target -> source edge.
      Index next_t_index = _input.jobs[t_route[t_rank + 1]].index();
      t_gain -= t_v.eval(next_s_index, next_t_index);
    }
  }

  if (s_v.has_end()) {
    // Update cost to source end because last job changed.
    auto end_s = s_v.end.value().index();
    s_gain += s_v.eval(last_s, end_s);
    s_gain -= s_v.eval(first_t, end_s);
  }

  if (t_v.has_start()) {
    // Spare cost from target start because first job changed.
    auto start_t = t_v.start.value().index();
    t_gain += t_v.eval(start_t, first_t);
    if (!last_in_source) {
      t_gain -= t_v.eval(start_t, last_s);
    } else {
      // No job from source route actually swapped to target route.
      if (!last_in_target) {
        // Going straight from start to next job in target route.
        Index next_index = _input.jobs[t_route[t_rank + 1]].index();
        t_gain -= t_v.eval(start_t, next_index);
      } else {
        // Emptying the whole target route here, so also gaining cost
        // to end if it exists.
        if (t_v.has_end()) {
          auto end_t = t_v.end.value().index();
          t_gain += t_v.eval(t_index, end_t);
        }
      }
    }
  }

  stored_gain = s_gain + t_gain;
  gain_computed = true;
}

bool ReverseTwoOpt::is_valid() {
  const auto& t_delivery = target.fwd_deliveries(t_rank);
  const auto& t_pickup = target.fwd_pickups(t_rank);

  bool valid = source.is_valid_addition_for_capacity_margins(_input,
                                                             t_pickup,
                                                             t_delivery,
                                                             s_rank + 1,
                                                             s_route.size());

  const auto& s_delivery = source.bwd_deliveries(s_rank);
  const auto& s_pickup = source.bwd_pickups(s_rank);

  valid = valid && target.is_valid_addition_for_capacity_margins(_input,
                                                                 s_pickup,
                                                                 s_delivery,
                                                                 0,
                                                                 t_rank + 1);

  const auto& s_v = _input.vehicles[s_vehicle];
  const auto s_travel_time = _sol_state.route_evals[s_vehicle].duration;
  valid = valid && (s_travel_time <= s_v.max_travel_time + s_gain.duration);

  const auto& t_v = _input.vehicles[t_vehicle];
  const auto t_travel_time = _sol_state.route_evals[t_vehicle].duration;
  valid = valid && (t_travel_time <= t_v.max_travel_time + t_gain.duration);

  valid =
    valid && source.is_valid_addition_for_capacity_inclusion(_input,
                                                             t_delivery,
                                                             t_route.rbegin() +
                                                               t_route.size() -
                                                               1 - t_rank,
                                                             t_route.rend(),
                                                             s_rank + 1,
                                                             s_route.size());

  valid =
    valid && target.is_valid_addition_for_capacity_inclusion(_input,
                                                             s_delivery,
                                                             s_route.rbegin(),
                                                             s_route.rbegin() +
                                                               s_route.size() -
                                                               1 - s_rank,
                                                             0,
                                                             t_rank + 1);

  return valid;
}

void ReverseTwoOpt::apply() {
  auto nb_source = s_route.size() - 1 - s_rank;

  t_route.insert(t_route.begin(),
                 s_route.rbegin(),
                 s_route.rbegin() + nb_source);
  s_route.erase(s_route.begin() + s_rank + 1, s_route.end());
  s_route.insert(s_route.end(),
                 t_route.rend() - t_rank - nb_source - 1,
                 t_route.rend() - nb_source);
  t_route.erase(t_route.begin() + nb_source,
                t_route.begin() + nb_source + t_rank + 1);

  source.update_amounts(_input);
  target.update_amounts(_input);
}

std::vector<Index> ReverseTwoOpt::addition_candidates() const {
  return {s_vehicle, t_vehicle};
}

std::vector<Index> ReverseTwoOpt::update_candidates() const {
  return {s_vehicle, t_vehicle};
}

} // namespace cvrp
} // namespace vroom
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

/// \file StereoSessionIsis.cc
///

// Vision Workbench
#include <vw/FileIO.h>
#include <vw/Math/Functors.h>
#include <vw/Math/Geometry.h>
#include <vw/Math/RANSAC.h>
#include <vw/InterestPoint.h>
#include <vw/Stereo/DisparityMap.h>
#include <vw/Cartography.h>

// Stereo Pipeline
#include <asp/Sessions/ISIS/StereoSessionIsis.h>
#include <asp/IsisIO/IsisCameraModel.h>
#include <asp/Core/StereoSettings.h>
#include <asp/IsisIO/IsisAdjustCameraModel.h>
#include <asp/IsisIO/DiskImageResourceIsis.h>
#include <asp/Sessions/ISIS/PhotometricOutlier.h>

// Boost
#include <boost/filesystem/operations.hpp>
#include <boost/shared_ptr.hpp>
namespace fs = boost::filesystem;

#include <algorithm>

using namespace vw;
using namespace vw::camera;
using namespace asp;

// Allows FileIO to correctly read/write these pixel types
namespace vw {
  template<> struct PixelFormatID<Vector3>   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
}

// Process a single ISIS image to find an ideal min max. The reason we
// need to do this, is that ASP is to get image intensity values in
// the range of 0-1. To some extent we are compressing the dynamic
// range, but we try to minimize that.
void find_ideal_isis_range( std::string const& in_file,
                            std::string const& tag,
                            float & isis_lo, float & isis_hi ) {

  boost::shared_ptr<DiskImageResourceIsis> isis_rsrc( new DiskImageResourceIsis(in_file) );
  DiskImageView<PixelGray<float> > disk_image(isis_rsrc);

  float isis_mean, isis_std;

  // Calculating statistics. We subsample the images so statistics
  // only does about a million samples.
  {
    vw_out(InfoMessage) << "\t--> Computing statistics for the "+tag+" image\n";
    int left_stat_scale = int(ceil(sqrt(float(disk_image.cols())*float(disk_image.rows()) / 1000000)));
    ChannelAccumulator<math::CDFAccumulator<float> > accumulator;
    for_each_pixel(
      subsample(create_mask( edge_extend(disk_image, ConstantEdgeExtension()),
                             isis_rsrc->valid_minimum(),
                             isis_rsrc->valid_maximum() ),
                left_stat_scale ),
      accumulator );
    isis_lo = accumulator.quantile(0);
    isis_hi = accumulator.quantile(1);
    isis_mean = accumulator.approximate_mean();
    isis_std  = accumulator.approximate_stddev();

    vw_out(InfoMessage) << "\t  "+tag+": [ lo:" << isis_lo << " hi:" << isis_hi
                        << " m: " << isis_mean << " s: " << isis_std <<  "]\n";
  }

  // Normalizing to -+2 sigmas around mean
  if ( stereo_settings().force_max_min == 0 ) {
    vw_out(InfoMessage) << "\t--> Adjusting hi and lo to -+2 sigmas around mean.\n";

    if ( isis_lo < isis_mean - 2*isis_std )
      isis_lo = isis_mean - 2*isis_std;
    if ( isis_hi > isis_mean + 2*isis_std )
      isis_hi = isis_mean + 2*isis_std;

    vw_out(InfoMessage) << "\t    "+tag+" changed: [ lo:"
                        << isis_lo << " hi:" << isis_hi << "]\n";
  }
}

// This tells the GDAL settings we should be using
//
// I don't like having this here. We should somehow use the settings
// decided by stereo. Unfortunately Sessions can not depend on the tool.
vw::DiskImageResourceGDAL::Options
gdal_settings( int32 const& cols, int32 const& rows ) {
  vw::DiskImageResourceGDAL::Options option;
#if defined(VW_HAS_BIGTIFF) && VW_HAS_BIGTIFF == 1
  option["COMPRESS"] = "LZW";
  if ( cols*rows > 10e6 )
    option["BIGTIFF"] = "IF_SAFER";
  else
    option["BIGTIFF"] = "NO";
#else
  option["COMPRESS"] = "NONE";
  option["BIGTIFF"] = "NO";
#endif
  return option;
}

// This actually modifies and writes the pre-processed image.
void write_preprocessed_isis_image( std::string const& in_file,
                                    std::string const& out_file,
                                    std::string const& tag,
                                    float const& isis_lo, float const& isis_hi,
                                    float const& out_lo, float const& out_hi,
                                    Matrix<double> const& matrix,
                                    Vector2i const& crop_size ) {
  DiskImageView<PixelGray<float> > disk_image(in_file);
  ImageViewRef<PixelGray<float> > applied_image;
  if ( matrix == math::identity_matrix<3>() ) {
    applied_image =
      crop(edge_extend(clamp(normalize(remove_isis_special_pixels(disk_image,
                                                                  isis_lo, isis_hi, out_lo),
                           out_lo, out_hi, 0.0, 1.0)),
                       ZeroEdgeExtension()),
           0, 0, crop_size[0], crop_size[1]);
  } else {
    applied_image =
      clamp(transform(normalize(remove_isis_special_pixels(disk_image,
                                                           isis_lo, isis_hi,
                                                           out_lo),
                                out_lo, out_hi, 0.0, 1.0),
                      HomographyTransform(matrix),
                      crop_size[0], crop_size[1]));
  }

  // Write the results to disk.
  vw_out() << "\t--> Writing normalized images.\n";
  DiskImageResourceGDAL out_rsrc( out_file, applied_image.format(),
                                  Vector2i(vw_settings().default_tile_size(),
                                           vw_settings().default_tile_size()),
                                  gdal_settings(applied_image.cols(),
                                                applied_image.rows()));
  block_write_image( out_rsrc, applied_image,
                     TerminalProgressCallback("asp", "\t  "+tag+":  "));
}

void
asp::StereoSessionIsis::pre_preprocessing_hook(std::string const& input_file1,
                                               std::string const& input_file2,
                                               std::string & output_file1,
                                               std::string & output_file2) {
  output_file1 = m_out_prefix + "-L.tif";
  output_file2 = m_out_prefix + "-R.tif";

  if ( fs::exists(output_file1) && fs::exists(output_file2) ) {
    try {
      vw_log().console_log().rule_set().add_rule(-1,"fileio");
      DiskImageView<PixelGray<float32> > out1(output_file1);
      DiskImageView<PixelGray<float32> > out2(output_file2);
      vw_out(InfoMessage) << "\t--> Using cached normalized input images.\n";
      vw_settings().reload_config();
      return;
    } catch (vw::ArgumentErr const& e) {
      // This throws on a corrupted file.
      vw_settings().reload_config();
    } catch (vw::IOErr const& e) {
      vw_settings().reload_config();
    }
  }

  float left_lo, left_hi, right_lo, right_hi;
  find_ideal_isis_range( input_file1, "left",
                         left_lo, left_hi );
  find_ideal_isis_range( input_file2, "right",
                         right_lo, right_hi );

  // Working out alignment
  float lo = std::min (left_lo, right_lo);  // Finding global
  float hi = std::max (left_hi, right_hi);
  Matrix<double> align_matrix(3,3);
  align_matrix.set_identity();
  if ( stereo_settings().keypoint_alignment) {
    DiskImageView<PixelGray<float> > left_disk_image(input_file1);
    DiskImageView<PixelGray<float> > right_disk_image(input_file2);
    ImageViewRef<PixelGray<float> > left_view =
      normalize(remove_isis_special_pixels(left_disk_image, lo),
                lo, hi, 0, 1.0);
    ImageViewRef<PixelGray<float> > right_view =
      normalize(remove_isis_special_pixels(right_disk_image, lo),
                lo, hi, 0, 1.0);
    align_matrix = determine_image_align(input_file1, input_file2,
                                         left_view, right_view );
  }
  write_matrix( m_out_prefix + "-align.exr", align_matrix );

  // Getting left image size
  Vector2i left_size;
  {
    DiskImageView<PixelGray<float> > left_image(input_file1);
    left_size = Vector2i(left_image.cols(), left_image.rows());
  }

  // Apply alignment and normalization
  if (stereo_settings().individually_normalize == 0 ) {
    vw_out() << "\t--> Normalizing globally to: ["<<lo<<" "<<hi<<"]\n";
    write_preprocessed_isis_image( input_file1, output_file1, "left",
                                   left_lo, left_hi, lo, hi,
                                   math::identity_matrix<3>(), left_size );
    write_preprocessed_isis_image( input_file2, output_file2, "right",
                                   right_lo, right_hi, lo, hi,
                                   align_matrix, left_size );
  } else {
    vw_out() << "\t--> Individually normalizing.\n";
    write_preprocessed_isis_image( input_file1, output_file1, "left",
                                   left_lo, left_hi, left_lo, left_hi,
                                   math::identity_matrix<3>(), left_size );
    write_preprocessed_isis_image( input_file2, output_file2, "right",
                                   right_lo, right_hi, right_lo, right_hi,
                                   align_matrix, left_size );
  }
}

inline std::string write_shadow_mask( std::string const& output_prefix,
                                      std::string const& input_image,
                                      std::string const& mask_postfix ) {
  // This thresholds at -25000 as the input sub4s for Apollo that I've
  // processed have a range somewhere between -32000 and +32000. -ZMM
  DiskImageView<PixelGray<float> > disk_image( input_image );
  DiskImageView<uint8> disk_mask( output_prefix + mask_postfix );
  ImageViewRef<uint8> mask =
    apply_mask(intersect_mask(create_mask(disk_mask),
                              create_mask(threshold(disk_image,-25000,0,1.0))));
  std::string output_mask =
    output_prefix+mask_postfix.substr(0,mask_postfix.size()-4)+"Debug.tif";

  DiskImageResourceGDAL
    out_mask_rsrc( output_mask, mask.format(),
                   Vector2i(vw_settings().default_tile_size(),
                            vw_settings().default_tile_size()),
                   gdal_settings( mask.cols(), mask.rows()) );
  block_write_image( out_mask_rsrc, mask );
  return output_mask;
}

// Stage 2: Correlation
//
// Pre file is a pair of grayscale images.  ( ImageView<PixelGray<float> > )
// Post file is a disparity map.            ( ImageView<PixelMask<Vector2f> > )
void
asp::StereoSessionIsis::pre_filtering_hook(std::string const& input_file,
                                           std::string & output_file) {
  output_file = input_file;

  // ****************************************************
  // The following code is for Apollo Metric Camera ONLY!
  // (use at your own risk)
  // ****************************************************
  if (stereo_settings().mask_flatfield) {
    vw_out() << "\t--> Masking pixels that are less than 0.0.  (NOTE: Use this option with Apollo Metric Camera frames only!)\n";
    output_file = m_out_prefix + "-R-masked.exr";

    std::string shadowLmask_name =
      write_shadow_mask( m_out_prefix, m_left_image_file,
                         "-lMask.tif" );
    std::string shadowRmask_name =
      write_shadow_mask( m_out_prefix, m_right_image_file,
                         "-rMask.tif" );

    DiskImageView<uint8> shadowLmask( shadowLmask_name );
    DiskImageView<uint8> shadowRmask( shadowRmask_name );

    DiskImageView<PixelMask<Vector2f> > disparity_disk_image(input_file);
    ImageViewRef<PixelMask<Vector2f> > disparity_map =
      stereo::disparity_mask(disparity_disk_image,
                             shadowLmask, shadowRmask );

    DiskImageResourceOpenEXR disparity_map_rsrc(output_file, disparity_map.format() );
    Vector2i block_size(std::min<size_t>(vw_settings().default_tile_size(),
                                         disparity_map.cols()),
                        std::min<size_t>(vw_settings().default_tile_size(),
                                         disparity_map.rows()));
    disparity_map_rsrc.set_block_write_size(block_size);
    block_write_image( disparity_map_rsrc, disparity_map,
                       TerminalProgressCallback( "asp", "\t--> Saving Mask :") );
  }
}

// Reverse any pre-alignment that was done to the images.
void
asp::StereoSessionIsis::pre_pointcloud_hook(std::string const& input_file,
                                            std::string & output_file) {

  // ****************************************************
  // The following code is for Apollo Metric Camera ONLY!
  // (use at your own risk)
  // ****************************************************
  std::string dust_result = input_file;
  if ( stereo_settings().mask_flatfield ) {
    vw_out() << "\t--> Masking pixels that appear to be dust.  (NOTE: Use this option with Apollo Metric Camera frames only!)\n";
    photometric_outlier_rejection( m_out_prefix, input_file,
                                   dust_result, stereo_settings().h_kern );
  }

  DiskImageView<PixelMask<Vector2f> > disparity_map(dust_result);
  output_file = m_out_prefix + "-F-corrected.tif";

  // We used a homography to line up the images, we may want
  // to generate pre-alignment disparities before passing this information
  // onto the camera model in the next stage of the stereo pipeline.
  Matrix<double> align_matrix;
  try {
    read_matrix(align_matrix, m_out_prefix + "-align.exr");
    vw_out(DebugMessage) << "Alignment Matrix: " << align_matrix << "\n";
  } catch (vw::IOErr const& e) {
    vw_out() << "\nCould not read in aligment matrix: " << m_out_prefix
             << "-align.exr.  Exiting. \n\n";
    exit(1);
  }

  // Remove pixels that are outside the bounds of the secondary image.
  DiskImageView<PixelGray<float> > right_disk_image(m_right_image_file);
  ImageViewRef<PixelMask<Vector2f> > result =
    stereo::disparity_range_mask(stereo::transform_disparities(disparity_map,
                                          HomographyTransform(align_matrix)),
                                 Vector2f(0,0),
                                 Vector2f( right_disk_image.cols(),
                                           right_disk_image.rows() ) );

  DiskImageResourceGDAL
    disparity_corrected_rsrc( output_file, result.format(),
                              Vector2i(vw_settings().default_tile_size(),
                                       vw_settings().default_tile_size()),
                              gdal_settings( result.cols(), result.rows() ) );
  block_write_image( disparity_corrected_rsrc, result,
                     TerminalProgressCallback("asp", "\t    Processing:"));
}

boost::shared_ptr<vw::camera::CameraModel>
asp::StereoSessionIsis::camera_model(std::string const& image_file,
                                     std::string const& camera_file) {

  if (boost::ends_with(boost::to_lower_copy(camera_file), ".isis_adjust")){
    // Creating Equations for the files
    std::ifstream input( camera_file.c_str() );
    boost::shared_ptr<asp::BaseEquation> posF = read_equation( input );
    boost::shared_ptr<asp::BaseEquation> poseF = read_equation( input );
    input.close();

    // Finally creating camera model
    return boost::shared_ptr<camera::CameraModel>(new IsisAdjustCameraModel( image_file, posF, poseF ));

  } else {
    return boost::shared_ptr<camera::CameraModel>(new IsisCameraModel(image_file));
  }

}

<commit_msg>Use Common for StereoSession parallel write<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

/// \file StereoSessionIsis.cc
///

// Vision Workbench
#include <vw/FileIO.h>
#include <vw/Math/Functors.h>
#include <vw/Math/Geometry.h>
#include <vw/Math/RANSAC.h>
#include <vw/InterestPoint.h>
#include <vw/Stereo/DisparityMap.h>
#include <vw/Cartography.h>

// Stereo Pipeline
#include <asp/Sessions/ISIS/StereoSessionIsis.h>
#include <asp/IsisIO/IsisCameraModel.h>
#include <asp/Core/StereoSettings.h>
#include <asp/IsisIO/IsisAdjustCameraModel.h>
#include <asp/IsisIO/DiskImageResourceIsis.h>
#include <asp/Sessions/ISIS/PhotometricOutlier.h>

// Boost
#include <boost/filesystem/operations.hpp>
#include <boost/shared_ptr.hpp>
namespace fs = boost::filesystem;

#include <algorithm>

using namespace vw;
using namespace vw::camera;
using namespace asp;

// Allows FileIO to correctly read/write these pixel types
namespace vw {
  template<> struct PixelFormatID<Vector3>   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
}

// Process a single ISIS image to find an ideal min max. The reason we
// need to do this, is that ASP is to get image intensity values in
// the range of 0-1. To some extent we are compressing the dynamic
// range, but we try to minimize that.
void find_ideal_isis_range( std::string const& in_file,
                            std::string const& tag,
                            float & isis_lo, float & isis_hi ) {

  boost::shared_ptr<DiskImageResourceIsis> isis_rsrc( new DiskImageResourceIsis(in_file) );
  DiskImageView<PixelGray<float> > disk_image(isis_rsrc);

  float isis_mean, isis_std;

  // Calculating statistics. We subsample the images so statistics
  // only does about a million samples.
  {
    vw_out(InfoMessage) << "\t--> Computing statistics for the "+tag+" image\n";
    int left_stat_scale = int(ceil(sqrt(float(disk_image.cols())*float(disk_image.rows()) / 1000000)));
    ChannelAccumulator<math::CDFAccumulator<float> > accumulator;
    for_each_pixel(
      subsample(create_mask( edge_extend(disk_image, ConstantEdgeExtension()),
                             isis_rsrc->valid_minimum(),
                             isis_rsrc->valid_maximum() ),
                left_stat_scale ),
      accumulator );
    isis_lo = accumulator.quantile(0);
    isis_hi = accumulator.quantile(1);
    isis_mean = accumulator.approximate_mean();
    isis_std  = accumulator.approximate_stddev();

    vw_out(InfoMessage) << "\t  "+tag+": [ lo:" << isis_lo << " hi:" << isis_hi
                        << " m: " << isis_mean << " s: " << isis_std <<  "]\n";
  }

  // Normalizing to -+2 sigmas around mean
  if ( stereo_settings().force_max_min == 0 ) {
    vw_out(InfoMessage) << "\t--> Adjusting hi and lo to -+2 sigmas around mean.\n";

    if ( isis_lo < isis_mean - 2*isis_std )
      isis_lo = isis_mean - 2*isis_std;
    if ( isis_hi > isis_mean + 2*isis_std )
      isis_hi = isis_mean + 2*isis_std;

    vw_out(InfoMessage) << "\t    "+tag+" changed: [ lo:"
                        << isis_lo << " hi:" << isis_hi << "]\n";
  }
}

// This actually modifies and writes the pre-processed image.
void write_preprocessed_isis_image( BaseOptions const& opt,
                                    std::string const& in_file,
                                    std::string const& out_file,
                                    std::string const& tag,
                                    float const& isis_lo, float const& isis_hi,
                                    float const& out_lo, float const& out_hi,
                                    Matrix<double> const& matrix,
                                    Vector2i const& crop_size ) {
  DiskImageView<PixelGray<float> > disk_image(in_file);
  ImageViewRef<PixelGray<float> > applied_image;
  if ( matrix == math::identity_matrix<3>() ) {
    applied_image =
      crop(edge_extend(clamp(normalize(remove_isis_special_pixels(disk_image,
                                                                  isis_lo, isis_hi, out_lo),
                           out_lo, out_hi, 0.0, 1.0)),
                       ZeroEdgeExtension()),
           0, 0, crop_size[0], crop_size[1]);
  } else {
    applied_image =
      clamp(transform(normalize(remove_isis_special_pixels(disk_image,
                                                           isis_lo, isis_hi,
                                                           out_lo),
                                out_lo, out_hi, 0.0, 1.0),
                      HomographyTransform(matrix),
                      crop_size[0], crop_size[1]));
  }

  // Write the results to disk.
  vw_out() << "\t--> Writing normalized images.\n";
  block_write_gdal_image( out_file, applied_image, opt,
                          TerminalProgressCallback("asp", "\t  "+tag+":  ") );
}

void
asp::StereoSessionIsis::pre_preprocessing_hook(std::string const& input_file1,
                                               std::string const& input_file2,
                                               std::string & output_file1,
                                               std::string & output_file2) {
  output_file1 = m_out_prefix + "-L.tif";
  output_file2 = m_out_prefix + "-R.tif";

  if ( fs::exists(output_file1) && fs::exists(output_file2) ) {
    try {
      vw_log().console_log().rule_set().add_rule(-1,"fileio");
      DiskImageView<PixelGray<float32> > out1(output_file1);
      DiskImageView<PixelGray<float32> > out2(output_file2);
      vw_out(InfoMessage) << "\t--> Using cached normalized input images.\n";
      vw_settings().reload_config();
      return;
    } catch (vw::ArgumentErr const& e) {
      // This throws on a corrupted file.
      vw_settings().reload_config();
    } catch (vw::IOErr const& e) {
      vw_settings().reload_config();
    }
  }

  float left_lo, left_hi, right_lo, right_hi;
  find_ideal_isis_range( input_file1, "left",
                         left_lo, left_hi );
  find_ideal_isis_range( input_file2, "right",
                         right_lo, right_hi );

  // Working out alignment
  float lo = std::min (left_lo, right_lo);  // Finding global
  float hi = std::max (left_hi, right_hi);
  Matrix<double> align_matrix(3,3);
  align_matrix.set_identity();
  if ( stereo_settings().keypoint_alignment) {
    DiskImageView<PixelGray<float> > left_disk_image(input_file1);
    DiskImageView<PixelGray<float> > right_disk_image(input_file2);
    ImageViewRef<PixelGray<float> > left_view =
      normalize(remove_isis_special_pixels(left_disk_image, lo),
                lo, hi, 0, 1.0);
    ImageViewRef<PixelGray<float> > right_view =
      normalize(remove_isis_special_pixels(right_disk_image, lo),
                lo, hi, 0, 1.0);
    align_matrix = determine_image_align(input_file1, input_file2,
                                         left_view, right_view );
  }
  write_matrix( m_out_prefix + "-align.exr", align_matrix );

  // Getting left image size
  Vector2i left_size;
  {
    DiskImageView<PixelGray<float> > left_image(input_file1);
    left_size = Vector2i(left_image.cols(), left_image.rows());
  }

  // Apply alignment and normalization
  if (stereo_settings().individually_normalize == 0 ) {
    vw_out() << "\t--> Normalizing globally to: ["<<lo<<" "<<hi<<"]\n";
    write_preprocessed_isis_image( m_options, input_file1, output_file1, "left",
                                   left_lo, left_hi, lo, hi,
                                   math::identity_matrix<3>(), left_size );
    write_preprocessed_isis_image( m_options, input_file2, output_file2, "right",
                                   right_lo, right_hi, lo, hi,
                                   align_matrix, left_size );
  } else {
    vw_out() << "\t--> Individually normalizing.\n";
    write_preprocessed_isis_image( m_options, input_file1, output_file1, "left",
                                   left_lo, left_hi, left_lo, left_hi,
                                   math::identity_matrix<3>(), left_size );
    write_preprocessed_isis_image( m_options, input_file2, output_file2, "right",
                                   right_lo, right_hi, right_lo, right_hi,
                                   align_matrix, left_size );
  }
}

inline std::string write_shadow_mask( BaseOptions const& opt,
                                      std::string const& output_prefix,
                                      std::string const& input_image,
                                      std::string const& mask_postfix ) {
  // This thresholds at -25000 as the input sub4s for Apollo that I've
  // processed have a range somewhere between -32000 and +32000. -ZMM
  DiskImageView<PixelGray<float> > disk_image( input_image );
  DiskImageView<uint8> disk_mask( output_prefix + mask_postfix );
  ImageViewRef<uint8> mask =
    apply_mask(intersect_mask(create_mask(disk_mask),
                              create_mask(threshold(disk_image,-25000,0,1.0))));
  std::string output_mask =
    output_prefix+mask_postfix.substr(0,mask_postfix.size()-4)+"Debug.tif";

  block_write_gdal_image( output_mask, mask, opt,
                          TerminalProgressCallback("asp","\t  Shadow:") );
  return output_mask;
}

// Stage 2: Correlation
//
// Pre file is a pair of grayscale images.  ( ImageView<PixelGray<float> > )
// Post file is a disparity map.            ( ImageView<PixelMask<Vector2f> > )
void
asp::StereoSessionIsis::pre_filtering_hook(std::string const& input_file,
                                           std::string & output_file) {
  output_file = input_file;

  // ****************************************************
  // The following code is for Apollo Metric Camera ONLY!
  // (use at your own risk)
  // ****************************************************
  if (stereo_settings().mask_flatfield) {
    vw_out() << "\t--> Masking pixels that are less than 0.0.  (NOTE: Use this option with Apollo Metric Camera frames only!)\n";
    output_file = m_out_prefix + "-R-masked.exr";

    std::string shadowLmask_name =
      write_shadow_mask( m_options, m_out_prefix, m_left_image_file,
                         "-lMask.tif" );
    std::string shadowRmask_name =
      write_shadow_mask( m_options, m_out_prefix, m_right_image_file,
                         "-rMask.tif" );

    DiskImageView<uint8> shadowLmask( shadowLmask_name );
    DiskImageView<uint8> shadowRmask( shadowRmask_name );

    DiskImageView<PixelMask<Vector2f> > disparity_disk_image(input_file);
    ImageViewRef<PixelMask<Vector2f> > disparity_map =
      stereo::disparity_mask(disparity_disk_image,
                             shadowLmask, shadowRmask );

    DiskImageResourceOpenEXR disparity_map_rsrc(output_file, disparity_map.format() );
    Vector2i block_size(std::min<size_t>(vw_settings().default_tile_size(),
                                         disparity_map.cols()),
                        std::min<size_t>(vw_settings().default_tile_size(),
                                         disparity_map.rows()));
    disparity_map_rsrc.set_block_write_size(block_size);
    block_write_image( disparity_map_rsrc, disparity_map,
                       TerminalProgressCallback( "asp", "\t--> Saving Mask :") );
  }
}

// Reverse any pre-alignment that was done to the images.
void
asp::StereoSessionIsis::pre_pointcloud_hook(std::string const& input_file,
                                            std::string & output_file) {

  // ****************************************************
  // The following code is for Apollo Metric Camera ONLY!
  // (use at your own risk)
  // ****************************************************
  std::string dust_result = input_file;
  if ( stereo_settings().mask_flatfield ) {
    vw_out() << "\t--> Masking pixels that appear to be dust.  (NOTE: Use this option with Apollo Metric Camera frames only!)\n";
    photometric_outlier_rejection( m_out_prefix, input_file,
                                   dust_result, stereo_settings().h_kern );
  }

  DiskImageView<PixelMask<Vector2f> > disparity_map(dust_result);
  output_file = m_out_prefix + "-F-corrected.tif";

  // We used a homography to line up the images, we may want
  // to generate pre-alignment disparities before passing this information
  // onto the camera model in the next stage of the stereo pipeline.
  Matrix<double> align_matrix;
  try {
    read_matrix(align_matrix, m_out_prefix + "-align.exr");
    vw_out(DebugMessage) << "Alignment Matrix: " << align_matrix << "\n";
  } catch (vw::IOErr const& e) {
    vw_out() << "\nCould not read in aligment matrix: " << m_out_prefix
             << "-align.exr.  Exiting. \n\n";
    exit(1);
  }

  // Remove pixels that are outside the bounds of the secondary image.
  DiskImageView<PixelGray<float> > right_disk_image(m_right_image_file);
  ImageViewRef<PixelMask<Vector2f> > result =
    stereo::disparity_range_mask(stereo::transform_disparities(disparity_map,
                                          HomographyTransform(align_matrix)),
                                 Vector2f(0,0),
                                 Vector2f( right_disk_image.cols(),
                                           right_disk_image.rows() ) );

  block_write_gdal_image( output_file, result, m_options,
                          TerminalProgressCallback("asp", "\t    Processing:") );
}

boost::shared_ptr<vw::camera::CameraModel>
asp::StereoSessionIsis::camera_model(std::string const& image_file,
                                     std::string const& camera_file) {

  if (boost::ends_with(boost::to_lower_copy(camera_file), ".isis_adjust")){
    // Creating Equations for the files
    std::ifstream input( camera_file.c_str() );
    boost::shared_ptr<asp::BaseEquation> posF = read_equation( input );
    boost::shared_ptr<asp::BaseEquation> poseF = read_equation( input );
    input.close();

    // Finally creating camera model
    return boost::shared_ptr<camera::CameraModel>(new IsisAdjustCameraModel( image_file, posF, poseF ));

  } else {
    return boost::shared_ptr<camera::CameraModel>(new IsisCameraModel(image_file));
  }

}

<|endoftext|>


<commit_before>#ifndef VECMATH_HPP
#define VECMATH_HPP

#include <SFML/System.hpp>
#include <cmath>

namespace vecmath
{
    const float pi = 3.1415926535897;

    template<typename T>
T norm(const sf::Vector2<T>& a)
{
    return std::sqrt(a.x*a.x + a.y*a.y);
}

template<typename T>

T dot(const sf::Vector2<T>& a, const sf::Vector2<T>& b)
{
    return a.x*b.x + a.y*b.y;
}
}

#endif /* VECMATH_HPP */
<commit_msg>Added function to compute intersection of two vectors<commit_after>#ifndef VECMATH_HPP
#define VECMATH_HPP

#include <SFML/System.hpp>
#include <cmath>

namespace vecmath
{
const float pi = 3.1415926535897;

template<typename T>
T norm(const sf::Vector2<T>& a)
{
    return std::sqrt(a.x*a.x + a.y*a.y);
}

template<typename T>
T dot(const sf::Vector2<T>& a, const sf::Vector2<T>& b)
{
    return a.x*b.x + a.y*b.y;
}

template<typename T>
bool intersect(const sf::Vector2<T>& p0, const sf::Vector2<T>& p1,
        const sf::Vector2<T>& q0, const sf::Vector2<T>& q1,
        sf::Vector2<T>* intersection)
{
    auto dp = sf::Vector2<T>(-(q1.y-q0.y), q1.x-q0.x);
    auto dq = q1 - q0;
    // dp is orthogonal to p1-p0, so if dp.dq = 0 then
    // dp is parallel to dq and there's no intersection
    if(std::abs(vecmath::dot(dp, dq)) < 10e-5) return false;
    float mu = vecmath::dot((p0 - q0), dp) / vecmath::dot(dp, dq);
    // mu is parameter for Q
    intersection->x = q0.x + mu * (q1.x-q0.x);
    intersection->y = q0.y + mu * (q1.y-q0.y);

    return true;
}
}

#endif /* VECMATH_HPP */
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("Sterlingcoin");

// Client version number
#define CLIENT_VERSION_SUFFIX   ""

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
#define GIT_ARCHIVE 1
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID ": Full Release"
//#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) ""

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<commit_msg>One release<commit_after>// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("Sterlingcoin");

// Client version number
#define CLIENT_VERSION_SUFFIX   ""

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
#define GIT_ARCHIVE 1
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID ": Release"
//#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) ""

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<|endoftext|>


<commit_before>#include "dynet/nodes.h"
#include "dynet/dynet.h"
#include "dynet/training.h"
#include "dynet/gpu-ops.h"
#include "dynet/expr.h"
#include "dynet/mp.h"
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <iostream>
#include <fstream>

using namespace std;
using namespace dynet;
using namespace dynet::expr;
using namespace dynet::mp;

struct Datum {
  Datum() {}
  Datum(const vector<dynet::real>& x, const dynet::real y) : x(x), y(y) {}

  vector<dynet::real> x;
  dynet::real y;
};

class XorModel {
public:
  XorModel(const unsigned hidden_size, Model& dynet_model) : pcg(nullptr) {
    p_W = dynet_model.add_parameters({hidden_size, 2});
    p_b = dynet_model.add_parameters({hidden_size});
    p_V = dynet_model.add_parameters({1, hidden_size});
    p_a = dynet_model.add_parameters({1});
  }

  void new_graph(ComputationGraph& cg) {
    W = parameter(cg, p_W);
    b = parameter(cg, p_b);
    V = parameter(cg, p_V);
    a = parameter(cg, p_a);
    pcg = &cg;
  }

  Expression compute_loss(const Datum& datum) {
    Expression x = input(*pcg, {2}, &datum.x);
    Expression y = input(*pcg, &datum.y);

    Expression h = tanh(W*x + b);
    Expression y_pred = V*h + a;
    Expression loss_expr = squared_distance(y_pred, y);
    return loss_expr;
  }

private:
  XorModel() : pcg(nullptr) {}

  Parameter p_W, p_b, p_V, p_a;
  Expression W, b, V, a;
  ComputationGraph* pcg;

  friend class boost::serialization::access;
  template<class Archive>
  void serialize(Archive& ar, const unsigned int) {
    ar & p_W & p_b & p_V & p_a;
  }
};

void serialize(const XorModel* const xor_model, const Model& dynet_model, const Trainer* const trainer) {
  // Remove existing stdout output
  int r = ftruncate(fileno(stdout), 0);
  if (r != 0) {}

  // Move the cursor to the beginning of the stdout stream
  fseek(stdout, 0, SEEK_SET);

  // Dump the model to stdout
  boost::archive::text_oarchive oa(cout);
  oa & dynet_model;
  oa & xor_model;
  oa & trainer;
}

void deserialize(const string& filename, XorModel* xor_model, Model& dynet_model, Trainer* trainer) {
  ifstream in(filename.c_str());
  boost::archive::text_iarchive ia(in);
  ia & dynet_model;
  ia & xor_model;
  ia & trainer;
  in.close();
}

class SufficientStats {
public:
  dynet::real loss;
  unsigned example_count;

  SufficientStats() : loss(), example_count() {}

  SufficientStats(dynet::real loss, unsigned example_count) : loss(loss), example_count(example_count) {}

  SufficientStats& operator+=(const SufficientStats& rhs) {
    loss += rhs.loss;
    example_count += rhs.example_count;
    return *this;
  }

  friend SufficientStats operator+(SufficientStats lhs, const SufficientStats& rhs) {
    lhs += rhs;
    return lhs;
  }

  bool operator<(const SufficientStats& rhs) {
    return loss < rhs.loss;
  }

  friend std::ostream& operator<< (std::ostream& stream, const SufficientStats& stats) {
    return stream << exp(stats.loss / stats.example_count) << " (" << stats.loss << " over " << stats.example_count << " examples)";
  }
};

class Learner : public ILearner<Datum, SufficientStats> {
public:
  Learner(XorModel* xor_model, Model& dynet_model, const Trainer* const trainer, bool quiet) : xor_model(xor_model), dynet_model(dynet_model), trainer(trainer), quiet(quiet) {}
  ~Learner() {}
  SufficientStats LearnFromDatum(const Datum& datum, bool learn) {
    ComputationGraph cg;
    xor_model->new_graph(cg);
    Expression loss_expr = xor_model->compute_loss(datum);
    dynet::real loss = as_scalar(loss_expr.value());

    if (learn) {
      cg.backward(loss_expr);
    }
    return SufficientStats(loss, 1);
  }

  void SaveModel() {
    if (!quiet) {
      serialize(xor_model, dynet_model, trainer);
    }
  }

private:
  XorModel* xor_model;
  Model& dynet_model;
  const Trainer* const trainer;
  bool quiet;
};

int main(int argc, char** argv) {
  dynet::initialize(argc, argv, true);

  // parameters
  const unsigned num_cores = 4;
  const unsigned ITERATIONS = 1000;
  Model dynet_model;
  XorModel* xor_model = nullptr;
  Trainer* trainer = nullptr;

  if (argc == 2) {
    // Load the model and parameters from file if given.
    deserialize(argv[1], xor_model, dynet_model, trainer);
  }
  else {
    // Otherwise, just create a new model.
    const unsigned HIDDEN_SIZE = 8;
    xor_model = new XorModel(HIDDEN_SIZE, dynet_model);
    trainer = new SimpleSGDTrainer(&dynet_model);
  }

  vector<Datum> data(4);
  data[0] = Datum({0, 0}, 0);
  data[1] = Datum({0, 1}, 1);
  data[2] = Datum({1, 0}, 1);
  data[3] = Datum({1, 1}, 0);

  Learner learner(xor_model, dynet_model, trainer, true);
  if (num_cores == 0) {
    run_single_process<Datum>(&learner, trainer, data, data, ITERATIONS, data.size(), data.size(), data.size());
  }
  else {
    run_multi_process<Datum>(num_cores, &learner, trainer, data, data, ITERATIONS, data.size(), data.size());
  }
}
<commit_msg>allow xor-mp to dump its model to stdout<commit_after>#include "dynet/nodes.h"
#include "dynet/dynet.h"
#include "dynet/training.h"
#include "dynet/gpu-ops.h"
#include "dynet/expr.h"
#include "dynet/mp.h"
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <iostream>
#include <fstream>

using namespace std;
using namespace dynet;
using namespace dynet::expr;
using namespace dynet::mp;

struct Datum {
  Datum() {}
  Datum(const vector<dynet::real>& x, const dynet::real y) : x(x), y(y) {}

  vector<dynet::real> x;
  dynet::real y;
};

class XorModel {
public:
  XorModel(const unsigned hidden_size, Model& dynet_model) : pcg(nullptr) {
    p_W = dynet_model.add_parameters({hidden_size, 2});
    p_b = dynet_model.add_parameters({hidden_size});
    p_V = dynet_model.add_parameters({1, hidden_size});
    p_a = dynet_model.add_parameters({1});
  }

  void new_graph(ComputationGraph& cg) {
    W = parameter(cg, p_W);
    b = parameter(cg, p_b);
    V = parameter(cg, p_V);
    a = parameter(cg, p_a);
    pcg = &cg;
  }

  Expression compute_loss(const Datum& datum) {
    Expression x = input(*pcg, {2}, &datum.x);
    Expression y = input(*pcg, &datum.y);

    Expression h = tanh(W*x + b);
    Expression y_pred = V*h + a;
    Expression loss_expr = squared_distance(y_pred, y);
    return loss_expr;
  }

private:
  XorModel() : pcg(nullptr) {}

  Parameter p_W, p_b, p_V, p_a;
  Expression W, b, V, a;
  ComputationGraph* pcg;

  friend class boost::serialization::access;
  template<class Archive>
  void serialize(Archive& ar, const unsigned int) {
    ar & p_W & p_b & p_V & p_a;
  }
};

void serialize(const XorModel* const xor_model, const Model& dynet_model, const Trainer* const trainer) {
  // Remove existing stdout output
  int r = ftruncate(fileno(stdout), 0);
  if (r != 0) {}

  // Move the cursor to the beginning of the stdout stream
  fseek(stdout, 0, SEEK_SET);

  // Dump the model to stdout
  boost::archive::text_oarchive oa(cout);
  oa & dynet_model;
  oa & xor_model;
  oa & trainer;
}

void deserialize(const string& filename, XorModel* xor_model, Model& dynet_model, Trainer* trainer) {
  ifstream in(filename.c_str());
  boost::archive::text_iarchive ia(in);
  ia & dynet_model;
  ia & xor_model;
  ia & trainer;
  in.close();
}

class SufficientStats {
public:
  dynet::real loss;
  unsigned example_count;

  SufficientStats() : loss(), example_count() {}

  SufficientStats(dynet::real loss, unsigned example_count) : loss(loss), example_count(example_count) {}

  SufficientStats& operator+=(const SufficientStats& rhs) {
    loss += rhs.loss;
    example_count += rhs.example_count;
    return *this;
  }

  friend SufficientStats operator+(SufficientStats lhs, const SufficientStats& rhs) {
    lhs += rhs;
    return lhs;
  }

  bool operator<(const SufficientStats& rhs) {
    return loss < rhs.loss;
  }

  friend std::ostream& operator<< (std::ostream& stream, const SufficientStats& stats) {
    return stream << exp(stats.loss / stats.example_count) << " (" << stats.loss << " over " << stats.example_count << " examples)";
  }
};

class Learner : public ILearner<Datum, SufficientStats> {
public:
  Learner(XorModel* xor_model, Model& dynet_model, const Trainer* const trainer, bool quiet) : xor_model(xor_model), dynet_model(dynet_model), trainer(trainer), quiet(quiet) {}
  ~Learner() {}
  SufficientStats LearnFromDatum(const Datum& datum, bool learn) {
    ComputationGraph cg;
    xor_model->new_graph(cg);
    Expression loss_expr = xor_model->compute_loss(datum);
    dynet::real loss = as_scalar(loss_expr.value());

    if (learn) {
      cg.backward(loss_expr);
    }
    return SufficientStats(loss, 1);
  }

  void SaveModel() {
    if (!quiet) {
      serialize(xor_model, dynet_model, trainer);
    }
  }

private:
  XorModel* xor_model;
  Model& dynet_model;
  const Trainer* const trainer;
  bool quiet;
};

int main(int argc, char** argv) {
  dynet::initialize(argc, argv, true);

  // parameters
  const unsigned num_cores = 4;
  const unsigned ITERATIONS = 1000;
  Model dynet_model;
  XorModel* xor_model = nullptr;
  Trainer* trainer = nullptr;

  if (argc == 2) {
    // Load the model and parameters from file if given.
    deserialize(argv[1], xor_model, dynet_model, trainer);
  }
  else {
    // Otherwise, just create a new model.
    const unsigned HIDDEN_SIZE = 8;
    xor_model = new XorModel(HIDDEN_SIZE, dynet_model);
    trainer = new SimpleSGDTrainer(&dynet_model);
  }

  vector<Datum> data(4);
  data[0] = Datum({0, 0}, 0);
  data[1] = Datum({0, 1}, 1);
  data[2] = Datum({1, 0}, 1);
  data[3] = Datum({1, 1}, 0);

  Learner learner(xor_model, dynet_model, trainer, false);
  if (num_cores == 0) {
    run_single_process<Datum>(&learner, trainer, data, data, ITERATIONS, data.size(), data.size(), data.size());
  }
  else {
    run_multi_process<Datum>(num_cores, &learner, trainer, data, data, ITERATIONS, data.size(), data.size());
  }
}
<|endoftext|>