<commit_before>#include "rosplan_planning_system/PlanDispatcher.h"
#include <map>

namespace KCL_rosplan {

	int PlanDispatcher::getCurrentAction() {
		return current_action;
	}

	void PlanDispatcher::reset() {
		dispatch_paused = false;
		current_action = 0;
		action_received.clear();
		action_completed.clear();
		replan_requested = false;
	}

	/*-----------------*/
	/* action dispatch */
	/*-----------------*/

	/*
	 * Loop through and publish planned actions
	 */
	bool PlanDispatcher::dispatchPlan(const std::vector<rosplan_dispatch_msgs::ActionDispatch> &actionList, double missionStart, double planStart) {

		ros::NodeHandle nh("~");
		ros::Rate loop_rate(10);

		ROS_INFO("KCL: (PS) Dispatching plan");
		replan_requested = false;
		bool repeatAction = false;
		while (ros::ok() && actionList.size() > current_action) {

			// get next action
			rosplan_dispatch_msgs::ActionDispatch currentMessage = actionList[current_action];
			if((unsigned int)currentMessage.action_id != current_action)
				ROS_ERROR("KCL: (PS) Message action_id [%d] does not meet expected [%zu]", currentMessage.action_id, current_action);

			// loop while waiting for dispatch time
			if(!dispatch_on_completion) {
				double wait_period = 10.0;
				int wait_print = (int)(currentMessage.dispatch_time + planStart - ros::WallTime::now().toSec()) / wait_period;
				while (ros::ok() && ros::WallTime::now().toSec() < currentMessage.dispatch_time + planStart) {
					ros::spinOnce();
					loop_rate.sleep();
					double remaining = planStart + currentMessage.dispatch_time - ros::WallTime::now().toSec();
					if(wait_print > (int)remaining / wait_period) {
						ROS_INFO("KCL: (PS) Waiting %f before dispatching action: [%i, %s, %f, %f]",
								remaining,currentMessage.action_id, currentMessage.name.c_str(),
								 (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
						wait_print--;
					}
				}
			}

			if(!checkPreconditions(currentMessage)) {
				ROS_INFO("KCL: (PS) Preconditions not achieved [%i, %s]", currentMessage.action_id, currentMessage.name.c_str());
			}

			// dispatch action
			ROS_INFO("KCL: (PS) Dispatching action [%i, %s, %f, %f]", currentMessage.action_id, currentMessage.name.c_str(), (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
			action_publisher.publish(currentMessage);
			double late_print = (ros::WallTime::now().toSec() - (currentMessage.dispatch_time + planStart));
			if(late_print>0.1) ROS_INFO("KCL: (PS) Action [%i] is %f second(s) late", currentMessage.action_id, late_print);

			// wait for action to complete
			if(!dispatch_concurrent) {
				int counter = 0;
				while (ros::ok() && !action_completed[current_action]) {
					ros::spinOnce();
					loop_rate.sleep();
					counter++;
					if (counter == 2000) {
						ROS_INFO("KCL: (PS) Action %i timed out now. Cancelling...", currentMessage.action_id);
						rosplan_dispatch_msgs::ActionDispatch cancelMessage;
						cancelMessage.action_id = currentMessage.action_id;
						cancelMessage.name = "cancel_action";
						action_publisher.publish(cancelMessage);
					}
				}
			}

			// get ready for next action
			if(!repeatAction) current_action++;
			repeatAction = false;
			action_received[current_action] = false;
			action_completed[current_action] = false;

			// finish dispatch and replan
			if(replan_requested) return false;
		}
		return true;
	}

	bool PlanDispatcher::checkPreconditions(rosplan_dispatch_msgs::ActionDispatch msg) {

		// setup service call
		ros::NodeHandle nh;
		ros::ServiceClient queryKnowledgeClient = nh.serviceClient<rosplan_knowledge_msgs::KnowledgeQueryService>("/kcl_rosplan/query_knowledge_base");
		rosplan_knowledge_msgs::KnowledgeQueryService querySrv;

		std::map<std::string, std::vector<std::vector<std::string> > >::iterator oit;
		oit = environment.domain_operator_precondition_map.find(msg.name);
		if(oit==environment.domain_operator_precondition_map.end()) return false;

		// iterate through conditions
		std::vector<std::vector<std::string> >::iterator cit = oit->second.begin();
		for(; cit!=oit->second.end(); cit++) {

			rosplan_knowledge_msgs::KnowledgeItem condition;

			// set fact or function
			std::map<std::string,std::vector<std::string> >::iterator dit = environment.domain_predicates.find((*cit)[0]);
			if(dit!=environment.domain_predicates.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_ATTRIBUTE;

			dit = environment.domain_functions.find((*cit)[0]);
			if(dit!=environment.domain_functions.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_FUNCTION;

			// populate parameters
			condition.attribute_name = (*cit)[0];
			int index = 1;
			std::vector<std::string>::iterator pit;
			for(pit=environment.domain_predicates[condition.attribute_name].begin();
					pit!=environment.domain_predicates[condition.attribute_name].end(); pit++) {
				// set parameter label to predicate label
				diagnostic_msgs::KeyValue param;
				param.key = *pit;
				// find label as it is in domain operator
				std::string conditionKey = (*cit)[index];
				index++;
				// set value
				std::vector<diagnostic_msgs::KeyValue>::iterator opit;
				for(opit = msg.parameters.begin(); opit!=msg.parameters.end(); opit++) {
					if(0==opit->value.compare(conditionKey))
						param.value = opit->value;
				}
				condition.values.push_back(param);
			}
			querySrv.request.knowledge.push_back(condition);
		}

		// check conditions in knowledge base
		if (queryKnowledgeClient.call(querySrv)) {

			if(!querySrv.response.all_true) {
				std::vector<rosplan_knowledge_msgs::KnowledgeItem>::iterator kit;
				for(kit=querySrv.response.false_knowledge.begin(); kit != querySrv.response.false_knowledge.end(); kit++)
					ROS_INFO("KCL: (PS)        [%s]", kit->attribute_name.c_str());
			}
			return querySrv.response.all_true;

		} else {
			ROS_ERROR("KCL: (PS) Failed to call service /kcl_rosplan/query_knowledge_base");
		}
	}

	/*------------------*/
	/* general feedback */
	/*------------------*/

	/**
	 * listen to and process actionFeedback topic.
	 */
	void PlanDispatcher::feedbackCallback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {

		// create error if the action is unrecognised
		ROS_INFO("KCL: (PS) Feedback received [%i,%s]", msg->action_id, msg->status.c_str());
		if(current_action != (unsigned int)msg->action_id)
			ROS_ERROR("KCL: (PS) Unexpected action ID: %d; current action: %zu", msg->action_id, current_action);

		// action enabled
		if(!action_received[msg->action_id] && (0 == msg->status.compare("action enabled")))
			action_received[msg->action_id] = true;

		// more specific feedback
		actionFeedback(msg);

		// action completed (successfuly)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action achieved"))
			action_completed[msg->action_id] = true;

		// action completed (failed)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action failed")) {
			replan_requested = true;
			action_completed[msg->action_id] = true;
		}
	}

	/*---------------------------*/
	/* Specific action responses */
	/*---------------------------*/

	/**
	 * processes single action feedback message.
	 * This method serves as the hook for defining more interesting behaviour on action feedback.
	 */
	void PlanDispatcher::actionFeedback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {
		// nothing yet...
	}
} // close namespace
<commit_msg>Prints<commit_after>#include "rosplan_planning_system/PlanDispatcher.h"
#include <map>

namespace KCL_rosplan {

	int PlanDispatcher::getCurrentAction() {
		return current_action;
	}

	void PlanDispatcher::reset() {
		dispatch_paused = false;
		current_action = 0;
		action_received.clear();
		action_completed.clear();
		replan_requested = false;
	}

	/*-----------------*/
	/* action dispatch */
	/*-----------------*/

	/*
	 * Loop through and publish planned actions
	 */
	bool PlanDispatcher::dispatchPlan(const std::vector<rosplan_dispatch_msgs::ActionDispatch> &actionList, double missionStart, double planStart) {

		ros::NodeHandle nh("~");
		ros::Rate loop_rate(10);

		ROS_INFO("KCL: (PS) Dispatching plan");
		replan_requested = false;
		bool repeatAction = false;
		while (ros::ok() && actionList.size() > current_action) {

			// get next action
			rosplan_dispatch_msgs::ActionDispatch currentMessage = actionList[current_action];
			if((unsigned int)currentMessage.action_id != current_action)
				ROS_ERROR("KCL: (PS) Message action_id [%d] does not meet expected [%zu]", currentMessage.action_id, current_action);

			// loop while waiting for dispatch time
			if(!dispatch_on_completion) {
				double wait_period = 10.0;
				int wait_print = (int)(currentMessage.dispatch_time + planStart - ros::WallTime::now().toSec()) / wait_period;
				while (ros::ok() && ros::WallTime::now().toSec() < currentMessage.dispatch_time + planStart) {
					ros::spinOnce();
					loop_rate.sleep();
					double remaining = planStart + currentMessage.dispatch_time - ros::WallTime::now().toSec();
					if(wait_print > (int)remaining / wait_period) {
						ROS_INFO("KCL: (PS) Waiting %f before dispatching action: [%i, %s, %f, %f]",
								remaining,currentMessage.action_id, currentMessage.name.c_str(),
								 (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
						wait_print--;
					}
				}
			}

			if(!checkPreconditions(currentMessage)) {
				ROS_INFO("KCL: (PS) Preconditions not achieved [%i, %s]", currentMessage.action_id, currentMessage.name.c_str());
			}

			// dispatch action
			ROS_INFO("KCL: (PS) Dispatching action [%i, %s, %f, %f]", currentMessage.action_id, currentMessage.name.c_str(), (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
			action_publisher.publish(currentMessage);
			double late_print = (ros::WallTime::now().toSec() - (currentMessage.dispatch_time + planStart));
			if(late_print>0.1) ROS_INFO("KCL: (PS) Action [%i] is %f second(s) late", currentMessage.action_id, late_print);

			// wait for action to complete
			if(!dispatch_concurrent) {
				int counter = 0;
				while (ros::ok() && !action_completed[current_action]) {
					ros::spinOnce();
					loop_rate.sleep();
					counter++;
					if (counter == 2000) {
						ROS_INFO("KCL: (PS) Action %i timed out now. Cancelling...", currentMessage.action_id);
						rosplan_dispatch_msgs::ActionDispatch cancelMessage;
						cancelMessage.action_id = currentMessage.action_id;
						cancelMessage.name = "cancel_action";
						action_publisher.publish(cancelMessage);
					}
				}
			}

			// get ready for next action
			if(!repeatAction) current_action++;
			repeatAction = false;
			action_received[current_action] = false;
			action_completed[current_action] = false;

			// finish dispatch and replan
			if(replan_requested) return false;
		}
		return true;
	}

	bool PlanDispatcher::checkPreconditions(rosplan_dispatch_msgs::ActionDispatch msg) {

		// setup service call
		ros::NodeHandle nh;
		ros::ServiceClient queryKnowledgeClient = nh.serviceClient<rosplan_knowledge_msgs::KnowledgeQueryService>("/kcl_rosplan/query_knowledge_base");
		rosplan_knowledge_msgs::KnowledgeQueryService querySrv;

		std::map<std::string, std::vector<std::vector<std::string> > >::iterator oit;
		oit = environment.domain_operator_precondition_map.find(msg.name);
		if(oit==environment.domain_operator_precondition_map.end()) return false;

		// iterate through conditions
		std::vector<std::vector<std::string> >::iterator cit = oit->second.begin();
		for(; cit!=oit->second.end(); cit++) {

			rosplan_knowledge_msgs::KnowledgeItem condition;

			// set fact or function
			std::map<std::string,std::vector<std::string> >::iterator dit = environment.domain_predicates.find((*cit)[0]);
			if(dit!=environment.domain_predicates.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_ATTRIBUTE;

			dit = environment.domain_functions.find((*cit)[0]);
			if(dit!=environment.domain_functions.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_FUNCTION;

			// populate parameters
std::cout << "---" << std::endl;
			condition.attribute_name = (*cit)[0];
std::cout << condition.attribute_name << std::endl;
			int index = 1;
			std::vector<std::string>::iterator pit;
			for(pit=environment.domain_predicates[condition.attribute_name].begin();
					pit!=environment.domain_predicates[condition.attribute_name].end(); pit++) {
				// set parameter label to predicate label
				diagnostic_msgs::KeyValue param;
				param.key = *pit;
std::cout << "-" << *pit;
				// find label as it is in domain operator
				std::string conditionKey = (*cit)[index];
				index++;
				// set value
				std::vector<diagnostic_msgs::KeyValue>::iterator opit;
				for(opit = msg.parameters.begin(); opit!=msg.parameters.end(); opit++) {
					if(0==opit->value.compare(conditionKey)) {
						param.value = opit->value;
std::cout << " : " << opit->value;
					}
				}
				condition.values.push_back(param);
std::cout << std::endl;
			}
			querySrv.request.knowledge.push_back(condition);
		}

		// check conditions in knowledge base
		if (queryKnowledgeClient.call(querySrv)) {

			if(!querySrv.response.all_true) {
				std::vector<rosplan_knowledge_msgs::KnowledgeItem>::iterator kit;
				for(kit=querySrv.response.false_knowledge.begin(); kit != querySrv.response.false_knowledge.end(); kit++)
					ROS_INFO("KCL: (PS)        [%s]", kit->attribute_name.c_str());
			}
			return querySrv.response.all_true;

		} else {
			ROS_ERROR("KCL: (PS) Failed to call service /kcl_rosplan/query_knowledge_base");
		}
	}

	/*------------------*/
	/* general feedback */
	/*------------------*/

	/**
	 * listen to and process actionFeedback topic.
	 */
	void PlanDispatcher::feedbackCallback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {

		// create error if the action is unrecognised
		ROS_INFO("KCL: (PS) Feedback received [%i,%s]", msg->action_id, msg->status.c_str());
		if(current_action != (unsigned int)msg->action_id)
			ROS_ERROR("KCL: (PS) Unexpected action ID: %d; current action: %zu", msg->action_id, current_action);

		// action enabled
		if(!action_received[msg->action_id] && (0 == msg->status.compare("action enabled")))
			action_received[msg->action_id] = true;

		// more specific feedback
		actionFeedback(msg);

		// action completed (successfuly)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action achieved"))
			action_completed[msg->action_id] = true;

		// action completed (failed)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action failed")) {
			replan_requested = true;
			action_completed[msg->action_id] = true;
		}
	}

	/*---------------------------*/
	/* Specific action responses */
	/*---------------------------*/

	/**
	 * processes single action feedback message.
	 * This method serves as the hook for defining more interesting behaviour on action feedback.
	 */
	void PlanDispatcher::actionFeedback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {
		// nothing yet...
	}
} // close namespace
<|endoftext|>


<commit_before>
#include <stdlib.h>     /* srand, rand */

#include <chrono>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>

#include "bpmf.h"

using namespace std;
using namespace Eigen;

typedef SparseMatrix<double> SparseMatrixD;

const int num_feat = 32;
unsigned num_p = 0;
unsigned num_m = 0;

const int alpha = 2;
const int nsims = 20;
const int burnin = 5;

double mean_rating = .0;

SparseMatrixD M;
typedef Eigen::Triplet<double> T;
vector<T> probe_vec;

typedef Matrix<double, num_feat, 1> VectorNd;
typedef Matrix<double, num_feat, num_feat> MatrixNNd;
typedef Matrix<double, num_feat, Dynamic> MatrixNXd;

VectorNd mu_u;
VectorNd mu_m;
MatrixNNd Lambda_u;
MatrixNNd Lambda_m;
MatrixNXd sample_u;
MatrixNXd sample_m;

// parameters of Inv-Whishart distribution (see paper for details)
MatrixNNd WI_u;
const int b0_u = 2;
const int df_u = num_feat;
VectorNd mu0_u;

MatrixNNd WI_m;
const int b0_m = 2;
const int df_m = num_feat;
VectorNd mu0_m;

void loadChemo(const char* fname)
{
    std::vector<T> lst;
    lst.reserve(100000);

    FILE *f = fopen(fname, "r");
    assert(f && "Could not open file");

    // skip header
    char buf[2048];
    fscanf(f, "%s\n", buf);

    // data
    unsigned i, j;
    double v;
    while (!feof(f)) {
        if (!fscanf(f, "%d,%d,%lg\n", &i, &j, &v)) continue;
        i--;
        j--;

        if ((rand() % 5) == 0) {
            probe_vec.push_back(T(i,j,log10(v)));
        }
#ifndef TEST_SAMPLE
        else // if not in test case -> remove probe_vec from lst
#endif
        {
            num_p = std::max(num_p, i);
            num_m = std::max(num_m, j);
            mean_rating += v;
            lst.push_back(T(i,j,log10(v)));
        }
    }
    num_p++;
    num_m++;
    mean_rating /= lst.size();
    fclose(f);

    M = SparseMatrix<double>(num_p, num_m);
    M.setFromTriplets(lst.begin(), lst.end());
}

void init() {
    mean_rating = M.sum() / M.nonZeros();
    Lambda_u.setIdentity();
    Lambda_m.setIdentity();

    sample_u = MatrixNXd(num_feat,num_p);
    sample_m = MatrixNXd(num_feat,num_m);
    sample_u.setZero();
    sample_m.setZero();

    // parameters of Inv-Whishart distribution (see paper for details)
    WI_u.setIdentity();
    mu0_u.setZero();

    WI_m.setIdentity();
    mu0_m.setZero();
}

pair<double,double> eval_probe_vec(const vector<T> &probe_vec, const MatrixNXd &sample_m, const MatrixNXd &sample_u, double mean_rating)
{
    unsigned n = probe_vec.size();
    unsigned correct = 0;
    double diff = .0;
    for(auto t : probe_vec) {
         double prediction = sample_m.col(t.col()).dot(sample_u.col(t.row())) + mean_rating;
         //cout << "prediction: " << prediction - mean_rating << " + " << mean_rating << " = " << prediction << endl;
         //cout << "actual: " << t.value() << endl;
         correct += (t.value() < log10(200)) == (prediction < log10(200));
         diff += abs(t.value() - prediction);
    }

    return std::make_pair((double)correct / n, diff / n);
}

void sample_movie(MatrixNXd &s, int mm, const SparseMatrixD &mat, double mean_rating,
    const MatrixNXd &samples, int alpha, const VectorNd &mu_u, const MatrixNNd &Lambda_u)
{
    int i = 0;
    MatrixNXd E(num_feat,mat.col(mm).nonZeros());
    VectorXd rr(mat.col(mm).nonZeros());
    //cout << "movie " << endl;
    for (SparseMatrixD::InnerIterator it(mat,mm); it; ++it, ++i) {
        // cout << "M[" << it.row() << "," << it.col() << "] = " << it.value() << endl;
        E.col(i) = samples.col(it.row());
        rr(i) = it.value() - mean_rating;
    }

    auto MM = E * E.transpose();
    auto MMs = alpha * MM;
    MatrixNNd covar = (Lambda_u + MMs).inverse();
    VectorNd MMrr = (E * rr) * alpha;
    auto U = Lambda_u * mu_u;
    auto mu = covar * (MMrr + U);

    MatrixNNd chol = covar.llt().matrixL();
#ifdef TEST_SAMPLE
    auto r(num_feat); r.setConstant(0.25);
#else
    auto r = nrandn(num_feat);
#endif
    s.col(mm) = chol * r + mu;

#ifdef TEST_SAMPLE
      cout << "movie " << mm << ":" << result.cols() << " x" << result.rows() << endl;
      cout << "mean rating " << mean_rating << endl;
      cout << "E = [" << E << "]" << endl;
      cout << "rr = [" << rr << "]" << endl;
      cout << "MM = [" << MM << "]" << endl;
      cout << "Lambda_u = [" << Lambda_u << "]" << endl;
      cout << "covar = [" << covar << "]" << endl;
      cout << "mu = [" << mu << "]" << endl;
      cout << "chol = [" << chol << "]" << endl;
      cout << "rand = [" << r <<"]" <<  endl;
      cout << "result = [" << result << "]" << endl;
#endif

}

#ifdef TEST_SAMPLE
void test() {
    MatrixNXd sample_u(num_p);
    MatrixNXd sample_m(num_m);

    mu_m.setZero();
    Lambda_m.setIdentity();
    sample_u.setConstant(2.0);
    Lambda_m *= 0.5;
    sample_m.col(0) = sample_movie(0, M, mean_rating, sample_u, alpha, mu_m, Lambda_m);
}

#else

void run() {
    auto start = std::chrono::steady_clock::now();

    SparseMatrixD Mt = M.transpose();

    std::cout << "Sampling" << endl;
    for(int i=0; i<nsims; ++i) {

      // Sample from movie hyperparams
      tie(mu_m, Lambda_m) = CondNormalWishart(sample_m, mu0_m, b0_m, WI_m, df_m);

      // Sample from user hyperparams
      tie(mu_u, Lambda_u) = CondNormalWishart(sample_u, mu0_u, b0_u, WI_u, df_u);

#pragma omp parallel for
      for(int mm = 0; mm < num_m; ++mm) {
        sample_movie(sample_m, mm, M, mean_rating, sample_u, alpha, mu_m, Lambda_m);
      }

#pragma omp parallel for
      for(int uu = 0; uu < num_p; ++uu) {
        sample_movie(sample_u, uu, Mt, mean_rating, sample_m, alpha, mu_u, Lambda_u);
      }

      auto eval = eval_probe_vec(probe_vec, sample_m, sample_u, mean_rating);
      double norm_u = sample_u.norm();
      double norm_m = sample_m.norm();
      auto end = std::chrono::steady_clock::now();
      auto elapsed = std::chrono::duration<double>(end - start);
      double samples_per_sec = (i + 1) * (num_p + num_m) / elapsed.count();

      printf("Iteration %d:\t num_correct: %3.2f%%\tavg_diff: %3.2f\tFU(%6.2f)\tFM(%6.2f)\tSamples/sec: %6.2f\n",
              i, 100*eval.first, eval.second, norm_u, norm_m, samples_per_sec);
    }
}

#endif

int main(int argc, char *argv[])
{
    const char *fname = argv[1];
    assert(fname && "filename missing");
    Eigen::initParallel();
    Eigen::setNbThreads(1);

    loadChemo(fname);
    init();
#ifdef TEST_SAMPLE
    test();
#else
    run();
#endif

    return 0;
}
<commit_msg>c++: now using matrix market matrices<commit_after>
#include <stdlib.h>     /* srand, rand */

#include <chrono>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>

#include <unsupported/Eigen/SparseExtra>

#include "bpmf.h"

using namespace std;
using namespace Eigen;

typedef SparseMatrix<double> SparseMatrixD;

const int num_feat = 32;

const int alpha = 2;
const int nsims = 20;
const int burnin = 5;

double mean_rating = .0;

SparseMatrixD M, P;

typedef Matrix<double, num_feat, 1> VectorNd;
typedef Matrix<double, num_feat, num_feat> MatrixNNd;
typedef Matrix<double, num_feat, Dynamic> MatrixNXd;

VectorNd mu_u;
VectorNd mu_m;
MatrixNNd Lambda_u;
MatrixNNd Lambda_m;
MatrixNXd sample_u;
MatrixNXd sample_m;

// parameters of Inv-Whishart distribution (see paper for details)
MatrixNNd WI_u;
const int b0_u = 2;
const int df_u = num_feat;
VectorNd mu0_u;

MatrixNNd WI_m;
const int b0_m = 2;
const int df_m = num_feat;
VectorNd mu0_m;

void init() {
    mean_rating = M.sum() / M.nonZeros();
    Lambda_u.setIdentity();
    Lambda_m.setIdentity();

    sample_u = MatrixNXd(num_feat,M.rows());
    sample_m = MatrixNXd(num_feat,M.cols());
    sample_u.setZero();
    sample_m.setZero();

    // parameters of Inv-Whishart distribution (see paper for details)
    WI_u.setIdentity();
    mu0_u.setZero();

    WI_m.setIdentity();
    mu0_m.setZero();
}

pair<double,double> eval_probe_vec(const MatrixNXd &sample_m, const MatrixNXd &sample_u, double mean_rating)
{
    unsigned n = P.nonZeros();
    unsigned correct = 0;
    double diff = .0;
    for (int k=0; k<P.outerSize(); ++k)
        for (SparseMatrix<double>::InnerIterator it(P,k); it; ++it) {
            double prediction = sample_m.col(it.col()).dot(sample_u.col(it.row())) + mean_rating;
            //cout << "prediction: " << prediction - mean_rating << " + " << mean_rating << " = " << prediction << endl;
            //cout << "actual: " << it.value() << endl;
            correct += (it.value() < log10(200)) == (prediction < log10(200));
            diff += abs(it.value() - prediction);
        }

    return std::make_pair((double)correct / n, diff / n);
}

void sample_movie(MatrixNXd &s, int mm, const SparseMatrixD &mat, double mean_rating,
    const MatrixNXd &samples, int alpha, const VectorNd &mu_u, const MatrixNNd &Lambda_u)
{
    int i = 0;
    MatrixNXd E(num_feat,mat.col(mm).nonZeros());
    VectorXd rr(mat.col(mm).nonZeros());
    //cout << "movie " << endl;
    for (SparseMatrixD::InnerIterator it(mat,mm); it; ++it, ++i) {
        // cout << "M[" << it.row() << "," << it.col() << "] = " << it.value() << endl;
        E.col(i) = samples.col(it.row());
        rr(i) = it.value() - mean_rating;
    }

    auto MM = E * E.transpose();
    auto MMs = alpha * MM;
    MatrixNNd covar = (Lambda_u + MMs).inverse();
    VectorNd MMrr = (E * rr) * alpha;
    auto U = Lambda_u * mu_u;
    auto mu = covar * (MMrr + U);

    MatrixNNd chol = covar.llt().matrixL();
#ifdef TEST_SAMPLE
    auto r(num_feat); r.setConstant(0.25);
#else
    auto r = nrandn(num_feat);
#endif
    s.col(mm) = chol * r + mu;

#ifdef TEST_SAMPLE
      cout << "movie " << mm << ":" << result.cols() << " x" << result.rows() << endl;
      cout << "mean rating " << mean_rating << endl;
      cout << "E = [" << E << "]" << endl;
      cout << "rr = [" << rr << "]" << endl;
      cout << "MM = [" << MM << "]" << endl;
      cout << "Lambda_u = [" << Lambda_u << "]" << endl;
      cout << "covar = [" << covar << "]" << endl;
      cout << "mu = [" << mu << "]" << endl;
      cout << "chol = [" << chol << "]" << endl;
      cout << "rand = [" << r <<"]" <<  endl;
      cout << "result = [" << result << "]" << endl;
#endif

}

#ifdef TEST_SAMPLE
void test() {
    MatrixNXd sample_u(M.rows());
    MatrixNXd sample_m(M.cols());

    mu_m.setZero();
    Lambda_m.setIdentity();
    sample_u.setConstant(2.0);
    Lambda_m *= 0.5;
    sample_m.col(0) = sample_movie(0, M, mean_rating, sample_u, alpha, mu_m, Lambda_m);
}

#else

void run() {
    auto start = std::chrono::steady_clock::now();

    SparseMatrixD Mt = M.transpose();

    std::cout << "Sampling" << endl;
    for(int i=0; i<nsims; ++i) {

      // Sample from movie hyperparams
      tie(mu_m, Lambda_m) = CondNormalWishart(sample_m, mu0_m, b0_m, WI_m, df_m);

      // Sample from user hyperparams
      tie(mu_u, Lambda_u) = CondNormalWishart(sample_u, mu0_u, b0_u, WI_u, df_u);

#pragma omp parallel for
      for(int mm = 0; mm < M.cols(); ++mm) {
        sample_movie(sample_m, mm, M, mean_rating, sample_u, alpha, mu_m, Lambda_m);
      }

#pragma omp parallel for
      for(int uu = 0; uu < M.rows(); ++uu) {
        sample_movie(sample_u, uu, Mt, mean_rating, sample_m, alpha, mu_u, Lambda_u);
      }

      auto eval = eval_probe_vec(sample_m, sample_u, mean_rating);
      double norm_u = sample_u.norm();
      double norm_m = sample_m.norm();
      auto end = std::chrono::steady_clock::now();
      auto elapsed = std::chrono::duration<double>(end - start);
      double samples_per_sec = (i + 1) * (M.rows() + M.cols()) / elapsed.count();

      printf("Iteration %d:\t num_correct: %3.2f%%\tavg_diff: %3.2f\tFU(%6.2f)\tFM(%6.2f)\tSamples/sec: %6.2f\n",
              i, 100*eval.first, eval.second, norm_u, norm_m, samples_per_sec);
    }
}

#endif

int main(int argc, char *argv[])
{
    assert(argv[1] && argv[2] && "filename missing");
    Eigen::initParallel();
    Eigen::setNbThreads(1);

    loadMarket(M, argv[1]);
    loadMarket(P, argv[2]);

    init();
#ifdef TEST_SAMPLE
    test();
#else
    run();
#endif

    return 0;
}
<|endoftext|>


<commit_before>#include "ChLcpSolverParallel.h"
#include "math/ChThrustLinearAlgebra.h"

using namespace chrono;

//// TODO:  For now, this is hard-coded for Hunt-Crossley with Simple Sliding Friction.
__host__ __device__
void function_CalcContactForces(int&       index,           // index of this contact pair
                                real&      dT,              // integration time step
                                real3*     pos,             // body positions
                                real4*     rot,             // body orientations
                                real3*     vel,             // body linear velocity (global frame)
                                real3*     omg,             // body angular velocity (local frame)
                                real2*     elastic_moduli,  // Young's modulus (per body)
                                real*      mu,              // coefficient of friction (per body)
                                real*      alpha,           // disipation coefficient (per body)
                                real*      cr,              // coefficient of restitution (per body)
                                real*      cohesion,        // cohesion force (per body)
                                int2*      body_id,         // body IDs (per contact)
                                real3*     pt1,             // point on shape 1 (per contact)
                                real3*     pt2,             // point on shape 2 (per contact)
                                real3*     normal,          // contact normal (per contact)
                                real*      depth,           // penetration depth (per contact)
                                real*      eff_radius,      // effective contact radius (per contact)
                                int*       ext_body_id,     // [output] body IDs (two per contact)
                                real3*     ext_body_force,  // [output] body force (two per contact)
                                real3*     ext_body_torque) // [output] body torque (two per contact)
{
	// Identify the two bodies in contact.
	int body1 = body_id[index].x;
	int body2 = body_id[index].y;

	// If the two contact shapes are actually separated, set zero forces and torques
	if (depth[index] >= 0) {
		ext_body_id[2*index] = body1;
		ext_body_id[2*index+1] = body2;
		ext_body_force[2*index] = ZERO_VECTOR;
		ext_body_force[2*index+1] = ZERO_VECTOR;
		ext_body_torque[2*index] = ZERO_VECTOR;
		ext_body_torque[2*index+1] = ZERO_VECTOR;

		return;
	}

	// Kinematic information
	// ---------------------

	// Express contact point locations in local frames
	//   s' = At * s = At * (rP - r)
	real3 pt1_loc = TransformParentToLocal(pos[body1], rot[body1], pt1[index]);
	real3 pt2_loc = TransformParentToLocal(pos[body2], rot[body2], pt2[index]);

	// Calculate relative velocity (in global frame)
	//   vP = v + omg x s = v + A * (omg' x s')
	real3 vel1 = vel[body1] + quatRotateMat(cross(omg[body1], pt1_loc), rot[body1]);
	real3 vel2 = vel[body2] + quatRotateMat(cross(omg[body2], pt2_loc), rot[body2]);
	real3 relvel = vel2 - vel1;
	real  relvel_n_mag = dot(relvel, normal[index]);
	real3 relvel_n = relvel_n_mag * normal[index];
	real3 relvel_t = relvel - relvel_n;
	real  relvel_t_mag = length(relvel_t);

	// Calculate composite material properties
	// ---------------------------------------

	real Y1 = elastic_moduli[body1].x;
	real Y2 = elastic_moduli[body2].x;
	real nu1 = elastic_moduli[body1].y;
	real nu2 = elastic_moduli[body2].y;
	real inv_E = (1 - nu1 * nu1) / Y1 + (1 - nu2 * nu2) / Y2;
	real inv_G = 2 * (2 + nu1) * (1 - nu1) / Y1 + 2 * (2 + nu2) * (1 - nu2) / Y2;

	real E_eff = 1 / inv_E;
	real G_eff = 1 / inv_G;

	real mu_eff = min(mu[body1], mu[body2]);
	//real cr_eff = (cr[body1] + cr[body2]) / 2;
	real alpha_eff = (alpha[body1] + alpha[body2]) / 2;

	real cohesion_eff = min(cohesion[body1], cohesion[body2]);

	// Contact force
	// -------------

	// Normal force: Hunt-Crossley
	real delta = -depth[index];
	real kn = (4.0 / 3) * E_eff * sqrt(eff_radius[index]);
	real forceN_elastic = kn * delta * sqrt(delta);
	real forceN_dissipation = 1.5 * alpha_eff * forceN_elastic * relvel_n_mag;
	real forceN = forceN_elastic - forceN_dissipation;

	// Cohesion force
	forceN -= cohesion_eff;

	real3 force = forceN * normal[index];

	// Tangential force: Simple Coulomb Sliding
	if (relvel_t_mag > 1e-4) {
		real forceT = mu_eff * abs(forceN);

		force -= (forceT / relvel_t_mag) * relvel_t;
	}

	// Body forces (in global frame) & torques (in local frame)
	// --------------------------------------------------------

	// Convert force into the local body frames and calculate induced torques
	//    n' = s' x F' = s' x (A*F)
	real3 torque1_loc = cross(pt1_loc, quatRotateMatT(force, rot[body1]));
	real3 torque2_loc = cross(pt2_loc, quatRotateMatT(force, rot[body2]));

	// Store body forces and torques
	ext_body_id[2*index]   = body1;
	ext_body_id[2*index+1] = body2;
	ext_body_force[2*index]   = -force;
	ext_body_force[2*index+1] =  force;
	ext_body_torque[2*index]   = -torque1_loc;
	ext_body_torque[2*index+1] =  torque2_loc;
}

void ChLcpSolverParallelDEM::host_CalcContactForces(custom_vector<int>&   ext_body_id,
                                                    custom_vector<real3>& ext_body_force,
                                                    custom_vector<real3>& ext_body_torque)
{
#pragma omp parallel for
	for (int index = 0; index < data_container->number_of_rigid_rigid; index++) {
		function_CalcContactForces(
			index,
			step_size,
			data_container->host_data.pos_data.data(),
			data_container->host_data.rot_data.data(),
			data_container->host_data.vel_data.data(),
			data_container->host_data.omg_data.data(),
			data_container->host_data.elastic_moduli.data(),
			data_container->host_data.mu.data(),
			data_container->host_data.alpha.data(),
			data_container->host_data.cr.data(),
			data_container->host_data.cohesion_data.data(),
			data_container->host_data.bids_rigid_rigid.data(),
			data_container->host_data.cpta_rigid_rigid.data(),
			data_container->host_data.cptb_rigid_rigid.data(),
			data_container->host_data.norm_rigid_rigid.data(),
			data_container->host_data.dpth_rigid_rigid.data(),
			data_container->host_data.erad_rigid_rigid.data(),
			ext_body_id.data(),
			ext_body_force.data(),
			ext_body_torque.data());
	}
}

void ChLcpSolverParallelDEM::host_AddContactForces(uint                        ct_body_count,
                                                   const custom_vector<int>&   ct_body_id,
                                                   const custom_vector<real3>& ct_body_force,
                                                   const custom_vector<real3>& ct_body_torque)
{
#pragma omp parallel for
	for (int index = 0; index < ct_body_count; index++) {
		data_container->host_data.frc_data[ct_body_id[index]] += step_size * ct_body_force[index];
		data_container->host_data.trq_data[ct_body_id[index]] += step_size * ct_body_torque[index];
	}
}

void ChLcpSolverParallelDEM::ProcessContacts()
{
	// 0. If the narrowphase collision detection does not set the effective contact
	//    radius, fill it with the value 1.
	if (!data_container->erad_is_set)
		data_container->host_data.erad_rigid_rigid.resize(data_container->number_of_rigid_rigid, 1.0);

	// 1. Calculate contact forces and torques - per contact basis
	//    For each pair of contact shapes that overlap, we calculate and store
	//    the IDs of the two corresponding bodies and the resulting contact
	//    forces and torques on the two bodies.
	custom_vector<int>   ext_body_id(2 * data_container->number_of_rigid_rigid);
	custom_vector<real3> ext_body_force(2 * data_container->number_of_rigid_rigid);
	custom_vector<real3> ext_body_torque(2 * data_container->number_of_rigid_rigid);

	host_CalcContactForces(ext_body_id, ext_body_force, ext_body_torque);

	// 2. Calculate contact forces and torques - per body basis
	//    Accumulate the contact forces and torques for all bodies that are involved
	//    in at least one contact, by reducing the contact forces and torques from
	//    all contacts these bodies are involved in. The number of bodies that
	//    experience at least one contact is calculated in 'ct_body_count'.
	thrust::sort_by_key(
		ext_body_id.begin(), ext_body_id.end(),
		thrust::make_zip_iterator(thrust::make_tuple(ext_body_force.begin(), ext_body_torque.begin())));

	custom_vector<int>   ct_body_id(data_container->number_of_rigid);
	custom_vector<real3> ct_body_force(data_container->number_of_rigid);
	custom_vector<real3> ct_body_torque(data_container->number_of_rigid);

	// Reduce contact forces from all contacts and count bodies currently involved in contact
	uint ct_body_count = thrust::reduce_by_key(
		ext_body_id.begin(),
		ext_body_id.end(),
		thrust::make_zip_iterator(thrust::make_tuple(ext_body_force.begin(), ext_body_torque.begin())),
		ct_body_id.begin(),
		thrust::make_zip_iterator(thrust::make_tuple(ct_body_force.begin(), ct_body_torque.begin())),
		thrust::equal_to<int>(),
		sum_tuples()
		).first - ct_body_id.begin();

	// 3. Add contact forces and torques to existing forces (impulses)
	//    For all bodies involved in a contact, update the body forces and torques,
	//    scaled by the integration time step.
	host_AddContactForces(ct_body_count, ct_body_id, ct_body_force, ct_body_torque);
}

void ChLcpSolverParallelDEM::RunTimeStep(real step)
{
	step_size = step;
	data_container->step_size = step;

	number_of_constraints = data_container->number_of_bilaterals;
	number_of_objects = data_container->number_of_rigid;

	// Calculate contact forces (impulses) and append them to the body forces
	if (data_container->number_of_rigid_rigid)
		ProcessContacts();

	// Include forces and torques (update derivatives: v += m_inv * h * f)
	Preprocess();

	//// TODO:  check and clean up everything that has to do with bilateral constraints...

	data_container->host_data.rhs_data.resize(number_of_constraints);
	data_container->host_data.diag.resize(number_of_constraints);
	data_container->host_data.gamma_data.resize(number_of_constraints);

#pragma omp parallel for
	for (int i = 0; i < number_of_constraints; i++) {
		data_container->host_data.gamma_data[i] = 0;
	}

	bilateral.Setup(data_container);

	solver.current_iteration = 0;
	solver.total_iteration = 0;
	solver.maxd_hist.clear();
	solver.maxdeltalambda_hist.clear();
	solver.iter_hist.clear();

	solver.SetTolerance(tolerance);

	////solver.lcp_omega_bilateral = lcp_omega_bilateral;  //// not used anywhere?
	solver.bilateral = &bilateral;
	solver.Initial(step, data_container);

	////bilateral.ComputeJacobians();    //// no-op
	bilateral.ComputeRHS();

	if (max_iter_bilateral > 0) {
		custom_vector<real> rhs_bilateral(data_container->number_of_bilaterals);
		thrust::copy_n(data_container->host_data.rhs_data.begin(), data_container->number_of_bilaterals, rhs_bilateral.begin());
		solver.SolveStab(data_container->host_data.gamma_bilateral, rhs_bilateral, max_iter_bilateral);
	}

	thrust::copy_n(data_container->host_data.gamma_bilateral.begin(), data_container->number_of_bilaterals, data_container->host_data.gamma_data.begin());

	//thrust::copy_n(data_container->host_data.gamma_data.begin() + data_container->number_of_rigid_rigid * 6, data_container->number_of_bilaterals, data_container->host_data.gamma_bilateral.begin());
	//for (int i = 0; i < data_container->number_of_bilaterals; i++) {
	//	data_container->host_data.gamma_bilateral[i] *= .5;
	//}

	solver.ComputeImpulses();

	tot_iterations = solver.GetIteration();
	residual = solver.GetResidual();

	////for (int i = 0; i < solver.iter_hist.size(); i++) {
	////	AtIterationEnd(solver.maxd_hist[i], solver.maxdeltalambda_hist[i], solver.iter_hist[i]);
	////}

}

<commit_msg>Some cleanup related to bilateral constraints.<commit_after>#include "ChLcpSolverParallel.h"
#include "math/ChThrustLinearAlgebra.h"

using namespace chrono;

//// TODO:  For now, this is hard-coded for Hunt-Crossley with Simple Sliding Friction.
__host__ __device__
void function_CalcContactForces(int&       index,           // index of this contact pair
                                real&      dT,              // integration time step
                                real3*     pos,             // body positions
                                real4*     rot,             // body orientations
                                real3*     vel,             // body linear velocity (global frame)
                                real3*     omg,             // body angular velocity (local frame)
                                real2*     elastic_moduli,  // Young's modulus (per body)
                                real*      mu,              // coefficient of friction (per body)
                                real*      alpha,           // disipation coefficient (per body)
                                real*      cr,              // coefficient of restitution (per body)
                                real*      cohesion,        // cohesion force (per body)
                                int2*      body_id,         // body IDs (per contact)
                                real3*     pt1,             // point on shape 1 (per contact)
                                real3*     pt2,             // point on shape 2 (per contact)
                                real3*     normal,          // contact normal (per contact)
                                real*      depth,           // penetration depth (per contact)
                                real*      eff_radius,      // effective contact radius (per contact)
                                int*       ext_body_id,     // [output] body IDs (two per contact)
                                real3*     ext_body_force,  // [output] body force (two per contact)
                                real3*     ext_body_torque) // [output] body torque (two per contact)
{
	// Identify the two bodies in contact.
	int body1 = body_id[index].x;
	int body2 = body_id[index].y;

	// If the two contact shapes are actually separated, set zero forces and torques
	if (depth[index] >= 0) {
		ext_body_id[2*index] = body1;
		ext_body_id[2*index+1] = body2;
		ext_body_force[2*index] = ZERO_VECTOR;
		ext_body_force[2*index+1] = ZERO_VECTOR;
		ext_body_torque[2*index] = ZERO_VECTOR;
		ext_body_torque[2*index+1] = ZERO_VECTOR;

		return;
	}

	// Kinematic information
	// ---------------------

	// Express contact point locations in local frames
	//   s' = At * s = At * (rP - r)
	real3 pt1_loc = TransformParentToLocal(pos[body1], rot[body1], pt1[index]);
	real3 pt2_loc = TransformParentToLocal(pos[body2], rot[body2], pt2[index]);

	// Calculate relative velocity (in global frame)
	//   vP = v + omg x s = v + A * (omg' x s')
	real3 vel1 = vel[body1] + quatRotateMat(cross(omg[body1], pt1_loc), rot[body1]);
	real3 vel2 = vel[body2] + quatRotateMat(cross(omg[body2], pt2_loc), rot[body2]);
	real3 relvel = vel2 - vel1;
	real  relvel_n_mag = dot(relvel, normal[index]);
	real3 relvel_n = relvel_n_mag * normal[index];
	real3 relvel_t = relvel - relvel_n;
	real  relvel_t_mag = length(relvel_t);

	// Calculate composite material properties
	// ---------------------------------------

	real Y1 = elastic_moduli[body1].x;
	real Y2 = elastic_moduli[body2].x;
	real nu1 = elastic_moduli[body1].y;
	real nu2 = elastic_moduli[body2].y;
	real inv_E = (1 - nu1 * nu1) / Y1 + (1 - nu2 * nu2) / Y2;
	real inv_G = 2 * (2 + nu1) * (1 - nu1) / Y1 + 2 * (2 + nu2) * (1 - nu2) / Y2;

	real E_eff = 1 / inv_E;
	real G_eff = 1 / inv_G;

	real mu_eff = min(mu[body1], mu[body2]);
	//real cr_eff = (cr[body1] + cr[body2]) / 2;
	real alpha_eff = (alpha[body1] + alpha[body2]) / 2;

	real cohesion_eff = min(cohesion[body1], cohesion[body2]);

	// Contact force
	// -------------

	// Normal force: Hunt-Crossley
	real delta = -depth[index];
	real kn = (4.0 / 3) * E_eff * sqrt(eff_radius[index]);
	real forceN_elastic = kn * delta * sqrt(delta);
	real forceN_dissipation = 1.5 * alpha_eff * forceN_elastic * relvel_n_mag;
	real forceN = forceN_elastic - forceN_dissipation;

	// Cohesion force
	forceN -= cohesion_eff;

	real3 force = forceN * normal[index];

	// Tangential force: Simple Coulomb Sliding
	if (relvel_t_mag > 1e-4) {
		real forceT = mu_eff * abs(forceN);

		force -= (forceT / relvel_t_mag) * relvel_t;
	}

	// Body forces (in global frame) & torques (in local frame)
	// --------------------------------------------------------

	// Convert force into the local body frames and calculate induced torques
	//    n' = s' x F' = s' x (A*F)
	real3 torque1_loc = cross(pt1_loc, quatRotateMatT(force, rot[body1]));
	real3 torque2_loc = cross(pt2_loc, quatRotateMatT(force, rot[body2]));

	// Store body forces and torques
	ext_body_id[2*index]   = body1;
	ext_body_id[2*index+1] = body2;
	ext_body_force[2*index]   = -force;
	ext_body_force[2*index+1] =  force;
	ext_body_torque[2*index]   = -torque1_loc;
	ext_body_torque[2*index+1] =  torque2_loc;
}

void ChLcpSolverParallelDEM::host_CalcContactForces(custom_vector<int>&   ext_body_id,
                                                    custom_vector<real3>& ext_body_force,
                                                    custom_vector<real3>& ext_body_torque)
{
#pragma omp parallel for
	for (int index = 0; index < data_container->number_of_rigid_rigid; index++) {
		function_CalcContactForces(
			index,
			step_size,
			data_container->host_data.pos_data.data(),
			data_container->host_data.rot_data.data(),
			data_container->host_data.vel_data.data(),
			data_container->host_data.omg_data.data(),
			data_container->host_data.elastic_moduli.data(),
			data_container->host_data.mu.data(),
			data_container->host_data.alpha.data(),
			data_container->host_data.cr.data(),
			data_container->host_data.cohesion_data.data(),
			data_container->host_data.bids_rigid_rigid.data(),
			data_container->host_data.cpta_rigid_rigid.data(),
			data_container->host_data.cptb_rigid_rigid.data(),
			data_container->host_data.norm_rigid_rigid.data(),
			data_container->host_data.dpth_rigid_rigid.data(),
			data_container->host_data.erad_rigid_rigid.data(),
			ext_body_id.data(),
			ext_body_force.data(),
			ext_body_torque.data());
	}
}

void ChLcpSolverParallelDEM::host_AddContactForces(uint                        ct_body_count,
                                                   const custom_vector<int>&   ct_body_id,
                                                   const custom_vector<real3>& ct_body_force,
                                                   const custom_vector<real3>& ct_body_torque)
{
#pragma omp parallel for
	for (int index = 0; index < ct_body_count; index++) {
		data_container->host_data.frc_data[ct_body_id[index]] += step_size * ct_body_force[index];
		data_container->host_data.trq_data[ct_body_id[index]] += step_size * ct_body_torque[index];
	}
}

void ChLcpSolverParallelDEM::ProcessContacts()
{
	// 0. If the narrowphase collision detection does not set the effective contact
	//    radius, fill it with the value 1.
	if (!data_container->erad_is_set)
		data_container->host_data.erad_rigid_rigid.resize(data_container->number_of_rigid_rigid, 1.0);

	// 1. Calculate contact forces and torques - per contact basis
	//    For each pair of contact shapes that overlap, we calculate and store
	//    the IDs of the two corresponding bodies and the resulting contact
	//    forces and torques on the two bodies.
	custom_vector<int>   ext_body_id(2 * data_container->number_of_rigid_rigid);
	custom_vector<real3> ext_body_force(2 * data_container->number_of_rigid_rigid);
	custom_vector<real3> ext_body_torque(2 * data_container->number_of_rigid_rigid);

	host_CalcContactForces(ext_body_id, ext_body_force, ext_body_torque);

	// 2. Calculate contact forces and torques - per body basis
	//    Accumulate the contact forces and torques for all bodies that are involved
	//    in at least one contact, by reducing the contact forces and torques from
	//    all contacts these bodies are involved in. The number of bodies that
	//    experience at least one contact is calculated in 'ct_body_count'.
	thrust::sort_by_key(
		ext_body_id.begin(), ext_body_id.end(),
		thrust::make_zip_iterator(thrust::make_tuple(ext_body_force.begin(), ext_body_torque.begin())));

	custom_vector<int>   ct_body_id(data_container->number_of_rigid);
	custom_vector<real3> ct_body_force(data_container->number_of_rigid);
	custom_vector<real3> ct_body_torque(data_container->number_of_rigid);

	// Reduce contact forces from all contacts and count bodies currently involved in contact
	uint ct_body_count = thrust::reduce_by_key(
		ext_body_id.begin(),
		ext_body_id.end(),
		thrust::make_zip_iterator(thrust::make_tuple(ext_body_force.begin(), ext_body_torque.begin())),
		ct_body_id.begin(),
		thrust::make_zip_iterator(thrust::make_tuple(ct_body_force.begin(), ct_body_torque.begin())),
		thrust::equal_to<int>(),
		sum_tuples()
		).first - ct_body_id.begin();

	// 3. Add contact forces and torques to existing forces (impulses)
	//    For all bodies involved in a contact, update the body forces and torques,
	//    scaled by the integration time step.
	host_AddContactForces(ct_body_count, ct_body_id, ct_body_force, ct_body_torque);
}

void ChLcpSolverParallelDEM::RunTimeStep(real step)
{
	step_size = step;
	data_container->step_size = step;

	number_of_constraints = data_container->number_of_bilaterals;
	number_of_objects = data_container->number_of_rigid;

	// Calculate contact forces (impulses) and append them to the body forces
	if (data_container->number_of_rigid_rigid)
		ProcessContacts();

	// Include forces and torques (update derivatives: v += m_inv * h * f)
	Preprocess();

	// Return now if there are no (bilateral) constraints
	if (number_of_constraints == 0)
		return;

	data_container->host_data.rhs_data.resize(number_of_constraints);
	data_container->host_data.diag.resize(number_of_constraints);
	data_container->host_data.gamma_data.resize(number_of_constraints);

	//// TODO: Is this needed?  If yes, we should initialize gamma_bilateral anyway...
#pragma omp parallel for
	for (int i = 0; i < number_of_constraints; i++) {
		data_container->host_data.gamma_data[i] = 0;
	}

	bilateral.Setup(data_container);

	solver.current_iteration = 0;
	solver.total_iteration = 0;
	solver.maxd_hist.clear();               ////
	solver.maxdeltalambda_hist.clear();     ////  currently not used
	solver.iter_hist.clear();               ////

	solver.SetTolerance(tolerance);

	////solver.lcp_omega_bilateral = lcp_omega_bilateral;  //// not used anywhere?
	solver.bilateral = &bilateral;
	solver.Initial(step, data_container);

	////bilateral.ComputeJacobians();    //// no-op
	bilateral.ComputeRHS();

	solver.SolveStab(data_container->host_data.gamma_bilateral, data_container->host_data.rhs_data, max_iter_bilateral);

	thrust::copy_n(data_container->host_data.gamma_bilateral.begin(), data_container->number_of_bilaterals, data_container->host_data.gamma_data.begin());

	solver.ComputeImpulses();

	tot_iterations = solver.GetIteration();
	residual = solver.GetResidual();

	////for (int i = 0; i < solver.iter_hist.size(); i++) {
	////	AtIterationEnd(solver.maxd_hist[i], solver.maxdeltalambda_hist[i], solver.iter_hist[i]);
	////}

}

<|endoftext|>


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

#include "gtest/gtest.h"
#include "modules/common/util/testdata/simple.pb.h"

#include "modules/common/util/util.h"

namespace apollo {
namespace common {
namespace util {

TEST(Util, MaxElement) {
  EXPECT_EQ(3, MaxElement(std::vector<int>{1, 2, 3}));
  EXPECT_FLOAT_EQ(3.3, MaxElement(std::vector<float>{1.1, 2.2, 3.3}));
}

TEST(Util, MinElement) {
  EXPECT_EQ(1, MinElement(std::vector<int>{1, 2, 3}));
  EXPECT_FLOAT_EQ(1.1, MinElement(std::vector<float>{1.1, 2.2, 3.3}));
}

TEST(Util, IsProtoEqual) {
  test::SimpleRepeatedMessage sim1;
  for (int i = 0; i < 10; ++i) {
    auto* t = sim1.add_message();
    t->set_integer(i);
    t->set_text(std::to_string(i));
  }
  auto sim2 = sim1;
  EXPECT_TRUE(IsProtoEqual(sim1, sim2));
  sim2.mutable_message(0)->set_integer(-1);
  EXPECT_FALSE(IsProtoEqual(sim1, sim2));
}

TEST(Util, DistanceXY) {
  class TestPoint {
   public:
    TestPoint(double x, double y) : x_(x), y_(y) {}
    double x() const { return x_; }
    double y() const { return y_; }

   private:
    double x_ = 0.0;
    double y_ = 0.0;
  };
  EXPECT_DOUBLE_EQ(0.0, DistanceXY(TestPoint(0, 0), TestPoint(0, 0)));
  EXPECT_DOUBLE_EQ(1.0, DistanceXY(TestPoint(1, 0), TestPoint(0, 0)));
  EXPECT_DOUBLE_EQ(1.0, DistanceXY(TestPoint(0, 0), TestPoint(1, 0)));
  EXPECT_DOUBLE_EQ(0.0, DistanceXY(TestPoint(1, 0), TestPoint(1, 0)));
}

TEST(Util, uniform_slice) {
  std::vector<double> result;
  uniform_slice(0.0, 10.0, 3, &result);
  ASSERT_EQ(4, result.size());
  EXPECT_DOUBLE_EQ(0.0, result[0]);
  EXPECT_DOUBLE_EQ(3.3333333, result[1]);
  EXPECT_DOUBLE_EQ(6.6666666, result[2]);
  EXPECT_DOUBLE_EQ(10.0, result[3]);

  uniform_slice(0.0, -10.0, 3, &result);
  ASSERT_EQ(4, result.size());
  EXPECT_DOUBLE_EQ(0.0, result[0]);
  EXPECT_DOUBLE_EQ(-3.3333333, result[1]);
  EXPECT_DOUBLE_EQ(-6.6666666, result[2]);
  EXPECT_DOUBLE_EQ(-10.0, result[3]);
}

}  // namespace util
}  // namespace common
}  // namespace apollo
<commit_msg>common: fix unit test.<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include <vector>

#include "gtest/gtest.h"
#include "modules/common/util/testdata/simple.pb.h"

#include "modules/common/util/util.h"

namespace apollo {
namespace common {
namespace util {

TEST(Util, MaxElement) {
  EXPECT_EQ(3, MaxElement(std::vector<int>{1, 2, 3}));
  EXPECT_FLOAT_EQ(3.3, MaxElement(std::vector<float>{1.1, 2.2, 3.3}));
}

TEST(Util, MinElement) {
  EXPECT_EQ(1, MinElement(std::vector<int>{1, 2, 3}));
  EXPECT_FLOAT_EQ(1.1, MinElement(std::vector<float>{1.1, 2.2, 3.3}));
}

TEST(Util, IsProtoEqual) {
  test::SimpleRepeatedMessage sim1;
  for (int i = 0; i < 10; ++i) {
    auto* t = sim1.add_message();
    t->set_integer(i);
    t->set_text(std::to_string(i));
  }
  auto sim2 = sim1;
  EXPECT_TRUE(IsProtoEqual(sim1, sim2));
  sim2.mutable_message(0)->set_integer(-1);
  EXPECT_FALSE(IsProtoEqual(sim1, sim2));
}

TEST(Util, DistanceXY) {
  class TestPoint {
   public:
    TestPoint(double x, double y) : x_(x), y_(y) {}
    double x() const { return x_; }
    double y() const { return y_; }

   private:
    double x_ = 0.0;
    double y_ = 0.0;
  };
  EXPECT_DOUBLE_EQ(0.0, DistanceXY(TestPoint(0, 0), TestPoint(0, 0)));
  EXPECT_DOUBLE_EQ(1.0, DistanceXY(TestPoint(1, 0), TestPoint(0, 0)));
  EXPECT_DOUBLE_EQ(1.0, DistanceXY(TestPoint(0, 0), TestPoint(1, 0)));
  EXPECT_DOUBLE_EQ(0.0, DistanceXY(TestPoint(1, 0), TestPoint(1, 0)));
}

TEST(Util, uniform_slice) {
  std::vector<double> result;
  uniform_slice(0.0, 10.0, 3, &result);
  ASSERT_EQ(4, result.size());
  EXPECT_DOUBLE_EQ(0.0, result[0]);
  EXPECT_DOUBLE_EQ(3.3333333333333335, result[1]);
  EXPECT_DOUBLE_EQ(6.666666666666667, result[2]);
  EXPECT_DOUBLE_EQ(10.0, result[3]);

  uniform_slice(0.0, -10.0, 3, &result);
  ASSERT_EQ(4, result.size());
  EXPECT_DOUBLE_EQ(0.0, result[0]);
  EXPECT_DOUBLE_EQ(-3.3333333333333335, result[1]);
  EXPECT_DOUBLE_EQ(-6.666666666666667, result[2]);
  EXPECT_DOUBLE_EQ(-10.0, result[3]);
}

}  // namespace util
}  // namespace common
}  // namespace apollo
<|endoftext|>


<commit_before>// Used for testing, do not use it as an example
#include <qpp.h>
#include <experimental/test.h>
// #include <MATLAB/matlab.h>
using namespace qpp;
using std::cout;
using std::endl;

int main()
{
    int i = 42;
    std::cout << i++ << std::endl;
    std::cout << i << std::endl;
}
<commit_msg>commit<commit_after>// Used for testing, do not use it as an example
#include <qpp.h>
#include <experimental/test.h>
// #include <MATLAB/matlab.h>
using namespace qpp;
using std::cout;
using std::endl;

int main()
{

}
<|endoftext|>


<commit_before>// Source: http://www.daniweb.com/software-development/cpp/code/427500/calculator-using-shunting-yard-algorithm#
// Author: Jesse Brown
// Modifications: Brandon Amos

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>

#include "shunting-yard.h"

int ShuntingYard::precedence(std::string op) const {
  return op_precedence_[op];
}

int ShuntingYard::stack_precedence() const {
  if (op_stack_.empty()) {
    return -1;
  }
  return precedence(op_stack_.top());
}

bool isVariableChar(const char c) {
  return isalpha(c) || c == '_';
}

tokenQueue_t ShuntingYard::convert(const std::string &infix) {
  const char* token = infix.c_str();
  while (*token) {
    while (*token && isspace(*token)) ++token;
    if (!*token) break;

    if (isdigit(*token)) {
      // If the token is a number, add it to the output queue.
      char* nextToken = 0;
      double digit = strtod(token, &nextToken);
#     ifdef DEBUG
        std::cout << digit << std::endl;
#     endif
      rpn_.push(new Token<double>(digit));
      token = nextToken;
    } else if (isVariableChar(*token)) {
      // If the function is a variable, resolve it and
      // add the parsed number to the output queue.
      if (!vars_) {
        std::cerr << "Error: Detected variable, " <<
          "but the variable map is null." << std::endl;
        exit(42);
      }

      std::stringstream ss;
      ss << *token;
      ++token;
      while (isVariableChar(*token)) {
        ss << *token;
        ++token;
      }
      std::string key = ss.str();
      std::map<std::string, double>::iterator it = vars_->find(key);
      if (it == vars_->end()) {
        std::cerr << "Error: Unable to find the variable '" <<
          key << "'." << std::endl;
        exit(42);
      }
      double val = vars_->find(key)->second;
#     ifdef DEBUG
        std::cout << val << std::endl;
#     endif
      rpn_.push(new Token<double>(val));;
    } else {
      // Otherwise, the variable is an operator or paranthesis.
      switch (*token) {
        case '(':
          op_stack_.push("(");
          ++token;
          break;
        case ')':
          while (op_stack_.top().compare("(")) {
            rpn_.push(new Token<std::string>(op_stack_.top()));
            op_stack_.pop();
          }
          op_stack_.pop();
          ++token;
          break;
        default:
          {
            // Let p(o) denote the precedence of an operator o.
            //
            // If the token is an operator, o1, then
            //   While there is an operator token, o2, at the top
            //       and p(o1) <= p(o2), then
            //     pop o2 off the stack onto the output queue.
            //   Push o1 on the stack.
            std::stringstream ss;
            ss << *token;
            ++token;
            while (*token && !isspace(*token) && !isdigit(*token)
                && *token != '(' && *token != ')') {
              ss << *token;
              ++token;
            }
            ss.clear();
            std::string str;
            ss >> str;
#           ifdef DEBUG
              std::cout << str << std::endl;
#           endif

            while (!op_stack_.empty() &&
                precedence(str) <= stack_precedence()) {
              rpn_.push(new Token<std::string>(op_stack_.top()));
              op_stack_.pop();
            }
            op_stack_.push(str);
          }
      }
    }
  }
  while (!op_stack_.empty()) {
    rpn_.push(new Token<std::string>(op_stack_.top()));
    op_stack_.pop();
  }
  return rpn_;
}

tokenQueue_t ShuntingYard::to_rpn() {
  return convert(expr_);
}

ShuntingYard::ShuntingYard (const std::string& infix,
    std::map<std::string, double>* vars) : expr_(infix), vars_(vars) {
  op_precedence_["("] = -1;
  op_precedence_["<<"] = 1; op_precedence_[">>"] = 1;
  op_precedence_["+"]  = 2; op_precedence_["-"]  = 2;
  op_precedence_["*"]  = 3; op_precedence_["/"]  = 3;
}

void calculator::consume(std::string op, std::stack<double>* operands) {
  double right = operands->top(); operands->pop();
  double left  = operands->top(); operands->pop();
  if (!op.compare("+")) {
    operands->push(left + right);
  } else if (!op.compare("*")) {
    operands->push(left * right);
  } else if (!op.compare("-")) {
    operands->push(left - right);
  } else if (!op.compare("/")) {
    operands->push(left / right);
  } else if (!op.compare("<<")) {
    operands->push((int) left << (int) right);
  } else if (!op.compare(">>")) {
    operands->push((int) left >> (int) right);
  } else {
    throw std::domain_error("Unknown operator: '" + op + "'.");
  }
}

double calculator::calculate(const std::string& expr,
    std::map<std::string, double>* vars) {
  ShuntingYard shunting(expr, vars);
  tokenQueue_t rpn = shunting.to_rpn();

  std::stack<double> operands;
  while (!rpn.empty()) {
    TokenBase* base = rpn.front();
    rpn.pop();

    Token<std::string>* strTok = dynamic_cast<Token<std::string>*>(base);
    if (strTok) {
      consume(strTok->val, &operands);
      delete base;
      continue;
    }

    Token<double>* doubleTok = dynamic_cast<Token<double>*>(base);
    if (doubleTok) {
      operands.push(doubleTok->val);
      delete base;
      continue;
    }

    std::cerr << "Invalid token." << std::endl;
    exit(42);
  }
  return operands.top();
}
<commit_msg>Improve error checking.<commit_after>// Source: http://www.daniweb.com/software-development/cpp/code/427500/calculator-using-shunting-yard-algorithm#
// Author: Jesse Brown
// Modifications: Brandon Amos

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>

#include "shunting-yard.h"

int ShuntingYard::precedence(std::string op) const {
  return op_precedence_[op];
}

int ShuntingYard::stack_precedence() const {
  if (op_stack_.empty()) {
    return -1;
  }
  return precedence(op_stack_.top());
}

bool isVariableChar(const char c) {
  return isalpha(c) || c == '_';
}

tokenQueue_t ShuntingYard::convert(const std::string &infix) {
  const char* token = infix.c_str();
  while (*token) {
    while (*token && isspace(*token)) ++token;
    if (!*token) break;

    if (isdigit(*token)) {
      // If the token is a number, add it to the output queue.
      char* nextToken = 0;
      double digit = strtod(token, &nextToken);
#     ifdef DEBUG
        std::cout << digit << std::endl;
#     endif
      rpn_.push(new Token<double>(digit));
      token = nextToken;
    } else if (isVariableChar(*token)) {
      // If the function is a variable, resolve it and
      // add the parsed number to the output queue.
      if (!vars_) {
        throw std::domain_error(
            "Detected variable, but the variable map is null.");
      }

      std::stringstream ss;
      ss << *token;
      ++token;
      while (isVariableChar(*token)) {
        ss << *token;
        ++token;
      }
      std::string key = ss.str();
      std::map<std::string, double>::iterator it = vars_->find(key);
      if (it == vars_->end()) {
        throw std::domain_error(
            "Unable to find the variable '" + key + "'.");
      }
      double val = vars_->find(key)->second;
#     ifdef DEBUG
        std::cout << val << std::endl;
#     endif
      rpn_.push(new Token<double>(val));;
    } else {
      // Otherwise, the variable is an operator or paranthesis.
      switch (*token) {
        case '(':
          op_stack_.push("(");
          ++token;
          break;
        case ')':
          while (op_stack_.top().compare("(")) {
            rpn_.push(new Token<std::string>(op_stack_.top()));
            op_stack_.pop();
          }
          op_stack_.pop();
          ++token;
          break;
        default:
          {
            // Let p(o) denote the precedence of an operator o.
            //
            // If the token is an operator, o1, then
            //   While there is an operator token, o2, at the top
            //       and p(o1) <= p(o2), then
            //     pop o2 off the stack onto the output queue.
            //   Push o1 on the stack.
            std::stringstream ss;
            ss << *token;
            ++token;
            while (*token && !isspace(*token) && !isdigit(*token)
                && *token != '(' && *token != ')') {
              ss << *token;
              ++token;
            }
            ss.clear();
            std::string str;
            ss >> str;
#           ifdef DEBUG
              std::cout << str << std::endl;
#           endif

            while (!op_stack_.empty() &&
                precedence(str) <= stack_precedence()) {
              rpn_.push(new Token<std::string>(op_stack_.top()));
              op_stack_.pop();
            }
            op_stack_.push(str);
          }
      }
    }
  }
  while (!op_stack_.empty()) {
    rpn_.push(new Token<std::string>(op_stack_.top()));
    op_stack_.pop();
  }
  return rpn_;
}

tokenQueue_t ShuntingYard::to_rpn() {
  return convert(expr_);
}

ShuntingYard::ShuntingYard (const std::string& infix,
    std::map<std::string, double>* vars) : expr_(infix), vars_(vars) {
  op_precedence_["("] = -1;
  op_precedence_["<<"] = 1; op_precedence_[">>"] = 1;
  op_precedence_["+"]  = 2; op_precedence_["-"]  = 2;
  op_precedence_["*"]  = 3; op_precedence_["/"]  = 3;
}

void calculator::consume(std::string op, std::stack<double>* operands) {
  if (operands->size() < 2) {
    throw std::domain_error("Invalid equation.");
  }
  double right = operands->top(); operands->pop();
  double left  = operands->top(); operands->pop();
  if (!op.compare("+")) {
    operands->push(left + right);
  } else if (!op.compare("*")) {
    operands->push(left * right);
  } else if (!op.compare("-")) {
    operands->push(left - right);
  } else if (!op.compare("/")) {
    operands->push(left / right);
  } else if (!op.compare("<<")) {
    operands->push((int) left << (int) right);
  } else if (!op.compare(">>")) {
    operands->push((int) left >> (int) right);
  } else {
    throw std::domain_error("Unknown operator: '" + op + "'.");
  }
}

double calculator::calculate(const std::string& expr,
    std::map<std::string, double>* vars) {
  ShuntingYard shunting(expr, vars);
  tokenQueue_t rpn = shunting.to_rpn();

  std::stack<double> operands;
  while (!rpn.empty()) {
    TokenBase* base = rpn.front();
    rpn.pop();

    Token<std::string>* strTok = dynamic_cast<Token<std::string>*>(base);
    if (strTok) {
      consume(strTok->val, &operands);
      delete base;
      continue;
    }

    Token<double>* doubleTok = dynamic_cast<Token<double>*>(base);
    if (doubleTok) {
      operands.push(doubleTok->val);
      delete base;
      continue;
    }

    throw std::domain_error("Invalid token.");
  }
  return operands.top();
}
<|endoftext|>


<commit_before>//===-- BitWriter.cpp -----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-c/BitWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

/*===-- Operations on modules ---------------------------------------------===*/

int LLVMWriteBitcodeToFile(LLVMModuleRef M, const char *Path) {
  std::string ErrorInfo;
  raw_fd_ostream OS(Path, ErrorInfo,
                    raw_fd_ostream::F_Binary);

  if (!ErrorInfo.empty())
    return -1;

  WriteBitcodeToFile(unwrap(M), OS);
  return 0;
}

#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR >= 4)
#include <ext/stdio_filebuf.h>

int LLVMWriteBitcodeToFileHandle(LLVMModuleRef M, int FileHandle) {
  raw_fd_ostream OS(FileHandle, false);

  WriteBitcodeToFile(unwrap(M), OS);
  return 0;
}

#else

int LLVMWriteBitcodeToFileHandle(LLVMModuleRef M, int FileHandle) {
  return -1; // Not supported.
}

#endif
<commit_msg>LLVMWriteBitcodeToFileHandle should work on all architectures now.<commit_after>//===-- BitWriter.cpp -----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-c/BitWriter.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

/*===-- Operations on modules ---------------------------------------------===*/

int LLVMWriteBitcodeToFile(LLVMModuleRef M, const char *Path) {
  std::string ErrorInfo;
  raw_fd_ostream OS(Path, ErrorInfo,
                    raw_fd_ostream::F_Binary);

  if (!ErrorInfo.empty())
    return -1;

  WriteBitcodeToFile(unwrap(M), OS);
  return 0;
}

int LLVMWriteBitcodeToFileHandle(LLVMModuleRef M, int FileHandle) {
  raw_fd_ostream OS(FileHandle, false);

  WriteBitcodeToFile(unwrap(M), OS);
  return 0;
}
<|endoftext|>


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

#include "pch.hpp"
#include <core/Library/LocalDB.h>
#include <core/Query/Base.h>
#include <core/Preferences.h>

#include <boost/bind.hpp>

using namespace musik::core;

//////////////////////////////////////////
///\brief
///Constructor.
///
///The constructor will not start the Library.
///
///\see
///Startup
//////////////////////////////////////////
Library::LocalDB::LocalDB(void){
}

Library::LocalDB::~LocalDB(void){
}

//////////////////////////////////////////
///\brief
///Get a short status string of what is going on in the Library.
///
///\returns
///Information string.
///
///The information is mostly used to get the information
///about the Indexer.
//////////////////////////////////////////
utfstring Library::LocalDB::GetInfo(){
    return this->indexer.GetStatus();
}

//////////////////////////////////////////
///\brief
///Startup the library threads.
///
///\returns
///True if successfully started. This should always be true. Nothing else is expected.
///
///Start up the Library like this:
///\code
/// // Create a library
/// musik::core::Library::LocalDB library;
/// // Start the library (and indexer that is included)
/// library.Startup();
/// // The library is now ready to recieve queries
///\endcode
//////////////////////////////////////////
bool Library::LocalDB::Startup(){

    // Start the library thread
    this->threads.create_thread(boost::bind(&Library::LocalDB::ThreadLoop,this));

    return true;
}

//////////////////////////////////////////
///\brief
///Create all tables, indexes, etc in the database.
///
///This will assume that the database has been initialized.
//////////////////////////////////////////
void Library::LocalDB::CreateDatabase(){
    // Create the tracks-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS tracks ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track INTEGER DEFAULT 0,"
            "bpm REAL DEFAULT 0,"
            "duration INTEGER DEFAULT 0,"
            "filesize INTEGER DEFAULT 0,"
            "year INTEGER DEFAULT 0,"
            "visual_genre_id INTEGER DEFAULT 0,"
            "visual_artist_id INTEGER DEFAULT 0,"
            "album_id INTEGER DEFAULT 0,"
            "folder_id INTEGER DEFAULT 0,"
            "title TEXT default '',"
            "filename TEXT default '',"
            "filetime INTEGER DEFAULT 0,"
            "thumbnail_id INTEGER DEFAULT 0,"
            "sort_order1 INTEGER)");

    // Create the genres-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS genres ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "aggregated INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS track_genres ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track_id INTEGER DEFAULT 0,"
            "genre_id INTEGER DEFAULT 0)");

    // Create the artists-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS artists ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "aggregated INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS track_artists ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track_id INTEGER DEFAULT 0,"
            "artist_id INTEGER DEFAULT 0)");

    // Create the meta-tables
    this->db.Execute("CREATE TABLE IF NOT EXISTS meta_keys ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS meta_values ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "meta_key_id INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0,"
            "content TEXT)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS track_meta ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track_id INTEGER DEFAULT 0,"
            "meta_value_id INTEGER DEFAULT 0)");

    // Create the albums-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS albums ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "thumbnail_id INTEGER default 0,"
            "sort_order INTEGER DEFAULT 0)");

    // Create the paths-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS paths ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "path TEXT default ''"
            ")");

    // Create the folders-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS folders ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "fullpath TEXT default '',"
            "parent_id INTEGER DEFAULT 0,"
            "path_id INTEGER DEFAULT 0"
            ")");

    // Create the folders-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS thumbnails ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "filename TEXT default '',"
            "filesize INTEGER DEFAULT 0,"
            "checksum INTEGER DEFAULT 0"
            ")");

    // Create the playlists-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS playlists ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default ''"
            ")");
    // Create the playlists-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS playlist_tracks ("
            "track_id INTEGER DEFAULT 0,"
            "playlist_id INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0"
            ")");

    // INDEXES
    this->db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS folders_index ON folders (name,parent_id,path_id)");
    this->db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS paths_index ON paths (path)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS genre_index ON genres (sort_order)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS artist_index ON artists (sort_order)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS album_index ON albums (sort_order)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS track_index1 ON tracks (album_id,sort_order1)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS track_index7 ON tracks (folder_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS thumbnail_index ON thumbnails (filesize)");

    this->db.Execute("CREATE INDEX IF NOT EXISTS trackgenre_index1 ON track_genres (track_id,genre_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackgenre_index2 ON track_genres (genre_id,track_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackartist_index1 ON track_artists (track_id,artist_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackartist_index2 ON track_artists (artist_id,track_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackmeta_index1 ON track_meta (track_id,meta_value_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackmeta_index2 ON track_meta (meta_value_id,track_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS metakey_index1 ON meta_keys (name)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS metavalues_index1 ON meta_values (meta_key_id)");

    this->db.Execute("CREATE INDEX IF NOT EXISTS playlist_index ON playlist_tracks (playlist_id,sort_order)");

    this->db.Execute("ANALYZE");
}

//////////////////////////////////////////
///\brief
///Main loop the library thread is running in.
///
///The loop will run until Exit(true) has been called.
//////////////////////////////////////////
void Library::LocalDB::ThreadLoop(){

    Preferences prefs("Library");

    utfstring database(this->GetDBPath());
    this->db.Open(database.c_str(),0,prefs.GetInt("DatabaseCache",4096));

    this->CreateDatabase();

    // Startup the indexer
    this->indexer.database    = database;
    this->indexer.Startup(this->GetLibraryDirectory());

    while(!this->Exit()){
        Query::Ptr query(this->GetNextQuery());

        if(query){    // No empty query

            ////////////////////////////////////////////////////////////
            // Add to the finished queries
            {
                boost::mutex::scoped_lock lock(this->libraryMutex);
                this->bCurrentQueryCanceled    = false;
                this->runningQuery    = query;
                this->outgoingQueries.push_back(query);

                // Set query as started
                query->status |= Query::Base::Status::Started;
            }

            ////////////////////////////////////////////////////////////
            // Lets parse the query
            query->ParseQuery(this,this->db);
            {
                boost::mutex::scoped_lock lock(this->libraryMutex);
                this->runningQuery.reset();
                // And set it as finished
                query->status |= Query::Base::Status::Ended;
            }

            ////////////////////////////////////////////////////////////
            // Notify that the Query is finished.
            this->waitCondition.notify_all();

        }else{

            ////////////////////////////////////////////////////////////
            // Tricky part, waiting for queries to be added.
            // Not sure I'm doing this the right way.
            // Could this part lead to a deadlock???
            boost::mutex::scoped_lock lock(this->libraryMutex);
            if(!this->exit && this->incomingQueries.size()==0 ){
                this->waitCondition.wait(lock);
            }
        }
    }

}

//////////////////////////////////////////
///\brief
///Cancel the current running query
///
///This method will also send a sqlite3_interrupt to cancel the
///current running SQL Query
//////////////////////////////////////////
void Library::LocalDB::CancelCurrentQuery( ){
    this->bCurrentQueryCanceled    = true;
    this->db.Interrupt();
}

musik::core::Indexer *Library::LocalDB::Indexer(){
    return &this->indexer;
}

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

#include "pch.hpp"
#include <core/Library/LocalDB.h>
#include <core/Query/Base.h>
#include <core/Preferences.h>

#include <boost/bind.hpp>

using namespace musik::core;

//////////////////////////////////////////
///\brief
///Constructor.
///
///The constructor will not start the Library.
///
///\see
///Startup
//////////////////////////////////////////
Library::LocalDB::LocalDB(void){
}

Library::LocalDB::~LocalDB(void){
    this->Exit(true);
    this->threads.join_all();
}

//////////////////////////////////////////
///\brief
///Get a short status string of what is going on in the Library.
///
///\returns
///Information string.
///
///The information is mostly used to get the information
///about the Indexer.
//////////////////////////////////////////
utfstring Library::LocalDB::GetInfo(){
    return this->indexer.GetStatus();
}

//////////////////////////////////////////
///\brief
///Startup the library threads.
///
///\returns
///True if successfully started. This should always be true. Nothing else is expected.
///
///Start up the Library like this:
///\code
/// // Create a library
/// musik::core::Library::LocalDB library;
/// // Start the library (and indexer that is included)
/// library.Startup();
/// // The library is now ready to recieve queries
///\endcode
//////////////////////////////////////////
bool Library::LocalDB::Startup(){

    // Start the library thread
    this->threads.create_thread(boost::bind(&Library::LocalDB::ThreadLoop,this));

    return true;
}

//////////////////////////////////////////
///\brief
///Create all tables, indexes, etc in the database.
///
///This will assume that the database has been initialized.
//////////////////////////////////////////
void Library::LocalDB::CreateDatabase(){
    // Create the tracks-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS tracks ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track INTEGER DEFAULT 0,"
            "bpm REAL DEFAULT 0,"
            "duration INTEGER DEFAULT 0,"
            "filesize INTEGER DEFAULT 0,"
            "year INTEGER DEFAULT 0,"
            "visual_genre_id INTEGER DEFAULT 0,"
            "visual_artist_id INTEGER DEFAULT 0,"
            "album_id INTEGER DEFAULT 0,"
            "folder_id INTEGER DEFAULT 0,"
            "title TEXT default '',"
            "filename TEXT default '',"
            "filetime INTEGER DEFAULT 0,"
            "thumbnail_id INTEGER DEFAULT 0,"
            "sort_order1 INTEGER)");

    // Create the genres-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS genres ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "aggregated INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS track_genres ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track_id INTEGER DEFAULT 0,"
            "genre_id INTEGER DEFAULT 0)");

