<commit_before>/*******************************************************
 * Copyright (c) 2020, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <common/Logger.hpp>
#include <common/err_common.hpp>
#include <common/util.hpp>
#include <cudnnModule.hpp>
#include <device_manager.hpp>
#include <utility.hpp>

#include <string>
#include <tuple>

using std::make_tuple;
using std::string;

namespace cuda {

spdlog::logger* cudnnModule::getLogger() const noexcept {
    return module.getLogger();
}

auto cudnnVersionComponents(size_t version) {
    size_t major = version / 1000;
    size_t minor = (version - (major * 1000)) / 100;
    size_t patch = (version - (major * 1000) - (minor * 100));
    return make_tuple(major, minor, patch);
}

cudnnModule::cudnnModule()
    : module({"cudnn"}, {"", "64_7", "64_8", "64_6", "64_5", "64_4"}, {""}) {
    if (!module.isLoaded()) {
        AF_TRACE(
            "WARNING: Unable to load cuDNN: {}"
            "\ncuDNN failed to load. Try installing cuDNN or check if cuDNN is "
            "in the search path. On Linux, you can set the LD_DEBUG=libs "
            "environment variable to debug loading issues. Falling back to "
            "matmul based implementation",
            module.getErrorMessage());

        return;
    }

    MODULE_FUNCTION_INIT(cudnnGetVersion);

    int rtmajor, rtminor;
    size_t cudnn_version          = this->cudnnGetVersion();
    size_t cudnn_rtversion        = 0;
    std::tie(major, minor, patch) = cudnnVersionComponents(cudnn_version);

    if (cudnn_version >= 6000) {
        MODULE_FUNCTION_INIT(cudnnGetCudartVersion);
        cudnn_rtversion = this->cudnnGetCudartVersion();
    } else {
        AF_TRACE(
            "Warning: This version of cuDNN({}.{}) does not support "
            "cudnnGetCudartVersion. No runtime checks performed.",
            major, minor);
    }

    std::tie(rtmajor, rtminor, std::ignore) =
        cudnnVersionComponents(cudnn_rtversion);

    AF_TRACE("cuDNN Version: {}.{}.{} cuDNN CUDA Runtime: {}.{}", major, minor,
             patch, rtmajor, rtminor);

    // Check to see if the version of cuDNN ArrayFire was compiled against
    // is compatible with the version loaded at runtime
    if (CUDNN_VERSION <= 6000 && cudnn_version > CUDNN_VERSION) {
        string error_msg = fmt::format(
            "ArrayFire was compiled with an older version of cuDNN({}.{}) that "
            "does not support the version that was loaded at runtime({}.{}).",
            CUDNN_MAJOR, CUDNN_MINOR, major, minor);
        AF_ERROR(error_msg, AF_ERR_NOT_SUPPORTED);
    }

    int afcuda_runtime = 0;
    cudaRuntimeGetVersion(&afcuda_runtime);
    if (afcuda_runtime != static_cast<int>(cudnn_version)) {
        getLogger()->warn(
            "WARNING: ArrayFire CUDA Runtime({}) and cuDNN CUDA "
            "Runtime({}.{}) do not match. For maximum compatibility, make sure "
            "the two versions match.(Ignoring check)",
            // NOTE: the int version formats from CUDA and cuDNN are different
            // so we are using int_version_to_string for the ArrayFire CUDA
            // runtime
            int_version_to_string(afcuda_runtime), rtmajor, rtminor);
    }

    MODULE_FUNCTION_INIT(cudnnConvolutionBackwardData);
    MODULE_FUNCTION_INIT(cudnnConvolutionBackwardFilter);
    MODULE_FUNCTION_INIT(cudnnConvolutionForward);
    MODULE_FUNCTION_INIT(cudnnCreate);
    MODULE_FUNCTION_INIT(cudnnCreateConvolutionDescriptor);
    MODULE_FUNCTION_INIT(cudnnCreateFilterDescriptor);
    MODULE_FUNCTION_INIT(cudnnCreateTensorDescriptor);
    MODULE_FUNCTION_INIT(cudnnDestroy);
    MODULE_FUNCTION_INIT(cudnnDestroyConvolutionDescriptor);
    MODULE_FUNCTION_INIT(cudnnDestroyFilterDescriptor);
    MODULE_FUNCTION_INIT(cudnnDestroyTensorDescriptor);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionBackwardDataWorkspaceSize);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionBackwardFilterAlgorithm);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionBackwardFilterWorkspaceSize);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionForwardAlgorithm);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionForwardWorkspaceSize);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionNdForwardOutputDim);
    MODULE_FUNCTION_INIT(cudnnSetConvolution2dDescriptor);
    MODULE_FUNCTION_INIT(cudnnSetFilter4dDescriptor);
    if (major == 4) { MODULE_FUNCTION_INIT(cudnnSetFilter4dDescriptor_v4); }
    MODULE_FUNCTION_INIT(cudnnSetStream);
    MODULE_FUNCTION_INIT(cudnnSetTensor4dDescriptor);

    // Check to see if the cuDNN runtime is compatible with the current device
    cudaDeviceProp prop = getDeviceProp(getActiveDeviceId());
    if (!checkDeviceWithRuntime(cudnn_rtversion, {prop.major, prop.minor})) {
        string error_message = fmt::format(
            "Error: cuDNN CUDA Runtime({}.{}) does not support the "
            "current device's compute capability(sm_{}{}).",
            rtmajor, rtminor, prop.major, prop.minor);
        AF_ERROR(error_message, AF_ERR_RUNTIME);
    }

    if (!module.symbolsLoaded()) {
        string error_message =
            "Error loading cuDNN symbols. ArrayFire was unable to load some "
            "symbols from the cuDNN library. Please create an issue on the "
            "ArrayFire repository with information about the installed cuDNN "
            "and ArrayFire on your system.";
        AF_ERROR(error_message, AF_ERR_LOAD_LIB);
    }
}

cudnnModule& getCudnnPlugin() noexcept {
    static auto* plugin = new cudnnModule();
    return *plugin;
}

}  // namespace cuda
<commit_msg>Add cudnn versions to lookup for dynamic loading<commit_after>/*******************************************************
 * Copyright (c) 2020, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <common/Logger.hpp>
#include <common/err_common.hpp>
#include <common/util.hpp>
#include <cudnnModule.hpp>
#include <device_manager.hpp>
#include <utility.hpp>

#include <array>
#include <string>
#include <tuple>

using common::Version;
using std::make_tuple;
using std::string;

namespace cuda {

// clang-format off
// Latest version from each minor releases are enlisted below
constexpr std::array<common::Version, 10> cudnnVersions = {
    make_tuple(7, 6,  5),
    make_tuple(7, 5,  1),
    make_tuple(7, 4,  2),
    make_tuple(7, 3,  1),
    make_tuple(7, 2,  1),
    make_tuple(7, 1,  4),
    make_tuple(7, 0,  5),
    make_tuple(6, 0, 21),
    make_tuple(5, 1, 10),
    make_tuple(4, 0,  7)
};
// clang-format on

spdlog::logger* cudnnModule::getLogger() const noexcept {
    return module.getLogger();
}

auto cudnnVersionComponents(size_t version) {
    size_t major = version / 1000;
    size_t minor = (version - (major * 1000)) / 100;
    size_t patch = (version - (major * 1000) - (minor * 100));
    return make_tuple(major, minor, patch);
}

cudnnModule::cudnnModule()
    : module({"cudnn"}, {"", "64_7", "64_8", "64_6", "64_5", "64_4"}, {""},
             cudnnVersions.size(), cudnnVersions.data()) {
    if (!module.isLoaded()) {
        AF_TRACE(
            "WARNING: Unable to load cuDNN: {}"
            "\ncuDNN failed to load. Try installing cuDNN or check if cuDNN is "
            "in the search path. On Linux, you can set the LD_DEBUG=libs "
            "environment variable to debug loading issues. Falling back to "
            "matmul based implementation",
            module.getErrorMessage());

        return;
    }

    MODULE_FUNCTION_INIT(cudnnGetVersion);

    int rtmajor, rtminor;
    size_t cudnn_version          = this->cudnnGetVersion();
    size_t cudnn_rtversion        = 0;
    std::tie(major, minor, patch) = cudnnVersionComponents(cudnn_version);

    if (cudnn_version >= 6000) {
        MODULE_FUNCTION_INIT(cudnnGetCudartVersion);
        cudnn_rtversion = this->cudnnGetCudartVersion();
    } else {
        AF_TRACE(
            "Warning: This version of cuDNN({}.{}) does not support "
            "cudnnGetCudartVersion. No runtime checks performed.",
            major, minor);
    }

    std::tie(rtmajor, rtminor, std::ignore) =
        cudnnVersionComponents(cudnn_rtversion);

    AF_TRACE("cuDNN Version: {}.{}.{} cuDNN CUDA Runtime: {}.{}", major, minor,
             patch, rtmajor, rtminor);

    // Check to see if the version of cuDNN ArrayFire was compiled against
    // is compatible with the version loaded at runtime
    if (CUDNN_VERSION <= 6000 && cudnn_version > CUDNN_VERSION) {
        string error_msg = fmt::format(
            "ArrayFire was compiled with an older version of cuDNN({}.{}) that "
            "does not support the version that was loaded at runtime({}.{}).",
            CUDNN_MAJOR, CUDNN_MINOR, major, minor);
        AF_ERROR(error_msg, AF_ERR_NOT_SUPPORTED);
    }

    int afcuda_runtime = 0;
    cudaRuntimeGetVersion(&afcuda_runtime);
    if (afcuda_runtime != static_cast<int>(cudnn_version)) {
        getLogger()->warn(
            "WARNING: ArrayFire CUDA Runtime({}) and cuDNN CUDA "
            "Runtime({}.{}) do not match. For maximum compatibility, make sure "
            "the two versions match.(Ignoring check)",
            // NOTE: the int version formats from CUDA and cuDNN are different
            // so we are using int_version_to_string for the ArrayFire CUDA
            // runtime
            int_version_to_string(afcuda_runtime), rtmajor, rtminor);
    }

    MODULE_FUNCTION_INIT(cudnnConvolutionBackwardData);
    MODULE_FUNCTION_INIT(cudnnConvolutionBackwardFilter);
    MODULE_FUNCTION_INIT(cudnnConvolutionForward);
    MODULE_FUNCTION_INIT(cudnnCreate);
    MODULE_FUNCTION_INIT(cudnnCreateConvolutionDescriptor);
    MODULE_FUNCTION_INIT(cudnnCreateFilterDescriptor);
    MODULE_FUNCTION_INIT(cudnnCreateTensorDescriptor);
    MODULE_FUNCTION_INIT(cudnnDestroy);
    MODULE_FUNCTION_INIT(cudnnDestroyConvolutionDescriptor);
    MODULE_FUNCTION_INIT(cudnnDestroyFilterDescriptor);
    MODULE_FUNCTION_INIT(cudnnDestroyTensorDescriptor);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionBackwardDataWorkspaceSize);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionBackwardFilterAlgorithm);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionBackwardFilterWorkspaceSize);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionForwardAlgorithm);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionForwardWorkspaceSize);
    MODULE_FUNCTION_INIT(cudnnGetConvolutionNdForwardOutputDim);
    MODULE_FUNCTION_INIT(cudnnSetConvolution2dDescriptor);
    MODULE_FUNCTION_INIT(cudnnSetFilter4dDescriptor);
    if (major == 4) { MODULE_FUNCTION_INIT(cudnnSetFilter4dDescriptor_v4); }
    MODULE_FUNCTION_INIT(cudnnSetStream);
    MODULE_FUNCTION_INIT(cudnnSetTensor4dDescriptor);

    // Check to see if the cuDNN runtime is compatible with the current device
    cudaDeviceProp prop = getDeviceProp(getActiveDeviceId());
    if (!checkDeviceWithRuntime(cudnn_rtversion, {prop.major, prop.minor})) {
        string error_message = fmt::format(
            "Error: cuDNN CUDA Runtime({}.{}) does not support the "
            "current device's compute capability(sm_{}{}).",
            rtmajor, rtminor, prop.major, prop.minor);
        AF_ERROR(error_message, AF_ERR_RUNTIME);
    }

    if (!module.symbolsLoaded()) {
        string error_message =
            "Error loading cuDNN symbols. ArrayFire was unable to load some "
            "symbols from the cuDNN library. Please create an issue on the "
            "ArrayFire repository with information about the installed cuDNN "
            "and ArrayFire on your system.";
        AF_ERROR(error_message, AF_ERR_LOAD_LIB);
    }
}

cudnnModule& getCudnnPlugin() noexcept {
    static auto* plugin = new cudnnModule();
    return *plugin;
}

}  // namespace cuda
<|endoftext|>


<commit_before>/*
 * 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.
 *
 * Copyright (C) 2012 Jacob Walker
 *
 * Code adapted from Gaussian Process Machine Learning Toolbox
 * http://www.gaussianprocess.org/gpml/code/matlab/doc/
 *
 */

