<commit_before>/*
 * Restructuring Shogun's statistical hypothesis testing framework.
 * Copyright (C) 2016  Soumyajit De
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <utility>
#include <vector>
#include <memory>
#include <type_traits>
#include <shogun/kernel/Kernel.h>
#include <shogun/kernel/CustomKernel.h>
#include <shogun/kernel/CombinedKernel.h>
#include <shogun/features/Features.h>
#include <shogun/statistical_testing/MMD.h>
#include <shogun/statistical_testing/QuadraticTimeMMD.h>
#include <shogun/statistical_testing/BTestMMD.h>
#include <shogun/statistical_testing/LinearTimeMMD.h>
#include <shogun/statistical_testing/internals/NextSamples.h>
#include <shogun/statistical_testing/internals/DataManager.h>
#include <shogun/statistical_testing/internals/KernelManager.h>
#include <shogun/statistical_testing/internals/ComputationManager.h>
#include <shogun/statistical_testing/internals/mmd/BiasedFull.h>
#include <shogun/statistical_testing/internals/mmd/UnbiasedFull.h>
#include <shogun/statistical_testing/internals/mmd/UnbiasedIncomplete.h>
#include <shogun/statistical_testing/internals/mmd/WithinBlockDirect.h>
#include <shogun/statistical_testing/internals/mmd/WithinBlockPermutation.h>

using namespace shogun;
using namespace internal;

struct CMMD::Self
{
	Self(CMMD& cmmd);

	void create_statistic_job();
	void create_variance_job();

	void create_computation_jobs();

	void merge_samples(NextSamples&, std::vector<std::shared_ptr<CFeatures>>&) const;
	void compute_kernel(ComputationManager&, std::vector<std::shared_ptr<CFeatures>>&, CKernel*) const;
	void compute_jobs(ComputationManager&) const;

	std::pair<float64_t, float64_t> compute_statistic_variance();
	SGVector<float64_t> sample_null();

	CMMD& owner;

	bool use_gpu_for_computation;
	index_t num_null_samples;

	EStatisticType statistic_type;
	EVarianceEstimationMethod variance_estimation_method;
	ENullApproximationMethod null_approximation_method;

	std::function<float64_t(SGMatrix<float64_t>)> statistic_job;
	std::function<float64_t(SGMatrix<float64_t>)> permutation_job;
	std::function<float64_t(SGMatrix<float64_t>)> variance_job;
};

CMMD::Self::Self(CMMD& cmmd) : owner(cmmd),
	use_gpu_for_computation(false), num_null_samples(250),
	statistic_type(EStatisticType::UNBIASED_FULL),
	variance_estimation_method(EVarianceEstimationMethod::DIRECT),
	null_approximation_method(ENullApproximationMethod::PERMUTATION),
	statistic_job(nullptr), variance_job(nullptr)
{
}

void CMMD::Self::create_computation_jobs()
{
	create_statistic_job();
	create_variance_job();
}

void CMMD::Self::create_statistic_job()
{
	const DataManager& dm = owner.get_data_manager();
	auto Bx = dm.blocksize_at(0);
	switch (statistic_type)
	{
		case EStatisticType::UNBIASED_FULL:
			statistic_job = mmd::UnbiasedFull(Bx);
			permutation_job = mmd::WithinBlockPermutation<mmd::UnbiasedFull>(Bx);
			break;
		case EStatisticType::UNBIASED_INCOMPLETE:
			statistic_job = mmd::UnbiasedIncomplete(Bx);
			permutation_job = mmd::WithinBlockPermutation<mmd::UnbiasedIncomplete>(Bx);
			break;
		case EStatisticType::BIASED_FULL:
			statistic_job = mmd::BiasedFull(Bx);
			permutation_job = mmd::WithinBlockPermutation<mmd::BiasedFull>(Bx);
			break;
		default : break;
	};
}

void CMMD::Self::create_variance_job()
{
	switch (variance_estimation_method)
	{
		case EVarianceEstimationMethod::DIRECT:
			variance_job = owner.get_direct_estimation_method();
			break;
		case EVarianceEstimationMethod::PERMUTATION:
			variance_job = permutation_job;
			break;
		default : break;
	};
}

#define get_block_p(i) next_burst[0][i]
#define get_block_q(i) next_burst[1][i]
void CMMD::Self::merge_samples(NextSamples& next_burst, std::vector<std::shared_ptr<CFeatures>>& blocks) const
{
	blocks.resize(next_burst.num_blocks());

#pragma omp parallel for
	for (size_t i = 0; i < blocks.size(); ++i)
	{
		auto block_p = get_block_p(i);
		auto block_q = get_block_q(i);

		auto block_p_and_q = block_p->create_merged_copy(block_q.get());
		SG_REF(block_p_and_q);

		block_p = nullptr;
		block_q = nullptr;

		blocks[i] = std::shared_ptr<CFeatures>(block_p_and_q, [](CFeatures* ptr) { SG_UNREF(ptr); });
	}
}
#undef get_block_p
#undef get_block_q

void CMMD::Self::compute_kernel(ComputationManager& cm, std::vector<std::shared_ptr<CFeatures>>& blocks, CKernel* kernel) const
{
	cm.num_data(blocks.size());

#pragma omp parallel for
	for (size_t i = 0; i < blocks.size(); ++i)
	{
		try
		{
			auto kernel_clone = std::unique_ptr<CKernel>(static_cast<CKernel*>(kernel->clone()));
			kernel_clone->init(blocks[i].get(), blocks[i].get());
			cm.data(i) = std::unique_ptr<CCustomKernel>(new CCustomKernel(kernel_clone.get()))->get_kernel_matrix();
			kernel_clone->remove_lhs_and_rhs();
		}
		catch (ShogunException e)
		{
			SG_SERROR("%s, Try using less number of blocks per burst!\n", e.get_exception_string());
		}
	}
}

void CMMD::Self::compute_jobs(ComputationManager& cm) const
{
	if (use_gpu_for_computation)
	{
		cm.use_gpu().compute();
	}
	else
	{
		cm.use_cpu().compute();
	}
}

std::pair<float64_t, float64_t> CMMD::Self::compute_statistic_variance()
{
	const KernelManager& km = owner.get_kernel_manager();
	auto kernel = km.kernel_at(0);
	REQUIRE(kernel != nullptr, "Kernel is not set!\n");

	float64_t statistic = 0;
	float64_t permuted_samples_statistic = 0;
	float64_t variance = 0;
	index_t term_counter = 1;

	DataManager& dm = owner.get_data_manager();
	ComputationManager cm;

	create_computation_jobs();
	cm.enqueue_job(statistic_job);
	cm.enqueue_job(variance_job);

	std::vector<std::shared_ptr<CFeatures>> blocks;

	dm.start();
	auto next_burst = dm.next();

	while (!next_burst.empty())
	{
		merge_samples(next_burst, blocks);
		compute_kernel(cm, blocks, kernel);
		compute_jobs(cm);

		auto mmds = cm.next_result();
		auto vars = cm.next_result();

		for (size_t i = 0; i < mmds.size(); ++i)
		{
			auto delta = mmds[i] - statistic;
			statistic += delta / term_counter;
		}

		if (variance_estimation_method == EVarianceEstimationMethod::DIRECT)
		{
			for (size_t i = 0; i < mmds.size(); ++i)
			{
				auto delta = vars[i] - variance;
				variance += delta / term_counter;
			}
		}
		else
		{
			for (size_t i = 0; i < mmds.size(); ++i)
			{
				auto delta = vars[i] - permuted_samples_statistic;
				permuted_samples_statistic += delta / term_counter;
				variance += delta * (vars[i] - permuted_samples_statistic);
			}
		}

		term_counter++;
		next_burst = dm.next();
	}

	dm.end();
	cm.done();

	// normalize statistic and variance
	statistic = owner.normalize_statistic(statistic);

	if (variance_estimation_method == EVarianceEstimationMethod::PERMUTATION)
	{
		variance = owner.normalize_variance(variance);
	}

	return std::make_pair(statistic, variance);
}

SGVector<float64_t> CMMD::Self::sample_null()
{
	const KernelManager& km = owner.get_kernel_manager();
	auto kernel = km.kernel_at(0);
	REQUIRE(kernel != nullptr, "Kernel is not set!\n");

	SGVector<float64_t> statistic(num_null_samples);
	index_t term_counter = 1;

	std::fill(statistic.vector, statistic.vector + statistic.vlen, 0);

	DataManager& dm = owner.get_data_manager();
	ComputationManager cm;

	create_statistic_job();
	cm.enqueue_job(permutation_job);

	std::vector<std::shared_ptr<CFeatures>> blocks;

	dm.start();
	auto next_burst = dm.next();

	while (!next_burst.empty())
	{
		merge_samples(next_burst, blocks);
		compute_kernel(cm, blocks, kernel);

		for (auto j = 0; j < num_null_samples; ++j)
		{
			compute_jobs(cm);
			auto mmds = cm.next_result();
			for (size_t i = 0; i < mmds.size(); ++i)
			{
				auto delta = mmds[i] - statistic[j];
				statistic[j] += delta / term_counter;
			}
		}

		term_counter++;
		next_burst = dm.next();
	}

	dm.end();
	cm.done();

	// normalize statistic
	std::for_each(statistic.vector, statistic.vector + statistic.vlen, [this](float64_t& value)
	{
		value = owner.normalize_statistic(value);
	});

	return statistic;
}

CMMD::CMMD() : CTwoSampleTest()
{
	self = std::unique_ptr<Self>(new Self(*this));
}

CMMD::~CMMD()
{
}

float64_t CMMD::compute_statistic()
{
	return self->compute_statistic_variance().first;
}

float64_t CMMD::compute_variance()
{
	return self->compute_statistic_variance().second;
}

SGVector<float64_t> CMMD::sample_null()
{
	return self->sample_null();
}

void CMMD::set_num_null_samples(index_t null_samples)
{
	self->num_null_samples = null_samples;
}

const index_t CMMD::get_num_null_samples() const
{
	return self->num_null_samples;
}

void CMMD::use_gpu(bool gpu)
{
	self->use_gpu_for_computation = gpu;
}

void CMMD::set_statistic_type(EStatisticType stype)
{
	self->statistic_type = stype;
}

const EStatisticType CMMD::get_statistic_type() const
{
	return self->statistic_type;
}

void CMMD::set_variance_estimation_method(EVarianceEstimationMethod vmethod)
{
	// TODO overload this
/*	if (std::is_same<Derived, CQuadraticTimeMMD>::value && vmethod == EVarianceEstimationMethod::PERMUTATION)
	{
		std::cerr << "cannot use permutation method for quadratic time MMD" << std::endl;
	}*/
	self->variance_estimation_method = vmethod;
}

const EVarianceEstimationMethod CMMD::get_variance_estimation_method() const
{
	return self->variance_estimation_method;
}

void CMMD::set_null_approximation_method(ENullApproximationMethod nmethod)
{
	// TODO overload this
/*	if (std::is_same<Derived, CQuadraticTimeMMD>::value && nmethod == ENullApproximationMethod::MMD1_GAUSSIAN)
	{
		std::cerr << "cannot use gaussian method for quadratic time MMD" << std::endl;
	}
	else if ((std::is_same<Derived, CBTestMMD>::value || std::is_same<Derived, CLinearTimeMMD>::value) &&
			(nmethod == ENullApproximationMethod::MMD2_SPECTRUM || nmethod == ENullApproximationMethod::MMD2_GAMMA))
	{
		std::cerr << "cannot use spectrum/gamma method for B-test/linear time MMD" << std::endl;
	}*/
	self->null_approximation_method = nmethod;
}

