matching: auction templates

This commit is contained in:
tqlong
2010-11-10 10:48:52 +00:00
parent bb4bce2f10
commit d067589a7a
9 changed files with 430 additions and 81 deletions
@@ -4,8 +4,10 @@ set(SOURCES
# auction_max_weight_matching
# naive_distance_matrix
# kdtree_distance_matrix
matching.cc
kdnode.cc
matching
kdnode
single_tree
auction_matching
)
# add directory name to sources
@@ -0,0 +1,120 @@
#ifndef AUCTION_MATCHING_H
#define AUCTION_MATCHING_H
#include <algorithm>
#include "matching.h"
MATCHING_NAMESPACE_BEGIN;
template <typename W>
class AuctionMatching
{
public:
typedef W weight_type;
protected:
weight_type& weight_;
double epsilon_;
std::vector<int> left_, right_, bidders_;
std::vector<double> bids_;
void clearMatches();
void forwardAuction(double &pruned, double &total);
void placeBid(int l, int r, double price);
void setMatch(int l, int r, double price);
public:
AuctionMatching(weight_type& weight);
void doMatch();
int n_left() const { return weight_.n_rows(); }
int n_right() const { return weight_.n_cols(); }
int left(int index) const { return left_.at(index); }
int right(int index) const { return right_.at(index); }
double getP(int l, int r) { return weight_.get(l, r)-weight_.price(r); }
double price(int r) { return weight_.price(r); }
};
template <typename W>
AuctionMatching<W>::AuctionMatching(weight_type &weight)
: weight_(weight), left_(n_left()), right_(n_right()),
bidders_(n_right()), bids_(n_right())
{
}
template <typename W>
void AuctionMatching<W>::doMatch()
{
// epsilon scaling
double total_pruned = 0, total_cals = 0;
for (epsilon_ = 1.0/n_left(); epsilon_ >= 1.0/n_left(); epsilon_ /= 2)
{
double pruned, total;
clearMatches();
forwardAuction(pruned, total);
total_pruned += pruned;
total_cals += total;
std::cout << "epsilon = " << epsilon_ << " cals = " << total_pruned << "/" << total_cals << "\n";
}
}
template <typename W>
void AuctionMatching<W>::clearMatches()
{
std::fill(left_.begin(), left_.end(), -1);
std::fill(right_.begin(), right_.end(), -1);
}
template <typename W>
void AuctionMatching<W>::forwardAuction(double &pruned, double &total)
{
pruned = total = 0;
while (1)
{
bool doneMatching = true;
std::fill(bids_.begin(), bids_.end(), -std::numeric_limits<double>::infinity());
std::fill(bidders_.begin(), bidders_.end(), -1);
weight_.refresh();
for (int i = 0; i < n_left(); i++) if (left(i) == -1)
{
doneMatching = false;
std::vector<int> bests(2, -1);
pruned += weight_.kBest(i, bests);
total += n_right();
if (bests[0] == -1 || bests[1] == -1)
{
printf("error kBest\n");
return;
}
double v = getP(i, bests[0]), w = getP(i, bests[1]);
placeBid(i, bests[0], price(bests[0])+v-w+epsilon_);
}
if (doneMatching) break;
for (int j = 0; j < n_right(); j++) if (bidders_[j] != -1)
{
setMatch(bidders_[j], j, bids_[j]);
}
}
}
template <typename W>
void AuctionMatching<W>::placeBid(int l, int r, double price)
{
if (bids_[r] < price)
{
bids_[r] = price;
bidders_[r] = l;
}
}
template <typename W>
void AuctionMatching<W>::setMatch(int l, int r, double price)
{
weight_.setPrice(r, price);
int ol = right(r);
left_[l] = r;
right_[r] = l;
if (ol != -1)
left_[ol] = -1;
}
MATCHING_NAMESPACE_END;
#endif // AUCTION_MATCHING_H
@@ -41,6 +41,12 @@ int KDNode::oldIndex(int index) const
return oldIndex_.at(index+dfsIndex_);
}
int KDNode::index(int index) const
{
if (index < 0 || index >= n_points_) return -1; // error
return index+dfsIndex_;
}
void KDNode::getPoint(int index, Vector &point) const
{
points_.MakeColumnVector(oldIndex(index), &point);
+3 -57
View File
@@ -41,6 +41,7 @@ public:
int n_points() const;
int n_dim() const;
int index(int idx) const;
int oldIndex(int index) const;
void getPoint(int index, Vector& point) const;
double get(int dim, int index) const;
@@ -92,63 +93,8 @@ public:
std::string toString(int depth = 0) const;
};
template <typename P, typename N>
KDNodeStats<P,N>::KDNodeStats(const Matrix &points)
: KDNode(points), pointStats_(*(new all_point_stats_type(n_points_))), changed_(true)
{
}
template <typename P, typename N>
KDNodeStats<P,N>::KDNodeStats(KDNodeStats *parent)
: KDNode(parent), pointStats_(parent->pointStats_), changed_(true)
{
}
template <typename P, typename N>
KDNodeStats<P,N>::~KDNodeStats()
{
if (isRoot()) delete &pointStats_;
}
template <typename P, typename N>
KDNode* KDNodeStats<P,N>::newNode(KDNode *parent)
{
return new KDNodeStats((KDNodeStats*) parent);
}
template <typename P, typename N>
void KDNodeStats<P,N>::setPointStats(int index, const point_stats_type &stats)
{
pointStats_[oldIndex(index)] = stats;
((KDNodeStats*)leaf(index))->setChanged(true);
}
template <typename P, typename N>
void KDNodeStats<P,N>::setChanged(bool changed)
{
if (changed_ == changed) return;
changed_ = changed;
if (changed && !isRoot())
((KDNodeStats*)parent())->setChanged(changed);
}
template <typename P, typename N>
void KDNodeStats<P,N>::visit(bool init)
{
if (!isChanged()) return; // the node is unchanged, not neccessary to proceed
if (isLeaf())
setLeafStats(init);
else
{
for (unsigned int i = 0; i < children_.size(); i++)
{
((KDNodeStats*) children_[i])->visit(init);
}
setNonLeafStats(init);
}
setChanged(false); // the node statistics is refreshed
}
MATCHING_NAMESPACE_END;
#include "kdnode_impl.h"
#endif // KDNODE_H
@@ -0,0 +1,67 @@
#ifndef KDNODE_IMPL_H
#define KDNODE_IMPL_H
#include "matching.h"
MATCHING_NAMESPACE_BEGIN;
template <typename P, typename N>
KDNodeStats<P,N>::KDNodeStats(const Matrix &points)
: KDNode(points), pointStats_(*(new all_point_stats_type(n_points_))), changed_(true)
{
}
template <typename P, typename N>
KDNodeStats<P,N>::KDNodeStats(KDNodeStats *parent)
: KDNode(parent), pointStats_(parent->pointStats_), changed_(true)
{
}
template <typename P, typename N>
KDNodeStats<P,N>::~KDNodeStats()
{
if (isRoot()) delete &pointStats_;
}
template <typename P, typename N>
KDNode* KDNodeStats<P,N>::newNode(KDNode *parent)
{
return new KDNodeStats((KDNodeStats*) parent);
}
template <typename P, typename N>
void KDNodeStats<P,N>::setPointStats(int index, const point_stats_type &stats)
{
pointStats_[oldIndex(index)] = stats;
((KDNodeStats*)leaf(index))->setChanged(true);
}
template <typename P, typename N>
void KDNodeStats<P,N>::setChanged(bool changed)
{
if (changed_ == changed) return;
changed_ = changed;
if (changed && !isRoot())
((KDNodeStats*)parent())->setChanged(changed);
}
template <typename P, typename N>
void KDNodeStats<P,N>::visit(bool init)
{
if (!isChanged()) return; // the node is unchanged, not neccessary to proceed
if (isLeaf())
setLeafStats(init);
else
{
for (unsigned int i = 0; i < children_.size(); i++)
{
((KDNodeStats*) children_[i])->visit(init);
}
setNonLeafStats(init);
}
setChanged(false); // the node statistics is refreshed
}
MATCHING_NAMESPACE_END;
#endif // KDNODE_IMPL_H
@@ -14,4 +14,19 @@ std::string toString (const Vector& v)
return s.str();
}
std::string toString (const Matrix& M)
{
std::stringstream s;
for (int i = 0; i < M.n_rows(); i++)
{
if (i > 0) s << " ";
else s << "(";
for (int j = 0; j < M.n_cols(); j++)
s << " " << M.get(i, j);
if (i < M.n_rows()-1) s << "\n";
else s << ")";
}
return s.str();
}
MATCHING_NAMESPACE_END;
@@ -16,6 +16,8 @@ MATCHING_NAMESPACE_BEGIN;
std::string toString (const Vector& v);
std::string toString (const Matrix& v);
MATCHING_NAMESPACE_END;
#endif // MATCHING_H
+165 -18
View File
@@ -7,6 +7,7 @@
#include "matching.h"
#include "kdnode.h"
#include "single_tree.h"
#include "auction_matching.h"
//namespace po = boost::program_options;
using namespace std;
@@ -170,19 +171,103 @@ template <>
return sqrt(s)+stats.minPrice_;
}
MATCHING_NAMESPACE_END;
int main(int argc, char** argv)
class Mat : public Matrix
{
process_options(argc, argv);
if (vm["random"].as<int>() > 0)
std::vector<double> price_;
public:
void Init(int rows, int cols)
{
generateRandom(vm["reference"].as<string>().c_str(), vm["query"].as<string>().c_str());
Matrix::Init(rows, cols);
price_ = std::vector<double>(n_cols(), 0);
}
void setPrice(int col, double price) { price_[col] = price; }
double price(int col) const { return price_.at(col); }
double getP(int row, int col) const { return get(row, col)-price(col); }
double kBest(int row, std::vector<int> &cols)
{
int k = (int) cols.size();
std::vector<double> maxs(k, -std::numeric_limits<double>::infinity());
for (int col = 0; col < n_cols(); col++)
{
double val = getP(row, col);
for (int o = 0; o < k; o++) if (val > maxs[o])
{
for (int k_r = k-1; k_r > o; k_r--)
{
maxs[k_r] = maxs[k_r-1];
cols[k_r] = cols[k_r-1];
}
maxs[o] = val;
cols[o] = col;
break;
}
}
return 0;
}
void refresh() {}
};
class KDMat
{
protected:
typedef KDNodeStats<PointStats, NodeStats> node_type;
typedef match::SingleTree<Vector, node_type> SingleTree;
const Matrix &ref_, &query_;
node_type* rRoot;
public:
KDMat(const Matrix& reference, const Matrix& query)
: ref_(reference), query_(query)
{
// cout << "start 0\n";
rRoot = new node_type(ref_);
rRoot->split();
for (int col = 0; col < n_cols(); col++)
rRoot->setPointStats(col, 0);
rRoot->visit(true);
// cout << "done 0\n";
}
~KDMat()
{
delete rRoot;
}
ptime time_start(second_clock::local_time());
int n_rows() const { return query_.n_cols(); }
int n_cols() const { return rRoot->n_points(); }
double get(int row, int col) const
{
Vector q_vec;
queryVec(row, q_vec);
return -SingleTree::distance(q_vec, *rRoot, col);
}
void setPrice(int col, PointStats price) { rRoot->setPointStats(col, price); }
PointStats price(int col) const { return rRoot->pointStats(col); }
double kBest(int row, std::vector<int> &cols)
{
// cout << "start 1\n";
std::vector<double> mins((int) cols.size(), std::numeric_limits<double>::infinity());
Vector q_vec;
queryVec(row, q_vec);
return SingleTree::kNearestNeighbor(q_vec, *rRoot, cols, mins);
// cout << "done 1\n";
}
void refresh()
{
rRoot->visit(false);
}
void queryVec(int row, Vector& q) const
{
query_.MakeColumnVector(row, &q);
}
void refVec(int col, Vector& r) const
{
rRoot->getPoint(col, r);
}
};
MATCHING_NAMESPACE_END;
void testKDNodeStats()
{
Matrix reference, query;
data::Load(vm["reference"].as<string>().c_str(), &reference);
data::Load(vm["query"].as<string>().c_str(), &query);
@@ -195,24 +280,86 @@ int main(int argc, char** argv)
cout << "Done set stats\n";
rRoot->visit(true);
cout << "Done visit\n";
cout << rRoot->toString() << "\n";
// cout << rRoot->toString() << "\n";
typedef match::SingleTree<Vector, Node> SingleTree;
SingleTree algo;
double total = 0;
for (int i = 0; i < query.n_cols(); i++)
{
int minIndex = -1; double minDistance = std::numeric_limits<double>::infinity();
Vector q, r;
Vector q;
query.MakeColumnVector(i, &q);
double pruned = algo.nearestNeighbor(q, *rRoot, minIndex, minDistance);
rRoot->getPoint(minIndex, r);
cout << "q = " << match::toString(q) << " --> r = " << match::toString(r)
<< " index = " << minIndex << " dist = " << minDistance
<< " pruned = " << pruned << "\n";
// int minIndex = -1; double minDistance = std::numeric_limits<double>::infinity();
// pruned += algo.nearestNeighbor(q, *rRoot, minIndex, minDistance);
// Vector r;
// rRoot->getPoint(minIndex, r);
// cout << "q = " << match::toString(q) << " --> r = " << match::toString(r)
// << " index = " << minIndex << " dist = " << minDistance
// << " pruned = " << pruned << "\n";
std::vector<int> minIndexes(2, -1); std::vector<double> minDistances(2, std::numeric_limits<double>::infinity());
double pruned = SingleTree::kNearestNeighbor(q, *rRoot, minIndexes, minDistances);
// cout << "q = " << match::toString(q) << " --> " << " index = " << minIndexes[0] << " " << minIndexes[1]
// << " dist = " << minDistances[0] << " " << minDistances[1]
// << " pruned = " << pruned << "\n";
total += pruned;
}
cout << "Done finding nearest neighbors pruned = " << total << "\n";
delete rRoot;
}
void testMatching()
{
int n = vm["random"].as<int>();
match::Mat W;
W.Init(n,n);
for (int i = 0; i < W.n_rows(); i++)
for (int j = 0; j < W.n_cols(); j++)
W.ref(i, j) = math::RandInt(0, 10);
// cout << match::toString(W) << "\n";
match::AuctionMatching<match::Mat> auction(W);
auction.doMatch();
for (int i = 0; i < auction.n_left(); i++)
cout << i << " --> " << auction.left(i) << " w = " << W.get(i, auction.left(i)) << "\n";
}
void testMatching1()
{
Matrix reference, query;
data::Load(vm["reference"].as<string>().c_str(), &reference);
data::Load(vm["query"].as<string>().c_str(), &query);
typedef match::KDNodeStats<match::PointStats, match::NodeStats> Node;
typedef match::KDMat Mat;
// cout << match::toString(W) << "\n";
Mat W(reference, query);
match::AuctionMatching<Mat> auction(W);
auction.doMatch();
// for (int i = 0; i < auction.n_left(); i++)
// cout << i << " --> " << auction.left(i) << " w = " << W.get(i, auction.left(i)) << "\n";
}
int main(int argc, char** argv)
{
process_options(argc, argv);
if (vm["random"].as<int>() > 0)
{
generateRandom(vm["reference"].as<string>().c_str(), vm["query"].as<string>().c_str());
}
ptime time_start(second_clock::local_time());
// testKDNodeStats();
// testMatching();
testMatching1();
ptime time_end(second_clock::local_time());
time_duration duration(time_end - time_start);
@@ -15,13 +15,14 @@ public:
typedef P point_type;
typedef T node_type;
double nearestNeighbor(const point_type& q, node_type& ref, int &minIndex, double &minDistance);
static double nearestNeighbor(const point_type& q, node_type& ref, int &minIndex, double &minDistance);
static double kNearestNeighbor(const point_type& q, node_type& ref, std::vector<int>& minIndexes, std::vector<double>& minDistances);
// distance of q from point index in ref
double distance(const point_type& q, node_type& ref, int index);
static double distance(const point_type& q, node_type& ref, int index);
// distance of q to bounding box of ref
double distance(const point_type& q, node_type& ref);
static double distance(const point_type& q, node_type& ref);
};
template <typename P, typename T>
@@ -41,7 +42,7 @@ template <typename P, typename T>
if (val < minDistance)
{
minDistance = val;
minIndex = i;
minIndex = ref.index(i); // return index from root view
}
}
return 0;
@@ -69,6 +70,49 @@ template <typename P, typename T>
// }
}
template <typename P, typename T>
double SingleTree<P,T>::kNearestNeighbor(const point_type &q, node_type &ref,
std::vector<int> &minIndexes, std::vector<double> &minDistances)
{
int k = (int) minIndexes.size();
if (distance(q, ref) >= minDistances[k-1])
{
return ref.n_points();
}
if (ref.isLeaf())
{
for (int i = 0; i < ref.n_points(); i++)
{
double val = distance(q, ref, i);
for (int order = 0; order < k; order++)
{
if (val < minDistances[order])
{
for (int k_reverse = k-1; k_reverse > order; k_reverse--)
{
minDistances[k_reverse] = minDistances[k_reverse-1];
minIndexes[k_reverse] = minIndexes[k_reverse-1];
}
minDistances[order] = val;
minIndexes[order] = ref.index(i); // return index from root view
break;
}
}
}
return 0;
}
else
{
double pruned = 0;
for (int i = 0; i < ref.n_children(); i++)
{
node_type* child = (node_type*)ref.child(i);
pruned += kNearestNeighbor(q, *child, minIndexes, minDistances);
}
return pruned;
}
}
MATCHING_NAMESPACE_END;
#endif // SINGLE_TREE_H