#include <shogun/lib/config.h>
#ifdef HAVE_EIGEN3
#ifdef HAVE_LAPACK

#include <shogun/io/SGIO.h>
#include <shogun/regression/GaussianProcessRegression.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/mathematics/Math.h>
#include <shogun/kernel/Kernel.h>
#include <shogun/labels/RegressionLabels.h>
#include <shogun/features/CombinedFeatures.h>

using namespace shogun;

CGaussianProcessRegression::CGaussianProcessRegression()
: CMachine()
{
	init();
}

CGaussianProcessRegression::CGaussianProcessRegression(CInferenceMethod* inf, CFeatures* data, CLabels* lab)
: CMachine()
{
	init();

	set_labels(lab);
	set_features(data);
	set_method(inf);
}

void CGaussianProcessRegression::init()
{

	m_features = NULL;
	m_method = NULL;
	m_data = NULL;
	m_return = GP_RETURN_MEANS;

	SG_ADD((CSGObject**) &m_features, "features", "Feature object.",
	    MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**) &m_method, "inference_method", "Inference Method.",
	    MS_AVAILABLE);
}

void CGaussianProcessRegression::update_kernel_matrices()
{
	CKernel* kernel = NULL;

	if (m_method)
		kernel = m_method->get_kernel();

	if (kernel)
	{
		float64_t m_scale = m_method->get_scale();

		/* set training data to latent features if exist, otherwise
		 * training features */
		CFeatures* latent_features = m_method->get_latent_features();
		if (latent_features)
		{
			kernel->init(latent_features, m_data);
			SG_UNREF(latent_features);
		}
		else
		{
			CFeatures* features=m_method->get_features();
			kernel->init(features, m_data);
			SG_UNREF(features);
		}

		//K(X_train, X_test)
		m_k_trts = kernel->get_kernel_matrix();

		for (index_t i = 0; i < m_k_trts.num_rows; i++)
		{
			for (index_t j = 0; j < m_k_trts.num_cols; j++)
				m_k_trts(i,j) *= (m_scale*m_scale);
		}

		kernel->init(m_data, m_data);
		m_k_tsts = kernel->get_kernel_matrix();

		for (index_t i = 0; i < m_k_tsts.num_rows; i++)
		{
			for (index_t j = 0; j < m_k_tsts.num_cols; j++)
				m_k_tsts(i,j) *= (m_scale*m_scale);
		}

		kernel->remove_lhs_and_rhs();

		SG_UNREF(kernel);
	}
}

CRegressionLabels* CGaussianProcessRegression::apply_regression(CFeatures* data)
{

	if (data)
	{
		if(data->get_feature_class() == C_COMBINED)
		{
			SG_WARNING("%s::apply_regression(): This only works for combined"
						" features which all share the same underlying object!\n",
						get_name());

			CDotFeatures* feat =
					(CDotFeatures*)((CCombinedFeatures*)data)->
					get_first_feature_obj();

			if (!feat->has_property(FP_DOT))
				SG_ERROR("Specified features are not of type CFeatures\n")

			if (feat->get_feature_class() != C_DENSE)
				SG_ERROR("Expected Dense Features\n")

			if (feat->get_feature_type() != F_DREAL)
				SG_ERROR("Expected Real Features\n")

			SG_UNREF(feat);
		}

		else
		{
			if (!data->has_property(FP_DOT))
				SG_ERROR("Specified features are not of type CFeatures\n")

			if (data->get_feature_class() != C_DENSE)
				SG_ERROR("Expected Simple Features\n")

			if (data->get_feature_type() != F_DREAL)
				SG_ERROR("Expected Real Features\n")
		}

		SG_REF(data);
		SG_UNREF(m_data);
		m_data = (CFeatures*)data;
		update_kernel_matrices();
	}

	else if (!m_data)
		SG_ERROR("No testing features!\n")

	else if (update_parameter_hash())
		update_kernel_matrices();

	if (m_return == GP_RETURN_COV)
	{
		CRegressionLabels* result =
				new CRegressionLabels(get_covariance_vector());

		return result;
	}

	if (m_return == GP_RETURN_MEANS)
	{
		get_mean_vector().display_size();
		SG_SPRINT("mean_vector %f\n", get_mean_vector()[0]);
		SG_SPRINT("mean_vector %f\n", get_mean_vector()[1]);
		SG_SPRINT("mean_vector %f\n", get_mean_vector()[2]);
		SG_SPRINT("mean_vector %f\n", get_mean_vector()[3]);
		SG_SPRINT("mean_vector %f\n", get_mean_vector()[4]);
		get_mean_vector().display_vector("mean_vector");
		CRegressionLabels* result =
				new CRegressionLabels(get_mean_vector());

		return result;
	}

	else
	{

		SGVector<float64_t> mean_vector = get_mean_vector();
		SGVector<float64_t> cov_vector = get_covariance_vector();

		index_t size = mean_vector.vlen+cov_vector.vlen;

		SGVector<float64_t> result_vector(size);

		for (index_t i = 0; i < size; i++)
		{
			if (i < mean_vector.vlen)
				result_vector[i] = mean_vector[i];
			else
				result_vector[i] = cov_vector[i-mean_vector.vlen];
		}

		CRegressionLabels* result =
				new CRegressionLabels(result_vector);

		return result;
	}

}

bool CGaussianProcessRegression::train_machine(CFeatures* data)
{
	return false;
}

SGVector<float64_t> CGaussianProcessRegression::get_mean_vector()
{

	SGVector<float64_t> m_alpha = m_method->get_alpha();

	CMeanFunction* mean_function = m_method->get_mean();

	SGMatrix<float64_t> features;
        if(m_data->get_feature_class() == C_COMBINED)
        {
        	SG_WARNING("%s::get_mean_vector(): This only works for combined"
        			" features which all share the same underlying object!\n",
        			get_name());
	        features = ((CDotFeatures*)((CCombinedFeatures*)m_data)->
                                        get_first_feature_obj())->
					get_computed_dot_feature_matrix();
	}

	else
	{
		features = ((CDotFeatures*)m_data)->
			get_computed_dot_feature_matrix();
	}

	REQUIRE(mean_function, "%s::get_mean_vector(): Mean function is NULL!\n",
			get_name());

	SGVector<float64_t> means = mean_function->get_mean_vector(features);

	SGVector< float64_t > result_vector(features.num_cols);

	//Here we multiply K*^t by alpha to receive the mean predictions.
	cblas_dgemv(CblasColMajor, CblasTrans, m_k_trts.num_rows,
		    m_alpha.vlen, 1.0, m_k_trts.matrix,
		    m_k_trts.num_cols, m_alpha.vector, 1, 0.0,
		    result_vector.vector, 1);

	for (index_t i = 0; i < result_vector.vlen; i++)
		result_vector[i] += means[i];

	CLikelihoodModel* lik = m_method->get_model();

	result_vector = lik->evaluate_means(result_vector);

	SG_UNREF(lik);
	SG_UNREF(mean_function);

	return result_vector;
}

SGVector<float64_t> CGaussianProcessRegression::get_covariance_vector()
{

	if (!m_data)
		SG_ERROR("No testing features!\n")

	SGVector<float64_t> diagonal = m_method->get_diagonal_vector();

	if (diagonal.vlen > 0)
	{
		SGVector<float64_t> diagonal2(m_data->get_num_vectors());

		SGMatrix<float64_t> temp1(m_data->get_num_vectors(), diagonal.vlen);

		SGMatrix<float64_t> m_L = m_method->get_cholesky();

		SGMatrix<float64_t> temp2(m_L.num_rows, m_L.num_cols);

		for (index_t i = 0; i < diagonal.vlen; i++)
		{
			for (index_t j = 0; j < m_data->get_num_vectors(); j++)
				temp1(j,i) = diagonal[i]*m_k_trts(j,i);
		}

		for (index_t i = 0; i < diagonal2.vlen; i++)
			diagonal2[i] = 0;

		memcpy(temp2.matrix, m_L.matrix,
				m_L.num_cols*m_L.num_rows*sizeof(float64_t));

		temp2.transpose_matrix(temp2.matrix, temp2.num_rows, temp2.num_cols);

		SGVector<int32_t> ipiv(temp2.num_cols);

		//Solve L^T V = K(Train,Test)*Diagonal Vector Entries for V
		clapack_dgetrf(CblasColMajor, temp2.num_rows, temp2.num_cols,
				temp2.matrix, temp2.num_cols, ipiv.vector);

		clapack_dgetrs(CblasColMajor, CblasNoTrans,
				temp2.num_rows, temp1.num_cols, temp2.matrix,
				temp2.num_cols, ipiv.vector, temp1.matrix,
				temp1.num_cols);

		for (index_t i = 0; i < temp1.num_rows; i++)
		{
			for (index_t j = 0; j < temp1.num_cols; j++)
				temp1(i,j) = temp1(i,j)*temp1(i,j);
		}

		for (index_t i = 0; i < temp1.num_cols; i++)
		{
			diagonal2[i] = 0;

			for (index_t j = 0; j < temp1.num_rows; j++)
				diagonal2[i] += temp1(j,i);
		}

		SGVector<float64_t> result(m_k_tsts.num_cols);

		//Subtract V from K(Test,Test) to get covariances.
		for (index_t i = 0; i < m_k_tsts.num_cols; i++)
			result[i] = m_k_tsts(i,i) - diagonal2[i];

		CLikelihoodModel* lik = m_method->get_model();

		SG_UNREF(lik);

		return lik->evaluate_variances(result);
	}

	else
	{
		SGMatrix<float64_t> m_L = m_method->get_cholesky();

		SGMatrix<float64_t> temp1(m_k_trts.num_rows, m_k_trts.num_cols);
		SGMatrix<float64_t> temp2(m_L.num_rows, m_L.num_cols);

		memcpy(temp1.matrix, m_k_trts.matrix,
				m_k_trts.num_cols*m_k_trts.num_rows*sizeof(float64_t));

		memcpy(temp2.matrix, m_L.matrix,
				m_L.num_cols*m_L.num_rows*sizeof(float64_t));

		cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, m_L.num_rows,
				m_k_trts.num_cols, m_L.num_rows, 1.0, m_L.matrix, m_L.num_cols,
				m_k_trts.matrix, m_k_trts.num_cols, 0.0, temp1.matrix,
				temp1.num_cols);

		for (index_t i = 0; i < temp1.num_rows; i++)
		{
			for (index_t j = 0; j < temp1.num_cols; j++)
				temp1(i,j) *= m_k_trts(i,j);
		}

		SGVector<float64_t> temp3(temp2.num_cols);

		for (index_t i = 0; i < temp1.num_cols; i++)
		{
			float64_t sum = 0;
			for (index_t j = 0; j < temp1.num_rows; j++)
				sum += temp1(j,i);
			temp3[i] = sum;
		}

		SGVector<float64_t> result(m_k_tsts.num_cols);

		for (index_t i = 0; i < m_k_tsts.num_cols; i++)
			result[i] = m_k_tsts(i,i) + temp3[i];

		CLikelihoodModel* lik = m_method->get_model();

		SG_UNREF(lik);

		return lik->evaluate_variances(result);
	}
}