    // Create the artists-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS artists ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "aggregated INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS track_artists ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track_id INTEGER DEFAULT 0,"
            "artist_id INTEGER DEFAULT 0)");

    // Create the meta-tables
    this->db.Execute("CREATE TABLE IF NOT EXISTS meta_keys ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS meta_values ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "meta_key_id INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0,"
            "content TEXT)");

    this->db.Execute("CREATE TABLE IF NOT EXISTS track_meta ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "track_id INTEGER DEFAULT 0,"
            "meta_value_id INTEGER DEFAULT 0)");

    // Create the albums-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS albums ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "thumbnail_id INTEGER default 0,"
            "sort_order INTEGER DEFAULT 0)");

    // Create the paths-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS paths ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "path TEXT default ''"
            ")");

    // Create the folders-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS folders ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default '',"
            "fullpath TEXT default '',"
            "parent_id INTEGER DEFAULT 0,"
            "path_id INTEGER DEFAULT 0"
            ")");

    // Create the folders-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS thumbnails ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "filename TEXT default '',"
            "filesize INTEGER DEFAULT 0,"
            "checksum INTEGER DEFAULT 0"
            ")");

    // Create the playlists-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS playlists ("
            "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            "name TEXT default ''"
            ")");
    // Create the playlists-table
    this->db.Execute("CREATE TABLE IF NOT EXISTS playlist_tracks ("
            "track_id INTEGER DEFAULT 0,"
            "playlist_id INTEGER DEFAULT 0,"
            "sort_order INTEGER DEFAULT 0"
            ")");

    // INDEXES
    this->db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS folders_index ON folders (name,parent_id,path_id)");
    this->db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS paths_index ON paths (path)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS genre_index ON genres (sort_order)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS artist_index ON artists (sort_order)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS album_index ON albums (sort_order)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS track_index1 ON tracks (album_id,sort_order1)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS track_index7 ON tracks (folder_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS thumbnail_index ON thumbnails (filesize)");

    this->db.Execute("CREATE INDEX IF NOT EXISTS trackgenre_index1 ON track_genres (track_id,genre_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackgenre_index2 ON track_genres (genre_id,track_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackartist_index1 ON track_artists (track_id,artist_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackartist_index2 ON track_artists (artist_id,track_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackmeta_index1 ON track_meta (track_id,meta_value_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS trackmeta_index2 ON track_meta (meta_value_id,track_id)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS metakey_index1 ON meta_keys (name)");
    this->db.Execute("CREATE INDEX IF NOT EXISTS metavalues_index1 ON meta_values (meta_key_id)");

    this->db.Execute("CREATE INDEX IF NOT EXISTS playlist_index ON playlist_tracks (playlist_id,sort_order)");

    this->db.Execute("ANALYZE");
}