const ENullApproximationMethod CMMD::get_null_approximation_method() const
{
	return self->null_approximation_method;
}

const char* CMMD::get_name() const
{
	return "MMD";
}
<commit_msg>fixed evil running average bug<commit_after>/*
 * Restructuring Shogun's statistical hypothesis testing framework.
 * Copyright (C) 2016  Soumyajit De
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <utility>
#include <vector>
#include <memory>
#include <type_traits>
#include <shogun/kernel/Kernel.h>
#include <shogun/kernel/CustomKernel.h>
#include <shogun/kernel/CombinedKernel.h>
#include <shogun/features/Features.h>
#include <shogun/statistical_testing/MMD.h>
#include <shogun/statistical_testing/QuadraticTimeMMD.h>
#include <shogun/statistical_testing/BTestMMD.h>
#include <shogun/statistical_testing/LinearTimeMMD.h>
#include <shogun/statistical_testing/internals/NextSamples.h>
#include <shogun/statistical_testing/internals/DataManager.h>
#include <shogun/statistical_testing/internals/KernelManager.h>
#include <shogun/statistical_testing/internals/ComputationManager.h>
#include <shogun/statistical_testing/internals/mmd/BiasedFull.h>
#include <shogun/statistical_testing/internals/mmd/UnbiasedFull.h>
#include <shogun/statistical_testing/internals/mmd/UnbiasedIncomplete.h>
#include <shogun/statistical_testing/internals/mmd/WithinBlockDirect.h>
#include <shogun/statistical_testing/internals/mmd/WithinBlockPermutation.h>

using namespace shogun;
using namespace internal;

struct CMMD::Self
{
	Self(CMMD& cmmd);

	void create_statistic_job();
	void create_variance_job();

	void create_computation_jobs();

	void merge_samples(NextSamples&, std::vector<std::shared_ptr<CFeatures>>&) const;
	void compute_kernel(ComputationManager&, std::vector<std::shared_ptr<CFeatures>>&, CKernel*) const;
	void compute_jobs(ComputationManager&) const;

	std::pair<float64_t, float64_t> compute_statistic_variance();
	SGVector<float64_t> sample_null();

	CMMD& owner;

	bool use_gpu_for_computation;
	index_t num_null_samples;

	EStatisticType statistic_type;
	EVarianceEstimationMethod variance_estimation_method;
	ENullApproximationMethod null_approximation_method;

	std::function<float64_t(SGMatrix<float64_t>)> statistic_job;
	std::function<float64_t(SGMatrix<float64_t>)> permutation_job;
	std::function<float64_t(SGMatrix<float64_t>)> variance_job;
};

CMMD::Self::Self(CMMD& cmmd) : owner(cmmd),
	use_gpu_for_computation(false), num_null_samples(250),
	statistic_type(EStatisticType::UNBIASED_FULL),
	variance_estimation_method(EVarianceEstimationMethod::DIRECT),
	null_approximation_method(ENullApproximationMethod::PERMUTATION),
	statistic_job(nullptr), variance_job(nullptr)
{
}

void CMMD::Self::create_computation_jobs()
{
	create_statistic_job();
	create_variance_job();
}

void CMMD::Self::create_statistic_job()
{
	const DataManager& dm = owner.get_data_manager();
	auto Bx = dm.blocksize_at(0);
	switch (statistic_type)
	{
		case EStatisticType::UNBIASED_FULL:
			statistic_job = mmd::UnbiasedFull(Bx);
			permutation_job = mmd::WithinBlockPermutation<mmd::UnbiasedFull>(Bx);
			break;
		case EStatisticType::UNBIASED_INCOMPLETE:
			statistic_job = mmd::UnbiasedIncomplete(Bx);
			permutation_job = mmd::WithinBlockPermutation<mmd::UnbiasedIncomplete>(Bx);
			break;
		case EStatisticType::BIASED_FULL:
			statistic_job = mmd::BiasedFull(Bx);
			permutation_job = mmd::WithinBlockPermutation<mmd::BiasedFull>(Bx);
			break;
		default : break;
	};
}

void CMMD::Self::create_variance_job()
{
	switch (variance_estimation_method)
	{
		case EVarianceEstimationMethod::DIRECT:
			variance_job = owner.get_direct_estimation_method();
			break;
		case EVarianceEstimationMethod::PERMUTATION:
			variance_job = permutation_job;
			break;
		default : break;
	};
}

#define get_block_p(i) next_burst[0][i]
#define get_block_q(i) next_burst[1][i]
void CMMD::Self::merge_samples(NextSamples& next_burst, std::vector<std::shared_ptr<CFeatures>>& blocks) const
{
	blocks.resize(next_burst.num_blocks());

#pragma omp parallel for
	for (size_t i = 0; i < blocks.size(); ++i)
	{
		auto block_p = get_block_p(i);
		auto block_q = get_block_q(i);

		auto block_p_and_q = block_p->create_merged_copy(block_q.get());
		SG_REF(block_p_and_q);

		block_p = nullptr;
		block_q = nullptr;

		blocks[i] = std::shared_ptr<CFeatures>(block_p_and_q, [](CFeatures* ptr) { SG_UNREF(ptr); });
	}
}
#undef get_block_p
#undef get_block_q

void CMMD::Self::compute_kernel(ComputationManager& cm, std::vector<std::shared_ptr<CFeatures>>& blocks, CKernel* kernel) const
{
	cm.num_data(blocks.size());

#pragma omp parallel for
	for (size_t i = 0; i < blocks.size(); ++i)
	{
		try
		{
			auto kernel_clone = std::unique_ptr<CKernel>(static_cast<CKernel*>(kernel->clone()));
			kernel_clone->init(blocks[i].get(), blocks[i].get());
			cm.data(i) = std::unique_ptr<CCustomKernel>(new CCustomKernel(kernel_clone.get()))->get_kernel_matrix();
			kernel_clone->remove_lhs_and_rhs();
		}
		catch (ShogunException e)
		{
			SG_SERROR("%s, Try using less number of blocks per burst!\n", e.get_exception_string());
		}
	}
}

void CMMD::Self::compute_jobs(ComputationManager& cm) const
{
	if (use_gpu_for_computation)
	{
		cm.use_gpu().compute();
	}
	else
	{
		cm.use_cpu().compute();
	}
}

std::pair<float64_t, float64_t> CMMD::Self::compute_statistic_variance()
{
	const KernelManager& km = owner.get_kernel_manager();
	auto kernel = km.kernel_at(0);
	REQUIRE(kernel != nullptr, "Kernel is not set!\n");

	float64_t statistic = 0;
	float64_t permuted_samples_statistic = 0;
	float64_t variance = 0;
	index_t statistic_term_counter = 1;
	index_t variance_term_counter = 1;

	DataManager& dm = owner.get_data_manager();
	ComputationManager cm;

	create_computation_jobs();
	cm.enqueue_job(statistic_job);
	cm.enqueue_job(variance_job);

	std::vector<std::shared_ptr<CFeatures>> blocks;

	dm.start();
	auto next_burst = dm.next();

	while (!next_burst.empty())
	{
		merge_samples(next_burst, blocks);
		compute_kernel(cm, blocks, kernel);
		compute_jobs(cm);

		auto mmds = cm.next_result();
		auto vars = cm.next_result();

		for (size_t i = 0; i < mmds.size(); ++i)
		{
			auto delta = mmds[i] - statistic;
			statistic += delta / statistic_term_counter;
			statistic_term_counter++;
		}

		if (variance_estimation_method == EVarianceEstimationMethod::DIRECT)
		{
			for (size_t i = 0; i < mmds.size(); ++i)
			{
				auto delta = vars[i] - variance;
				variance += delta / variance_term_counter;
				variance_term_counter++;
			}
		}
		else
		{
			for (size_t i = 0; i < vars.size(); ++i)
			{
				auto delta = vars[i] - permuted_samples_statistic;
				permuted_samples_statistic += delta / variance_term_counter;
				variance += delta * (vars[i] - permuted_samples_statistic);
				variance_term_counter++;
			}
		}
		next_burst = dm.next();
	}

	dm.end();
	cm.done();

	// normalize statistic and variance
	statistic = owner.normalize_statistic(statistic);

	if (variance_estimation_method == EVarianceEstimationMethod::PERMUTATION)
	{
		variance = owner.normalize_variance(variance);
	}

	return std::make_pair(statistic, variance);
}

SGVector<float64_t> CMMD::Self::sample_null()
{
	const KernelManager& km = owner.get_kernel_manager();
	auto kernel = km.kernel_at(0);
	REQUIRE(kernel != nullptr, "Kernel is not set!\n");

	SGVector<float64_t> statistic(num_null_samples);
	std::vector<index_t> term_counters(num_null_samples);

	std::fill(statistic.vector, statistic.vector + statistic.vlen, 0);
	std::fill(term_counters.data(), term_counters.data() + term_counters.size(), 1);

	DataManager& dm = owner.get_data_manager();
	ComputationManager cm;

	create_statistic_job();
	cm.enqueue_job(permutation_job);

	std::vector<std::shared_ptr<CFeatures>> blocks;

	dm.start();
	auto next_burst = dm.next();

	while (!next_burst.empty())
	{
		merge_samples(next_burst, blocks);
		compute_kernel(cm, blocks, kernel);

		for (auto j = 0; j < num_null_samples; ++j)
		{
			compute_jobs(cm);
			auto mmds = cm.next_result();
			for (size_t i = 0; i < mmds.size(); ++i)
			{
				auto delta = mmds[i] - statistic[j];
				statistic[j] += delta / term_counters[j];
				term_counters[j]++;
			}
		}
		next_burst = dm.next();
	}

	dm.end();
	cm.done();

	// normalize statistic
	std::for_each(statistic.vector, statistic.vector + statistic.vlen, [this](float64_t& value)
	{
		value = owner.normalize_statistic(value);
	});

	return statistic;
}

CMMD::CMMD() : CTwoSampleTest()
{
	self = std::unique_ptr<Self>(new Self(*this));
}

CMMD::~CMMD()
{
}

float64_t CMMD::compute_statistic()
{
	return self->compute_statistic_variance().first;
}

float64_t CMMD::compute_variance()
{
	return self->compute_statistic_variance().second;
}

SGVector<float64_t> CMMD::sample_null()
{
	return self->sample_null();
}

void CMMD::set_num_null_samples(index_t null_samples)
{
	self->num_null_samples = null_samples;
}

const index_t CMMD::get_num_null_samples() const
{
	return self->num_null_samples;
}

void CMMD::use_gpu(bool gpu)
{
	self->use_gpu_for_computation = gpu;
}

void CMMD::set_statistic_type(EStatisticType stype)
{
	self->statistic_type = stype;
}

const EStatisticType CMMD::get_statistic_type() const
{
	return self->statistic_type;
}

void CMMD::set_variance_estimation_method(EVarianceEstimationMethod vmethod)
{
	// TODO overload this
/*	if (std::is_same<Derived, CQuadraticTimeMMD>::value && vmethod == EVarianceEstimationMethod::PERMUTATION)
	{
		std::cerr << "cannot use permutation method for quadratic time MMD" << std::endl;
	}*/
	self->variance_estimation_method = vmethod;
}