CGaussianProcessRegression::~CGaussianProcessRegression()
{
	SG_UNREF(m_features);
	SG_UNREF(m_method);
	SG_UNREF(m_data);
}

void CGaussianProcessRegression::set_kernel(CKernel* k)
{
	m_method->set_kernel(k);
}

bool CGaussianProcessRegression::load(FILE* srcfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}

CKernel* CGaussianProcessRegression::get_kernel()
{
	return m_method->get_kernel();
}

bool CGaussianProcessRegression::save(FILE* dstfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}
#endif
#endif
<commit_msg>minor stuff and replaced a (buggy) lapack call by eigen3. This fixed the bug where GPR crashed when there was more test than training data<commit_after>/*
 * 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.
 *
 * Copyright (C) 2012 Jacob Walker
 *
 * Code adapted from Gaussian Process Machine Learning Toolbox
 * http://www.gaussianprocess.org/gpml/code/matlab/doc/
 *
 */

#include <shogun/lib/config.h>
#ifdef HAVE_EIGEN3
#ifdef HAVE_LAPACK

#include <shogun/io/SGIO.h>
#include <shogun/regression/GaussianProcessRegression.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/mathematics/Math.h>
#include <shogun/kernel/Kernel.h>
#include <shogun/labels/RegressionLabels.h>
#include <shogun/features/CombinedFeatures.h>
using namespace shogun;

#include <Eigen/Dense>
using namespace Eigen;

CGaussianProcessRegression::CGaussianProcessRegression()
: CMachine()
{
	init();
}

CGaussianProcessRegression::CGaussianProcessRegression(CInferenceMethod* inf, CFeatures* data, CLabels* lab)
: CMachine()
{
	init();

	set_labels(lab);
	set_features(data);
	set_method(inf);
}

void CGaussianProcessRegression::init()
{

	m_features = NULL;
	m_method = NULL;
	m_data = NULL;
	m_return = GP_RETURN_MEANS;

	SG_ADD((CSGObject**) &m_features, "features", "Feature object.",
	    MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**) &m_method, "inference_method", "Inference Method.",
	    MS_AVAILABLE);
}

void CGaussianProcessRegression::update_kernel_matrices()
{
	CKernel* kernel = NULL;

	if (m_method)
		kernel = m_method->get_kernel();

	if (kernel)
	{
		float64_t m_scale = m_method->get_scale();

		/* set training data to latent features if exist, otherwise
		 * training features */
		CFeatures* latent_features = m_method->get_latent_features();
		if (latent_features)
		{
			kernel->init(latent_features, m_data);
			SG_UNREF(latent_features);
		}
		else
		{
			CFeatures* features=m_method->get_features();
			kernel->init(features, m_data);
			SG_UNREF(features);
		}

		//K(X_train, X_test)
		m_k_trts = kernel->get_kernel_matrix();

		for (index_t i = 0; i < m_k_trts.num_rows; i++)
		{
			for (index_t j = 0; j < m_k_trts.num_cols; j++)
				m_k_trts(i,j) *= (m_scale*m_scale);
		}

		kernel->init(m_data, m_data);
		m_k_tsts = kernel->get_kernel_matrix();

		for (index_t i = 0; i < m_k_tsts.num_rows; i++)
		{
			for (index_t j = 0; j < m_k_tsts.num_cols; j++)
				m_k_tsts(i,j) *= (m_scale*m_scale);
		}

		kernel->remove_lhs_and_rhs();

		SG_UNREF(kernel);
	}
}

CRegressionLabels* CGaussianProcessRegression::apply_regression(CFeatures* data)
{

	if (data)
	{
		if(data->get_feature_class() == C_COMBINED)
		{
			SG_WARNING("%s::apply_regression(): This only works for combined"
						" features which all share the same underlying object!\n",
						get_name());

			CDotFeatures* feat =
					(CDotFeatures*)((CCombinedFeatures*)data)->
					get_first_feature_obj();

			if (!feat->has_property(FP_DOT))
				SG_ERROR("Specified features are not of type CFeatures\n")

			if (feat->get_feature_class() != C_DENSE)
				SG_ERROR("Expected Dense Features\n")

			if (feat->get_feature_type() != F_DREAL)
				SG_ERROR("Expected Real Features\n")

			SG_UNREF(feat);
		}

		else
		{
			if (!data->has_property(FP_DOT))
				SG_ERROR("Specified features are not of type CFeatures\n")

			if (data->get_feature_class() != C_DENSE)
				SG_ERROR("Expected Simple Features\n")

			if (data->get_feature_type() != F_DREAL)
				SG_ERROR("Expected Real Features\n")
		}

		SG_REF(data);
		SG_UNREF(m_data);
		m_data = (CFeatures*)data;
		update_kernel_matrices();
	}

	else if (!m_data)
		SG_ERROR("No testing features!\n")

	else if (update_parameter_hash())
		update_kernel_matrices();

	if (m_return == GP_RETURN_COV)
	{
		CRegressionLabels* result =
				new CRegressionLabels(get_covariance_vector());

		return result;
	}

	if (m_return == GP_RETURN_MEANS)
	{
		CRegressionLabels* result =
				new CRegressionLabels(get_mean_vector());

		return result;
	}

	else
	{

		SGVector<float64_t> mean_vector = get_mean_vector();
		SGVector<float64_t> cov_vector = get_covariance_vector();

		index_t size = mean_vector.vlen+cov_vector.vlen;

		SGVector<float64_t> result_vector(size);

		for (index_t i = 0; i < size; i++)
		{
			if (i < mean_vector.vlen)
				result_vector[i] = mean_vector[i];
			else
				result_vector[i] = cov_vector[i-mean_vector.vlen];
		}

		CRegressionLabels* result =
				new CRegressionLabels(result_vector);

		return result;
	}

}

bool CGaussianProcessRegression::train_machine(CFeatures* data)
{
	return false;
}

SGVector<float64_t> CGaussianProcessRegression::get_mean_vector()
{

	SGVector<float64_t> alpha = m_method->get_alpha();

	CMeanFunction* mean_function = m_method->get_mean();

	SGMatrix<float64_t> features;
	if(m_data->get_feature_class() == C_COMBINED)
	{
		SG_WARNING("%s::get_mean_vector(): This only works for combined"
				" features which all share the same underlying object!\n",
				get_name());
		features = ((CDotFeatures*)((CCombinedFeatures*)m_data)->
									get_first_feature_obj())->
											get_computed_dot_feature_matrix();
	}

	else
	{
		features = ((CDotFeatures*)m_data)->
			get_computed_dot_feature_matrix();
	}

	REQUIRE(mean_function, "%s::get_mean_vector(): Mean function is NULL!\n",
			get_name());

	SGVector<float64_t> means = mean_function->get_mean_vector(features);
	SGVector< float64_t > result_vector(features.num_cols);

	/* create eigen3 views an multiply */
	Map<MatrixXd> K(m_k_trts.matrix, m_k_trts.num_rows, m_k_trts.num_cols);
	Map<VectorXd> a(alpha.vector, alpha.vlen);
	Map<VectorXd> r(result_vector.vector, result_vector.vlen);
	r=K.transpose()*a;

	for (index_t i = 0; i < result_vector.vlen; i++)
		result_vector[i] += means[i];

	CLikelihoodModel* lik = m_method->get_model();

	result_vector = lik->evaluate_means(result_vector);

	SG_UNREF(lik);
	SG_UNREF(mean_function);

	return result_vector;
}

SGVector<float64_t> CGaussianProcessRegression::get_covariance_vector()
{

	if (!m_data)
		SG_ERROR("No testing features!\n")

	SGVector<float64_t> diagonal = m_method->get_diagonal_vector();

	if (diagonal.vlen > 0)
	{
		SGVector<float64_t> diagonal2(m_data->get_num_vectors());

		SGMatrix<float64_t> temp1(m_data->get_num_vectors(), diagonal.vlen);

		SGMatrix<float64_t> m_L = m_method->get_cholesky();

		SGMatrix<float64_t> temp2(m_L.num_rows, m_L.num_cols);

		for (index_t i = 0; i < diagonal.vlen; i++)
		{
			for (index_t j = 0; j < m_data->get_num_vectors(); j++)
				temp1(j,i) = diagonal[i]*m_k_trts(j,i);
		}

		for (index_t i = 0; i < diagonal2.vlen; i++)
			diagonal2[i] = 0;

		memcpy(temp2.matrix, m_L.matrix,
				m_L.num_cols*m_L.num_rows*sizeof(float64_t));

		temp2.transpose_matrix(temp2.matrix, temp2.num_rows, temp2.num_cols);

		SGVector<int32_t> ipiv(temp2.num_cols);

		//Solve L^T V = K(Train,Test)*Diagonal Vector Entries for V
		clapack_dgetrf(CblasColMajor, temp2.num_rows, temp2.num_cols,
				temp2.matrix, temp2.num_cols, ipiv.vector);

		clapack_dgetrs(CblasColMajor, CblasNoTrans,
				temp2.num_rows, temp1.num_cols, temp2.matrix,
				temp2.num_cols, ipiv.vector, temp1.matrix,
				temp1.num_cols);

		for (index_t i = 0; i < temp1.num_rows; i++)
		{
			for (index_t j = 0; j < temp1.num_cols; j++)
				temp1(i,j) = temp1(i,j)*temp1(i,j);
		}

		for (index_t i = 0; i < temp1.num_cols; i++)
		{
			diagonal2[i] = 0;

			for (index_t j = 0; j < temp1.num_rows; j++)
				diagonal2[i] += temp1(j,i);
		}

		SGVector<float64_t> result(m_k_tsts.num_cols);

		//Subtract V from K(Test,Test) to get covariances.
		for (index_t i = 0; i < m_k_tsts.num_cols; i++)
			result[i] = m_k_tsts(i,i) - diagonal2[i];

		CLikelihoodModel* lik = m_method->get_model();

		SG_UNREF(lik);

		return lik->evaluate_variances(result);
	}

	else
	{
		SGMatrix<float64_t> m_L = m_method->get_cholesky();

		SGMatrix<float64_t> temp1(m_k_trts.num_rows, m_k_trts.num_cols);
		SGMatrix<float64_t> temp2(m_L.num_rows, m_L.num_cols);

		memcpy(temp1.matrix, m_k_trts.matrix,
				m_k_trts.num_cols*m_k_trts.num_rows*sizeof(float64_t));

		memcpy(temp2.matrix, m_L.matrix,
				m_L.num_cols*m_L.num_rows*sizeof(float64_t));

		cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, m_L.num_rows,
				m_k_trts.num_cols, m_L.num_rows, 1.0, m_L.matrix, m_L.num_cols,
				m_k_trts.matrix, m_k_trts.num_cols, 0.0, temp1.matrix,
				temp1.num_cols);

		for (index_t i = 0; i < temp1.num_rows; i++)
		{
			for (index_t j = 0; j < temp1.num_cols; j++)
				temp1(i,j) *= m_k_trts(i,j);
		}

		SGVector<float64_t> temp3(temp2.num_cols);

		for (index_t i = 0; i < temp1.num_cols; i++)
		{
			float64_t sum = 0;
			for (index_t j = 0; j < temp1.num_rows; j++)
				sum += temp1(j,i);
			temp3[i] = sum;
		}

		SGVector<float64_t> result(m_k_tsts.num_cols);

		for (index_t i = 0; i < m_k_tsts.num_cols; i++)
			result[i] = m_k_tsts(i,i) + temp3[i];

		CLikelihoodModel* lik = m_method->get_model();

		SG_UNREF(lik);

		return lik->evaluate_variances(result);
	}
}