//////////////////////////////////////////
///\brief
///Main loop the library thread is running in.
///
///The loop will run until Exit(true) has been called.
//////////////////////////////////////////
void Library::LocalDB::ThreadLoop(){

    Preferences prefs("Library");

    utfstring database(this->GetDBPath());
    this->db.Open(database.c_str(),0,prefs.GetInt("DatabaseCache",4096));

    this->CreateDatabase();

    // Startup the indexer
    this->indexer.database    = database;
    this->indexer.Startup(this->GetLibraryDirectory());

    while(!this->Exit()){
        Query::Ptr query(this->GetNextQuery());

        if(query){    // No empty query

            ////////////////////////////////////////////////////////////
            // Add to the finished queries
            {
                boost::mutex::scoped_lock lock(this->libraryMutex);
                this->bCurrentQueryCanceled    = false;
                this->runningQuery    = query;
                this->outgoingQueries.push_back(query);

                // Set query as started
                query->status |= Query::Base::Status::Started;
            }

            ////////////////////////////////////////////////////////////
            // Lets parse the query
            query->ParseQuery(this,this->db);
            {
                boost::mutex::scoped_lock lock(this->libraryMutex);
                this->runningQuery.reset();
                // And set it as finished
                query->status |= Query::Base::Status::Ended;
            }

            ////////////////////////////////////////////////////////////
            // Notify that the Query is finished.
            this->waitCondition.notify_all();

        }else{

            ////////////////////////////////////////////////////////////
            // Tricky part, waiting for queries to be added.
            // Not sure I'm doing this the right way.
            // Could this part lead to a deadlock???
            boost::mutex::scoped_lock lock(this->libraryMutex);
            if(!this->exit && this->incomingQueries.size()==0 ){
                this->waitCondition.wait(lock);
            }
        }
    }

}