const EVarianceEstimationMethod CMMD::get_variance_estimation_method() const
{
	return self->variance_estimation_method;
}

void CMMD::set_null_approximation_method(ENullApproximationMethod nmethod)
{
	// TODO overload this
/*	if (std::is_same<Derived, CQuadraticTimeMMD>::value && nmethod == ENullApproximationMethod::MMD1_GAUSSIAN)
	{
		std::cerr << "cannot use gaussian method for quadratic time MMD" << std::endl;
	}
	else if ((std::is_same<Derived, CBTestMMD>::value || std::is_same<Derived, CLinearTimeMMD>::value) &&
			(nmethod == ENullApproximationMethod::MMD2_SPECTRUM || nmethod == ENullApproximationMethod::MMD2_GAMMA))
	{
		std::cerr << "cannot use spectrum/gamma method for B-test/linear time MMD" << std::endl;
	}*/
	self->null_approximation_method = nmethod;
}

const ENullApproximationMethod CMMD::get_null_approximation_method() const
{
	return self->null_approximation_method;
}

const char* CMMD::get_name() const
{
	return "MMD";
}
<|endoftext|>


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

#include "base/stl_helpers.hh"
#include "mem/protocol/MachineType.hh"
#include "mem/protocol/Protocol.hh"
#include "mem/protocol/TopologyType.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/network/simple/Switch.hh"
#include "mem/ruby/network/simple/Topology.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/system/System.hh"

using namespace std;
using m5::stl_helpers::deletePointers;

#if 0
// ***BIG HACK*** - This is actually code that _should_ be in Network.cc

// Note: Moved to Princeton Network
// calls new to abstract away from the network
Network*
Network::createNetwork(int nodes)
{
    return new SimpleNetwork(nodes);
}
#endif

SimpleNetwork::SimpleNetwork(const Params *p)
    : Network(p)
{
    // Note: the parent Network Object constructor is called before the
    // SimpleNetwork child constructor.  Therefore, the member variables
    // used below should already be initialized.

    m_endpoint_switches.resize(m_nodes);

    m_in_use.resize(m_virtual_networks);
    m_ordered.resize(m_virtual_networks);
    for (int i = 0; i < m_virtual_networks; i++) {
        m_in_use[i] = false;
        m_ordered[i] = false;
    }

    // Allocate to and from queues
    m_toNetQueues.resize(m_nodes);
    m_fromNetQueues.resize(m_nodes);
    for (int node = 0; node < m_nodes; node++) {
        m_toNetQueues[node].resize(m_virtual_networks);
        m_fromNetQueues[node].resize(m_virtual_networks);
        for (int j = 0; j < m_virtual_networks; j++) {
            m_toNetQueues[node][j] =
                new MessageBuffer(csprintf("toNet node %d j %d", node, j));
            m_fromNetQueues[node][j] =
                new MessageBuffer(csprintf("fromNet node %d j %d", node, j));
        }
    }
}

void
SimpleNetwork::init()
{
    Network::init();

    // The topology pointer should have already been initialized in
    // the parent class network constructor.
    assert(m_topology_ptr != NULL);
    int number_of_switches = m_topology_ptr->numSwitches();
    for (int i = 0; i < number_of_switches; i++) {
        m_switch_ptr_vector.push_back(new Switch(i, this));
    }

    // false because this isn't a reconfiguration
    m_topology_ptr->createLinks(this, false);
}

void
SimpleNetwork::reset()
{
    for (int node = 0; node < m_nodes; node++) {
        for (int j = 0; j < m_virtual_networks; j++) {
            m_toNetQueues[node][j]->clear();
            m_fromNetQueues[node][j]->clear();
        }
    }

    for(int i = 0; i < m_switch_ptr_vector.size(); i++){
        m_switch_ptr_vector[i]->clearBuffers();
    }
}

SimpleNetwork::~SimpleNetwork()
{
    for (int i = 0; i < m_nodes; i++) {
        deletePointers(m_toNetQueues[i]);
        deletePointers(m_fromNetQueues[i]);
    }
    deletePointers(m_switch_ptr_vector);
    deletePointers(m_buffers_to_free);
    // delete m_topology_ptr;
}

// From a switch to an endpoint node
void
SimpleNetwork::makeOutLink(SwitchID src, NodeID dest,
    const NetDest& routing_table_entry, int link_latency, int link_weight,
    int bw_multiplier, bool isReconfiguration)
{
    assert(dest < m_nodes);
    assert(src < m_switch_ptr_vector.size());
    assert(m_switch_ptr_vector[src] != NULL);

    if (isReconfiguration) {
        m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
        return;
    }

    m_switch_ptr_vector[src]->addOutPort(m_fromNetQueues[dest],
        routing_table_entry, link_latency, bw_multiplier);
    m_endpoint_switches[dest] = m_switch_ptr_vector[src];
}

// From an endpoint node to a switch
void
SimpleNetwork::makeInLink(NodeID src, SwitchID dest,
    const NetDest& routing_table_entry, int link_latency, int bw_multiplier,
    bool isReconfiguration)
{
    assert(src < m_nodes);
    if (isReconfiguration) {
        // do nothing
        return;
    }

    m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
}

// From a switch to a switch
void
SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest,
    const NetDest& routing_table_entry, int link_latency, int link_weight,
    int bw_multiplier, bool isReconfiguration)
{
    if (isReconfiguration) {
        m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
        return;
    }

    // Create a set of new MessageBuffers
    std::vector<MessageBuffer*> queues;
    for (int i = 0; i < m_virtual_networks; i++) {
        // allocate a buffer
        MessageBuffer* buffer_ptr = new MessageBuffer;
        buffer_ptr->setOrdering(true);
        if (m_buffer_size > 0) {
            buffer_ptr->resize(m_buffer_size);
        }
        queues.push_back(buffer_ptr);
        // remember to deallocate it
        m_buffers_to_free.push_back(buffer_ptr);
    }
    // Connect it to the two switches
    m_switch_ptr_vector[dest]->addInPort(queues);
    m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry,
        link_latency, bw_multiplier);
}

void
SimpleNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_num)
{
    ASSERT(id < m_nodes);
    ASSERT(network_num < m_virtual_networks);

    if (ordered) {
        m_ordered[network_num] = true;
    }
    m_in_use[network_num] = true;
}

MessageBuffer*
SimpleNetwork::getToNetQueue(NodeID id, bool ordered, int network_num)
{
    checkNetworkAllocation(id, ordered, network_num);
    return m_toNetQueues[id][network_num];
}

MessageBuffer*
SimpleNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num)
{
    checkNetworkAllocation(id, ordered, network_num);
    return m_fromNetQueues[id][network_num];
}

const std::vector<Throttle*>*
SimpleNetwork::getThrottles(NodeID id) const
{
    assert(id >= 0);
    assert(id < m_nodes);
    assert(m_endpoint_switches[id] != NULL);
    return m_endpoint_switches[id]->getThrottles();
}

void
SimpleNetwork::printStats(ostream& out) const
{
    out << endl;
    out << "Network Stats" << endl;
    out << "-------------" << endl;
    out << endl;
    for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
        m_switch_ptr_vector[i]->printStats(out);
    }
    m_topology_ptr->printStats(out);
}

void
SimpleNetwork::clearStats()
{
    for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
        m_switch_ptr_vector[i]->clearStats();
    }
    m_topology_ptr->clearStats();
}

void
SimpleNetwork::printConfig(ostream& out) const
{
    out << endl;
    out << "Network Configuration" << endl;
    out << "---------------------" << endl;
    out << "network: SIMPLE_NETWORK" << endl;
    out << "topology: " << m_topology_ptr->getName() << endl;
    out << endl;

    for (int i = 0; i < m_virtual_networks; i++) {
        out << "virtual_net_" << i << ": ";
        if (m_in_use[i]) {
            out << "active, ";
            if (m_ordered[i]) {
                out << "ordered" << endl;
            } else {
                out << "unordered" << endl;
            }
        } else {
            out << "inactive" << endl;
        }
    }
    out << endl;

    for(int i = 0; i < m_switch_ptr_vector.size(); i++) {
        m_switch_ptr_vector[i]->printConfig(out);
    }

    m_topology_ptr->printConfig(out);
}

void
SimpleNetwork::print(ostream& out) const
{
    out << "[SimpleNetwork]";
}

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

#include <numeric>

#include "base/stl_helpers.hh"
#include "mem/protocol/MachineType.hh"
#include "mem/protocol/Protocol.hh"
#include "mem/protocol/TopologyType.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/simple/SimpleNetwork.hh"
#include "mem/ruby/network/simple/Switch.hh"
#include "mem/ruby/network/simple/Throttle.hh"
#include "mem/ruby/network/simple/Topology.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/system/System.hh"

using namespace std;
using m5::stl_helpers::deletePointers;

#if 0
// ***BIG HACK*** - This is actually code that _should_ be in Network.cc

// Note: Moved to Princeton Network
// calls new to abstract away from the network
Network*
Network::createNetwork(int nodes)
{
    return new SimpleNetwork(nodes);
}
#endif

SimpleNetwork::SimpleNetwork(const Params *p)
    : Network(p)
{
    // Note: the parent Network Object constructor is called before the
    // SimpleNetwork child constructor.  Therefore, the member variables
    // used below should already be initialized.

    m_endpoint_switches.resize(m_nodes);

    m_in_use.resize(m_virtual_networks);
    m_ordered.resize(m_virtual_networks);
    for (int i = 0; i < m_virtual_networks; i++) {
        m_in_use[i] = false;
        m_ordered[i] = false;
    }

    // Allocate to and from queues
    m_toNetQueues.resize(m_nodes);
    m_fromNetQueues.resize(m_nodes);
    for (int node = 0; node < m_nodes; node++) {
        m_toNetQueues[node].resize(m_virtual_networks);
        m_fromNetQueues[node].resize(m_virtual_networks);
        for (int j = 0; j < m_virtual_networks; j++) {
            m_toNetQueues[node][j] =
                new MessageBuffer(csprintf("toNet node %d j %d", node, j));
            m_fromNetQueues[node][j] =
                new MessageBuffer(csprintf("fromNet node %d j %d", node, j));
        }
    }
}

void
SimpleNetwork::init()
{
    Network::init();

    // The topology pointer should have already been initialized in
    // the parent class network constructor.
    assert(m_topology_ptr != NULL);
    int number_of_switches = m_topology_ptr->numSwitches();
    for (int i = 0; i < number_of_switches; i++) {
        m_switch_ptr_vector.push_back(new Switch(i, this));
    }

    // false because this isn't a reconfiguration
    m_topology_ptr->createLinks(this, false);
}

void
SimpleNetwork::reset()
{
    for (int node = 0; node < m_nodes; node++) {
        for (int j = 0; j < m_virtual_networks; j++) {
            m_toNetQueues[node][j]->clear();
            m_fromNetQueues[node][j]->clear();
        }
    }

    for(int i = 0; i < m_switch_ptr_vector.size(); i++){
        m_switch_ptr_vector[i]->clearBuffers();
    }
}