CGaussianProcessRegression::~CGaussianProcessRegression()
{
	SG_UNREF(m_features);
	SG_UNREF(m_method);
	SG_UNREF(m_data);
}

void CGaussianProcessRegression::set_kernel(CKernel* k)
{
	m_method->set_kernel(k);
}

bool CGaussianProcessRegression::load(FILE* srcfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}

CKernel* CGaussianProcessRegression::get_kernel()
{
	return m_method->get_kernel();
}

bool CGaussianProcessRegression::save(FILE* dstfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}
#endif
#endif
<|endoftext|>


<commit_before>m#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  imshow("webcam", image);

// thresholds on dark regions

  Mat black, blurred_gray, threshold_gray;
  cvtColor(image, black, CV_BGR2GRAY);
  blur(black, blurred_gray, Size(width/4.5,height/9));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);

  threshold(blurred_gray, threshold_gray, 220, 255, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat topHat;
  Mat kernel = Mat::ones(15,15,CV_8UC1);
  morphologyEx(black, topHat, MORPH_TOPHAT, kernel);
  imshow("tophat", topHat);

/*
  split(image, channel);
  channel[0] = channel[0].mul(black);
  channel[1] = channel[1].mul(black);
  channel[2] = channel[2].mul(black);
  merge(channel, 3, image);
*/
//  imshow("yox", image);

//do some weird morphological closing thing
//  Mat channel[3];

/*
  Mat canny;
  Canny(image, canny, 0, 50);
  imshow("canny", canny);
*/

/*
  Mat fill = image.clone();
  Point seed(rand()%width, rand()%height);
  floodFill(fill, seed, Scalar(200,0,0), 0, Scalar(0,0,0), Scalar(25,25,25));
  imshow("fill", fill);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  imshow("webcam", image);

// thresholds on dark regions

  Mat black, blurred_gray, threshold_gray;
  cvtColor(image, black, CV_BGR2GRAY);
  blur(black, blurred_gray, Size(width/4.5,height/9));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);

  threshold(blurred_gray, threshold_gray, 220, 255, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat topHat;
  Mat kernel = Mat::ones(15,15,CV_8UC1);
  morphologyEx(black, topHat, MORPH_TOPHAT, kernel);
  imshow("tophat", topHat);

/*
  split(image, channel);
  channel[0] = channel[0].mul(black);
  channel[1] = channel[1].mul(black);
  channel[2] = channel[2].mul(black);
  merge(channel, 3, image);
*/
//  imshow("yox", image);

//do some weird morphological closing thing
//  Mat channel[3];

/*
  Mat canny;
  Canny(image, canny, 0, 50);
  imshow("canny", canny);
*/

/*
  Mat fill = image.clone();
  Point seed(rand()%width, rand()%height);
  floodFill(fill, seed, Scalar(200,0,0), 0, Scalar(0,0,0), Scalar(25,25,25));
  imshow("fill", fill);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2019 Carsten Burstedde, Donna Calhoun, Scott Aiton, Grady Wright
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.

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 HOLDER 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 "fc2d_multigrid.h"
#include "fc2d_multigrid_options.h"
#include "fc2d_multigrid_vector.hpp"

#include <fclaw2d_elliptic_solver.h>

#include <fclaw2d_clawpatch.h>
#include <fclaw2d_clawpatch_options.h>
#include <fclaw2d_clawpatch_output_ascii.h>
#include <fclaw2d_clawpatch_output_vtk.h>

#include <fclaw2d_global.h>
#include <fclaw2d_patch.h>
#include <fclaw2d_vtable.h>

#include <p4est_bits.h>
#include <p4est_wrap.h>

#include <Thunderegg/BiCGStab.h>
#include <Thunderegg/BilinearInterpolator.h>
#include <Thunderegg/FivePtPatchOperator.h>
#include <Thunderegg/GMG/CycleFactory2d.h>
#include <Thunderegg/Operators/SchurDomainOp.h>
#include <Thunderegg/P4estDCG.h>
#include <Thunderegg/PatchSolvers/FftwPatchSolver.h>
using namespace std;
extern "C" {
void fc2d_multigrid_solve(fclaw2d_global_t *glob) {
    // this should be moved somewhere else
    PetscInitialize(nullptr, nullptr, nullptr, nullptr);

    // create thunderegg vector for eqn 0
    std::shared_ptr<Vector<2>> f(new fc2d_multigrid_vector(glob, 0));

    // get patch size
    fclaw2d_clawpatch_options_t *clawpatch_opt =
        fclaw2d_clawpatch_get_options(glob);
    std::array<int, 2> ns = {clawpatch_opt->mx, clawpatch_opt->my};

    // get p4est structure
    fclaw2d_domain_t *domain = glob->domain;
    p4est_wrap_t *wrap = (p4est_wrap_t *)domain->pp;

    // generates levels of patches for GMG
    shared_ptr<P4estDCG> dcg(new P4estDCG(wrap->p4est, ns));

    // get finest level
    shared_ptr<DomainCollection<2>> dc = dcg->getFinestDC();

    // define operators for problems
    // set the patch solver
    shared_ptr<PatchSolver<2>> solver(new FftwPatchSolver<2>(*dc));

    // patch operator
    shared_ptr<PatchOperator<2>> op(new FivePtPatchOperator());

    // interface interpolator
    shared_ptr<IfaceInterp<2>> interp(new BilinearInterpolator());

    // create SchurHelper
    shared_ptr<SchurHelper<2>> sh(new SchurHelper<2>(dc, solver, op, interp));

    // create matrix
    shared_ptr<Operator<2>> A(new SchurDomainOp<2>(sh));

    // create gmg preconditioner
    shared_ptr<Operator<2>> M =
        GMG::CycleFactory2d::getCycle("gmg.json", dcg, solver, op, interp);

    // solve
    shared_ptr<VectorGenerator<2>> vg(new DomainCollectionVG<2>(dc));
    shared_ptr<Vector<2>> u = vg->getNewVector();

    int its = BiCGStab<2>::solve(vg, A, u, f, M);

    printf("Iterations: %i\n", its);
    printf("f-2norm: %f\n", f->twoNorm());
    printf("f-infnorm: %f\n", f->infNorm());
    printf("u-2norm: %f\n", u->twoNorm());
    printf("u-infnorm: %f\n\n", u->infNorm());

    // copy solution into rhs
    f->copy(u);
    printf("Checking if copy function works:\n");
    printf("fcopy-2norm: %f\n", f->twoNorm());
    printf("fcopy-infnorm: %f\n\n", f->infNorm());
}
}
<commit_msg>(multigrid) Add parallel logging<commit_after>/*
Copyright (c) 2019 Carsten Burstedde, Donna Calhoun, Scott Aiton, Grady Wright
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.

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 HOLDER 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 "fc2d_multigrid.h"
#include "fc2d_multigrid_options.h"
#include "fc2d_multigrid_vector.hpp"

#include <fclaw2d_elliptic_solver.h>

#include <fclaw2d_clawpatch.h>
#include <fclaw2d_clawpatch_options.h>
#include <fclaw2d_clawpatch_output_ascii.h>
#include <fclaw2d_clawpatch_output_vtk.h>

#include <fclaw2d_global.h>
#include <fclaw2d_patch.h>
#include <fclaw2d_vtable.h>

#include <p4est_bits.h>
#include <p4est_wrap.h>

#include <Thunderegg/BiCGStab.h>
#include <Thunderegg/BilinearInterpolator.h>
#include <Thunderegg/FivePtPatchOperator.h>
#include <Thunderegg/GMG/CycleFactory2d.h>
#include <Thunderegg/Operators/SchurDomainOp.h>
#include <Thunderegg/P4estDCG.h>
#include <Thunderegg/PatchSolvers/FftwPatchSolver.h>
using namespace std;
extern "C" {
void fc2d_multigrid_solve(fclaw2d_global_t *glob) {
    // this should be moved somewhere else
    PetscInitialize(nullptr, nullptr, nullptr, nullptr);

    // create thunderegg vector for eqn 0
    std::shared_ptr<Vector<2>> f(new fc2d_multigrid_vector(glob, 0));

    // get patch size
    fclaw2d_clawpatch_options_t *clawpatch_opt =
        fclaw2d_clawpatch_get_options(glob);
    std::array<int, 2> ns = {clawpatch_opt->mx, clawpatch_opt->my};

    // get p4est structure
    fclaw2d_domain_t *domain = glob->domain;
    p4est_wrap_t *wrap = (p4est_wrap_t *)domain->pp;

    // generates levels of patches for GMG
    shared_ptr<P4estDCG> dcg(new P4estDCG(wrap->p4est, ns));

    // get finest level
    shared_ptr<DomainCollection<2>> dc = dcg->getFinestDC();

    // define operators for problems
    // set the patch solver
    shared_ptr<PatchSolver<2>> solver(new FftwPatchSolver<2>(*dc));

    // patch operator
    shared_ptr<PatchOperator<2>> op(new FivePtPatchOperator());

    // interface interpolator
    shared_ptr<IfaceInterp<2>> interp(new BilinearInterpolator());

    // create SchurHelper
    shared_ptr<SchurHelper<2>> sh(new SchurHelper<2>(dc, solver, op, interp));

    // create matrix
    shared_ptr<Operator<2>> A(new SchurDomainOp<2>(sh));

    // create gmg preconditioner
    shared_ptr<Operator<2>> M =
        GMG::CycleFactory2d::getCycle("gmg.json", dcg, solver, op, interp);

    // solve
    shared_ptr<VectorGenerator<2>> vg(new DomainCollectionVG<2>(dc));
    shared_ptr<Vector<2>> u = vg->getNewVector();

    int its = BiCGStab<2>::solve(vg, A, u, f, M);

    fclaw_global_productionf("Iterations: %i\n", its);
    fclaw_global_productionf("f-2norm: %f\n", f->twoNorm());
    fclaw_global_productionf("f-infnorm: %f\n", f->infNorm());
    fclaw_global_productionf("u-2norm: %f\n", u->twoNorm());
    fclaw_global_productionf("u-infnorm: %f\n\n", u->infNorm());

    // copy solution into rhs
    f->copy(u);
    fclaw_global_productionf("Checking if copy function works:\n");
    fclaw_global_productionf("fcopy-2norm: %f\n", f->twoNorm());
    fclaw_global_productionf("fcopy-infnorm: %f\n\n", f->infNorm());
}
}
<|endoftext|>


<commit_before>#include "physics/barycentric_rotating_dynamic_frame.hpp"

#include <memory>

#include "astronomy/frames.hpp"
#include "geometry/frame.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/rotation.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "integrators/symplectic_runge_kutta_nyström_integrator.hpp"
#include "physics/ephemeris.hpp"
#include "physics/mock_continuous_trajectory.hpp"
#include "physics/mock_ephemeris.hpp"
#include "physics/solar_system.hpp"
#include "quantities/constants.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using astronomy::ICRFJ2000Equator;
using geometry::Bivector;
using geometry::Instant;
using geometry::Rotation;
using geometry::Vector;
using quantities::Time;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;
using quantities::si::Radian;
using quantities::si::Second;
using testing_utilities::AbsoluteError;
using testing_utilities::AlmostEquals;
using ::testing::InSequence;
using ::testing::Lt;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::_;

namespace physics {

namespace {

constexpr char kBig[] = "Big";
constexpr char kSmall[] = "Small";

}  // namespace

class BarycentricRotatingDynamicFrameTest : public ::testing::Test {
 protected:
  // The rotating frame centred on the barycentre of the two bodies.
  using BigSmallFrame = Frame<serialization::Frame::TestTag,
                              serialization::Frame::TEST, false /*inertial*/>;
  using MockFrame = Frame<serialization::Frame::TestTag,
                          serialization::Frame::TEST1, false /*inertial*/>;

  BarycentricRotatingDynamicFrameTest()
      : period_(10 * π * sqrt(5.0 / 7.0) * Second),
        centre_of_mass_initial_state_(Position<ICRFJ2000Equator>(),
                                      Velocity<ICRFJ2000Equator>()),
        big_initial_state_(Position<ICRFJ2000Equator>(),
                           Velocity<ICRFJ2000Equator>()),
        small_initial_state_(Position<ICRFJ2000Equator>(),
                             Velocity<ICRFJ2000Equator>()) {
    solar_system_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model_two_bodies_test.proto.txt",
        SOLUTION_DIR / "astronomy" / "initial_state_two_bodies_test.proto.txt");
    t0_ = solar_system_.epoch();
    ephemeris_ = solar_system_.MakeEphemeris(
                     integrators::McLachlanAtela1992Order4Optimal<
                         Position<ICRFJ2000Equator>>(),
                     10 * Milli(Second),
                     1 * Milli(Metre));
    ephemeris_->Prolong(t0_ + 2 * period_);
    big_initial_state_ = solar_system_.initial_state(kBig);
    big_gravitational_parameter_ = solar_system_.gravitational_parameter(kBig);
    small_initial_state_ = solar_system_.initial_state(kSmall);
    small_gravitational_parameter_ =
        solar_system_.gravitational_parameter(kSmall);
    centre_of_mass_initial_state_ =
        Barycentre<ICRFJ2000Equator, GravitationalParameter>(
            {big_initial_state_, small_initial_state_},
            {big_gravitational_parameter_, small_gravitational_parameter_});
    big_small_frame_ =
        std::make_unique<
            BarycentricRotatingDynamicFrame<ICRFJ2000Equator, BigSmallFrame>>(
                ephemeris_.get(),
                solar_system_.massive_body(*ephemeris_, kBig),
                solar_system_.massive_body(*ephemeris_, kSmall));

    mock_ephemeris_ =
       std::make_unique<StrictMock<MockEphemeris<ICRFJ2000Equator>>>();
    EXPECT_CALL(*mock_ephemeris_,
                trajectory(solar_system_.massive_body(*ephemeris_, kBig)))
        .WillOnce(Return(&mock_big_trajectory_));
    EXPECT_CALL(*mock_ephemeris_,
                trajectory(solar_system_.massive_body(*ephemeris_, kSmall)))
        .WillOnce(Return(&mock_small_trajectory_));
    mock_frame_ =
        std::make_unique<
            BarycentricRotatingDynamicFrame<ICRFJ2000Equator, MockFrame>>(
                mock_ephemeris_.get(),
                solar_system_.massive_body(*ephemeris_, kBig),
                solar_system_.massive_body(*ephemeris_, kSmall));
  }

  Time const period_;
  Instant t0_;
  DegreesOfFreedom<ICRFJ2000Equator> centre_of_mass_initial_state_;
  DegreesOfFreedom<ICRFJ2000Equator> big_initial_state_;
  DegreesOfFreedom<ICRFJ2000Equator> small_initial_state_;
  GravitationalParameter big_gravitational_parameter_;
  GravitationalParameter small_gravitational_parameter_;
  std::unique_ptr<BarycentricRotatingDynamicFrame<ICRFJ2000Equator,
                  BigSmallFrame>> big_small_frame_;
  std::unique_ptr<Ephemeris<ICRFJ2000Equator>> ephemeris_;
  SolarSystem<ICRFJ2000Equator> solar_system_;

  MockContinuousTrajectory<ICRFJ2000Equator> mock_big_trajectory_;
  MockContinuousTrajectory<ICRFJ2000Equator> mock_small_trajectory_;
  std::unique_ptr<BarycentricRotatingDynamicFrame<ICRFJ2000Equator,
                  MockFrame>> mock_frame_;
  std::unique_ptr<StrictMock<MockEphemeris<ICRFJ2000Equator>>> mock_ephemeris_;
};