//////////////////////////////////////////
///\brief
///Cancel the current running query
///
///This method will also send a sqlite3_interrupt to cancel the
///current running SQL Query
//////////////////////////////////////////
void Library::LocalDB::CancelCurrentQuery( ){
    this->bCurrentQueryCanceled    = true;
    this->db.Interrupt();
}

musik::core::Indexer *Library::LocalDB::Indexer(){
    return &this->indexer;
}

<|endoftext|>


<commit_before>
#pragma once

#include <reflectionzeug/property/PropertyGroup.h>

namespace reflectionzeug
{

template <typename Type, typename... Args>
Property<Type> * PropertyGroup::addProperty(const std::string & name, Args&&... args)
{
    // Create new property
    auto property = new Property<Type>(name, std::forward<Args>(args)...);
    if (this->addProperty(property))
    {
        return property;
    }

    // Error, delete property and return
    delete property;
    return nullptr;
}

template <typename Type>
Type PropertyGroup::value(const std::string & path) const
{
    // Get property by path
    const AbstractProperty * property = this->property(path);
    if (!property) {
        return nullptr;
    }

    // Convert into requested type
    Property<Type> * typed = property->as<Property<Type>>();
    if (!typed) {
        return nullptr;
    }

    // Get value
    return typed->value();
}

template <typename Type>
void PropertyGroup::setValue(const std::string & path, const Type & value)
{
    // Get property by path
    const AbstractProperty * property = this->property(path);
    if (!property) {
        return;
    }

    // Convert into requested type
    Property<Type> * typed = property->as<Property<Type>>();
    if (!typed) {
        return;
    }

    // Set value
    typed->setValue(value);
}

} // namespace reflectionzeug
<commit_msg>Add Property.h include, remove const qualifier for AbstractProperty in PropertyGroup.hpp<commit_after>
#pragma once