SimpleNetwork::~SimpleNetwork()
{
    for (int i = 0; i < m_nodes; i++) {
        deletePointers(m_toNetQueues[i]);
        deletePointers(m_fromNetQueues[i]);
    }
    deletePointers(m_switch_ptr_vector);
    deletePointers(m_buffers_to_free);
    // delete m_topology_ptr;
}

// From a switch to an endpoint node
void
SimpleNetwork::makeOutLink(SwitchID src, NodeID dest,
    const NetDest& routing_table_entry, int link_latency, int link_weight,
    int bw_multiplier, bool isReconfiguration)
{
    assert(dest < m_nodes);
    assert(src < m_switch_ptr_vector.size());
    assert(m_switch_ptr_vector[src] != NULL);

    if (isReconfiguration) {
        m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
        return;
    }

    m_switch_ptr_vector[src]->addOutPort(m_fromNetQueues[dest],
        routing_table_entry, link_latency, bw_multiplier);
    m_endpoint_switches[dest] = m_switch_ptr_vector[src];
}

// From an endpoint node to a switch
void
SimpleNetwork::makeInLink(NodeID src, SwitchID dest,
    const NetDest& routing_table_entry, int link_latency, int bw_multiplier,
    bool isReconfiguration)
{
    assert(src < m_nodes);
    if (isReconfiguration) {
        // do nothing
        return;
    }

    m_switch_ptr_vector[dest]->addInPort(m_toNetQueues[src]);
}

// From a switch to a switch
void
SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest,
    const NetDest& routing_table_entry, int link_latency, int link_weight,
    int bw_multiplier, bool isReconfiguration)
{
    if (isReconfiguration) {
        m_switch_ptr_vector[src]->reconfigureOutPort(routing_table_entry);
        return;
    }

    // Create a set of new MessageBuffers
    std::vector<MessageBuffer*> queues;
    for (int i = 0; i < m_virtual_networks; i++) {
        // allocate a buffer
        MessageBuffer* buffer_ptr = new MessageBuffer;
        buffer_ptr->setOrdering(true);
        if (m_buffer_size > 0) {
            buffer_ptr->resize(m_buffer_size);
        }
        queues.push_back(buffer_ptr);
        // remember to deallocate it
        m_buffers_to_free.push_back(buffer_ptr);
    }
    // Connect it to the two switches
    m_switch_ptr_vector[dest]->addInPort(queues);
    m_switch_ptr_vector[src]->addOutPort(queues, routing_table_entry,
        link_latency, bw_multiplier);
}

void
SimpleNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_num)
{
    ASSERT(id < m_nodes);
    ASSERT(network_num < m_virtual_networks);

    if (ordered) {
        m_ordered[network_num] = true;
    }
    m_in_use[network_num] = true;
}

MessageBuffer*
SimpleNetwork::getToNetQueue(NodeID id, bool ordered, int network_num)
{
    checkNetworkAllocation(id, ordered, network_num);
    return m_toNetQueues[id][network_num];
}

MessageBuffer*
SimpleNetwork::getFromNetQueue(NodeID id, bool ordered, int network_num)
{
    checkNetworkAllocation(id, ordered, network_num);
    return m_fromNetQueues[id][network_num];
}

const std::vector<Throttle*>*
SimpleNetwork::getThrottles(NodeID id) const
{
    assert(id >= 0);
    assert(id < m_nodes);
    assert(m_endpoint_switches[id] != NULL);
    return m_endpoint_switches[id]->getThrottles();
}

void
SimpleNetwork::printStats(ostream& out) const
{
    out << endl;
    out << "Network Stats" << endl;
    out << "-------------" << endl;
    out << endl;

    //
    // Determine total counts before printing out each switch's stats
    //
    std::vector<uint64> total_msg_counts;
    total_msg_counts.resize(MessageSizeType_NUM);
    for (MessageSizeType type = MessageSizeType_FIRST;
         type < MessageSizeType_NUM;
         ++type) {
        total_msg_counts[type] = 0;
    }

    for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
        const std::vector<Throttle*>* throttles =
            m_switch_ptr_vector[i]->getThrottles();

        for (int p = 0; p < throttles->size(); p++) {

            const std::vector<std::vector<int> >& message_counts =
                ((*throttles)[p])->getCounters();

            for (MessageSizeType type = MessageSizeType_FIRST;
                 type < MessageSizeType_NUM;
                 ++type) {

                const std::vector<int> &mct = message_counts[type];
                int sum = accumulate(mct.begin(), mct.end(), 0);
                total_msg_counts[type] += uint64(sum);
            }
        }
    }
    uint64 total_msgs = 0;
    uint64 total_bytes = 0;
    for (MessageSizeType type = MessageSizeType_FIRST;
         type < MessageSizeType_NUM;
         ++type) {

        if (total_msg_counts[type] > 0) {
            out << "total_msg_count_" << type << ": " << total_msg_counts[type]
                << " " << total_msg_counts[type] *
                uint64(RubySystem::getNetwork()->MessageSizeType_to_int(type))
                << endl;

            total_msgs += total_msg_counts[type];

            total_bytes += total_msg_counts[type] *
                uint64(RubySystem::getNetwork()->MessageSizeType_to_int(type));

        }
    }

    out << "total_msgs: " << total_msgs
        << " total_bytes: " << total_bytes << endl;

    out << endl;
    for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
        m_switch_ptr_vector[i]->printStats(out);
    }
    m_topology_ptr->printStats(out);
}

void
SimpleNetwork::clearStats()
{
    for (int i = 0; i < m_switch_ptr_vector.size(); i++) {
        m_switch_ptr_vector[i]->clearStats();
    }
    m_topology_ptr->clearStats();
}

void
SimpleNetwork::printConfig(ostream& out) const
{
    out << endl;
    out << "Network Configuration" << endl;
    out << "---------------------" << endl;
    out << "network: SIMPLE_NETWORK" << endl;
    out << "topology: " << m_topology_ptr->getName() << endl;
    out << endl;

    for (int i = 0; i < m_virtual_networks; i++) {
        out << "virtual_net_" << i << ": ";
        if (m_in_use[i]) {
            out << "active, ";
            if (m_ordered[i]) {
                out << "ordered" << endl;
            } else {
                out << "unordered" << endl;
            }
        } else {
            out << "inactive" << endl;
        }
    }
    out << endl;

    for(int i = 0; i < m_switch_ptr_vector.size(); i++) {
        m_switch_ptr_vector[i]->printConfig(out);
    }

    m_topology_ptr->printConfig(out);
}

void
SimpleNetwork::print(ostream& out) const
{
    out << "[SimpleNetwork]";
}

SimpleNetwork *
SimpleNetworkParams::create()
{
    return new SimpleNetwork(this);
}
<|endoftext|>


<commit_before>//
//  riscv-disasm.cc
//

#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <cassert>
#include <map>
#include <algorithm>
#include <functional>
#include <vector>
#include <deque>
#include <string>

#include "riscv-types.h"
#include "riscv-endian.h"
#include "riscv-format.h"
#include "riscv-meta.h"
#include "riscv-codec.h"
#include "riscv-format.h"
#include "riscv-strings.h"
#include "riscv-util.h"
#include "riscv-disasm.h"

using namespace riscv;

const char* riscv::null_symbol_lookup(uintptr_t, bool nearest) { return nullptr; }
const char* riscv::null_symbol_colorize(const char *type) { return ""; }

static const void print_add(size_t &offset, const char *str)
{
	printf("%s", str);
	offset += strlen(str);
}

static const void print_pad(size_t &offset, size_t pad_to)
{
	static const char *space32 = "                                        ";
	if (pad_to < offset) pad_to = offset;
	size_t x = std::min(strlen(space32), std::max((pad_to - offset), 0UL));
	printf("%s", space32 + strlen(space32) - x);
	offset += x;
}

static const void print_fmt(size_t &offset, const char* fmt, ...)
{
    std::vector<char> buf(32);
    va_list ap;

    va_start(ap, fmt);
    int len = vsnprintf(buf.data(), buf.capacity(), fmt, ap);
    va_end(ap);

    std::string str;
    if (len >= (int)buf.capacity()) {
        buf.resize(len + 1);
        va_start(ap, fmt);
        vsnprintf(buf.data(), buf.capacity(), fmt, ap);
        va_end(ap);
    }
    printf("%s", buf.data());
    offset += strlen(buf.data());
}

static const void print_pad(size_t &offset, size_t pad_to, const char *str)
{
	print_add(offset, str);
	print_pad(offset, pad_to);
}

static const void print_addr(size_t &offset, uint64_t addr,
	riscv::symbol_name_fn symlookup, riscv::symbol_colorize_fn colorize)
{
	print_pad(offset, 80);
	printf("%s", colorize("address"));
	print_add(offset, "# ");
	print_fmt(offset, "0x%016tx", addr);
	printf("%s", colorize("reset"));
	const char* symbol_name = symlookup((uintptr_t)addr, true);
	if (symbol_name) {
		printf(" %s", colorize("label"));
		print_fmt(offset, "%s", symbol_name);
		printf("%s", colorize("reset"));
	}
}