TEST_F(BarycentricRotatingDynamicFrameTest, ToBigSmallFrameAtTime) {
  int const kSteps = 100;

  ContinuousTrajectory<ICRFJ2000Equator>::Hint big_hint;
  ContinuousTrajectory<ICRFJ2000Equator>::Hint small_hint;
  for (Instant t = t0_; t < t0_ + 1 * period_; t += period_ / kSteps) {
    auto const to_big_small_frame_at_t = big_small_frame_->ToThisFrameAtTime(t);

    // Check that the centre of mass is at the origin and doesn't move.
    DegreesOfFreedom<BigSmallFrame> const centre_of_mass_in_big_small_at_t =
        to_big_small_frame_at_t(centre_of_mass_initial_state_);
    EXPECT_THAT(AbsoluteError(centre_of_mass_in_big_small_at_t.position() -
                                  BigSmallFrame::origin,
                              Displacement<BigSmallFrame>()),
                Lt(1.0E-11 * Metre));
    EXPECT_THAT(AbsoluteError(centre_of_mass_in_big_small_at_t.velocity(),
                              Velocity<BigSmallFrame>()),
                Lt(1.0E-11 * Metre / Second));

    // Check that the bodies don't move and are at the right locations.
    DegreesOfFreedom<ICRFJ2000Equator> const big_in_inertial_frame_at_t =
        solar_system_.trajectory(*ephemeris_, kBig).
            EvaluateDegreesOfFreedom(t, &big_hint);
    DegreesOfFreedom<ICRFJ2000Equator> const small_in_inertial_frame_at_t =
        solar_system_.trajectory(*ephemeris_, kSmall).
            EvaluateDegreesOfFreedom(t, &small_hint);

    DegreesOfFreedom<BigSmallFrame> const big_in_big_small_at_t =
        to_big_small_frame_at_t(big_in_inertial_frame_at_t);
    DegreesOfFreedom<BigSmallFrame> const small_in_big_small_at_t =
        to_big_small_frame_at_t(small_in_inertial_frame_at_t);
    EXPECT_THAT(AbsoluteError(big_in_big_small_at_t.position() -
                                  BigSmallFrame::origin,
                              Displacement<BigSmallFrame>({
                                  15.0 / 7.0 * Kilo(Metre),
                                  0 * Kilo(Metre),
                                  0 * Kilo(Metre)})),
                Lt(1.0E-6 * Metre));
    EXPECT_THAT(AbsoluteError(big_in_big_small_at_t.velocity(),
                              Velocity<BigSmallFrame>()),
                Lt(1.0E-4 * Metre / Second));
    EXPECT_THAT(AbsoluteError(small_in_big_small_at_t.position() -
                                  BigSmallFrame::origin,
                              Displacement<BigSmallFrame>({
                                  -20.0 / 7.0 * Kilo(Metre),
                                  0 * Kilo(Metre),
                                  0 * Kilo(Metre)})),
                Lt(1.0E-5 * Metre));
    EXPECT_THAT(AbsoluteError(small_in_big_small_at_t.velocity(),
                              Velocity<BigSmallFrame>()),
                Lt(1.0E-4 * Metre / Second));
  }
}

TEST_F(BarycentricRotatingDynamicFrameTest, Inverse) {
  int const kSteps = 100;
  for (Instant t = t0_; t < t0_ + 1 * period_; t += period_ / kSteps) {
    auto const from_big_small_frame_at_t =
        big_small_frame_->FromThisFrameAtTime(t);
    auto const to_big_small_frame_at_t = big_small_frame_->ToThisFrameAtTime(t);
    auto const small_initial_state_transformed_and_back =
        from_big_small_frame_at_t(to_big_small_frame_at_t(
            small_initial_state_));
    EXPECT_THAT(
        AbsoluteError(small_initial_state_transformed_and_back.position() -
                          ICRFJ2000Equator::origin,
                      small_initial_state_.position() -
                          ICRFJ2000Equator::origin),
        Lt(1.0E-11 * Metre));
    EXPECT_THAT(
        AbsoluteError(small_initial_state_transformed_and_back.velocity(),
                      small_initial_state_.velocity()),
        Lt(1.0E-11 * Metre / Second));
  }
}