#include <reflectionzeug/property/PropertyGroup.h>
#include <reflectionzeug/property/Property.h>

namespace reflectionzeug
{

template <typename Type, typename... Args>
Property<Type> * PropertyGroup::addProperty(const std::string & name, Args&&... args)
{
    // Create new property
    auto property = new Property<Type>(name, std::forward<Args>(args)...);
    if (this->addProperty(property))
    {
        return property;
    }

    // Error, delete property and return
    delete property;
    return nullptr;
}

template <typename Type>
Type PropertyGroup::value(const std::string & path) const
{
    // Get property by path
    AbstractProperty * property = this->property(path);
    if (!property) {
        return nullptr;
    }

    // Convert into requested type
    Property<Type> * typed = property->as<Property<Type>>();
    if (!typed) {
        return nullptr;
    }

    // Get value
    return typed->value();
}

template <typename Type>
void PropertyGroup::setValue(const std::string & path, const Type & value)
{
    // Get property by path
    AbstractProperty * property = this->property(path);
    if (!property) {
        return;
    }

    // Convert into requested type
    Property<Type> * typed = property->as<Property<Type>>();
    if (!typed) {
        return;
    }

    // Set value
    typed->setValue(value);
}

} // namespace reflectionzeug
<|endoftext|>


<commit_before>#ifndef LUABIND_CRTP_ITERATOR_HPP_INCLUDED
#define LUABIND_CRTP_ITERATOR_HPP_INCLUDED
#include <iterator>