void riscv::disasm_inst_print(disasm &dec, std::deque<disasm> &dec_hist,
	uintptr_t pc, uintptr_t pc_offset, uintptr_t gp,
	riscv::symbol_name_fn symlookup, riscv::symbol_colorize_fn colorize)
{
	size_t offset = 0;
	uint64_t addr = pc - pc_offset;
	const char *fmt = riscv_inst_format[dec.op];
	const char *symbol_name = symlookup((uintptr_t)addr, false);
	const char* csr_name = nullptr;

	// print symbol name if present
	if (symbol_name) {
		printf("\n%s", colorize("address"));
		print_fmt(offset, "0x%016tx: ", addr);
		printf("%s", colorize("reset"));
		printf("%s", colorize("label"));
		print_fmt(offset, "%s", symbol_name);
		printf("%s\n", colorize("reset"));
		offset = 0;
	}
	print_pad(offset, 12);

	// print address
	printf("%s", colorize("address"));
	print_fmt(offset, "%8tx:", addr & 0xffffffff);
	printf("%s", colorize("reset"));
	print_pad(offset, 24);

	// print instruction bytes
	switch (inst_length(dec.inst)) {
		case 2: print_fmt(offset, "%04llx", dec.inst); break;
		case 4: print_fmt(offset, "%08llx", dec.inst); break;
		case 6: print_fmt(offset, "%012llx", dec.inst); break;
		case 8: print_fmt(offset, "%016llx", dec.inst); break;
	}
	print_pad(offset, 45);

	// print arguments
	while (*fmt) {
		switch (*fmt) {
			case '(': print_add(offset, "("); break;
			case ',': print_add(offset, ", "); break;
			case ')': print_add(offset, ")"); break;
			case '0': print_add(offset, riscv_ireg_name_sym[dec.rd]); break;
			case '1': print_add(offset, riscv_ireg_name_sym[dec.rs1]); break;
			case '2': print_add(offset, riscv_ireg_name_sym[dec.rs2]); break;
			case '3': print_add(offset, riscv_freg_name_sym[dec.rd]); break;
			case '4': print_add(offset, riscv_freg_name_sym[dec.rs1]); break;
			case '5': print_add(offset, riscv_freg_name_sym[dec.rs2]); break;
			case '6': print_add(offset, riscv_freg_name_sym[dec.rs3]); break;
			case '7': print_fmt(offset, "%d", dec.rs1); break;
			case 'i': print_fmt(offset, "%lld", dec.imm); break;
			case 'o':
				print_fmt(offset, "pc %c %td",
					intptr_t(dec.imm) < 0 ? '-' : '+',
					intptr_t(dec.imm) < 0 ? -intptr_t(dec.imm) : intptr_t(dec.imm));
				break;
			case 'c':
				csr_name = riscv_csr_name_sym[dec.imm & 0xfff];
				if (csr_name) print_fmt(offset, "%s", csr_name);
				else print_fmt(offset, "0x%03x", dec.imm & 0xfff);
				break;
			case 'r':
				switch(dec.rm) {
					case riscv_rm_rne: print_add(offset, "rne"); break;
					case riscv_rm_rtz: print_add(offset, "rtz"); break;
					case riscv_rm_rdn: print_add(offset, "rdn"); break;
					case riscv_rm_rup: print_add(offset, "rup"); break;
					case riscv_rm_rmm: print_add(offset, "rmm"); break;
					default:           print_add(offset, "unk"); break;
				}
				break;
			case 'p':
				if (dec.pred & riscv_fence_i) print_add(offset, "i");
				if (dec.pred & riscv_fence_o) print_add(offset, "o");
				if (dec.pred & riscv_fence_r) print_add(offset, "r");
				if (dec.pred & riscv_fence_w) print_add(offset, "w");
				break;
			case 's':
				if (dec.succ & riscv_fence_i) print_add(offset, "i");
				if (dec.succ & riscv_fence_o) print_add(offset, "o");
				if (dec.succ & riscv_fence_r) print_add(offset, "r");
				if (dec.succ & riscv_fence_w) print_add(offset, "w");
				break;
			case 'O':
				printf("%s", colorize("opcode"));
				print_add(offset, riscv_inst_name_sym[dec.op]);
 				break;
			case '\t':
				print_pad(offset, 60, "");
				printf("%s", colorize("reset"));
 				break;
			case 'A':
				if (dec.aq) print_add(offset, ".aq"); break;
			case 'R':
				if (dec.rl) print_add(offset, ".rl"); break;
 				break;
			default:
				break;
		}
		fmt++;
	}

	// decode address
	addr = 0;
	bool decoded_address = false;
	if (!decoded_address) decoded_address = decode_pcrel(dec, addr, pc, pc_offset);
	if (!decoded_address) decoded_address = decode_pairs(dec, addr, dec_hist, pc_offset);
	if (!decoded_address) decoded_address = deocde_gprel(dec, addr, gp);

	// print address if present
	if (decoded_address) print_addr(offset, addr, symlookup, colorize);
	printf("\n");

	// clear the instruction history on jump boundaries
	switch(dec.op) {
		case riscv_op_jal:
		case riscv_op_jalr:
			dec_hist.clear();
			break;
		default:
			break;
	}

	// save instruction in deque
	dec_hist.push_back(dec);
	if (dec_hist.size() > rvx_instruction_buffer_len) {
		dec_hist.pop_front();
	}
}
<commit_msg>Fix indentation and remove redundant break statement<commit_after>//
//  riscv-disasm.cc
//

#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <cassert>
#include <map>
#include <algorithm>
#include <functional>
#include <vector>
#include <deque>
#include <string>

#include "riscv-types.h"
#include "riscv-endian.h"
#include "riscv-format.h"
#include "riscv-meta.h"
#include "riscv-codec.h"
#include "riscv-format.h"
#include "riscv-strings.h"
#include "riscv-util.h"
#include "riscv-disasm.h"

using namespace riscv;

const char* riscv::null_symbol_lookup(uintptr_t, bool nearest) { return nullptr; }
const char* riscv::null_symbol_colorize(const char *type) { return ""; }

static const void print_add(size_t &offset, const char *str)
{
	printf("%s", str);
	offset += strlen(str);
}

static const void print_pad(size_t &offset, size_t pad_to)
{
	static const char *space32 = "                                        ";
	if (pad_to < offset) pad_to = offset;
	size_t x = std::min(strlen(space32), std::max((pad_to - offset), 0UL));
	printf("%s", space32 + strlen(space32) - x);
	offset += x;
}

static const void print_fmt(size_t &offset, const char* fmt, ...)
{
    std::vector<char> buf(32);
    va_list ap;

    va_start(ap, fmt);
    int len = vsnprintf(buf.data(), buf.capacity(), fmt, ap);
    va_end(ap);

    std::string str;
    if (len >= (int)buf.capacity()) {
        buf.resize(len + 1);
        va_start(ap, fmt);
        vsnprintf(buf.data(), buf.capacity(), fmt, ap);
        va_end(ap);
    }
    printf("%s", buf.data());
    offset += strlen(buf.data());
}

static const void print_pad(size_t &offset, size_t pad_to, const char *str)
{
	print_add(offset, str);
	print_pad(offset, pad_to);
}

static const void print_addr(size_t &offset, uint64_t addr,
	riscv::symbol_name_fn symlookup, riscv::symbol_colorize_fn colorize)
{
	print_pad(offset, 80);
	printf("%s", colorize("address"));
	print_add(offset, "# ");
	print_fmt(offset, "0x%016tx", addr);
	printf("%s", colorize("reset"));
	const char* symbol_name = symlookup((uintptr_t)addr, true);
	if (symbol_name) {
		printf(" %s", colorize("label"));
		print_fmt(offset, "%s", symbol_name);
		printf("%s", colorize("reset"));
	}
}

void riscv::disasm_inst_print(disasm &dec, std::deque<disasm> &dec_hist,
	uintptr_t pc, uintptr_t pc_offset, uintptr_t gp,
	riscv::symbol_name_fn symlookup, riscv::symbol_colorize_fn colorize)
{
	size_t offset = 0;
	uint64_t addr = pc - pc_offset;
	const char *fmt = riscv_inst_format[dec.op];
	const char *symbol_name = symlookup((uintptr_t)addr, false);
	const char* csr_name = nullptr;

	// print symbol name if present
	if (symbol_name) {
		printf("\n%s", colorize("address"));
		print_fmt(offset, "0x%016tx: ", addr);
		printf("%s", colorize("reset"));
		printf("%s", colorize("label"));
		print_fmt(offset, "%s", symbol_name);
		printf("%s\n", colorize("reset"));
		offset = 0;
	}
	print_pad(offset, 12);

	// print address
	printf("%s", colorize("address"));
	print_fmt(offset, "%8tx:", addr & 0xffffffff);
	printf("%s", colorize("reset"));
	print_pad(offset, 24);

	// print instruction bytes
	switch (inst_length(dec.inst)) {
		case 2: print_fmt(offset, "%04llx", dec.inst); break;
		case 4: print_fmt(offset, "%08llx", dec.inst); break;
		case 6: print_fmt(offset, "%012llx", dec.inst); break;
		case 8: print_fmt(offset, "%016llx", dec.inst); break;
	}
	print_pad(offset, 45);

	// print arguments
	while (*fmt) {
		switch (*fmt) {
			case '(': print_add(offset, "("); break;
			case ',': print_add(offset, ", "); break;
			case ')': print_add(offset, ")"); break;
			case '0': print_add(offset, riscv_ireg_name_sym[dec.rd]); break;
			case '1': print_add(offset, riscv_ireg_name_sym[dec.rs1]); break;
			case '2': print_add(offset, riscv_ireg_name_sym[dec.rs2]); break;
			case '3': print_add(offset, riscv_freg_name_sym[dec.rd]); break;
			case '4': print_add(offset, riscv_freg_name_sym[dec.rs1]); break;
			case '5': print_add(offset, riscv_freg_name_sym[dec.rs2]); break;
			case '6': print_add(offset, riscv_freg_name_sym[dec.rs3]); break;
			case '7': print_fmt(offset, "%d", dec.rs1); break;
			case 'i': print_fmt(offset, "%lld", dec.imm); break;
			case 'o':
				print_fmt(offset, "pc %c %td",
					intptr_t(dec.imm) < 0 ? '-' : '+',
					intptr_t(dec.imm) < 0 ? -intptr_t(dec.imm) : intptr_t(dec.imm));
				break;
			case 'c':
				csr_name = riscv_csr_name_sym[dec.imm & 0xfff];
				if (csr_name) print_fmt(offset, "%s", csr_name);
				else print_fmt(offset, "0x%03x", dec.imm & 0xfff);
				break;
			case 'r':
				switch(dec.rm) {
					case riscv_rm_rne: print_add(offset, "rne"); break;
					case riscv_rm_rtz: print_add(offset, "rtz"); break;
					case riscv_rm_rdn: print_add(offset, "rdn"); break;
					case riscv_rm_rup: print_add(offset, "rup"); break;
					case riscv_rm_rmm: print_add(offset, "rmm"); break;
					default:           print_add(offset, "unk"); break;
				}
				break;
			case 'p':
				if (dec.pred & riscv_fence_i) print_add(offset, "i");
				if (dec.pred & riscv_fence_o) print_add(offset, "o");
				if (dec.pred & riscv_fence_r) print_add(offset, "r");
				if (dec.pred & riscv_fence_w) print_add(offset, "w");
				break;
			case 's':
				if (dec.succ & riscv_fence_i) print_add(offset, "i");
				if (dec.succ & riscv_fence_o) print_add(offset, "o");
				if (dec.succ & riscv_fence_r) print_add(offset, "r");
				if (dec.succ & riscv_fence_w) print_add(offset, "w");
				break;
			case 'O':
				printf("%s", colorize("opcode"));
				print_add(offset, riscv_inst_name_sym[dec.op]);
 				break;
			case '\t':
				print_pad(offset, 60, "");
				printf("%s", colorize("reset"));
 				break;
			case 'A':
				if (dec.aq) print_add(offset, ".aq");
				break;
			case 'R':
				if (dec.rl) print_add(offset, ".rl");
				break;
			default:
				break;
		}
		fmt++;
	}

	// decode address
	addr = 0;
	bool decoded_address = false;
	if (!decoded_address) decoded_address = decode_pcrel(dec, addr, pc, pc_offset);
	if (!decoded_address) decoded_address = decode_pairs(dec, addr, dec_hist, pc_offset);
	if (!decoded_address) decoded_address = deocde_gprel(dec, addr, gp);

	// print address if present
	if (decoded_address) print_addr(offset, addr, symlookup, colorize);
	printf("\n");

	// clear the instruction history on jump boundaries
	switch(dec.op) {
		case riscv_op_jal:
		case riscv_op_jalr:
			dec_hist.clear();
			break;
		default:
			break;
	}

	// save instruction in deque
	dec_hist.push_back(dec);
	if (dec_hist.size() > rvx_instruction_buffer_len) {
		dec_hist.pop_front();
	}
}
<|endoftext|>