TEST_F(BarycentricRotatingDynamicFrameTest, CentrifugalAcceleration) {
  Instant const t = t0_ + 0 * Second;
  DegreesOfFreedom<MockFrame> point_dof =
      {Displacement<MockFrame>({1 * Metre, 0 * Metre, 0 * Metre}) +
           MockFrame::origin,
       Velocity<MockFrame>({1 * Metre / Second,
                            0 * Metre / Second,
                            0 * Metre / Second})};
  DegreesOfFreedom<ICRFJ2000Equator> big_dof =
      {Displacement<ICRFJ2000Equator>({2 * Metre, 0 * Metre, 0 * Metre}) +
           ICRFJ2000Equator::origin,
       Velocity<ICRFJ2000Equator>({2 * Metre / Second,
                                   2 * Metre / Second,
                                   0 * Metre / Second})};
  DegreesOfFreedom<ICRFJ2000Equator> small_dof =
      {Displacement<ICRFJ2000Equator>({1 * Metre, 0 * Metre, 0 * Metre}) +
           ICRFJ2000Equator::origin,
       Velocity<ICRFJ2000Equator>({1 * Metre / Second,
                                   1 * Metre / Second,
                                   0 * Metre / Second})};
  DegreesOfFreedom<ICRFJ2000Equator> const barycentre_dof =
      Barycentre<ICRFJ2000Equator, GravitationalParameter>(
          {big_dof, small_dof},
          {big_gravitational_parameter_, small_gravitational_parameter_});

  EXPECT_CALL(mock_big_trajectory_, EvaluateDegreesOfFreedom(t, _))
      .Times(2)
      .WillRepeatedly(Return(big_dof));
  EXPECT_CALL(mock_small_trajectory_, EvaluateDegreesOfFreedom(t, _))
      .Times(2)
      .WillRepeatedly(Return(small_dof));
  {
    InSequence s;
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(big_dof.position(), t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(small_dof.position(), t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(_, t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(barycentre_dof.position(), t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
  }

  auto const actual = mock_frame_->GeometricAcceleration(t, point_dof);
}

}  // namespace physics
}  // namespace principia
<commit_msg>Strict all the mocks.<commit_after>#include "physics/barycentric_rotating_dynamic_frame.hpp"

#include <memory>

#include "astronomy/frames.hpp"
#include "geometry/frame.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/rotation.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "integrators/symplectic_runge_kutta_nyström_integrator.hpp"
#include "physics/ephemeris.hpp"
#include "physics/mock_continuous_trajectory.hpp"
#include "physics/mock_ephemeris.hpp"
#include "physics/solar_system.hpp"
#include "quantities/constants.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using astronomy::ICRFJ2000Equator;
using geometry::Bivector;
using geometry::Instant;
using geometry::Rotation;
using geometry::Vector;
using quantities::Time;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;
using quantities::si::Radian;
using quantities::si::Second;
using testing_utilities::AbsoluteError;
using testing_utilities::AlmostEquals;
using ::testing::InSequence;
using ::testing::Lt;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::_;

namespace physics {

namespace {

constexpr char kBig[] = "Big";
constexpr char kSmall[] = "Small";

}  // namespace

class BarycentricRotatingDynamicFrameTest : public ::testing::Test {
 protected:
  // The rotating frame centred on the barycentre of the two bodies.
  using BigSmallFrame = Frame<serialization::Frame::TestTag,
                              serialization::Frame::TEST, false /*inertial*/>;
  using MockFrame = Frame<serialization::Frame::TestTag,
                          serialization::Frame::TEST1, false /*inertial*/>;

  BarycentricRotatingDynamicFrameTest()
      : period_(10 * π * sqrt(5.0 / 7.0) * Second),
        centre_of_mass_initial_state_(Position<ICRFJ2000Equator>(),
                                      Velocity<ICRFJ2000Equator>()),
        big_initial_state_(Position<ICRFJ2000Equator>(),
                           Velocity<ICRFJ2000Equator>()),
        small_initial_state_(Position<ICRFJ2000Equator>(),
                             Velocity<ICRFJ2000Equator>()) {
    solar_system_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model_two_bodies_test.proto.txt",
        SOLUTION_DIR / "astronomy" / "initial_state_two_bodies_test.proto.txt");
    t0_ = solar_system_.epoch();
    ephemeris_ = solar_system_.MakeEphemeris(
                     integrators::McLachlanAtela1992Order4Optimal<
                         Position<ICRFJ2000Equator>>(),
                     10 * Milli(Second),
                     1 * Milli(Metre));
    ephemeris_->Prolong(t0_ + 2 * period_);
    big_initial_state_ = solar_system_.initial_state(kBig);
    big_gravitational_parameter_ = solar_system_.gravitational_parameter(kBig);
    small_initial_state_ = solar_system_.initial_state(kSmall);
    small_gravitational_parameter_ =
        solar_system_.gravitational_parameter(kSmall);
    centre_of_mass_initial_state_ =
        Barycentre<ICRFJ2000Equator, GravitationalParameter>(
            {big_initial_state_, small_initial_state_},
            {big_gravitational_parameter_, small_gravitational_parameter_});
    big_small_frame_ =
        std::make_unique<
            BarycentricRotatingDynamicFrame<ICRFJ2000Equator, BigSmallFrame>>(
                ephemeris_.get(),
                solar_system_.massive_body(*ephemeris_, kBig),
                solar_system_.massive_body(*ephemeris_, kSmall));

    mock_ephemeris_ =
       std::make_unique<StrictMock<MockEphemeris<ICRFJ2000Equator>>>();
    EXPECT_CALL(*mock_ephemeris_,
                trajectory(solar_system_.massive_body(*ephemeris_, kBig)))
        .WillOnce(Return(&mock_big_trajectory_));
    EXPECT_CALL(*mock_ephemeris_,
                trajectory(solar_system_.massive_body(*ephemeris_, kSmall)))
        .WillOnce(Return(&mock_small_trajectory_));
    mock_frame_ =
        std::make_unique<
            StrictMock<BarycentricRotatingDynamicFrame<ICRFJ2000Equator,
                       MockFrame>>>(
                mock_ephemeris_.get(),
                solar_system_.massive_body(*ephemeris_, kBig),
                solar_system_.massive_body(*ephemeris_, kSmall));
  }

  Time const period_;
  Instant t0_;
  DegreesOfFreedom<ICRFJ2000Equator> centre_of_mass_initial_state_;
  DegreesOfFreedom<ICRFJ2000Equator> big_initial_state_;
  DegreesOfFreedom<ICRFJ2000Equator> small_initial_state_;
  GravitationalParameter big_gravitational_parameter_;
  GravitationalParameter small_gravitational_parameter_;
  std::unique_ptr<BarycentricRotatingDynamicFrame<ICRFJ2000Equator,
                  BigSmallFrame>> big_small_frame_;
  std::unique_ptr<Ephemeris<ICRFJ2000Equator>> ephemeris_;
  SolarSystem<ICRFJ2000Equator> solar_system_;

  StrictMock<MockContinuousTrajectory<ICRFJ2000Equator>> mock_big_trajectory_;
  StrictMock<MockContinuousTrajectory<ICRFJ2000Equator>> mock_small_trajectory_;
  std::unique_ptr<StrictMock<BarycentricRotatingDynamicFrame<ICRFJ2000Equator,
                             MockFrame>>> mock_frame_;
  std::unique_ptr<StrictMock<MockEphemeris<ICRFJ2000Equator>>> mock_ephemeris_;
};

TEST_F(BarycentricRotatingDynamicFrameTest, ToBigSmallFrameAtTime) {
  int const kSteps = 100;

  ContinuousTrajectory<ICRFJ2000Equator>::Hint big_hint;
  ContinuousTrajectory<ICRFJ2000Equator>::Hint small_hint;
  for (Instant t = t0_; t < t0_ + 1 * period_; t += period_ / kSteps) {
    auto const to_big_small_frame_at_t = big_small_frame_->ToThisFrameAtTime(t);

    // Check that the centre of mass is at the origin and doesn't move.
    DegreesOfFreedom<BigSmallFrame> const centre_of_mass_in_big_small_at_t =
        to_big_small_frame_at_t(centre_of_mass_initial_state_);
    EXPECT_THAT(AbsoluteError(centre_of_mass_in_big_small_at_t.position() -
                                  BigSmallFrame::origin,
                              Displacement<BigSmallFrame>()),
                Lt(1.0E-11 * Metre));
    EXPECT_THAT(AbsoluteError(centre_of_mass_in_big_small_at_t.velocity(),
                              Velocity<BigSmallFrame>()),
                Lt(1.0E-11 * Metre / Second));

    // Check that the bodies don't move and are at the right locations.
    DegreesOfFreedom<ICRFJ2000Equator> const big_in_inertial_frame_at_t =
        solar_system_.trajectory(*ephemeris_, kBig).
            EvaluateDegreesOfFreedom(t, &big_hint);
    DegreesOfFreedom<ICRFJ2000Equator> const small_in_inertial_frame_at_t =
        solar_system_.trajectory(*ephemeris_, kSmall).
            EvaluateDegreesOfFreedom(t, &small_hint);

    DegreesOfFreedom<BigSmallFrame> const big_in_big_small_at_t =
        to_big_small_frame_at_t(big_in_inertial_frame_at_t);
    DegreesOfFreedom<BigSmallFrame> const small_in_big_small_at_t =
        to_big_small_frame_at_t(small_in_inertial_frame_at_t);
    EXPECT_THAT(AbsoluteError(big_in_big_small_at_t.position() -
                                  BigSmallFrame::origin,
                              Displacement<BigSmallFrame>({
                                  15.0 / 7.0 * Kilo(Metre),
                                  0 * Kilo(Metre),
                                  0 * Kilo(Metre)})),
                Lt(1.0E-6 * Metre));
    EXPECT_THAT(AbsoluteError(big_in_big_small_at_t.velocity(),
                              Velocity<BigSmallFrame>()),
                Lt(1.0E-4 * Metre / Second));
    EXPECT_THAT(AbsoluteError(small_in_big_small_at_t.position() -
                                  BigSmallFrame::origin,
                              Displacement<BigSmallFrame>({
                                  -20.0 / 7.0 * Kilo(Metre),
                                  0 * Kilo(Metre),
                                  0 * Kilo(Metre)})),
                Lt(1.0E-5 * Metre));
    EXPECT_THAT(AbsoluteError(small_in_big_small_at_t.velocity(),
                              Velocity<BigSmallFrame>()),
                Lt(1.0E-4 * Metre / Second));
  }
}

TEST_F(BarycentricRotatingDynamicFrameTest, Inverse) {
  int const kSteps = 100;
  for (Instant t = t0_; t < t0_ + 1 * period_; t += period_ / kSteps) {
    auto const from_big_small_frame_at_t =
        big_small_frame_->FromThisFrameAtTime(t);
    auto const to_big_small_frame_at_t = big_small_frame_->ToThisFrameAtTime(t);
    auto const small_initial_state_transformed_and_back =
        from_big_small_frame_at_t(to_big_small_frame_at_t(
            small_initial_state_));
    EXPECT_THAT(
        AbsoluteError(small_initial_state_transformed_and_back.position() -
                          ICRFJ2000Equator::origin,
                      small_initial_state_.position() -
                          ICRFJ2000Equator::origin),
        Lt(1.0E-11 * Metre));
    EXPECT_THAT(
        AbsoluteError(small_initial_state_transformed_and_back.velocity(),
                      small_initial_state_.velocity()),
        Lt(1.0E-11 * Metre / Second));
  }
}

TEST_F(BarycentricRotatingDynamicFrameTest, CentrifugalAcceleration) {
  Instant const t = t0_ + 0 * Second;
  DegreesOfFreedom<MockFrame> const point_dof =
      {Displacement<MockFrame>({1 * Metre, 0 * Metre, 0 * Metre}) +
           MockFrame::origin,
       Velocity<MockFrame>({1 * Metre / Second,
                            0 * Metre / Second,
                            0 * Metre / Second})};
  DegreesOfFreedom<ICRFJ2000Equator> const big_dof =
      {Displacement<ICRFJ2000Equator>({2 * Metre, 0 * Metre, 0 * Metre}) +
           ICRFJ2000Equator::origin,
       Velocity<ICRFJ2000Equator>({2 * Metre / Second,
                                   2 * Metre / Second,
                                   0 * Metre / Second})};
  DegreesOfFreedom<ICRFJ2000Equator> const small_dof =
      {Displacement<ICRFJ2000Equator>({1 * Metre, 0 * Metre, 0 * Metre}) +
           ICRFJ2000Equator::origin,
       Velocity<ICRFJ2000Equator>({1 * Metre / Second,
                                   1 * Metre / Second,
                                   0 * Metre / Second})};
  DegreesOfFreedom<ICRFJ2000Equator> const barycentre_dof =
      Barycentre<ICRFJ2000Equator, GravitationalParameter>(
          {big_dof, small_dof},
          {big_gravitational_parameter_, small_gravitational_parameter_});

  EXPECT_CALL(mock_big_trajectory_, EvaluateDegreesOfFreedom(t, _))
      .Times(2)
      .WillRepeatedly(Return(big_dof));
  EXPECT_CALL(mock_small_trajectory_, EvaluateDegreesOfFreedom(t, _))
      .Times(2)
      .WillRepeatedly(Return(small_dof));
  {
    InSequence s;
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(big_dof.position(), t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(small_dof.position(), t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(_, t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
    EXPECT_CALL(*mock_ephemeris_,
                ComputeGravitationalAcceleration(barycentre_dof.position(), t))
        .WillOnce(Return(Vector<Acceleration, ICRFJ2000Equator>()));
  }

  auto const acceleration = mock_frame_->GeometricAcceleration(t, point_dof);
}

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);

  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny", (canny+threshold_gray).mul(gray));

/*
  bitwise_not(gray,gray);
  Mat mask = threshold_gray.mul(gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);

  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny", canny);

  Mat mask;
  bitwise_or(canny, threshold_gray, mask);
  Mat kernel = ones(15, 15, CV_8UC1);
  morphologyEx(mask, mask, MORPH_CLOSE, kernel, Point(-1,-1), 3);
  imshow("yo",gray.mul(mask));

/*
  bitwise_not(gray,gray);
  Mat mask = threshold_gray.mul(gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION     3
#define MINOR_VERSION     28
#define BUILD_NUMBER      36
#define PATCH_LEVEL       0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 1

// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the build system script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    SNPrintF(str, "%d.%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
             is_simulator);
  } else {
    SNPrintF(str, "%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), candidate,
             is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      SNPrintF(str, "libv8-%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<commit_msg>[Auto-roll] Bump up version to 3.28.37.0<commit_after>// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION     3
#define MINOR_VERSION     28
#define BUILD_NUMBER      37
#define PATCH_LEVEL       0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 1

// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the build system script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    SNPrintF(str, "%d.%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
             is_simulator);
  } else {
    SNPrintF(str, "%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), candidate,
             is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      SNPrintF(str, "libv8-%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012-2014 Yule Fox. All rights reserved.
 * http://www.yulefox.com/
 */

#include <elf/db.h>
#include <elf/log.h>
#include <elf/memory.h>
#include <elf/pc.h>
#include <elf/thread.h>
#include <deque>
#include <map>
#include <string>

using namespace google::protobuf;

namespace elf {
enum query_type {
    QUERY_NO_RES,       // no response
    QUERY_RAW,          // response with raw result
    QUERY_FIELD,        // response with PB field result
    QUERY_PB,           // response with PB result
};

struct query_t {
    query_type type;    // type
    std::string cmd;    // command
    oid_t oid;          // associated object id
    MYSQL_RES *data;    // query result
    pb_t *pb;           // store query data
    std::string field;  // pb field
    db_callback proc;   // callback function
    time64_t stamp;     // request time stamp
};

typedef struct mysql_thread_s {
    int idx;
    thread_t tid;
    MYSQL *mysql;
    xqueue<query_t *> req;
} mysql_thread_t;

typedef struct thread_list_s {
    int idx;
    int num;
    mysql_thread_t *threads;
}thread_list_t;

typedef std::map<int, thread_list_t*> thread_list_map;
static thread_list_map s_threads;

static const int THREAD_NUM_DEFAULT = 5;
//static const int THREAD_NUM = 5;
//static const int THREAD_INDEX[THREAD_NUM] = {0, 1, 2, 3, 4};
//static MYSQL *s_mysqls[THREAD_NUM] = {NULL, NULL, NULL, NULL};
//static MYSQL_MAP s_mysqls;
//static THREAD_MAP s_threads;
//static xqueue<query_t *> s_queue_req[THREAD_NUM];
static xqueue<query_t *> s_queue_res;

static void *handle(void *args);
static void query(mysql_thread_t *th);
static void destroy(query_t *q);
static void response(query_t *q);
static void retrieve_pb(query_t *q);
static void retrieve_field(query_t *q);

volatile int _running;

static void *handle(void *args)
{
    mysql_thread_t *self = (mysql_thread_t*)args;

    if (self == NULL) {
        LOG_ERROR("db", "Create thread failed: %s", "mysql_thread_t is NULL");
        return NULL;
    }

    while (_running) {
        query(self);
    }
    return NULL;
}

static void query(mysql_thread_t *th)
{
    query_t *q = NULL;
    MYSQL *m = th->mysql;

    try {
        th->req.pop(q);
        assert(m && q);

        // query
        int status = mysql_real_query(m, q->cmd.c_str(), q->cmd.length());

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    q->cmd.c_str(), mysql_error(m));
            destroy(q);
            return;
        }
        if (q->type == QUERY_NO_RES) {
            destroy(q);
            return;
        }

        q->data = NULL;
        do {
            MYSQL_RES *res = mysql_store_result(m);

            if (res) {
                if (q->data == NULL) {
                    q->data = res;
                    s_queue_res.push(q);
                } else {
                    mysql_free_result(res);
                }
            }
        } while (!mysql_next_result(m));
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                q->cmd.c_str(), mysql_error(m));
    }
}

static void destroy(query_t *q)
{
    assert(q);

    if (q->data) {
        mysql_free_result(q->data);
    }
    E_DELETE(q->pb);
    E_DELETE(q);
}

static void retrieve_pb(query_t *q)
{
    assert(q && q->data && q->pb);

    const Descriptor *des = q->pb->GetDescriptor();
    const int field_num = mysql_num_fields(q->data);
    const MYSQL_ROW row = mysql_fetch_row(q->data);
    size_t *len = mysql_fetch_lengths(q->data);

    for (int c = 0; c < field_num; ++c) {
        const MYSQL_FIELD *ifd = mysql_fetch_field_direct(q->data, c);
        const FieldDescriptor *ofd = des->FindFieldByName(ifd->name);

        if (ofd == NULL) {
            continue;
        }
        if (row[c] == NULL || (strlen(row[c]) == 0)) {
            pb_set_field(q->pb, ofd, "");
        } else {
            pb_set_field(q->pb, ofd, row[c], len[c]);
        }
    }
}

static void retrieve_field(query_t *q)
{
    assert(q && q->data && q->pb);

    const Reflection *ref = q->pb->GetReflection();
    const Descriptor *des = q->pb->GetDescriptor();
    const FieldDescriptor *ctn = des->FindFieldByName(q->field);
    const int row_num = mysql_num_rows(q->data);
    const int field_num = mysql_num_fields(q->data);

    assert(ctn);
    for (int r = 0; r < row_num; ++r) {
        pb_t *item = ref->AddMessage(q->pb, ctn);
        const MYSQL_ROW row = mysql_fetch_row(q->data);
        unsigned long *len = mysql_fetch_lengths(q->data);

        des = item->GetDescriptor();
        for (int c = 0; c < field_num; ++c) {
            const MYSQL_FIELD *ifd = mysql_fetch_field_direct(q->data, c);
            const FieldDescriptor *ofd =
                des->FindFieldByName(ifd->name);

            if (ofd == NULL) {
                continue;
            }
            if (row[c] == NULL || (strlen(row[c]) == 0)) {
                pb_set_field(item, ofd, "");
            } else {
                pb_set_field(item, ofd, row[c], len[c]);
            }
        }
    }
}

int db_init(void)
{
    MODULE_IMPORT_SWITCH;
    _running = 1;
    return ELF_RC_DB_OK;
}

int db_fini(void)
{
    MODULE_IMPORT_SWITCH;

    _running = 0;
    thread_list_map::iterator itr = s_threads.begin();
    for (;itr != s_threads.end(); ++itr) {
        thread_list_t *th_list = itr->second;
        for (int i = 0;i < th_list->num; ++i) {
            mysql_thread_t *th = th_list->threads + i;
            thread_fini(th->tid);
            if (th->mysql) {
                mysql_close(th->mysql);
            }
        }
        E_DELETE th_list->threads;
        E_DELETE th_list;
    }
    s_threads.clear();
    return ELF_RC_DB_OK;
}

int db_connect(int idx, const std::string &host, const std::string &user,
        const std::string &passwd, const std::string &db, unsigned int port,
        int num)
{
    if (num <= 0) {
        num = THREAD_NUM_DEFAULT;
    }
    thread_list_t *th_list = NULL;

    thread_list_map::iterator itr = s_threads.find(idx);
    if (itr != s_threads.end()) {
        th_list = itr->second;
    } else {
        th_list = E_NEW thread_list_t;
        th_list->idx = idx;
        th_list->num = num;
        th_list->threads = E_NEW mysql_thread_t[num];
        for (int i = 0;i < num; i++) {
            mysql_thread_t *th = th_list->threads + i;
            th->mysql = NULL;
        }
        s_threads[idx] = th_list;
    }

    for (int i = 0; i < num; ++i) {
        mysql_thread_t *th = NULL;
        th = th_list->threads + i;

        char value = 1;
        MYSQL * m = th->mysql;
        try {
            if (m && 0 == mysql_ping(m)) {
                return ELF_RC_DB_OK;
            }
            m = mysql_init(NULL);
            mysql_options(m, MYSQL_OPT_RECONNECT, (char *)&value);
            mysql_options(m, MYSQL_SET_CHARSET_NAME, "utf8");
            if (!mysql_real_connect(m, host.c_str(), user.c_str(),
                    passwd.c_str(), db.c_str(), port,
                    NULL, CLIENT_MULTI_STATEMENTS)) {
                LOG_ERROR("db", "Connect DB failed: %s.",
                        mysql_error(m));
                return ELF_RC_DB_INIT_FAILED;
            }
            th->mysql = m;
            th->tid = thread_init(handle, (void *)th);
        } catch(...) {
            LOG_ERROR("db", "Connect DB failed: %s.",
                    mysql_error(m));
            return ELF_RC_DB_INIT_FAILED;
        }
    }
    return ELF_RC_DB_OK;
}

int db_proc(void)
{
    if (s_threads.empty()) return -1;

    std::deque<query_t *> list;
    std::deque<query_t *>::iterator itr;

    s_queue_res.swap(list);
    for (itr = list.begin(); itr != list.end(); ++itr) {
        query_t *q = *itr;

        // object has not been destroyed
        response(q);
    }
    return 0;
}

void db_req(int idx, const char *cmd, bool sim, db_callback proc,
        oid_t oid, pb_t *out, const std::string &field)
{
    thread_list_map::iterator itr = s_threads.find(idx);
    if (itr == s_threads.end()) {
        return;
    }
    thread_list_t *th_list = itr->second;

    int tidx = 0;
    query_t *q = E_NEW query_t;

    if (proc == NULL && out == NULL) {
        q->type = QUERY_NO_RES;
    } else if (out == NULL) {
        q->type = QUERY_RAW;
    } else if (field == "") {
        q->type = QUERY_PB;
    } else {
        q->type = QUERY_FIELD;
    }
    q->cmd = cmd;
    q->stamp = time_ms();
    q->oid = oid;
    q->pb = out;
    q->field = field;
    q->proc = proc;
    q->data = NULL;
    if (sim) {
        tidx = oid % (th_list->num - 1) + 1;
    }
    mysql_thread_t *th = th_list->threads + tidx;
    th->req.push(q);
}

void response(query_t *q)
{
    assert(q);
    switch (q->type) {
        case QUERY_RAW:
            if (q->proc) {
                q->proc(q->oid, q->data);
            }
            break;
        case QUERY_PB:
            retrieve_pb(q);
            if (q->proc) {
                q->proc(q->oid, q->pb);
            }
            break;
        case QUERY_FIELD:
            retrieve_field(q);
            if (q->proc) {
                q->proc(q->oid, q->pb);
            }
            break;
        default:
            assert(0);
            break;
    }
    destroy(q);
}

size_t db_pending_size(int idx)
{
    size_t sum = 0;
    thread_list_map::iterator itr = s_threads.find(idx);
    if (itr == s_threads.end()) {
        return 0;
    }

    thread_list_t *th_list = itr->second;
    for (int i = 0;i < th_list->num; i++) {
        mysql_thread_t *th = th_list->threads + i;
        sum += th->req.size();
    }
    return sum;
}
} // namespace elf

<commit_msg>[MOD] db req<commit_after>/*
 * Copyright (C) 2012-2014 Yule Fox. All rights reserved.
 * http://www.yulefox.com/
 */

#include <elf/db.h>
#include <elf/log.h>
#include <elf/memory.h>
#include <elf/pc.h>
#include <elf/thread.h>
#include <deque>
#include <map>
#include <string>

using namespace google::protobuf;

namespace elf {
enum query_type {
    QUERY_NO_RES,       // no response
    QUERY_RAW,          // response with raw result
    QUERY_FIELD,        // response with PB field result
    QUERY_PB,           // response with PB result
};

struct query_t {
    query_type type;    // type
    std::string cmd;    // command
    oid_t oid;          // associated object id
    MYSQL_RES *data;    // query result
    pb_t *pb;           // store query data
    std::string field;  // pb field
    db_callback proc;   // callback function
    time64_t stamp;     // request time stamp
};

typedef struct mysql_thread_s {
    int idx;
    thread_t tid;
    MYSQL *mysql;
    xqueue<query_t *> req;
} mysql_thread_t;

typedef struct thread_list_s {
    int idx;
    int num;
    mysql_thread_t *threads;
}thread_list_t;

typedef std::map<int, thread_list_t*> thread_list_map;
static thread_list_map s_threads;

static const int THREAD_NUM_DEFAULT = 5;
//static const int THREAD_NUM = 5;
//static const int THREAD_INDEX[THREAD_NUM] = {0, 1, 2, 3, 4};
//static MYSQL *s_mysqls[THREAD_NUM] = {NULL, NULL, NULL, NULL};
//static MYSQL_MAP s_mysqls;
//static THREAD_MAP s_threads;
//static xqueue<query_t *> s_queue_req[THREAD_NUM];
static xqueue<query_t *> s_queue_res;

static void *handle(void *args);
static void query(mysql_thread_t *th);
static void destroy(query_t *q);
static void response(query_t *q);
static void retrieve_pb(query_t *q);
static void retrieve_field(query_t *q);

volatile int _running;

static void *handle(void *args)
{
    mysql_thread_t *self = (mysql_thread_t*)args;

    if (self == NULL) {
        LOG_ERROR("db", "Create thread failed: %s", "mysql_thread_t is NULL");
        return NULL;
    }

    while (_running) {
        query(self);
    }
    return NULL;
}

static void query(mysql_thread_t *th)
{
    query_t *q = NULL;
    MYSQL *m = th->mysql;

    try {
        th->req.pop(q);
        assert(m && q);

        // query
        int status = mysql_real_query(m, q->cmd.c_str(), q->cmd.length());

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    q->cmd.c_str(), mysql_error(m));
            destroy(q);
            return;
        }
        if (q->type == QUERY_NO_RES) {
            destroy(q);
            return;
        }

        q->data = NULL;
        do {
            MYSQL_RES *res = mysql_store_result(m);

            if (res) {
                if (q->data == NULL) {
                    q->data = res;
                    s_queue_res.push(q);
                } else {
                    mysql_free_result(res);
                }
            }
        } while (!mysql_next_result(m));
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                q->cmd.c_str(), mysql_error(m));
    }
}