namespace luabind {
	namespace detail {

		template< typename CRTP, typename Category, typename ValueType, typename ReferenceType = ValueType&, typename DifferenceType = ptrdiff_t >
		class crtp_iterator :
			public std::iterator<Category, ValueType, DifferenceType, ValueType*, ReferenceType >
		{
		public:
			using base_type = std::iterator<Category, ValueType, DifferenceType, ValueType*, ReferenceType >;

			CRTP& operator++()
			{
				upcast().increment();
				return upcast();
			}

			CRTP operator++(int)
			{
				CRTP tmp(*this);
				upcast().increment();
				return tmp;
			}

			bool operator==(const CRTP& rhs)
			{
				return upcast().equal(rhs);
			}

			bool operator!=(const CRTP& rhs)
			{
				return !upcast().equal(rhs);
			}

			typename base_type::reference operator*()
			{
				return upcast().dereference();
			}

			typename base_type::reference operator->()
			{
				return upcast().dereference();
			}

		private:
			CRTP& upcast() { return static_cast<CRTP&>(*this); }
			const CRTP& upcast() const { return static_cast<const CRTP&>(*this); }
		};

	}
}

#endif

<commit_msg>fixed iterator post-increment<commit_after>#ifndef LUABIND_CRTP_ITERATOR_HPP_INCLUDED
#define LUABIND_CRTP_ITERATOR_HPP_INCLUDED
#include <iterator>

namespace luabind {
	namespace detail {

		template< typename CRTP, typename Category, typename ValueType, typename ReferenceType = ValueType&, typename DifferenceType = ptrdiff_t >
		class crtp_iterator :
			public std::iterator<Category, ValueType, DifferenceType, ValueType*, ReferenceType >
		{
		public:
			using base_type = std::iterator<Category, ValueType, DifferenceType, ValueType*, ReferenceType >;

			CRTP& operator++()
			{
				upcast().increment();
				return upcast();
			}

			CRTP operator++(int)
			{
				CRTP tmp(upcast());
				upcast().increment();
				return tmp;
			}

			bool operator==(const CRTP& rhs)
			{
				return upcast().equal(rhs);
			}

			bool operator!=(const CRTP& rhs)
			{
				return !upcast().equal(rhs);
			}

			typename base_type::reference operator*()
			{
				return upcast().dereference();
			}

			typename base_type::reference operator->()
			{
				return upcast().dereference();
			}

		private:
			CRTP& upcast() { return static_cast<CRTP&>(*this); }
			const CRTP& upcast() const { return static_cast<const CRTP&>(*this); }
		};

	}
}

#endif

<|endoftext|>