<commit_before>/**
 * @file softmax_regression_test.cpp
 * @author Siddharth Agrawal
 *
 * Test the SoftmaxRegression class.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/softmax_regression/softmax_regression.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::regression;
using namespace mlpack::distribution;

BOOST_AUTO_TEST_SUITE(SoftmaxRegressionTest);

BOOST_AUTO_TEST_CASE(SoftmaxRegressionFunctionEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t inputSize = 10;
  const size_t numClasses = 5;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(inputSize, points);

  // Create random class labels.
  arma::vec labels(points);
  for(size_t i = 0; i < points; i++)
    labels(i) = math::RandInt(0, numClasses);

  // Create a SoftmaxRegressionFunction. Regularization term ignored.
  SoftmaxRegressionFunction srf(data, labels, inputSize, numClasses, 0);

  // Run a number of trials.
  for(size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(numClasses, inputSize);

    double logLikelihood = 0;

    // Compute error for each training example.
    for(size_t j = 0; j < points; j++)
    {
      arma::mat hypothesis, probabilities;

      hypothesis = arma::exp(parameters * data.col(j));
      probabilities = hypothesis / arma::accu(hypothesis);

      logLikelihood += log(probabilities(labels(j), 0));
    }
    logLikelihood /= points;

    // Compare with the value returned by the function.
    BOOST_REQUIRE_CLOSE(srf.Evaluate(parameters), -logLikelihood, 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionFunctionRegularizationEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t inputSize = 10;
  const size_t numClasses = 5;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(inputSize, points);

  // Create random class labels.
  arma::vec labels(points);
  for(size_t i = 0; i < points; i++)
    labels(i) = math::RandInt(0, numClasses);

  // 3 objects for comparing regularization costs.
  SoftmaxRegressionFunction srfNoReg(data, labels, inputSize, numClasses, 0);
  SoftmaxRegressionFunction srfSmallReg(data, labels, inputSize, numClasses, 1);
  SoftmaxRegressionFunction srfBigReg(data, labels, inputSize, numClasses, 20);

  // Run a number of trials.
  for (size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(numClasses, inputSize);

    double wL2SquaredNorm;
    wL2SquaredNorm = arma::accu(parameters % parameters);

    // Calculate regularization terms.
    const double smallRegTerm = 0.5 * wL2SquaredNorm;
    const double bigRegTerm = 10 * wL2SquaredNorm;

    BOOST_REQUIRE_CLOSE(srfNoReg.Evaluate(parameters) + smallRegTerm,
        srfSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(srfNoReg.Evaluate(parameters) + bigRegTerm,
        srfBigReg.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionFunctionGradient)
{
  const size_t points = 1000;
  const size_t inputSize = 10;
  const size_t numClasses = 5;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(inputSize, points);

  // Create random class labels.
  arma::vec labels(points);
  for(size_t i = 0; i < points; i++)
    labels(i) = math::RandInt(0, numClasses);

  // 2 objects for 2 terms in the cost function. Each term contributes towards
  // the gradient and thus need to be checked independently.
  SoftmaxRegressionFunction srf1(data, labels, inputSize, numClasses, 0);
  SoftmaxRegressionFunction srf2(data, labels, inputSize, numClasses, 20);

  // Create a random set of parameters.
  arma::mat parameters;
  parameters.randu(numClasses, inputSize);

  // Get gradients for the current parameters.
  arma::mat gradient1, gradient2;
  srf1.Gradient(parameters, gradient1);
  srf2.Gradient(parameters, gradient2);

  // Perturbation constant.
  const double epsilon = 0.0001;
  double costPlus1, costMinus1, numGradient1;
  double costPlus2, costMinus2, numGradient2;

  // For each parameter.
  for (size_t i = 0; i < numClasses; i++)
  {
    for (size_t j = 0; j < inputSize; j++)
    {
      // Perturb parameter with a positive constant and get costs.
      parameters(i, j) += epsilon;
      costPlus1 = srf1.Evaluate(parameters);
      costPlus2 = srf2.Evaluate(parameters);

      // Perturb parameter with a negative constant and get costs.
      parameters(i, j) -= 2 * epsilon;
      costMinus1 = srf1.Evaluate(parameters);
      costMinus2 = srf2.Evaluate(parameters);

      // Compute numerical gradients using the costs calculated above.
      numGradient1 = (costPlus1 - costMinus1) / (2 * epsilon);
      numGradient2 = (costPlus2 - costMinus2) / (2 * epsilon);

      // Restore the parameter value.
      parameters(i, j) += epsilon;

      // Compare numerical and backpropagation gradient values.
      BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 1e-2);
    }
  }
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionTwoClasses)
{
  const size_t points = 1000;
  const size_t inputSize = 3;
  const size_t numClasses = 2;
  const double lambda = 0.5;

  // Generate two-Gaussian dataset.
  GaussianDistribution g1(arma::vec("1.0 9.0 1.0"), arma::eye<arma::mat>(3, 3));
  GaussianDistribution g2(arma::vec("4.0 3.0 4.0"), arma::eye<arma::mat>(3, 3));

  arma::mat data(inputSize, points);
  arma::vec labels(points);

  for (size_t i = 0; i < points/2; i++)
  {
    data.col(i) = g1.Random();
    labels(i) = 0;
  }
  for (size_t i = points/2; i < points; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }

  // Train softmax regression object.
  SoftmaxRegression<> sr(data, labels, inputSize, numClasses, lambda);

  // Compare training accuracy to 100.
  const double acc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(acc, 100.0, 0.3);

  // Create test dataset.
  for (size_t i = 0; i < points/2; i++)
  {
    data.col(i) = g1.Random();
    labels(i) =  0;
  }
  for (size_t i = points/2; i < points; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }

  // Compare test accuracy to 100.
  const double testAcc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.6);
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionMultipleClasses)
{
  const size_t points = 5000;
  const size_t inputSize = 5;
  const size_t numClasses = 5;
  const double lambda = 0.5;

  // Generate five-Gaussian dataset.
  arma::mat identity = arma::eye<arma::mat>(5, 5);
  GaussianDistribution g1(arma::vec("1.0 9.0 1.0 2.0 2.0"), identity);
  GaussianDistribution g2(arma::vec("4.0 3.0 4.0 2.0 2.0"), identity);
  GaussianDistribution g3(arma::vec("3.0 2.0 7.0 0.0 5.0"), identity);
  GaussianDistribution g4(arma::vec("4.0 1.0 1.0 2.0 7.0"), identity);
  GaussianDistribution g5(arma::vec("1.0 0.0 1.0 8.0 3.0"), identity);

  arma::mat data(inputSize, points);
  arma::vec labels(points);

  for (size_t i = 0; i < points/5; i++)
  {
    data.col(i) = g1.Random();
    labels(i) = 0;
  }
  for (size_t i = points/5; i < (2*points)/5; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }
  for (size_t i = (2*points)/5; i < (3*points)/5; i++)
  {
    data.col(i) = g3.Random();
    labels(i) = 2;
  }
  for (size_t i = (3*points)/5; i < (4*points)/5; i++)
  {
    data.col(i) = g4.Random();
    labels(i) = 3;
  }
  for (size_t i = (4*points)/5; i < points; i++)
  {
    data.col(i) = g5.Random();
    labels(i) = 4;
  }

  // Train softmax regression object.
  SoftmaxRegression<> sr(data, labels, inputSize, numClasses, lambda);

  // Compare training accuracy to 100.
  const double acc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(acc, 100.0, 2.0);

  // Create test dataset.
  for (size_t i = 0; i < points/5; i++)
  {
    data.col(i) = g1.Random();
    labels(i) = 0;
  }
  for (size_t i = points/5; i < (2*points)/5; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }
  for (size_t i = (2*points)/5; i < (3*points)/5; i++)
  {
    data.col(i) = g3.Random();
    labels(i) = 2;
  }
  for (size_t i = (3*points)/5; i < (4*points)/5; i++)
  {
    data.col(i) = g4.Random();
    labels(i) = 3;
  }
  for (size_t i = (4*points)/5; i < points; i++)
  {
    data.col(i) = g5.Random();
    labels(i) = 4;
  }

  // Compare test accuracy to 100.
  const double testAcc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(testAcc, 100.0, 2.0);
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Slightly widen tolerance.<commit_after>/**
 * @file softmax_regression_test.cpp
 * @author Siddharth Agrawal
 *
 * Test the SoftmaxRegression class.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/softmax_regression/softmax_regression.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::regression;
using namespace mlpack::distribution;

BOOST_AUTO_TEST_SUITE(SoftmaxRegressionTest);

BOOST_AUTO_TEST_CASE(SoftmaxRegressionFunctionEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t inputSize = 10;
  const size_t numClasses = 5;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(inputSize, points);

  // Create random class labels.
  arma::vec labels(points);
  for(size_t i = 0; i < points; i++)
    labels(i) = math::RandInt(0, numClasses);

  // Create a SoftmaxRegressionFunction. Regularization term ignored.
  SoftmaxRegressionFunction srf(data, labels, inputSize, numClasses, 0);

  // Run a number of trials.
  for(size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(numClasses, inputSize);

    double logLikelihood = 0;

    // Compute error for each training example.
    for(size_t j = 0; j < points; j++)
    {
      arma::mat hypothesis, probabilities;

      hypothesis = arma::exp(parameters * data.col(j));
      probabilities = hypothesis / arma::accu(hypothesis);

      logLikelihood += log(probabilities(labels(j), 0));
    }
    logLikelihood /= points;

    // Compare with the value returned by the function.
    BOOST_REQUIRE_CLOSE(srf.Evaluate(parameters), -logLikelihood, 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionFunctionRegularizationEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t inputSize = 10;
  const size_t numClasses = 5;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(inputSize, points);

  // Create random class labels.
  arma::vec labels(points);
  for(size_t i = 0; i < points; i++)
    labels(i) = math::RandInt(0, numClasses);

  // 3 objects for comparing regularization costs.
  SoftmaxRegressionFunction srfNoReg(data, labels, inputSize, numClasses, 0);
  SoftmaxRegressionFunction srfSmallReg(data, labels, inputSize, numClasses, 1);
  SoftmaxRegressionFunction srfBigReg(data, labels, inputSize, numClasses, 20);

  // Run a number of trials.
  for (size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(numClasses, inputSize);

    double wL2SquaredNorm;
    wL2SquaredNorm = arma::accu(parameters % parameters);

    // Calculate regularization terms.
    const double smallRegTerm = 0.5 * wL2SquaredNorm;
    const double bigRegTerm = 10 * wL2SquaredNorm;

    BOOST_REQUIRE_CLOSE(srfNoReg.Evaluate(parameters) + smallRegTerm,
        srfSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(srfNoReg.Evaluate(parameters) + bigRegTerm,
        srfBigReg.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionFunctionGradient)
{
  const size_t points = 1000;
  const size_t inputSize = 10;
  const size_t numClasses = 5;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(inputSize, points);

  // Create random class labels.
  arma::vec labels(points);
  for(size_t i = 0; i < points; i++)
    labels(i) = math::RandInt(0, numClasses);

  // 2 objects for 2 terms in the cost function. Each term contributes towards
  // the gradient and thus need to be checked independently.
  SoftmaxRegressionFunction srf1(data, labels, inputSize, numClasses, 0);
  SoftmaxRegressionFunction srf2(data, labels, inputSize, numClasses, 20);

  // Create a random set of parameters.
  arma::mat parameters;
  parameters.randu(numClasses, inputSize);

  // Get gradients for the current parameters.
  arma::mat gradient1, gradient2;
  srf1.Gradient(parameters, gradient1);
  srf2.Gradient(parameters, gradient2);

  // Perturbation constant.
  const double epsilon = 0.0001;
  double costPlus1, costMinus1, numGradient1;
  double costPlus2, costMinus2, numGradient2;

  // For each parameter.
  for (size_t i = 0; i < numClasses; i++)
  {
    for (size_t j = 0; j < inputSize; j++)
    {
      // Perturb parameter with a positive constant and get costs.
      parameters(i, j) += epsilon;
      costPlus1 = srf1.Evaluate(parameters);
      costPlus2 = srf2.Evaluate(parameters);

      // Perturb parameter with a negative constant and get costs.
      parameters(i, j) -= 2 * epsilon;
      costMinus1 = srf1.Evaluate(parameters);
      costMinus2 = srf2.Evaluate(parameters);

      // Compute numerical gradients using the costs calculated above.
      numGradient1 = (costPlus1 - costMinus1) / (2 * epsilon);
      numGradient2 = (costPlus2 - costMinus2) / (2 * epsilon);

      // Restore the parameter value.
      parameters(i, j) += epsilon;

      // Compare numerical and backpropagation gradient values.
      BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 1e-2);
    }
  }
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionTwoClasses)
{
  const size_t points = 1000;
  const size_t inputSize = 3;
  const size_t numClasses = 2;
  const double lambda = 0.5;

  // Generate two-Gaussian dataset.
  GaussianDistribution g1(arma::vec("1.0 9.0 1.0"), arma::eye<arma::mat>(3, 3));
  GaussianDistribution g2(arma::vec("4.0 3.0 4.0"), arma::eye<arma::mat>(3, 3));

  arma::mat data(inputSize, points);
  arma::vec labels(points);

  for (size_t i = 0; i < points/2; i++)
  {
    data.col(i) = g1.Random();
    labels(i) = 0;
  }
  for (size_t i = points/2; i < points; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }

  // Train softmax regression object.
  SoftmaxRegression<> sr(data, labels, inputSize, numClasses, lambda);

  // Compare training accuracy to 100.
  const double acc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(acc, 100.0, 0.5);

  // Create test dataset.
  for (size_t i = 0; i < points/2; i++)
  {
    data.col(i) = g1.Random();
    labels(i) =  0;
  }
  for (size_t i = points/2; i < points; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }

  // Compare test accuracy to 100.
  const double testAcc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.6);
}

BOOST_AUTO_TEST_CASE(SoftmaxRegressionMultipleClasses)
{
  const size_t points = 5000;
  const size_t inputSize = 5;
  const size_t numClasses = 5;
  const double lambda = 0.5;

  // Generate five-Gaussian dataset.
  arma::mat identity = arma::eye<arma::mat>(5, 5);
  GaussianDistribution g1(arma::vec("1.0 9.0 1.0 2.0 2.0"), identity);
  GaussianDistribution g2(arma::vec("4.0 3.0 4.0 2.0 2.0"), identity);
  GaussianDistribution g3(arma::vec("3.0 2.0 7.0 0.0 5.0"), identity);
  GaussianDistribution g4(arma::vec("4.0 1.0 1.0 2.0 7.0"), identity);
  GaussianDistribution g5(arma::vec("1.0 0.0 1.0 8.0 3.0"), identity);

  arma::mat data(inputSize, points);
  arma::vec labels(points);

  for (size_t i = 0; i < points/5; i++)
  {
    data.col(i) = g1.Random();
    labels(i) = 0;
  }
  for (size_t i = points/5; i < (2*points)/5; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }
  for (size_t i = (2*points)/5; i < (3*points)/5; i++)
  {
    data.col(i) = g3.Random();
    labels(i) = 2;
  }
  for (size_t i = (3*points)/5; i < (4*points)/5; i++)
  {
    data.col(i) = g4.Random();
    labels(i) = 3;
  }
  for (size_t i = (4*points)/5; i < points; i++)
  {
    data.col(i) = g5.Random();
    labels(i) = 4;
  }

  // Train softmax regression object.
  SoftmaxRegression<> sr(data, labels, inputSize, numClasses, lambda);

  // Compare training accuracy to 100.
  const double acc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(acc, 100.0, 2.0);

  // Create test dataset.
  for (size_t i = 0; i < points/5; i++)
  {
    data.col(i) = g1.Random();
    labels(i) = 0;
  }
  for (size_t i = points/5; i < (2*points)/5; i++)
  {
    data.col(i) = g2.Random();
    labels(i) = 1;
  }
  for (size_t i = (2*points)/5; i < (3*points)/5; i++)
  {
    data.col(i) = g3.Random();
    labels(i) = 2;
  }
  for (size_t i = (3*points)/5; i < (4*points)/5; i++)
  {
    data.col(i) = g4.Random();
    labels(i) = 3;
  }
  for (size_t i = (4*points)/5; i < points; i++)
  {
    data.col(i) = g5.Random();
    labels(i) = 4;
  }

  // Compare test accuracy to 100.
  const double testAcc = sr.ComputeAccuracy(data, labels);
  BOOST_REQUIRE_CLOSE(testAcc, 100.0, 2.0);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/*
 * kdenlivetitle_wrapper.cpp -- kdenlivetitle wrapper
 * Copyright (c) 2009 Marco Gittler <g.marco@freenet.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QtGui/QImage>
#include <QtGui/QPainter>
#include <QtCore/QCoreApplication>
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtGui/QGraphicsView>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsTextItem>
#include <QtGui/QGraphicsPolygonItem>
#include <QtGui/QTextCursor>
#include "kdenlivetitle_wrapper.h"
#include <framework/mlt_producer.h>
extern "C" {
    void init_qt (const char* c){
        titleclass=new Title(QString(c));
    }
    void refresh_kdenlivetitle( uint8_t* buffer, int width, int height , double position){
       titleclass->drawKdenliveTitle(buffer,width,height,position);
       int i=0;
       uint8_t* pointer;
       //rotate bytes for correct order in mlt
       for (i=0;i<width*height*4;i+=4){
            pointer=buffer+i;
            uint8_t a=pointer[0],r=pointer[1],g=pointer[2],b=pointer[3];
            pointer[0]=g;//g
            pointer[1]=r;//r
            pointer[2]=b;//b
            pointer[3]=a;//a
       }
    }
}
Title::Title(const QString& filename){
    int argc=0;
    char* argv[1];
    argv[0]="xxx";
    app=new QApplication(argc,argv);
    //must be extracted from kdenlive title
    start =new QGraphicsPolygonItem(QPolygonF(QRectF(100, 100, 600, 600)));;
    end=new QGraphicsPolygonItem(QPolygonF(QRectF(0, 0, 300, 300)));;
    m_scene=new QGraphicsScene;
    loadDocument(filename,start,end);
}
void Title::drawKdenliveTitle(uint8_t * buffer ,int width,int height,double position){
    //qDebug() << width << height;
    QImage img((uchar*)buffer,width,height,width*4,QImage::Format_ARGB32);
    img.fill(Qt::transparent);
    //img.fill(66);
    QRectF rstart=start->boundingRect();
    QRectF rend=end->boundingRect();
    QPointF topleft=rstart.topLeft()+(rend.topLeft()-rstart.topLeft())*position;
    QPointF bottomRight=rstart.bottomRight()+(rend.bottomRight()-rstart.bottomRight())*position;
    QPainter p1;
    p1.begin(&img);
    p1.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing|QPainter::SmoothPixmapTransform );
    m_scene->render(&p1,QRect(0,0,width,height),QRectF(topleft,bottomRight));
    p1.end();
    //qDebug() << img.hasAlphaChannel();
    //img.save("test.png");
}
int Title::loadDocument(const QString& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv)
{
    QDomDocument doc;
    if (!m_scene)
        return -1;

        QFile file(url);
        if (file.open(QIODevice::ReadOnly)) {
            doc.setContent(&file, false);
            file.close();
        }
        return loadFromXml(doc, startv, endv);
}
int Title::loadFromXml(QDomDocument doc, QGraphicsPolygonItem* /*startv*/, QGraphicsPolygonItem* /*endv*/)
{
    QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
    int maxZValue = 0;
    if (titles.size()) {

        QDomNodeList items = titles.item(0).childNodes();
        for (int i = 0; i < items.count(); i++) {
            QGraphicsItem *gitem = NULL;
            int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
            if (zValue > -1000) {
                if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
                    QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
                    QFont font(txtProperties.namedItem("font").nodeValue());
                    font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
                    font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
                    font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
                    // Older Kdenlive version did not store pixel size but point size
                    if (txtProperties.namedItem("font-pixel-size").isNull()) {
                        QFont f2;
                        f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
                        font.setPixelSize(QFontInfo(f2).pixelSize());
                    } else
                        font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
                    QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
                    QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
                    txt->setDefaultTextColor(col);
                    txt->setTextInteractionFlags(Qt::NoTextInteraction);
                    if (txtProperties.namedItem("alignment").isNull() == false) {
                        txt->setTextWidth(txt->boundingRect().width());
                        QTextCursor cur = txt->textCursor();
                        QTextBlockFormat format = cur.blockFormat();
                        format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
                        cur.select(QTextCursor::Document);
                        cur.setBlockFormat(format);
                        txt->setTextCursor(cur);
                        cur.clearSelection();
                        txt->setTextCursor(cur);
                    }

                    if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
                        //txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
                    }
                    if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
                        //txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
                    }

                    gitem = txt;
                } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
                    QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
                    QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
                    QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
                    double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
                    QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
                    gitem = rec;
                } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
                    QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
                    QPixmap pix(url);
                    QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
                    rec->setData(Qt::UserRole, url);
                    gitem = rec;
                } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
                    QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
                    //QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
                    //m_scene->addItem(rec);
                    //rec->setData(Qt::UserRole, url);
                    //gitem = rec;
                }
            }
            //pos and transform
            if (gitem) {
                QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
                          items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
                gitem->setPos(p);
                gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
                int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
                if (zValue > maxZValue) maxZValue = zValue;
                gitem->setZValue(zValue);
                gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
            }
            if (items.item(i).nodeName() == "background") {
                QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
                //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
                QList<QGraphicsItem *> items = m_scene->items();
                for (int i = 0; i < items.size(); i++) {
                    if (items.at(i)->zValue() == -1100) {
                        ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
                        break;
                    }
                }
            } /*else if (items.item(i).nodeName() == "startviewport" && startv) {
                    QPointF p(items.item(i).attributes().namedItem("x").nodeValue().toDouble(), items.item(i).attributes().namedItem("y").nodeValue().toDouble());
                    double width = items.item(i).attributes().namedItem("size").nodeValue().toDouble();
                    QRectF rect(-width, -width / aspect_ratio, width*2.0, width / aspect_ratio*2.0);
                    kDebug() << width << rect;
                    startv->setPolygon(rect);
                    startv->setPos(p);
                } else if (items.item(i).nodeName() == "endviewport" && endv) {
                    QPointF p(items.item(i).attributes().namedItem("x").nodeValue().toDouble(), items.item(i).attributes().namedItem("y").nodeValue().toDouble());
                    double width = items.item(i).attributes().namedItem("size").nodeValue().toDouble();
                    QRectF rect(-width, -width / aspect_ratio, width*2.0, width / aspect_ratio*2.0);
                    kDebug() << width << rect;
                    endv->setPolygon(rect);
                    endv->setPos(p);
                }*/
        }
    }
    return maxZValue;
}