static void destroy(query_t *q)
{
    assert(q);

    if (q->data) {
        mysql_free_result(q->data);
    }
    E_DELETE(q->pb);
    E_DELETE(q);
}

static void retrieve_pb(query_t *q)
{
    assert(q && q->data && q->pb);

    const Descriptor *des = q->pb->GetDescriptor();
    const int field_num = mysql_num_fields(q->data);
    const MYSQL_ROW row = mysql_fetch_row(q->data);
    size_t *len = mysql_fetch_lengths(q->data);

    for (int c = 0; c < field_num; ++c) {
        const MYSQL_FIELD *ifd = mysql_fetch_field_direct(q->data, c);
        const FieldDescriptor *ofd = des->FindFieldByName(ifd->name);

        if (ofd == NULL) {
            continue;
        }
        if (row[c] == NULL || (strlen(row[c]) == 0)) {
            pb_set_field(q->pb, ofd, "");
        } else {
            pb_set_field(q->pb, ofd, row[c], len[c]);
        }
    }
}

static void retrieve_field(query_t *q)
{
    assert(q && q->data && q->pb);

    const Reflection *ref = q->pb->GetReflection();
    const Descriptor *des = q->pb->GetDescriptor();
    const FieldDescriptor *ctn = des->FindFieldByName(q->field);
    const int row_num = mysql_num_rows(q->data);
    const int field_num = mysql_num_fields(q->data);

    assert(ctn);
    for (int r = 0; r < row_num; ++r) {
        pb_t *item = ref->AddMessage(q->pb, ctn);
        const MYSQL_ROW row = mysql_fetch_row(q->data);
        unsigned long *len = mysql_fetch_lengths(q->data);

        des = item->GetDescriptor();
        for (int c = 0; c < field_num; ++c) {
            const MYSQL_FIELD *ifd = mysql_fetch_field_direct(q->data, c);
            const FieldDescriptor *ofd =
                des->FindFieldByName(ifd->name);

            if (ofd == NULL) {
                continue;
            }
            if (row[c] == NULL || (strlen(row[c]) == 0)) {
                pb_set_field(item, ofd, "");
            } else {
                pb_set_field(item, ofd, row[c], len[c]);
            }
        }
    }
}

