diff --git a/src/shogun/lib/computation/job/DenseExactLogJob.cpp b/src/shogun/lib/computation/job/DenseExactLogJob.cpp new file mode 100644 index 00000000000..a280b0e0266 --- /dev/null +++ b/src/shogun/lib/computation/job/DenseExactLogJob.cpp @@ -0,0 +1,92 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#include + +#ifdef HAVE_EIGEN3 +#include +#include +#include +#include +#include +#include + +using namespace Eigen; + +namespace shogun +{ + +CDenseExactLogJob::CDenseExactLogJob() + : CIndependentJob(), m_log_operator(NULL) +{ + SG_GCDEBUG("%s created (%p)\n", this->get_name(), this) +} + +CDenseExactLogJob::CDenseExactLogJob(CJobResultAggregator* aggregator) + : CIndependentJob(aggregator), m_log_operator(NULL) +{ + SG_GCDEBUG("%s created (%p)\n", this->get_name(), this) +} + +CDenseExactLogJob::~CDenseExactLogJob() +{ + SG_UNREF(m_log_operator); + SG_GCDEBUG("%s destroyed (%p)\n", this->get_name(), this) +} + +void CDenseExactLogJob::compute() +{ + SG_DEBUG("Entering...\n") + + // apply the log to m_vector + SGVector vec=m_log_operator->apply(m_vector); + + // compute the vector-vector dot product using Eigen3 + Map v(vec.vector, vec.vlen); + Map s(m_vector.vector, m_vector.vlen); + + CScalarResult* result=new CScalarResult(s.dot(v)); + SG_REF(result); + m_aggregator->submit_result(result); + SG_UNREF(result); + + SG_DEBUG("Leaving...\n") +} + +SGVector CDenseExactLogJob::get_vector() const +{ + return m_vector; +} + +void CDenseExactLogJob::set_vector(SGVector vec) +{ + m_vector=vec; +} + +CDenseMatrixOperator* CDenseExactLogJob::get_operator() const +{ + return m_log_operator; +} + +void CDenseExactLogJob::set_operator(CDenseMatrixOperator* op) +{ + // DEBUG COMMENT: SG_REF should increase here!! + // Its important that we first increase the refcount and then + // decrease it. Param might be same, for example, and unref-ing it + // first may accidentally delete it! + // The following is surely a weird way, but works! + CDenseMatrixOperator* old_op=m_log_operator; + SG_UNREF(m_log_operator); + m_log_operator=op; + SG_REF(m_log_operator); + SG_UNREF(old_op); +} + +} +#endif // HAVE_EIGEN3 diff --git a/src/shogun/lib/computation/job/DenseExactLogJob.h b/src/shogun/lib/computation/job/DenseExactLogJob.h new file mode 100644 index 00000000000..b1586420840 --- /dev/null +++ b/src/shogun/lib/computation/job/DenseExactLogJob.h @@ -0,0 +1,70 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#ifndef DENSE_EXACT_LOG_JOB_H_ +#define DENSE_EXACT_LOG_JOB_H_ + +#include + +#ifdef HAVE_EIGEN3 +#include + +namespace shogun +{ +template class SGVector; +template class CDenseMatrixOperator; + +/** @brief Class that represents the job of applying the log of + * a CDenseMatrixOperator on a real vector + */ +class CDenseExactLogJob : public CIndependentJob +{ +public: + /** default constructor, no args */ + CDenseExactLogJob(); + + /** default constructor, one arg */ + CDenseExactLogJob(CJobResultAggregator* aggregator); + + /** destructor */ + virtual ~CDenseExactLogJob(); + + /** implementation of compute method for the job */ + virtual void compute(); + + /** get the vector */ + SGVector get_vector() const; + + /** set the vector */ + void set_vector(SGVector vec); + + /** get the linear operator */ + CDenseMatrixOperator* get_operator() const; + + /** set the linear operator */ + void set_operator(CDenseMatrixOperator* op); + + /** @return object name */ + virtual const char* get_name() const + { + return "CDenseExactLogJob"; + } + +private: + /** the log of a CDenseMatrixOperator */ + CDenseMatrixOperator* m_log_operator; + + /** the trace-sample */ + SGVector m_vector; +}; + +} + +#endif // HAVE_EIGEN3 +#endif // DENSE_EXACT_LOG_JOB_H_ diff --git a/src/shogun/lib/computation/job/IndependentJob.h b/src/shogun/lib/computation/job/IndependentJob.h new file mode 100644 index 00000000000..9050958ab8d --- /dev/null +++ b/src/shogun/lib/computation/job/IndependentJob.h @@ -0,0 +1,67 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#ifndef INDEPENDENT_JOB_H_ +#define INDEPENDENT_JOB_H_ + +#include +#include +#include + +namespace shogun +{ + +/** @brief Abstract base for general computation jobs to be registered + * in CIndependentComputationEngine. compute method produces a job result + * and submits it to the internal JobResultAggregator. Each set of jobs + * that form a result will share the same job result aggregator. + */ +class CIndependentJob : public CSGObject +{ +public: + /** default constructor, no args */ + CIndependentJob() + : CSGObject(), m_aggregator(NULL) + { + SG_GCDEBUG("%s created (%p)\n", this->get_name(), this) + } + + /** default constructor, one arg */ + CIndependentJob(CJobResultAggregator* aggregator) + : CSGObject(), m_aggregator(aggregator) + { + SG_REF(m_aggregator); + SG_GCDEBUG("%s created (%p)\n", this->get_name(), this) + } + + /** destructor */ + virtual ~CIndependentJob() + { + SG_UNREF(m_aggregator); + SG_GCDEBUG("%s destroyed (%p)\n", this->get_name(), this) + } + + /** abstract compute method that computes the job, creates a CJobResult, + * submits the result to the job result aggregator + */ + virtual void compute() = 0; + + /** @return object name */ + virtual const char* get_name() const + { + return "CIndependentJob"; + } +protected: + /** the job result aggregator for the current job */ + CJobResultAggregator* m_aggregator; +}; + +} + +#endif // INDEPENDENT_JOB_H_ diff --git a/src/shogun/lib/computation/job/JobResultAggregator.h b/src/shogun/lib/computation/job/JobResultAggregator.h new file mode 100644 index 00000000000..2ea00d6d9bb --- /dev/null +++ b/src/shogun/lib/computation/job/JobResultAggregator.h @@ -0,0 +1,70 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#ifndef JOB_RESULT_AGGREGATOR_H_ +#define JOB_RESULT_AGGREGATOR_H_ + +#include +#include +#include + +namespace shogun +{ + +/** @brief Abstract base class that provides an interface for computing an + * aggeregation of the job results of independent computation jobs as + * they are submitted and also for finalizing the aggregation. + */ +class CJobResultAggregator : public CSGObject +{ +public: + /** default constructor */ + CJobResultAggregator() + : CSGObject(), m_result(NULL) + { + SG_GCDEBUG("%s created (%p)\n", this->get_name(), this) + } + + /** destructor */ + virtual ~CJobResultAggregator() + { + SG_UNREF(m_result); + SG_GCDEBUG("%s destroyed (%p)\n", this->get_name(), this) + } + + /** abstract method that submits the result of an independent job, and + * computes the aggregation with the previously submitted result + * @param the result of an independent job + */ + virtual void submit_result(CJobResult* result) = 0; + + /** abstract method that finalizes the aggregation and computes the result, + * its necessary to call finalize before getting the final result + */ + virtual void finalize() = 0; + + /** @return the final result */ + CJobResult* get_final_result() const + { + return m_result; + } + + /** @return object name */ + virtual const char* get_name() const + { + return "CJobResultAggregator"; + } +protected: + /** the final job result */ + CJobResult* m_result; +}; + +} + +#endif // JOB_RESULT_AGGREGATOR_H_ diff --git a/src/shogun/lib/computation/job/StoreScalarAggregator.cpp b/src/shogun/lib/computation/job/StoreScalarAggregator.cpp new file mode 100644 index 00000000000..647f884348e --- /dev/null +++ b/src/shogun/lib/computation/job/StoreScalarAggregator.cpp @@ -0,0 +1,78 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#include +#include +#include + +namespace shogun +{ +template +CStoreScalarAggregator::CStoreScalarAggregator() + : CJobResultAggregator(), m_aggregate(static_cast(0)) + { + SG_GCDEBUG("%s created (%p)\n", this->get_name(), this) + } + +template +CStoreScalarAggregator::~CStoreScalarAggregator() + { + SG_GCDEBUG("%s destroyed (%p)\n", this->get_name(), this) + } + +template +void CStoreScalarAggregator::submit_result(CJobResult* result) + { + SG_GCDEBUG("Entering ...\n") + + // check for proper typecast + // DEBUG COMMENT : the following does NOT increase refcount of result + CScalarResult* new_result=dynamic_cast*>(result); + if (!new_result) + SG_ERROR("result is not of CScalarResult type!\n"); + // aggregate it with previous + m_aggregate+=new_result->get_result(); + + SG_GCDEBUG("Leaving ...\n") + } + +template<> +void CStoreScalarAggregator::submit_result(CJobResult* result) + { + SG_NOTIMPLEMENTED + } + +template<> +void CStoreScalarAggregator::submit_result(CJobResult* result) + { + SG_NOTIMPLEMENTED + } + +template +void CStoreScalarAggregator::finalize() + { + m_result=(CJobResult*)(new CScalarResult(m_aggregate)); + SG_REF(m_result); + } + +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +template class CStoreScalarAggregator; +} diff --git a/src/shogun/lib/computation/job/StoreScalarAggregator.h b/src/shogun/lib/computation/job/StoreScalarAggregator.h new file mode 100644 index 00000000000..cfbfcf24341 --- /dev/null +++ b/src/shogun/lib/computation/job/StoreScalarAggregator.h @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#ifndef STORE_SCALAR_AGGREGATOR_H_ +#define STORE_SCALAR_AGGREGATOR_H_ + +#include +#include + +namespace shogun +{ +class CJobResult; +template class CScalarResult; + +/** @brief Template class that aggregates scalar job results in each + * submit_result call, finalize then transforms current aggregation into + * a CScalarResult. + */ +template class CStoreScalarAggregator : public CJobResultAggregator +{ +public: + /** default constructor, no args */ + CStoreScalarAggregator(); + + /** destructor */ + virtual ~CStoreScalarAggregator(); + + /** method that submits the result (scalar) of an independent job, and + * computes the aggregation with the previously submitted result + * @param the result of an independent job + */ + virtual void submit_result(CJobResult* result); + + /** method that finalizes the aggregation and computes the result (scalar), + * its necessary to call finalize before getting the final result + */ + virtual void finalize(); + + /** @return object name */ + virtual const char* get_name() const + { + return "CStoreScalarAggregator"; + } +private: + /** the aggregation */ + T m_aggregate; +}; + +} + +#endif // STORE_SCALAR_AGGREGATOR_H_ diff --git a/tests/unit/lib/computation/StoreScalarAggregator_unittest.cc b/tests/unit/lib/computation/StoreScalarAggregator_unittest.cc new file mode 100644 index 00000000000..91fb030805b --- /dev/null +++ b/tests/unit/lib/computation/StoreScalarAggregator_unittest.cc @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#include +#include +#include +#include + +using namespace shogun; + +TEST(StoreScalarAggregator, submit_result) +{ + CStoreScalarAggregator* agg=new CStoreScalarAggregator; + const index_t num_results=10; + + for (index_t i=0; i* result + =new CScalarResult((float64_t)i); + agg->submit_result((CJobResult*)result); + delete result; + } + agg->finalize(); + float64_t result=dynamic_cast*> + (agg->get_final_result())->get_result(); + + EXPECT_NEAR(result, 45.0, 1E-16); + delete agg; +} + diff --git a/tests/unit/mathematics/logdet/DenseExactLogJob_unittest.cc b/tests/unit/mathematics/logdet/DenseExactLogJob_unittest.cc new file mode 100644 index 00000000000..5b385f8c366 --- /dev/null +++ b/tests/unit/mathematics/logdet/DenseExactLogJob_unittest.cc @@ -0,0 +1,75 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Written (W) 2013 Soumyajit De + */ + +#include + +#ifdef HAVE_EIGEN3 +#include + +#if EIGEN_VERSION_AT_LEAST(3,1,0) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Eigen; +using namespace shogun; + +TEST(DenseExactLogJob, log_det) +{ + const index_t size=2; + + // create the matrix whose log-det has to be found + SGMatrix mat(size, size); + SGMatrix log_mat(size, size); + mat(0,0)=2.0; + mat(0,1)=1.0; + mat(1,0)=1.0; + mat(1,1)=3.0; + Map m(mat.matrix, mat.num_rows, mat.num_cols); + Map log_m(log_mat.matrix, log_mat.num_rows, log_mat.num_cols); + log_m=m.log(); + + // create linear operator and aggregator + CDenseMatrixOperator* log_op=new CDenseMatrixOperator + (log_mat); + SG_REF(log_op); + CStoreScalarAggregator* agg=new CStoreScalarAggregator; + SG_REF(agg); + + // create jobs with unit-vectors to extract the trace of log(mat) + for (index_t i=0; i s(size); + s.set_const(0.0); + s[i]=1.0; + CDenseExactLogJob *job=new CDenseExactLogJob((CJobResultAggregator*)agg); + job->set_operator(log_op); + job->set_vector(s); + job->compute(); + delete job; + } + // its really important we call finalize before getting the final result + agg->finalize(); + + CScalarResult* r=dynamic_cast*> + (agg->get_final_result()); + + EXPECT_NEAR(r->get_result(), CStatistics::log_det(mat), 1E-16); + + SG_UNREF(log_op); + SG_UNREF(agg); +} +#endif // EIGEN_VERSION_AT_LEAST(3,1,0) +#endif // HAVE_EIGEN3