QString Title::colorToString(const QColor& c)
{
    QString ret = "%1,%2,%3,%4";
    ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
    return ret;
}

QString Title::rectFToString(const QRectF& c)
{
    QString ret = "%1,%2,%3,%4";
    ret = ret.arg(c.top()).arg(c.left()).arg(c.width()).arg(c.height());
    return ret;
}

QRectF Title::stringToRect(const QString & s)
{

    QStringList l = s.split(',');
    if (l.size() < 4)
        return QRectF();
    return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
}

QColor Title::stringToColor(const QString & s)
{
    QStringList l = s.split(',');
    if (l.size() < 4)
        return QColor();
    return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
}
QTransform Title::stringToTransform(const QString& s)
{
    QStringList l = s.split(',');
    if (l.size() < 9)
        return QTransform();
    return QTransform(
               l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
               l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
               l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
           );
}
<commit_msg>don't block under qt-application (kdenlive)<commit_after>/*
 * kdenlivetitle_wrapper.cpp -- kdenlivetitle wrapper
 * Copyright (c) 2009 Marco Gittler <g.marco@freenet.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QtGui/QImage>
#include <QtGui/QPainter>
#include <QtCore/QCoreApplication>
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtGui/QGraphicsView>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsTextItem>
#include <QtGui/QGraphicsPolygonItem>
#include <QtGui/QTextCursor>
#include "kdenlivetitle_wrapper.h"
#include <framework/mlt_producer.h>
extern "C" {
    void init_qt (const char* c){
        titleclass=new Title(QString(c));
    }
    void refresh_kdenlivetitle( uint8_t* buffer, int width, int height , double position){
       titleclass->drawKdenliveTitle(buffer,width,height,position);
       int i=0;
       uint8_t* pointer;
       //rotate bytes for correct order in mlt
       for (i=0;i<width*height*4;i+=4){
            pointer=buffer+i;
            uint8_t a=pointer[0],r=pointer[1],g=pointer[2],b=pointer[3];
            pointer[0]=g;//g
            pointer[1]=r;//r
            pointer[2]=b;//b
            pointer[3]=a;//a
       }
    }
}
Title::Title(const QString& filename){
    int argc=0;
    char* argv[1];
    argv[0]="xxx";
    if (! QApplication::activeWindow())
        app=new QApplication(argc,argv);
    //must be extracted from kdenlive title
    start =new QGraphicsPolygonItem(QPolygonF(QRectF(100, 100, 600, 600)));;
    end=new QGraphicsPolygonItem(QPolygonF(QRectF(0, 0, 300, 300)));;
    m_scene=new QGraphicsScene;
    loadDocument(filename,start,end);
}
void Title::drawKdenliveTitle(uint8_t * buffer ,int width,int height,double position){
    //qDebug() << width << height;
    QImage img((uchar*)buffer,width,height,width*4,QImage::Format_ARGB32);
    img.fill(Qt::transparent);
    //img.fill(66);
    QRectF rstart=start->boundingRect();
    QRectF rend=end->boundingRect();
    QPointF topleft=rstart.topLeft()+(rend.topLeft()-rstart.topLeft())*position;
    QPointF bottomRight=rstart.bottomRight()+(rend.bottomRight()-rstart.bottomRight())*position;
    QPainter p1;
    p1.begin(&img);
    p1.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing|QPainter::SmoothPixmapTransform );
    m_scene->render(&p1,QRect(0,0,width,height),QRectF(topleft,bottomRight));
    p1.end();
    //qDebug() << img.hasAlphaChannel();
    //img.save("test.png");
}
int Title::loadDocument(const QString& url, QGraphicsPolygonItem* startv, QGraphicsPolygonItem* endv)
{
    QDomDocument doc;
    if (!m_scene)
        return -1;

        QFile file(url);
        if (file.open(QIODevice::ReadOnly)) {
            doc.setContent(&file, false);
            file.close();
        }
        return loadFromXml(doc, startv, endv);
}
int Title::loadFromXml(QDomDocument doc, QGraphicsPolygonItem* /*startv*/, QGraphicsPolygonItem* /*endv*/)
{
    QDomNodeList titles = doc.elementsByTagName("kdenlivetitle");
    int maxZValue = 0;
    if (titles.size()) {

        QDomNodeList items = titles.item(0).childNodes();
        for (int i = 0; i < items.count(); i++) {
            QGraphicsItem *gitem = NULL;
            int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
            if (zValue > -1000) {
                if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsTextItem") {
                    QDomNamedNodeMap txtProperties = items.item(i).namedItem("content").attributes();
                    QFont font(txtProperties.namedItem("font").nodeValue());
                    font.setBold(txtProperties.namedItem("font-bold").nodeValue().toInt());
                    font.setItalic(txtProperties.namedItem("font-italic").nodeValue().toInt());
                    font.setUnderline(txtProperties.namedItem("font-underline").nodeValue().toInt());
                    // Older Kdenlive version did not store pixel size but point size
                    if (txtProperties.namedItem("font-pixel-size").isNull()) {
                        QFont f2;
                        f2.setPointSize(txtProperties.namedItem("font-size").nodeValue().toInt());
                        font.setPixelSize(QFontInfo(f2).pixelSize());
                    } else
                        font.setPixelSize(txtProperties.namedItem("font-pixel-size").nodeValue().toInt());
                    QColor col(stringToColor(txtProperties.namedItem("font-color").nodeValue()));
                    QGraphicsTextItem *txt = m_scene->addText(items.item(i).namedItem("content").firstChild().nodeValue(), font);
                    txt->setDefaultTextColor(col);
                    txt->setTextInteractionFlags(Qt::NoTextInteraction);
                    if (txtProperties.namedItem("alignment").isNull() == false) {
                        txt->setTextWidth(txt->boundingRect().width());
                        QTextCursor cur = txt->textCursor();
                        QTextBlockFormat format = cur.blockFormat();
                        format.setAlignment((Qt::Alignment) txtProperties.namedItem("alignment").nodeValue().toInt());
                        cur.select(QTextCursor::Document);
                        cur.setBlockFormat(format);
                        txt->setTextCursor(cur);
                        cur.clearSelection();
                        txt->setTextCursor(cur);
                    }

                    if (!txtProperties.namedItem("kdenlive-axis-x-inverted").isNull()) {
                        //txt->setData(OriginXLeft, txtProperties.namedItem("kdenlive-axis-x-inverted").nodeValue().toInt());
                    }
                    if (!txtProperties.namedItem("kdenlive-axis-y-inverted").isNull()) {
                        //txt->setData(OriginYTop, txtProperties.namedItem("kdenlive-axis-y-inverted").nodeValue().toInt());
                    }

                    gitem = txt;
                } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsRectItem") {
                    QString rect = items.item(i).namedItem("content").attributes().namedItem("rect").nodeValue();
                    QString br_str = items.item(i).namedItem("content").attributes().namedItem("brushcolor").nodeValue();
                    QString pen_str = items.item(i).namedItem("content").attributes().namedItem("pencolor").nodeValue();
                    double penwidth = items.item(i).namedItem("content").attributes().namedItem("penwidth").nodeValue().toDouble();
                    QGraphicsRectItem *rec = m_scene->addRect(stringToRect(rect), QPen(QBrush(stringToColor(pen_str)), penwidth), QBrush(stringToColor(br_str)));
                    gitem = rec;
                } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsPixmapItem") {
                    QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
                    QPixmap pix(url);
                    QGraphicsPixmapItem *rec = m_scene->addPixmap(pix);
                    rec->setData(Qt::UserRole, url);
                    gitem = rec;
                } else if (items.item(i).attributes().namedItem("type").nodeValue() == "QGraphicsSvgItem") {
                    QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
                    //QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
                    //m_scene->addItem(rec);
                    //rec->setData(Qt::UserRole, url);
                    //gitem = rec;
                }
            }
            //pos and transform
            if (gitem) {
                QPointF p(items.item(i).namedItem("position").attributes().namedItem("x").nodeValue().toDouble(),
                          items.item(i).namedItem("position").attributes().namedItem("y").nodeValue().toDouble());
                gitem->setPos(p);
                gitem->setTransform(stringToTransform(items.item(i).namedItem("position").firstChild().firstChild().nodeValue()));
                int zValue = items.item(i).attributes().namedItem("z-index").nodeValue().toInt();
                if (zValue > maxZValue) maxZValue = zValue;
                gitem->setZValue(zValue);
                gitem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
            }
            if (items.item(i).nodeName() == "background") {
                QColor color = QColor(stringToColor(items.item(i).attributes().namedItem("color").nodeValue()));
                //color.setAlpha(items.item(i).attributes().namedItem("alpha").nodeValue().toInt());
                QList<QGraphicsItem *> items = m_scene->items();
                for (int i = 0; i < items.size(); i++) {
                    if (items.at(i)->zValue() == -1100) {
                        ((QGraphicsRectItem *)items.at(i))->setBrush(QBrush(color));
                        break;
                    }
                }
            } /*else if (items.item(i).nodeName() == "startviewport" && startv) {
                    QPointF p(items.item(i).attributes().namedItem("x").nodeValue().toDouble(), items.item(i).attributes().namedItem("y").nodeValue().toDouble());
                    double width = items.item(i).attributes().namedItem("size").nodeValue().toDouble();
                    QRectF rect(-width, -width / aspect_ratio, width*2.0, width / aspect_ratio*2.0);
                    kDebug() << width << rect;
                    startv->setPolygon(rect);
                    startv->setPos(p);
                } else if (items.item(i).nodeName() == "endviewport" && endv) {
                    QPointF p(items.item(i).attributes().namedItem("x").nodeValue().toDouble(), items.item(i).attributes().namedItem("y").nodeValue().toDouble());
                    double width = items.item(i).attributes().namedItem("size").nodeValue().toDouble();
                    QRectF rect(-width, -width / aspect_ratio, width*2.0, width / aspect_ratio*2.0);
                    kDebug() << width << rect;
                    endv->setPolygon(rect);
                    endv->setPos(p);
                }*/
        }
    }
    return maxZValue;
}