int db_init(void)
{
    MODULE_IMPORT_SWITCH;
    _running = 1;
    return ELF_RC_DB_OK;
}

int db_fini(void)
{
    MODULE_IMPORT_SWITCH;

    _running = 0;
    thread_list_map::iterator itr = s_threads.begin();
    for (;itr != s_threads.end(); ++itr) {
        thread_list_t *th_list = itr->second;
        for (int i = 0;i < th_list->num; ++i) {
            mysql_thread_t *th = th_list->threads + i;
            thread_fini(th->tid);
            if (th->mysql) {
                mysql_close(th->mysql);
            }
        }
        E_DELETE th_list->threads;
        E_DELETE th_list;
    }
    s_threads.clear();
    return ELF_RC_DB_OK;
}

int db_connect(int idx, const std::string &host, const std::string &user,
        const std::string &passwd, const std::string &db, unsigned int port,
        int num)
{
    if (num <= 0) {
        num = THREAD_NUM_DEFAULT;
    }
    thread_list_t *th_list = NULL;

    thread_list_map::iterator itr = s_threads.find(idx);
    if (itr != s_threads.end()) {
        th_list = itr->second;
    } else {
        th_list = E_NEW thread_list_t;
        th_list->idx = idx;
        th_list->num = num;
        th_list->threads = E_NEW mysql_thread_t[num];
        for (int i = 0;i < num; i++) {
            mysql_thread_t *th = th_list->threads + i;
            th->mysql = NULL;
        }
        s_threads[idx] = th_list;
    }

    for (int i = 0; i < num; ++i) {
        mysql_thread_t *th = NULL;
        th = th_list->threads + i;

        char value = 1;
        MYSQL * m = th->mysql;
        try {
            if (m && 0 == mysql_ping(m)) {
                return ELF_RC_DB_OK;
            }
            m = mysql_init(NULL);
            mysql_options(m, MYSQL_OPT_RECONNECT, (char *)&value);
            mysql_options(m, MYSQL_SET_CHARSET_NAME, "utf8");
            if (!mysql_real_connect(m, host.c_str(), user.c_str(),
                    passwd.c_str(), db.c_str(), port,
                    NULL, CLIENT_MULTI_STATEMENTS)) {
                LOG_ERROR("db", "Connect DB failed: %s.",
                        mysql_error(m));
                return ELF_RC_DB_INIT_FAILED;
            }
            th->mysql = m;
            th->tid = thread_init(handle, (void *)th);
        } catch(...) {
            LOG_ERROR("db", "Connect DB failed: %s.",
                    mysql_error(m));
            return ELF_RC_DB_INIT_FAILED;
        }
    }
    return ELF_RC_DB_OK;
}

int db_proc(void)
{
    if (s_threads.empty()) return -1;

    std::deque<query_t *> list;
    std::deque<query_t *>::iterator itr;

    s_queue_res.swap(list);
    for (itr = list.begin(); itr != list.end(); ++itr) {
        query_t *q = *itr;

        // object has not been destroyed
        response(q);
    }
    return 0;
}

void db_req(int idx, const char *cmd, bool sim, db_callback proc,
        oid_t oid, pb_t *out, const std::string &field)
{
    thread_list_map::iterator itr = s_threads.find(idx);
    if (itr == s_threads.end()) {
        return;
    }
    thread_list_t *th_list = itr->second;

    int tidx = 0;
    query_t *q = E_NEW query_t;

    if (proc == NULL && out == NULL) {
        q->type = QUERY_NO_RES;
    } else if (out == NULL) {
        q->type = QUERY_RAW;
    } else if (field == "") {
        q->type = QUERY_PB;
    } else {
        q->type = QUERY_FIELD;
    }
    q->cmd = cmd;
    q->stamp = time_ms();
    q->oid = oid;
    q->pb = out;
    q->field = field;
    q->proc = proc;
    q->data = NULL;
    if (oid != elf::OID_NIL) {
        tidx = oid % (th_list->num - 1) + 1;
    }
    mysql_thread_t *th = th_list->threads + tidx;
    th->req.push(q);
}

void response(query_t *q)
{
    assert(q);
    switch (q->type) {
        case QUERY_RAW:
            if (q->proc) {
                q->proc(q->oid, q->data);
            }
            break;
        case QUERY_PB:
            retrieve_pb(q);
            if (q->proc) {
                q->proc(q->oid, q->pb);
            }
            break;
        case QUERY_FIELD:
            retrieve_field(q);
            if (q->proc) {
                q->proc(q->oid, q->pb);
            }
            break;
        default:
            assert(0);
            break;
    }
    destroy(q);
}

size_t db_pending_size(int idx)
{
    size_t sum = 0;
    thread_list_map::iterator itr = s_threads.find(idx);
    if (itr == s_threads.end()) {
        return 0;
    }

    thread_list_t *th_list = itr->second;
    for (int i = 0;i < th_list->num; i++) {
        mysql_thread_t *th = th_list->threads + i;
        sum += th->req.size();
    }
    return sum;
}
} // namespace elf

<|endoftext|>