QString Title::colorToString(const QColor& c)
{
    QString ret = "%1,%2,%3,%4";
    ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
    return ret;
}

QString Title::rectFToString(const QRectF& c)
{
    QString ret = "%1,%2,%3,%4";
    ret = ret.arg(c.top()).arg(c.left()).arg(c.width()).arg(c.height());
    return ret;
}

QRectF Title::stringToRect(const QString & s)
{

    QStringList l = s.split(',');
    if (l.size() < 4)
        return QRectF();
    return QRectF(l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(), l.at(3).toDouble()).normalized();
}

QColor Title::stringToColor(const QString & s)
{
    QStringList l = s.split(',');
    if (l.size() < 4)
        return QColor();
    return QColor(l.at(0).toInt(), l.at(1).toInt(), l.at(2).toInt(), l.at(3).toInt());;
}
QTransform Title::stringToTransform(const QString& s)
{
    QStringList l = s.split(',');
    if (l.size() < 9)
        return QTransform();
    return QTransform(
               l.at(0).toDouble(), l.at(1).toDouble(), l.at(2).toDouble(),
               l.at(3).toDouble(), l.at(4).toDouble(), l.at(5).toDouble(),
               l.at(6).toDouble(), l.at(7).toDouble(), l.at(8).toDouble()
           );
}
<|endoftext|>