thor moved into the main line -- tree code experiences radical changes

This commit is contained in:
Garry Boyer
2007-08-07 20:36:01 +00:00
parent 4164231aa2
commit eb97ff8285
49 changed files with 1424 additions and 1876 deletions
+1 -1
View File
@@ -97,7 +97,7 @@ EXCLUDE_PATTERNS = */auton/* \
*_impl.h \
*_impl.cc \
*/u/* \
*test.cc
*_test.cc
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
+25 -2
View File
@@ -6,7 +6,7 @@
#include "ccmem.h"
/*void mem::SwapBytes__Chars(long *a_lp_in, long *b_lp_in, size_t remaining) {
void mem::SwapBytes__Chars(long *a_lp_in, long *b_lp_in, ssize_t remaining) {
char *a_cp = reinterpret_cast<char*>(a_lp_in);
char *b_cp = reinterpret_cast<char*>(b_lp_in);
@@ -19,4 +19,27 @@
*a_cp = tb;
a_cp++;
}
}*/
}
void mem::SwapBytes__Impl(long *a_lp, long *b_lp, ssize_t remaining) {
//DEBUG_MSG(3.0,"Swapping %d bytes, %d left", int(elems), int(remaining));
// TODO: Not as good as an MMX memcpy, but still good...
// TODO: replace 'remaining' decrement with end pointer
for (;;) {
remaining -= sizeof(long);
if (unlikely(remaining < 0)) break;
long ta = *a_lp;
long tb = *b_lp;
*b_lp = ta;
b_lp++;
*a_lp = tb;
a_lp++;
}
remaining += sizeof(long);
if (unlikely(remaining != 0)) {
SwapBytes__Chars(a_lp, b_lp, remaining);
}
}
+22 -42
View File
@@ -68,7 +68,7 @@ namespace mem {
* @param elems number of *elements*
*/
template<typename T>
void DebugPoison(T* array, size_t elems) {
void DebugPoison(T* array, size_t elems = 1) {
DEBUG_ONLY(DebugPoisonBytes(array, elems * sizeof(T)));
}
@@ -332,55 +332,35 @@ namespace mem {
inline T* CopyConstruct(T* dest, const T* src, size_t elems = 1) {
for (size_t i = 0; i < elems; i++) new(dest+i)T(src[i]); return dest;
}
template<>
inline char* CopyConstruct<char>(char* dest, const char* src, size_t elems) {
::memcpy(dest, src, elems); return dest;
}
#define BASE_CCMEM__FAST_COPY(T) \
template<> inline T* CopyConstruct<T>(T* dest, const T* src, size_t elems) \
{ ::memcpy(dest, src, elems * sizeof(T)); return dest; }
BASE_CCMEM__FAST_COPY(char)
BASE_CCMEM__FAST_COPY(short)
BASE_CCMEM__FAST_COPY(int)
BASE_CCMEM__FAST_COPY(long)
BASE_CCMEM__FAST_COPY(long long)
BASE_CCMEM__FAST_COPY(unsigned char)
BASE_CCMEM__FAST_COPY(unsigned short)
BASE_CCMEM__FAST_COPY(unsigned int)
BASE_CCMEM__FAST_COPY(unsigned long)
BASE_CCMEM__FAST_COPY(unsigned long long)
BASE_CCMEM__FAST_COPY(float)
BASE_CCMEM__FAST_COPY(double)
#undef BASE_CCMEM__FAST_COPY
template<typename T>
inline T* DupConstruct(const T* src, size_t elems = 1) {
return CopyConstruct(Alloc<T>(elems), src, elems);
}
inline void SwapBytes__Chars(long *a_lp_in, long *b_lp_in, size_t remaining) {
char *a_cp = reinterpret_cast<char*>(a_lp_in);
char *b_cp = reinterpret_cast<char*>(b_lp_in);
while (remaining) {
char ta = *a_cp;
char tb = *b_cp;
remaining--;
*b_cp = ta;
b_cp++;
*a_cp = tb;
a_cp++;
}
}
void SwapBytes__Chars(long *a_lp_in, long *b_lp_in, ssize_t remaining);
void SwapBytes__Impl(long *a_lp_in, long *b_lp_in, ssize_t remaining);
template<typename T>
void SwapBytes(T* a, T* b, size_t bytes) {
long *a_lp = reinterpret_cast<long*>(a);
long *b_lp = reinterpret_cast<long*>(b);
ssize_t remaining = bytes;
//DEBUG_MSG(3.0,"Swapping %d bytes, %d left", int(elems), int(remaining));
// TODO: Not as good as an MMX memcpy, but still good...
// TODO: replace 'remaining' decrement with end pointer
while (likely((remaining -= sizeof(long)) >= 0)) {
long ta = *a_lp;
long tb = *b_lp;
*b_lp = ta;
b_lp++;
*a_lp = tb;
a_lp++;
}
remaining += sizeof(long);
if (unlikely(remaining != 0)) {
SwapBytes__Chars(a_lp, b_lp, remaining);
}
SwapBytes__Impl(reinterpret_cast<long*>(a), reinterpret_cast<long*>(b),
bytes);
}
template<typename T>
+281 -184
View File
@@ -8,21 +8,30 @@
* traversal framework allows for the following to be available at no
* additional work on the application programmer:
*
* @li Serialization (save to disk)
* @li Deserialization (read from disk)
* @li Serialization (save to byte stream)
* @li Deserialization (read from byte stream)
* @li Object freezing/thawing/refreezing
* (storing bulk flattened objects in RAM)
* @li Debug print, or save to s-expression or XML
* @li Destructors and copy constructors
*
* We define the concept of an object-traversal (OT) compliant class:
*
* This has no support for (at least currently):
* @li No polymorphism, i.e. virtual functions
* @li No cycles in the pointer graph (actually there are a few exceptions,
* such as trees can have parent pointers, see OT_FIX)
* @li No inheritance, although non-polymorphic inheritance may be a
* possibility
* @li Blank default constructor that puts object into an "invalid" state,
* with Init methods
*
* @li Cycles
* @li Polymorphism (i.e. object-oriented inheritance)
* These classes can be thought of as "pure data structures". If your class
* is not OT-compliant, you probably want to put the FORBID_COPY header in
* your class. This is not to say that non-OT-compliant classes aren't
* useful -- it's definitely true that some objects aren't really meant to
* be copied or sent over the network. Think for example the Thread class.
*/
#ifndef BASE_OTRAV_H
#define BASE_OTRAV_H
@@ -32,8 +41,6 @@
#include <stdarg.h>
#include <ctype.h>
// TODO: Remove nullability from arrays
#define OT__NAME(x) v_OT->Name( #x )
/**
@@ -56,27 +63,67 @@
* Within OT_DEF, declare an array being pointed to, managed by
* new[] and delete[].
*/
#define OT_ARRAY(x, i) (OT__NAME(x), v_OT->Array(this->x, i, false))
#define OT_ARRAY(x, i) (OT__NAME(x), v_OT->Array(this->x, i))
/**
* Within OT_DEF, declare an array or object being pointed to managed by
* malloc and free.
*/
#define OT_MALLOC_ARRAY(x, i) (OT__NAME(x), v_OT->MallocArray(this->x, i, false))
#define OT_MALLOC_ARRAY(x, i) (OT__NAME(x), v_OT->MallocArray(this->x, i))
/**
* Within OT_DEF, declare a pointer to an object that might be NULL.
* Within OT_DEF, declare a pointer to a new-delete object that might be NULL.
*/
#define OT_PTR_NULLABLE(x) (OT__NAME(x), v_OT->Ptr(this->x, true))
/**
* Within OT_DEF, declare a pointer to an array that might be NULL.
*/
#define OT_ARRAY_NULLABLE(x, i) (OT__NAME(x), v_OT->Array(this->x, i, true))
/**
* Within OT_DEF, declare a pointer to a malloced array that might be NULL.
*/
#define OT_MALLOC_ARRAY_NULLABLE(x, i) (OT__NAME(x), v_OT->MallocArray(this->x, i, true))
/**
* Define the object traversal for this object.
* Like OT_DEF but doesn't define any of the automatic freebies.
*
* @see OT_DEF
*/
#define OT_DEF_ONLY(AClass) \
public: \
template<typename Visitor> \
friend void TraverseObject(AClass *obj_OT, Visitor *v_OT) { \
obj_OT->TraverseObject__OT_(v_OT); \
} \
private: \
template<typename Visitor> \
void TraverseObject__OT_(Visitor *v_OT)
/**
* Automatically generate a copy constructor based on the object traversal.
*/
#define OT_GEN_COPY_CONSTRUCTOR(AClass) \
public: AClass(const AClass& other) { ot_private::DeepCopyImplementation(other, this); } private:
/**
* Automatically create a dstructor based on object traversal.
*/
#define OT_GEN_DESTRUCTOR(AClass) \
public: ~AClass() { ot_private::DestructorImplementation(this); } private:
/**
* Automatically create a dstructor based on object traversal.
*/
#define OT_GEN_ASSIGN(AClass) \
public: const AClass& operator = (const AClass& other) \
{ this->~AClass(); new(this)AClass(other); return *this; } \
private:
/**
* Generate a default constructor.
*/
#define OT_GEN_DEFAULT_CONSTRUCTOR(AClass) \
public: AClass() { } private:
/**
* Automatically create a Copy method based on the copy constructor.
*/
#define OT_GEN_COPY_METHOD(AClass) \
public: void Copy(const AClass& other) { new(this)AClass(other); } private:
/**
* Define the object traversal for this object, and clearly defines its
* lifecycle and resource allocation as FASTlib-compliant.
*
* Example:
* @code
@@ -87,7 +134,7 @@
* MyTree *right;
* int num_extra_data;
* Data *extra_data_array;
*
*
* OT_DEF(MyTree) {
* OT_MY_OBJECT(value);
* OT_PTR_NULLABLE(left);
@@ -99,39 +146,73 @@
* ... rest of class definition ...
* @endcode
*
* The OT_DEF declares its own members, and its pointers. Notice that
* <code>OT_MY_OBJECT(num_extra_data)</code> must come before the subsequent
* line that uses num_extra_data as an array length. If deserialization is
* occuring, each <code>OT_...</code> call is actually deserializing each
* member, so num_extra_data is uninitialized until <code>OT_MY_OBJECT</code>
* is called on it.
* The OT_DEF is used to declare a class's members, and its pointers.
* Notice that <code>OT_MY_OBJECT(num_extra_data)</code> must come before
* the subsequent line that uses num_extra_data as an array length. If
* deserialization is occuring, each <code>OT_...</code> call is actually
* deserializing each member, so num_extra_data is uninitialized until
* <code>OT_MY_OBJECT</code> is called on it.
*
* Fine-point: If you have an array of pointers, you are pretty much doomed
* to declare the array of pointers and iterate over the array yourself for
* each pointer, treating each element of the array as a separate pointer.
* Note that all your familiar programming concepts like if-statements and
* for-loops are valid in the OT_DEF block because it's just a function,
* just make sure you're careful about only accessing members that have
* already been "traversed".
*
* This macro will also make your class FASTlib-compliant by creating a
* default constructor, copy constructor, assignment operator,
* and Copy method.
*
* @see OT_MY_OBJECT, OT_MY_ARRAY, OT_PTR, OT_ARRAY, OT_MALLOC_ARRAY,
* OT_PTR_NULLABLE, OT_ARRAY_NULLABLE, OT_MALLOC_ARRAY_NULLABLE.
*/
#define OT_DEF(AClass) \
public: \
template<typename Visitor> \
friend void TraverseObject(AClass *obj_OT, Visitor *v_OT) { \
obj_OT->TraverseObject__OT_(v_OT); \
} \
private: \
template<typename Visitor> \
void TraverseObject__OT_(Visitor *v_OT)
OT_GEN_DEFAULT_CONSTRUCTOR(AClass) \
OT_GEN_COPY_CONSTRUCTOR(AClass) \
OT_GEN_DESTRUCTOR(AClass) \
OT_GEN_COPY_METHOD(AClass) \
OT_GEN_ASSIGN(AClass) \
OT_DEF_ONLY(AClass)
/**
* Defines object traversal for classes with no pointer members.
*
* This will use the compiler's default copy constructor and default
* destructor, which are almost certainly faster than the ot-based one.
*/
#define OT_DEF_BASIC(AClass) \
public: \
OT_GEN_DEFAULT_CONSTRUCTOR(AClass) \
OT_GEN_COPY_METHOD(AClass) \
OT_GEN_ASSIGN(AClass) \
OT_DEF_ONLY(AClass)
/**
* Declares automatic OT features for a class for classes that have no
* pointers.
*
* This ensures you have a valid,
*/
#define OT_DEFAULTS
/**
* Declare automatic OT features for a class, but for classes that have
* pointers.
*/
#define OT_DEFAULTS_PTR
// Re-think how this is supposed to work.
// /**
// * Create an automatically-generated print method for your class.
// */
// #define OT_GENERATE_PRINT(AClass)
// public:
// template<>
// friend void Print(const AClass& obj, FILE *stream) {
// OTPrint(obj, stream);
// #define OT_GENERATE_PRINT(AClass)
// public:
// template<>
// friend void Print(const AClass& obj, FILE *stream) {
// OTPrint(obj, stream);
// }
// TODO: Automatically generate copy constructors and the like
@@ -229,87 +310,18 @@ inline void TraverseArray(T* x, index_t n_elems, Visitor *v) {
namespace ot_private {
// TODO: Space-conservatory serialization and deserialization
// (Currently only freezing/thawing is supported)
// These have to be hoisted out of the class.
// Apparently explicit specialization for templates cannot be done in class
// scope.
/** Visits an object with no OT implementation. */
/* template<typename DefaultPrinter, typename Printer, typename T>
void OTPrinter_Primitive(
const char *name, T& x, Printer* printer) {
DefaultPrinter::Print(name, x, printer);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, const char* x, Printer* printer) {
printer->Write("%s : string = %s", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, char x, Printer* printer) {
if (isprint(x)) {
printer->Write("%s : char = %d '%c'", name, x, x);
} else {
printer->Write("%s : char = %d", name, x);
}
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, short x, Printer* printer) {
printer->Write("%s : short = %d", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, int x, Printer* printer) {
printer->Write("%s : int = %d", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, long x, Printer* printer) {
printer->Write("%s : long = %ld", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, unsigned char x, Printer* printer) {
printer->Write("%s : uchar = %u", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, unsigned short x, Printer* printer) {
printer->Write("%s : ushort = %u", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, unsigned int x, Printer* printer) {
printer->Write("%s : uint = %u", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, unsigned long x, Printer* printer) {
printer->Write("%s : ulong = %lu", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, float x, Printer* printer) {
printer->Write("%s : float = %f", name, x);
}
template<typename DefaultPrinter, typename Printer>
inline void OTPrinter_Primitive(
const char *name, double x, Printer* printer) {
printer->Write("%s : double = %f", name, x);
}
*/
template<typename DefaultPrinter, typename Printer, typename T>
struct OTPrinter_Primitive {
struct OTPrinter_Dispatcher {
static void Print(const char *name, T& x, Printer* printer) {
DefaultPrinter::Print(name, x, printer);
}
};
/* macro for use within this file */
#define OTPRINTER__SPECIAL(T, format_str) \
template<typename DefaultPrinter, typename Printer> \
struct OTPrinter_Primitive<DefaultPrinter, Printer, T> { \
struct OTPrinter_Dispatcher<DefaultPrinter, Printer, T> { \
static void Print(const char *name, T x, Printer *printer) { \
printer->Write("%s : "format_str, name, x); \
} \
@@ -334,7 +346,7 @@ namespace ot_private {
FILE *stream_;
int indent_amount_;
const char *name_;
private:
template<typename T>
struct DefaultPrimitivePrinter {
@@ -361,10 +373,11 @@ namespace ot_private {
public:
template<typename T>
void InitBegin(const T& x, FILE *stream_in) {
void Doit(const T& x, FILE *stream_in) {
stream_ = stream_in;
indent_amount_ = 0;
TraverseObject(const_cast<T*>(&x), this);
name_ = "<root>";
Object(const_cast<T*>(&x), false, "");
}
/** Stores the name of the object going to come in. */
@@ -373,7 +386,7 @@ namespace ot_private {
}
template<typename T> void Primitive(T& x) {
OTPrinter_Primitive< DefaultPrimitivePrinter<T>, OTPrinter, T >
OTPrinter_Dispatcher< DefaultPrimitivePrinter<T>, OTPrinter, T >
::Print(name_, x, this);
}
@@ -382,29 +395,27 @@ namespace ot_private {
if (nullable && !obj) {
Write("%s : %s %s = NULL", name_, label, typeid(T).name());
} else {
OTPrinter_Primitive< DefaultObjectPrinter<T>, OTPrinter, T >
OTPrinter_Dispatcher< DefaultObjectPrinter<T>, OTPrinter, T >
::Print(name_, *obj, this);
}
}
template<typename T> void Array(T* array, index_t len,
bool nullable) {
if (nullable && !array) {
Write("%s : %s[] = NULL", name_, typeid(T).name());
} else {
Write("%s : %s[%"LI"d] = {", name_, typeid(T).name(), len);
template<typename T> void Array(T* array, index_t len) {
if (array == NULL) {
len = 0;
}
Write("%s : %s[%"LI"d] = {", name_, typeid(T).name(), len);
Indent(2);
for (index_t i = 0; i < len; i++) {
Write("element %"LI"d {", i);
Indent(2);
for (index_t i = 0; i < len; i++) {
Write("element %"LI"d {", i);
Indent(2);
name_ = "(array element)";
TraverseObject(&array[i], this);
Indent(-2);
Write("}");
}
name_ = "(array element)";
TraverseObject(&array[i], this);
Indent(-2);
Write("}");
}
Indent(-2);
Write("}");
}
/** Visits an internal object. */
@@ -415,7 +426,7 @@ namespace ot_private {
/** Visits an array. */
template<typename T> void MyArray(T* x, index_t len) {
// Recurse in case any of these objects have pointers
Array(x, len, false);
Array(x, len);
}
/**
@@ -429,20 +440,19 @@ namespace ot_private {
}
/** Visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& source_region, index_t len,
bool nullable) {
Array(source_region, len, nullable);
template<typename T> void MallocArray(T*& source_region, index_t len) {
Array(source_region, len);
}
public:
void Indent(int delta) {
indent_amount_ += delta;
}
void Write(const char *format, ...);
void ShowIndents();
FILE *stream() const {
return stream_;
}
@@ -476,26 +486,26 @@ namespace ot_private {
* being considered.
*/
ptrdiff_t freeze_offset_;
public:
template<typename T>
void InitBegin(const T& x, char *block_in) {
void Doit(const T& x, char *block_in) {
block_ = block_in;
pos_ = sizeof(T);
freeze_offset_ = mem::PointerDiff(block_, &x);
mem::Copy(reinterpret_cast<T*>(block_), &x);
// we must cast away const due to TraverseObject's limitations
TraverseObject(const_cast<T*>(&x), this);
}
size_t size() const {
return stride_align_max(pos_);
}
/** Receives the nanme of the upcoming object -- we ignore this. */
void Name(const char *s) {}
/** Visits an object with no OT implementation. */
template<typename T> void Primitive(T& x) {
// Primitives can be bit-copied
@@ -526,15 +536,13 @@ namespace ot_private {
* This allocates space within the block for the array, copies the
* data pointed to, and recurses on the array's elements.
*/
template<typename T> void Array(T*& source_region, index_t len,
bool nullable);
template<typename T> void Array(T*& source_region, index_t len);
/** Visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& source_region, index_t len,
bool nullable) {
Array(source_region, len, nullable);
template<typename T> void MallocArray(T*& source_region, index_t len) {
Array(source_region, len);
}
private:
template <typename T>
/**
@@ -603,8 +611,8 @@ namespace ot_private {
}
template<typename T> void OTPointerFreezer::Array(
T*& source_region, index_t len, bool nullable) {
if (nullable && unlikely(source_region == NULL)) {
T*& source_region, index_t len) {
if (len == 0) {
*DestinationEquivalentPointer_(&source_region) = NULL;
} else {
// Get the pointer we will write into, and fix our internal pointer
@@ -632,7 +640,7 @@ namespace ot_private {
public:
template<typename T>
void InitBegin(const T& obj) {
void Doit(const T& obj) {
pos_ = sizeof(T);
TraverseObject(const_cast<T*>(&obj), this);
}
@@ -646,7 +654,7 @@ namespace ot_private {
/** Receives the nanme of the upcoming object -- we ignore this. */
void Name(const char *s) {}
/** visits an object with no OT implementation */
template<typename T> void Primitive(T& x) {}
/** visits an internal object */
@@ -657,7 +665,7 @@ namespace ot_private {
template<typename T> void MyArray(T* x, index_t len) {
TraverseArray(x, len, this);
}
/** visits an object pointed to, allocated with new */
template<typename T> void Ptr(T*& x, bool nullable) {
if (!nullable || x != NULL) {
@@ -666,15 +674,15 @@ namespace ot_private {
}
}
/** visits an array pointed to, allocated with new[] */
template<typename T> void Array(T*& x, index_t len, bool nullable) {
if (!nullable || x != NULL) {
template<typename T> void Array(T*& x, index_t len) {
if (len != 0) {
PretendLayout_<T>(len);
TraverseArray(x, len, this);
}
}
/** visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& x, index_t len, bool nullable) {
Array(x, len, nullable);
template<typename T> void MallocArray(T*& x, index_t len) {
Array(x, len);
}
private:
@@ -687,24 +695,24 @@ namespace ot_private {
class OTPointerThawer {
private:
ptrdiff_t offset_;
public:
template<typename T>
T* InitBegin(ptrdiff_t offset_in, char *data) {
T* Doit(ptrdiff_t offset_in, char *data) {
offset_ = offset_in;
T* dest = reinterpret_cast<T*>(data);
MyObject(*dest);
return dest;
}
template<typename T>
T* InitBegin(char *data) {
return InitBegin<T>(data, reinterpret_cast<ptrdiff_t>(data));
T* Doit(char *data) {
return Doit<T>(data, reinterpret_cast<ptrdiff_t>(data));
}
/** Receives the nanme of the upcoming object -- we ignore this. */
void Name(const char *s) {}
/** visits an object with no OT implementation */
template<typename T> void Primitive(T& x) {}
/** visits an internal object */
@@ -726,15 +734,15 @@ namespace ot_private {
}
}
/** visits an array pointed to, allocated with new[] */
template<typename T> void Array(T*& x, index_t len, bool nullable) {
if (!nullable || x != NULL) {
template<typename T> void Array(T*& x, index_t len) {
if (len != 0) {
x = mem::PointerAdd(x, offset_);
MyArray(x, len);
}
}
/** visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& x, index_t len, bool nullable) {
Array(x, len, nullable);
template<typename T> void MallocArray(T*& x, index_t len) {
Array(x, len);
}
};
@@ -742,7 +750,7 @@ namespace ot_private {
private:
ptrdiff_t pre_offset_;
ptrdiff_t post_offset_;
public:
/**
* Fixes pointers.
@@ -756,13 +764,13 @@ namespace ot_private {
* @param dest the object to recurse on
*/
template<typename T>
T* InitBegin(ptrdiff_t pre_offset_in, ptrdiff_t post_offset_in, T *dest) {
T* Doit(ptrdiff_t pre_offset_in, ptrdiff_t post_offset_in, T *dest) {
pre_offset_ = pre_offset_in;
post_offset_ = post_offset_in;
TraverseObject(dest, this);
return dest;
}
/** Receives the nanme of the upcoming object -- we ignore this. */
void Name(const char *s) {}
@@ -784,17 +792,98 @@ namespace ot_private {
}
}
/** visits an array pointed to, allocated with new[] */
template<typename T> void Array(T*& x, index_t len, bool nullable) {
if (!nullable || x != NULL) {
template<typename T> void Array(T*& x, index_t len) {
if (len != 0) {
TraverseArray(mem::PointerAdd(x, pre_offset_), len, this);
x = mem::PointerAdd(x, post_offset_);
}
}
/** visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& x, index_t len, bool nullable) {
Array(x, len, nullable);
template<typename T> void MallocArray(T*& x, index_t len) {
Array(x, len);
}
};
struct OTDeepCopier {
public:
/** Receives the nanme of the upcoming object -- we ignore this. */
void Name(const char *s) {}
/** visits an object with no OT implementation */
template<typename T> void Primitive(T& x) {}
/** visits an internal object */
template<typename T> void MyObject(T& x) {
TraverseObject(&x, this);
}
/** visits an array */
template<typename T> void MyArray(T* x, index_t len) {
TraverseArray(x, len, this);
}
/** visits an object pointed to, allocated with new */
template<typename T> void Ptr(T*& x, bool nullable) {
if (!nullable || x != NULL) {
x = new T(*x);
}
}
/** visits an array pointed to, allocated with new[] */
template<typename T> void Array(T*& x, index_t len) {
x = mem::CopyConstruct(new T[len], x, len);
}
/** visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& x, index_t len) {
x = mem::CopyConstruct(mem::Alloc<T>(len), x, len);
}
};
struct OTDestructor {
public:
/** Receives the nanme of the upcoming object -- we ignore this. */
void Name(const char *s) {}
/** visits an object with no OT implementation */
template<typename T> void Primitive(T& x) {}
/** visits an internal object */
template<typename T> void MyObject(T& x) {
// C++ will automatically chain this
}
/** visits an array */
template<typename T> void MyArray(T* x, index_t len) {
// C++ will automatically chain this
}
/** visits an object pointed to, allocated with new */
template<typename T> void Ptr(T*& x, bool nullable) {
if (!nullable || x != NULL) {
delete x;
}
DEBUG_POISON_PTR(x);
}
/** visits an array pointed to, allocated with new[] */
template<typename T> void Array(T*& x, index_t len, bool nullable) {
delete[] x;
DEBUG_POISON_PTR(x);
}
/** visits an array pointed to, allocated with malloc */
template<typename T> void MallocArray(T*& x, index_t len) {
T *tmpx = x;
mem::DestructAll(tmpx, len);
mem::Free(tmpx);
DEBUG_POISON_PTR(x);
}
};
template<typename T>
void DestructorImplementation(T *dest) {
ot_private::OTDestructor d;
TraverseObject(dest, &d);
// can't poison this because of destructor chanining
}
template<typename T>
void DeepCopyImplementation(const T& src, T *dest) {
ot_private::OTDeepCopier d;
mem::Copy(dest, &src, 1);
TraverseObject(dest, &d);
}
}; // namespace ot_private
namespace ot {
@@ -807,7 +896,7 @@ namespace ot {
template<typename T>
void Print(const T& object, FILE *stream = stderr) {
ot_private::OTPrinter printer;
printer.InitBegin(object, stream);
printer.Doit(object, stream);
}
/**
@@ -826,7 +915,7 @@ namespace ot {
const char *PrintMsg(const T& object, const char *message) {
ot_private::OTPrinter printer;
fprintf(stderr, ANSI_HRED"---- PRINTING %s ----"ANSI_CLEAR"\n", message);
printer.InitBegin(object, stderr);
printer.Doit(object, stderr);
return message;
}
@@ -836,7 +925,7 @@ namespace ot {
template<typename T>
size_t PointerFrozenSize(const T& obj) {
ot_private::OTFrozenSizeCalculator calc;
calc.InitBegin(obj);
calc.Doit(obj);
return calc.size();
}
@@ -846,7 +935,7 @@ namespace ot {
template<typename T>
void PointerFreeze(const T& live_object, char *block) {
ot_private::OTPointerFreezer freezer;
freezer.InitBegin(live_object, block);
freezer.Doit(live_object, block);
DEBUG_SAME_INT(freezer.size(), ot::PointerFrozenSize(live_object));
}
@@ -857,7 +946,7 @@ namespace ot {
template<typename T>
void PointerRefreeze(T* obj) {
ot_private::OTPointerRelocator fixer;
fixer.InitBegin<T>(
fixer.Doit<T>(
0, -mem::PointerAbsoluteAddress(obj),
reinterpret_cast<T*>(obj));
}
@@ -875,7 +964,7 @@ namespace ot {
template<typename T>
void PointerRefreeze(const T* src, char* dest) {
ot_private::OTPointerRelocator fixer;
fixer.InitBegin<T>(
fixer.Doit<T>(
mem::PointerDiff(dest, src), -mem::PointerAbsoluteAddress(src),
reinterpret_cast<T*>(dest));
}
@@ -890,7 +979,7 @@ namespace ot {
template<typename T>
T* PointerThaw(char *block) {
ot_private::OTPointerThawer fixer;
return fixer.InitBegin<T>(
return fixer.Doit<T>(
mem::PointerAbsoluteAddress(block),
block);
}
@@ -903,11 +992,19 @@ namespace ot {
template<typename T>
void PointerRelocate(const char *old_location, char *new_location) {
ot_private::OTPointerRelocator fixer;
fixer.InitBegin<T>(
fixer.Doit<T>(
mem::PointerDiff(new_location, old_location),
mem::PointerDiff(new_location, old_location),
reinterpret_cast<T*>(new_location));
}
/**
* Deep-copy initializer for OT-compliant classes.
*/
template<typename T>
void Copy(const T& src, T* dest) {
new(dest)T(src);
}
};
#endif
+2 -25
View File
@@ -66,9 +66,9 @@ class ArrayList {
index_t size_;
index_t cap_;
OT_DEF(ArrayList) {
OT_DEF_ONLY(ArrayList) {
OT_MY_OBJECT(size_);
OT_MALLOC_ARRAY_NULLABLE(ptr_, size_);
OT_MALLOC_ARRAY(ptr_, size_);
}
OT_FIX(ArrayList) {
@@ -298,29 +298,6 @@ class ArrayList {
}
}
/**
* Serializes this arraylist.
*
* Currently only works for things that are bit-copiable, containing no
* pointers.
*/
template<typename Serializer>
void Serialize(Serializer *s) const {
s->Put(size_);
s->Put(ptr_, size_);
}
/**
* Initializes this list, deserializing from the given source.
*/
template<typename Deserializer>
void Deserialize(Deserializer *s) {
s->Get(&size_);
cap_ = size_;
ptr_ = mem::Alloc<Element>(cap_);
s->Get(ptr_, size_);
}
/**
* Use this to shrink the ArrayList.
*/
+2 -2
View File
@@ -9,11 +9,11 @@ librule(
binrule(
name = "col_test",
sources = ["col_test.cc"],
linkables = [":col"])
deplibs = [":col"])
binrule(
name = "timing_test",
sources = ["timing_test.cc"],
linkables = [":col", "fx:fx"])
deplibs = [":col", "fx:fx"])
+1 -42
View File
@@ -35,22 +35,11 @@ class MinHeap {
ArrayList<Entry> entries_;
OT_DEF(MinHeap) {
OT_DEF_BASIC(MinHeap) {
OT_MY_OBJECT(entries_);
}
public:
MinHeap() {}
~MinHeap() {}
/**
* Copy constructor (for use in collections only!).
*/
MinHeap(const MinHeap& other) {
Copy(other);
}
CC_ASSIGNMENT_OPERATOR(MinHeap);
/**
* Initializes an empty priority queue.
*/
@@ -64,29 +53,6 @@ class MinHeap {
bool is_empty() const {
return entries_.size() == 0;
}
/**
* Serializes this heap.
*
* Currently only works for things that are bit-copiable, containing no
* pointers.
*
* @deprecated Use otrav instead.
*/
template<typename Serializer>
void Serialize(Serializer *s) const {
entries_.Serialize(s);
}
/**
* Initializes this heap, deserializing from the given source.
*
* @deprecated Use otrav instead.
*/
template<typename Deserializer>
void Deserialize(Deserializer *s) {
entries_.Deserialize(s);
}
/**
* Places a value at the specified priority.
@@ -160,13 +126,6 @@ class MinHeap {
return entries_.size();
}
/**
* Copies another MinHeap.
*/
void Copy(const MinHeap& other) {
entries_.Copy(other.entries_);
}
private:
static index_t ChildIndex_(index_t i) {
return (i << 1) + 1;
+37 -10
View File
@@ -4,10 +4,18 @@
* Dense integer-to-value map.
*/
#ifndef COL_INTMAP_H
#define COL_INTMAP_H
#include "base/common.h"
#include "base/ccmem.h"
#include "base/otrav.h"
/**
* A dense grow-as-needed array that serves as an integer-keyed map.
*/
template<class TValue>
class DenseIntMap {
FORBID_COPY(DenseIntMap);
public:
typedef TValue Value;
@@ -16,32 +24,43 @@ class DenseIntMap {
index_t size_;
Value default_value_;
public:
DenseIntMap() {
DEBUG_POISON_PTR(ptr_);
size_ = BIG_BAD_NUMBER;
}
~DenseIntMap() {
DEBUG_ASSERT(size_ != BIG_BAD_NUMBER);
mem::Free(ptr_);
OT_DEF(DenseIntMap) {
OT_MY_OBJECT(size_);
OT_MY_OBJECT(default_value_);
OT_MALLOC_ARRAY(ptr_, size_);
}
public:
/** Creates a blank mapping. */
void Init() {
ptr_ = NULL;
size_ = 0;
}
/** Accesses the default value. Use this to set it. */
Value& default_value() {
return default_value_;
}
/** Accesses the default value. */
const Value& default_value() const {
return default_value_;
}
/**
* Gets a non-inclusive upper bound on the last non-default element.
*
* Iterating up to size() is guaranteed to hit all elements without
* growing the internal array.
*/
index_t size() const {
return size_;
}
/**
* Accesses an element, expanding if necessary.
*
* If you are just probing, beware that this might actually grow the array!
*/
Value& operator [] (index_t index) {
DEBUG_BOUNDS(index, BIG_BAD_NUMBER);
if (unlikely(index >= size_)) {
@@ -54,9 +73,15 @@ class DenseIntMap {
}
return ptr_[index];
}
/**
* Accesses an element from a static context.
*/
const Value& operator [] (index_t index) const {
return get(index);
}
/**
* Accesses an element, never growing the internal representation.
*/
const Value& get(index_t index) const {
DEBUG_BOUNDS(index, BIG_BAD_NUMBER);
if (likely(index < size_)) {
@@ -66,3 +91,5 @@ class DenseIntMap {
}
}
};
#endif
+2
View File
@@ -3,6 +3,8 @@
template<typename T>
class Queue {
FORBID_COPY(Queue); // No copy constructor defined (yet)
private:
struct Node {
T data;
+2 -2
View File
@@ -21,7 +21,7 @@ class RangeSet {
Boundary begin;
Boundary end;
OT_DEF(Range) {
OT_DEF_BASIC(Range) {
OT_MY_OBJECT(begin);
OT_MY_OBJECT(end);
}
@@ -89,7 +89,7 @@ class RangeSet {
// replace the list
ranges_.Swap(&new_list);
}
const ArrayList<Range>& ranges() const {
return ranges_;
}
+1 -14
View File
@@ -30,19 +30,11 @@ class String {
private:
ArrayList<char> array_;
OT_DEF(String) {
OT_DEF_BASIC(String) {
OT_MY_OBJECT(array_);
}
public:
String() {}
~String() {}
String(const String& other) {
Copy(other);
}
CC_ASSIGNMENT_OPERATOR(String);
/**
* Implicit conversion constructor.
*/
@@ -74,11 +66,6 @@ class String {
COMPILER_PRINTF(2, 3)
const String& InitSprintf(const char *format, ...);
/** Copies another string. */
void Copy(const String& other) {
array_.Copy(other.array_);
}
/**
* Initializes as a copy of an existing region of characters.
* The existing array does not need to be null terminated.
+1 -1
View File
@@ -7,5 +7,5 @@ librule(
binrule(
name = "dataset_test",
sources = ["dataset_test.cc"],
linkables = [":data", "fx:fx", "math:math"])
deplibs = [":data", "fx:fx", "math:math"])
-23
View File
@@ -48,9 +48,6 @@ class DatasetFeature {
}
public:
DatasetFeature() {}
~DatasetFeature() {}
/**
* Initialize to be a continuous feature.
*
@@ -172,8 +169,6 @@ class DatasetFeature {
* Information describing a dataset and its features.
*/
class DatasetInfo {
FORBID_COPY(DatasetInfo);
private:
String name_;
ArrayList<DatasetFeature> features_;
@@ -184,9 +179,6 @@ class DatasetInfo {
}
public:
DatasetInfo() {}
~DatasetInfo() {}
/** Gets a mutable list of all features. */
ArrayList<DatasetFeature>& features() {
return features_;
@@ -315,17 +307,7 @@ class DatasetInfo {
success_t ReadPoint(TextLineReader *reader, double *point,
bool *is_done) const;
/**
* Initializes to be a copy.
* @param other data set feature information to copy
*/
void Copy(const DatasetInfo& other) {
name_.Copy(other.name_);
features_.Copy(other.features_);
}
private:
char *SkipSpace_(char *s);
char *SkipNonspace_(char *s);
@@ -347,8 +329,6 @@ class DatasetInfo {
* may be an issue, especially if this is Boolean data.)
*/
class Dataset {
FORBID_COPY(Dataset);
private:
Matrix matrix_;
DatasetInfo info_;
@@ -359,9 +339,6 @@ class Dataset {
}
public:
Dataset() {}
~Dataset() {}
/**
* Metadata about the feature types and names for the dataset.
*
+1 -1
View File
@@ -21,4 +21,4 @@ librule(
binrule(
name = "otrav_test",
sources = ["otrav_test.cc"],
linkables = [":fastlib_int"])
deplibs = [":fastlib_int"])
-1
View File
@@ -22,7 +22,6 @@
#include "data/dataset.h"
#include "data/crossvalidation.h"
#include "math/math.h"
#include "file/serialize.h"
#include "file/textfile.h"
#include "fx/fx.h"
+13 -1
View File
@@ -38,4 +38,16 @@ void TestDatasetLayout() {
d3->WriteArff("test_dataset_layout.arff");
}
TEST_SUITE_END(otrav, TestDatasetPrint, TestDatasetLayout)
void TestCopy() {
Dataset *d = new Dataset;
d->InitFromFile("fake.arff");
Dataset d2(*d);
delete d;
d2.WriteArff("test_dataset_copy.arff");
}
TEST_SUITE_END(otrav, TestDatasetPrint, TestDatasetLayout, TestCopy)
+3 -3
View File
@@ -1,6 +1,6 @@
librule(
sources = ["textfile.cc", "serialize.cc"],
headers = ["textfile.h", "serialize.h"],
sources = ["textfile.cc"],
headers = ["textfile.h"],
deplibs = ["base:base", "col:col"],
)
@@ -14,7 +14,7 @@ librule(
binrule(
name = "textfile_test",
sources = ["textfile_test.cc"],
linkables = [":file", "fx:fx"]
deplibs = [":file", "fx:fx"]
)
-79
View File
@@ -1,79 +0,0 @@
/**
* @file serialize.cc
*
* Definitions for serialization methods.
*/
#include "serialize.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
file::magic_t file::CreateMagic(const char *str) {
magic_t magic = 0x31415926;
for (; *str != '\0'; str++) {
magic = (magic << 9) + (magic >> 11) + *str;
}
return magic;
}
success_t NativeArraySerializer::WriteFile(const char *fname) {
FILE *f = fopen(fname, "wb");
if (unlikely(!f)) {
return SUCCESS_FAIL;
}
if (unlikely(index_t(fwrite(ptr(), 1, size(), f)) != index_t(size()))) {
(void) fclose(f);
return SUCCESS_FAIL;
}
return SUCCESS_FROM_INT(fclose(f));
}
success_t NativeFileDeserializer::Init(const char *fname) {
struct stat info;
FILE *f;
size_t file_size;
char *data;
DEBUG_MSG(1.0, "Opening a native file deserializer.");
if (unlikely(stat(fname, &info) < 0)) {
NONFATAL("File [%s] does not exist.", fname);
data = NULL;
} else {
f = fopen(fname, "rb");
if (unlikely(!f)) {
data = NULL;
NONFATAL("Cannot read [%s], but it exists.", fname);
} else {
file_size = size_t(info.st_size);
data = mem::Alloc<char>(file_size);
if (unlikely(fread(data, 1, file_size, f) != file_size)) {
mem::Free(data);
data = NULL;
NONFATAL("Error reading contents of [%s].", fname);
}
(void) fclose(f);
}
}
if (data == NULL) {
// We have to initialize this into a valid state, or else the program
// will segfault.
file_size = 0;
}
NativeArrayDeserializer::Init(data, file_size);
return (data != NULL) ? SUCCESS_PASS : SUCCESS_FAIL;
}
-257
View File
@@ -1,257 +0,0 @@
// Copyright 2007 Georgia Institute of Technology. All rights reserved.
// ABSOLUTELY NOT FOR DISTRIBUTION
/**
* @file serialize.h
*
* Tools for serialization.
*
* See NativeArraySerializer and NativeArrayDeserializer for an example of
* the Serializer and Deserializer "concepts".
*
* WARNING: This has been only casually tested, not thoroughly tested.
* Use at your own risk.
*/
#ifndef FILE_SERIALIZE_H
#define FILE_SERIALIZE_H
#include "base/common.h"
#include "base/ccmem.h"
#include "col/arraylist.h"
#include <typeinfo>
namespace file {
/**
* Magic number type.
*/
typedef uint32 magic_t;
/**
* Automatically creates a magic number by hashing the
* string.
*/
magic_t CreateMagic(const char *str);
};
/**
* Automatically creates a magic number for a class.
*
* This is especially useful if you have a templated class.
* You can add other magic numbers to it if you want the number to be
* more specific, like MAGIC_NUMBER(a) + MAGIC_NUMBER(b).
*
* @param classname the name of the class
*/
#define MAGIC_NUMBER(classname) \
(file::CreateMagic(typeid(classname).name()))
/**
* Use this to serialize a stream of objects in an array.
*
* Useful before sending canonical versions over MPI, or to a file.
*
* The computer reading this should use the same CPU type.
* In particular, the type sizes and byte order must remain the same.
*
* Only primitives or structs of primitives should be stored; in
* particular, no pointers.
*
* TODO: More complicated serializers (like text serializers) later
* might have a slight problem with serializing structs. Come back
* later for info. Maybe we'll decide against text serializers.
*/
class NativeArraySerializer {
FORBID_COPY(NativeArraySerializer);
private:
ArrayList<char> data_;
public:
NativeArraySerializer() {}
~NativeArraySerializer() {}
void Init() {
data_.Init();
}
void PutMagic(file::magic_t magic_num) {
Put(magic_num);
}
/**
* Appends a struct or primitive to the end.
*
* This will store the object bit-by-bit, so don't store any
* pointers.
*/
template<typename T>
void Put(const T& val) {
mem::CopyBytes(data_.AddBack(sizeof(T)), &val, sizeof(T));
}
/**
* Appends an array of structs or primtives to the end.
*
* This will store the object bit-by-bit, so don't store any
* pointers.
*/
template<typename T>
void Put(const T* array, index_t count) {
size_t bytes = count * sizeof(T);
mem::CopyBytes(data_.AddBack(bytes), array, bytes);
}
/**
* Appends an array of non-primitives to the end.
*/
template<typename T>
void Serialize(const T* array, index_t count) {
for (index_t i = 0; i < count; i++) {
array[i].Serialize(this);
}
}
/**
* Returns the data serialized, clearing the internal
* state of this serializer.
*
* The pointer must eventually be freed with mem::Free.
*
* @return a pointer that can later be passed to deserializer
*/
char *ReleasePointer() {
data_.Trim();
return data_.ReleasePointer();
}
const char *ptr() const {
return data_.begin();
}
index_t size() const {
return data_.size();
}
/**
* Dumps to a file.
*/
success_t WriteFile(const char *fname);
};
/**
* Use this to deserialize a stream created by NativeArraySerializer.
*
* This computer should use the same architecture as was used to seralize.
* Specifically, the type sizes and byte order must be identical.
*/
class NativeArrayDeserializer {
private:
const char *ptr_;
index_t pos_;
index_t size_;
public:
NativeArrayDeserializer() {
DEBUG_POISON_PTR(ptr_);
}
~NativeArrayDeserializer() {}
/**
* Initializes given a pointer.
*
* The pointer will not be freed.
*/
void Init(const char *ptr_in, index_t size_in) {
ptr_ = ptr_in;
size_ = size_in;
pos_ = 0;
}
success_t CheckMagic(file::magic_t magic_num) {
file::magic_t x;
Get(&x);
return likely(x == magic_num) ? SUCCESS_PASS : SUCCESS_FAIL;
}
void AssertMagic(file::magic_t magic_num) {
file::magic_t x;
Get(&x);
assert(x == magic_num);
}
/**
* Retrieves the next struct or primtiive.
*/
template<typename T>
void Get(T *dest) {
DEBUG_ASSERT(size_t(pos_ + sizeof(T)) <= size_t(size_));
mem::CopyBytes(dest, ptr_ + pos_, sizeof(T));
pos_ += sizeof(T);
}
/**
* Retrieves the next array of structs or primitives.
*/
template<typename T>
void Get(T *dest, index_t count) {
size_t bytes = count * sizeof(T);
DEBUG_ASSERT(index_t(pos_ + bytes) <= index_t(size_));
mem::CopyBytes(dest, ptr_ + pos_, bytes);
pos_ += bytes;
}
/**
* Retrieves an array of Serializables.
*/
template<typename T>
void Deserialize(T *dest, index_t count) {
for (index_t i = 0; i < count; i++) {
dest[i].Deserialize(this);
}
}
/**
* Returns whether finished.
*
* You are not recommended to use this; store counts instead.
*
* @return true iff there is no data remaining
*/
bool done() const {
return pos_ == size_;
}
size_t size() const {
return size_;
}
size_t pos() const {
return pos_;
}
const char *ptr() const {
return ptr_;
}
};
/**
* Deserializer from a file.
*
* NOTE: This currently uses a NativeArrayDeserializer, but in the future
* may use buffering.
*/
class NativeFileDeserializer : public NativeArrayDeserializer {
public:
NativeFileDeserializer() {}
~NativeFileDeserializer() {
mem::Free(const_cast<char*>(ptr()));
}
/**
* Initializes by reading the entire file into memory.
*/
success_t Init(const char *fname);
};
#endif
+2 -2
View File
@@ -50,10 +50,10 @@ librule(
binrule(
name = "uselapack_test",
sources = ["uselapack_test.cc"],
linkables = [":la"])
deplibs = [":la"])
binrule(
name = "la_test",
sources = ["la_test.cc"],
headers = [],
linkables = [":la"])
deplibs = [":la"])
+5 -37
View File
@@ -51,7 +51,7 @@ class Vector {
/** Whether this should be freed, i.e. it is not an alias. */
bool should_free_;
OT_DEF(Vector) {
OT_DEF_ONLY(Vector) {
OT_MY_OBJECT(length_);
OT_MALLOC_ARRAY(ptr_, length_);
}
@@ -201,21 +201,6 @@ class Vector {
should_free_ = true;
}
template<typename Serializer>
void Serialize(Serializer *s) const {
s->Put(length_);
s->Put(ptr_, length_);
}
template<typename Deserializer>
void Deserialize(Deserializer *s) {
DEBUG_ONLY(AssertUninitialized_());
s->Get(&length_);
ptr_ = mem::Alloc<double>(length_);
s->Get(ptr_, length_);
should_free_ = true;
}
/**
* Initializes an uninitialized vector as an alias to a a sub-region
* of this vector.
@@ -365,13 +350,13 @@ class Matrix {
index_t n_cols_;
/** Whether I am a strong copy (not an alias). */
bool should_free_;
OT_DEF(Matrix) {
OT_DEF_ONLY(Matrix) {
OT_MY_OBJECT(n_rows_);
OT_MY_OBJECT(n_cols_);
OT_MALLOC_ARRAY(ptr_, n_elements());
}
OT_FIX(Matrix) {
should_free_ = true;
}
@@ -577,24 +562,7 @@ class Matrix {
n_cols_ = n_cols_in;
should_free_ = true;
}
template<typename Serializer>
void Serialize(Serializer *s) const {
s->Put(n_rows_);
s->Put(n_cols_);
s->Put(ptr_, n_elements());
}
template<typename Deserializer>
void Deserialize(Deserializer *s) {
DEBUG_ONLY(AssertUninitialized_());
s->Get(&n_rows_);
s->Get(&n_cols_);
ptr_ = mem::Alloc<double>(n_elements());
s->Get(ptr_, n_elements());
should_free_ = true;
}
/**
* Make a matrix that is an alias of a particular slice of my columns.
*
+2 -1
View File
@@ -273,9 +273,10 @@ void TestVector() {
TEST_ASSERT(v8[3] == 3);
MakeConstantVector(10, 3.5, &v9);
TEST_ASSERT(v9[0] == 3.5);
TEST_ASSERT(v1[0] == 0.0);
v9.SwapValues(&v1);
TEST_DOUBLE_EXACT(v1[0], 3.5);
TEST_ASSERT(v9[0] == 0.0);
TEST_ASSERT(v1[0] == 3.5);
TEST_ASSERT(v2[0] == 3.5);
TEST_ASSERT(v3[0] == 3.5);
TEST_ASSERT(v4[0] != 3.5);
+1 -1
View File
@@ -8,5 +8,5 @@ librule(
binrule(
name = "math_test",
sources = ["math_test.cc"],
linkables = [":math"])
deplibs = [":math"])
+2 -18
View File
@@ -25,7 +25,7 @@ struct GaussianKernel {
private:
double inv_bandwidth_2sq_;
OT_DEF(GaussianKernel) {
OT_DEF_BASIC(GaussianKernel) {
OT_MY_OBJECT(inv_bandwidth_2sq_);
}
@@ -33,10 +33,6 @@ struct GaussianKernel {
static const bool HAS_CUTOFF = false;
public:
GaussianKernel() {}
~GaussianKernel() {}
/**
* Initializes to a specific bandwidth.
*
@@ -46,10 +42,6 @@ struct GaussianKernel {
inv_bandwidth_2sq_ = 1.0 / (2.0 * bandwidth_in * bandwidth_in);
}
void Copy(const GaussianKernel& other) {
inv_bandwidth_2sq_ = other.inv_bandwidth_2sq_;
}
/**
* Evaluates an unnormalized density, given the distance between
* the kernel's mean and a query point.
@@ -93,7 +85,7 @@ struct EpanKernel {
double inv_bandwidth_sq_;
double bandwidth_sq_;
OT_DEF(EpanKernel) {
OT_DEF_BASIC(EpanKernel) {
OT_MY_OBJECT(inv_bandwidth_sq_);
OT_MY_OBJECT(bandwidth_sq_);
}
@@ -102,9 +94,6 @@ struct EpanKernel {
static const bool HAS_CUTOFF = true;
public:
EpanKernel() {}
~EpanKernel() {}
/**
* Initializes to a specific bandwidth.
*/
@@ -113,11 +102,6 @@ struct EpanKernel {
inv_bandwidth_sq_ = 1.0 / bandwidth_sq_;
}
void Copy(const EpanKernel& other) {
bandwidth_sq_ = other.bandwidth_sq_;
inv_bandwidth_sq_ = other.inv_bandwidth_sq_;
}
/**
* Evaluates an unnormalized density, given the distance between
* the kernel's mean and a query point.
+59
View File
@@ -209,6 +209,65 @@ namespace math {
}
};
/**
* A value which is the min or max of multiple other values.
*
* Comes with a highly optimized version of x = max(x, y).
*
* The template argument should be something like double, with greater-than,
* less-than, and equals operators.
*/
template<typename TValue>
class MinMaxVal {
public:
typedef TValue Value;
public:
/** The underlying value. */
Value val;
OT_DEF_BASIC(MinMaxVal) {
OT_MY_OBJECT(val);
}
public:
/**
* Converts implicitly to the value.
*/
operator Value() const { return val; }
/**
* Sets the value.
*/
const Value& operator = (Value val_in) {
return (val = val_in);
}
/**
* Efficiently performs this->val = min(this->val, incoming_val).
*
* The expectation is that it is higly unlikely for the incoming
* value to be the new minimum.
*/
void MinWith(Value incoming_val) {
if (unlikely(incoming_val < val)) {
val = incoming_val;
}
}
/**
* Efficiently performs this->val = min(this->val, incoming_val).
*
* The expectation is that it is higly unlikely for the incoming
* value to be the new maximum.
*/
void MaxWith(Value incoming_val) {
if (unlikely(incoming_val > val)) {
val = incoming_val;
}
}
};
#include "discrete.h"
#include "kernel.h"
#include "geometry.h"
+2 -2
View File
@@ -88,8 +88,8 @@ void TestPow() {
TEST_DOUBLE_EXACT((math::Pow<2, 1>(3.0)), 9.0);
TEST_DOUBLE_EXACT((math::Pow<1, 2>(9.0)), 3.0);
TEST_DOUBLE_EXACT((math::Pow<3, 3>(9.0)), 9.0);
TEST_DOUBLE_EXACT((math::Pow<1, 3>(8.0)), 2.0);
TEST_DOUBLE_EXACT((math::PowAbs<1, 3>(-8.0)), 2.0);
TEST_DOUBLE_APPROX((math::Pow<1, 3>(8.0)), 2.0, 1.0e-6);
TEST_DOUBLE_APPROX((math::PowAbs<1, 3>(-8.0)), 2.0, 1.0e-6);
TEST_DOUBLE_EXACT((math::PowAbs<1, 1>(-8.0)), 8.0);
TEST_DOUBLE_EXACT((math::PowAbs<2, 1>(-8.0)), 64.0);
}
-7
View File
@@ -3,10 +3,3 @@ librule(
sources = ["thread.cc"],
headers = ["thread.h", "task.h", "grain.h"],
deplibs = ["base:base", "col:col"])
librule(
name = "mpi",
sources = [],
headers = ["mpigrain.h"],
deplibs = [":par"])
-398
View File
@@ -1,398 +0,0 @@
// Copyright 2007 Georgia Institute of Technology. All rights reserved.
// ABSOLUTELY NOT FOR DISTRIBUTION
/**
* @file mpigrain.h
*
* Tool for creating simple MPI parallel programs.
* You must build with --compiler=mpi.
*
* WARNING! This currently DOES NOT have ANY WAY for you to send
* results back!
*
* TODO: Broken
*/
#ifndef PAR_MPIGRAIN_H
#define PAR_MPIGRAIN_H
#include "xrun/xrun.h"
#include "grain.h"
#include <mpi.h>
/**
* Grain-based parallelism over MPI.
*
* Grains must be bit-copiable. In the future serialization might be a better
* idea.
*
* Uses single master that maintains priority queue, and handles work out
* to slaves.
*
* TODO: This does NOT have any way for you to send results back to the
* mater computer.
*/
template<typename TGrain, typename TContext = int>
class MPIGrainRunner {
FORBID_COPY(MPIGrainRunner);
friend class MPIDispatcher;
public:
typedef TGrain Grain;
typedef TContext Context;
class Dispatcher {
FORBID_COPY(Dispatcher);
friend class MPIGrainRunner;
private:
class MPIMasterTask : public Task {
private:
struct MPIGrainRunner *runner_;
public:
MPIMasterTask(MPIGrainRunner *runner_in) {
runner_ = runner_in;
}
void Run() {
int rank;
int message;
int n_slaves_alive = 0;
int n_slaves_busy = 0;
DEBUG_MSG(1.0, "DISPATCH: Firing up the cannons.");
DEBUG_MSG(1.0, "DISPATCH: We will accomplish %u tasks.",
unsigned(runner_->dispatcher_->queue_->size()));
for (;;) {
runner_->RecvInt_(&rank, &message);
runner_->mutex_.Lock();
Grain* grain = runner_->dispatcher_->queue_->Pop();
runner_->mutex_.Unlock();
if (message == BIRTH) {
DEBUG_MSG(1.0, "DISPATCH: Received birth message.");
n_slaves_alive++;
n_slaves_busy++;
} else {
DEBUG_ASSERT(message == GIVE_ME_WORK);
DEBUG_MSG(1.0, "DISPATCH: Somebody wants more work.");
}
if (grain) {
char buf[sizeof(Grain) + 1];
buf[0] = 1; // data is available
mem::CopyBytes(buf + 1, grain, sizeof(*grain));
delete grain;
DEBUG_MSG(1.0, "DISPATCH: Sending work on over.");
MPI_Send(buf, sizeof(buf), MPI_CHAR, rank,
runner_->tag_, MPI_COMM_WORLD);
} else if (n_slaves_alive == runner_->n_slaves_) {
// we have to make sure all workers are born before we quit,
// otherwise the worker will wait infinitely for work.
break;
}
}
DEBUG_MSG(1.0, "DISPATCH: Waiting for workers to die...");
/* Wait for all to die */
while (n_slaves_alive != 0) {
// we received a message from the last loop
if (message == GIVE_ME_WORK) {
char buf[1];
buf[0] = 0; // tell them to die
MPI_Send(buf, sizeof(buf), MPI_CHAR, rank,
runner_->tag_, MPI_COMM_WORLD);
DEBUG_MSG(1.0, "DISPATCH: I told a worker to die.");
n_slaves_busy--;
} else if (message == DEATH) {
DEBUG_MSG(1.0, "DISPATCH: A worker died.");
n_slaves_alive--;
} else {
DEBUG_ASSERT_MSG(0, "DISPATCHED: Message was %d??",
message);
}
if (n_slaves_alive != 0) {
runner_->RecvInt_(&rank, &message);
}
}
DEBUG_MSG(1.0, "DISPATCH: All workers have died.");
delete this;
}
};
private:
MPIGrainRunner *runner_;
GrainQueue<Grain> *queue_;
public:
Dispatcher() {}
~Dispatcher() {}
void Init(MPIGrainRunner *runner_in) {
queue_ = NULL;
runner_ = runner_in;
}
void set_queue(GrainQueue<Grain> *queue_in) {
queue_ = queue_in;
}
private:
void MasterLoop_() {
if (runner_->n_slaves_ > 0) {
MPIMasterTask *task = new MPIMasterTask(runner_);
task->Run();
}
}
};
private:
class ConsumerTask : public Task {
FORBID_COPY(ConsumerTask);
private:
struct MPIGrainRunner *runner_;
public:
ConsumerTask(MPIGrainRunner *runner_in) {
runner_ = runner_in;
}
void Run() {
int my_grains = 0;
for (;;) {
Grain *grain = runner_->NextGrain_();
if (!grain) {
break;
}
grain->Run(runner_->context_);
delete grain;
my_grains++;
}
DEBUG_MSG(1.0, "A thread on rank %d is done, completed %d grains.",
runner_->my_rank_, my_grains);
delete this;
}
};
private:
enum { BIRTH = 27, GIVE_ME_WORK, DEATH };
private:
int tag_;
Context context_;
int master_rank_;
int my_rank_;
int n_nodes_;
int n_slaves_;
Dispatcher *dispatcher_;
WaitCondition need_work_cond_;
volatile int need_work_;
WaitCondition have_work_cond_;
volatile int have_work_;
Mutex mutex_;
ArrayList<Grain *> slave_grains_;
public:
MPIGrainRunner() {}
~MPIGrainRunner() {}
/**
* Initialize this.
*
* @param name name to associate information with
* @param tag_in the tag for this to use; this will occupy both the
* specified tag AND the one after it
* @param context_in the context to run grains with
* @param master_rank_in the rank of the master (defaults to first)
*/
void Init(const char *name, int tag_in, Context context_in, int master_rank_in = 0) {
tag_ = tag_in;
context_ = context_in;
master_rank_ = master_rank_in;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank_);
MPI_Comm_size(MPI_COMM_WORLD, &n_nodes_);
n_slaves_ = n_nodes_ - 1;
DEBUG_MSG(1.0, "my_rank = %d", my_rank_);
if (master_rank_ == my_rank_) {
dispatcher_ = new Dispatcher();
dispatcher_->Init(this);
} else {
dispatcher_ = NULL;
}
have_work_ = 0;
need_work_ = 0;
slave_grains_.Init();
xrun_subparam_set(name, "n_nodes", "%d", n_nodes_);
}
Dispatcher *dispatcher() const {
return dispatcher_;
}
Thread *SpawnThread() {
ConsumerTask *task = new ConsumerTask(this);
Thread *thread = new Thread();
thread->Init(task);
thread->Start();
return thread;
}
/**
* Creates the specified number of threads, and uses those to execute
* all grains of work.
*
* Use this rather than the other SpawnThread methods.
*/
void RunThreads(int num_threads) {
DEBUG_MSG(1.0, "Rank %d is ready to roll.", my_rank_);
ArrayList<Thread*> threads;
int num_worker_threads = num_threads;
if (num_worker_threads != 2) abort();
threads.Init(num_worker_threads);
for (int i = 0; i < num_worker_threads; i++) {
threads[i] = SpawnThread();
}
if (dispatcher_) {
dispatcher_->MasterLoop_();
DEBUG_MSG(1.0, "Master loop done, cleaning up.");
} else {
SlaveLoop_();
DEBUG_MSG(1.0, "Slave %d loop done, cleaning up.", my_rank_);
}
for (int i = num_worker_threads; i--;) {
threads[i]->WaitStop();
delete threads[i];
}
if (!dispatcher_) {
// Let the master know I'm done.
SendInt_(master_rank_, DEATH);
}
DEBUG_MSG(1.0, "Rank %d killed all threads.", my_rank_);
}
private:
void SendInt_(int dest_rank, int num) {
MPI_Send(&num, 1,
MPI_INT, dest_rank,
tag_ + 1,
MPI_COMM_WORLD);
}
void RecvInt_(int *send_rank, int *num_ptr) {
MPI_Status status;
MPI_Recv(num_ptr, 1,
MPI_INT,
MPI_ANY_SOURCE,
tag_ + 1,
MPI_COMM_WORLD,
&status);
*send_rank = status.MPI_SOURCE;
}
Grain *NextGrain_() {
Grain *grain;
if (dispatcher_) {
DEBUG_ASSERT((my_rank_ == master_rank_));
mutex_.Lock();
grain = dispatcher_->queue_->Pop();
mutex_.Unlock();
} else {
DEBUG_ASSERT((my_rank_ != master_rank_));
mutex_.Lock();
need_work_++;
mutex_.Unlock();
need_work_cond_.Signal();
mutex_.Lock();
while (!have_work_) {
have_work_cond_.Wait(&mutex_);
}
if (slave_grains_.size() > 0) {
grain = *slave_grains_.PopBackPtr();
have_work_--;
} else {
grain = NULL;
}
mutex_.Unlock();
DEBUG_MSG(2.0, "Slave gave me stuff!");
}
return grain;
}
void SlaveLoop_() {
bool done = false;
DEBUG_MSG(1.0, "%d, WORKER: Announcing birth...", my_rank_);
SendInt_(master_rank_, BIRTH);
while (!done) {
char buf[sizeof(Grain) + 1] = "q";
MPI_Status status;
DEBUG_MSG(1.0, "%d, WORKER: Waiting for work...", my_rank_);
MPI_Recv(buf, sizeof(buf),
MPI_CHAR, MPI_ANY_SOURCE,
tag_,
MPI_COMM_WORLD, &status);
Grain *grain = NULL;
if (buf[0] == 1) {
DEBUG_MSG(1.0, "%d, WORKER: Got some work. There are %d waiting.",
my_rank_, need_work_);
grain = new Grain();
mem::CopyBytes(grain, buf+1, sizeof(Grain));
mutex_.Lock();
while (need_work_ == 0) {
need_work_cond_.Wait(&mutex_);
}
need_work_--;
have_work_++;
*slave_grains_.AddBack() = grain;
mutex_.Unlock();
have_work_cond_.Signal();
SendInt_(master_rank_, GIVE_ME_WORK);
} else {
DEBUG_ASSERT_MSG(buf[0] == 0, "buf[0] = %d", buf[0]);
grain = NULL;
done = true;
}
}
DEBUG_MSG(1.0, "%d, WORKER: Duly dying !!!!!!!!!!!!!!!!!!!", my_rank_);
mutex_.Lock();
have_work_ = -1;
mutex_.Unlock();
have_work_cond_.Broadcast();
}
};
#endif
+7 -1
View File
@@ -1,7 +1,13 @@
#ifndef THOR_BLOCKDEV_H
#define THOR_BLOCKDEV_H
#include "fastlib/fastlib_int.h"
#include "base/common.h"
#include "base/otrav.h"
#include "col/intmap.h"
#include "col/string.h"
#include "fx/fx.h"
#include "par/thread.h"
class BlockDevice {
FORBID_COPY(BlockDevice);
+33
View File
@@ -0,0 +1,33 @@
#ifndef THOR_CACHE_H
#define THOR_CACHE_H
#include "blockdev.h"
/**
* Handles events associated with a cache pulling blocks in and out of memory.
*/
class BlockHandler {
FORBID_COPY(BlockHandler);
public:
BlockHandler() {}
virtual ~BlockHandler() {}
/** Save state. */
virtual void Serialize(ArrayList<char>* data) const = 0;
/** Initialize from state. */
virtual void Deserialize(const ArrayList<char>& data) = 0;
/** Initialize a chunk in frozen state. */
virtual void BlockInitFrozen(BlockDevice::blockid_t blockid,
BlockDevice::offset_t begin,
BlockDevice::offset_t bytes, char *block) = 0;
/** Freeze a chunk so it can be sent over net, or stored. */
virtual void BlockFreeze(BlockDevice::blockid_t blockid,
BlockDevice::offset_t begin, BlockDevice::offset_t bytes,
const char *old_location, char *block) = 0;
/** Thaw a chunk so it can be accessed via pointers. */
virtual void BlockThaw(BlockDevice::blockid_t blockid,
BlockDevice::offset_t begin, BlockDevice::offset_t bytes,
char *block) = 0;
};
#endif
+439
View File
@@ -0,0 +1,439 @@
#ifndef THOR_DFS_H
#define THOR_DFS_H
#include "gnp.h"
#include "cachearray.h"
/**
* Depth-first dual-tree solver.
*/
template<typename GNP>
class DualTreeDepthFirst {
FORBID_COPY(DualTreeDepthFirst);
private:
struct QMutables {
typename GNP::QSummaryResult summary_result;
typename GNP::QPostponed postponed;
OT_DEF(QMutables) {
OT_MY_OBJECT(summary_result);
OT_MY_OBJECT(postponed);
}
};
private:
typename GNP::Param param_;
typename GNP::GlobalResult global_result_;
CacheArray<typename GNP::QPoint> q_points_;
CacheArray<typename GNP::QNode> q_nodes_;
CacheArray<typename GNP::QResult> q_results_;
SubsetArray<QMutables> q_mutables_;
CacheArray<typename GNP::RPoint> r_points_;
CacheArray<typename GNP::RNode> r_nodes_;
const typename GNP::RNode *r_root_;
bool do_naive_;
//datanode *datanode_;
uint64 n_naive_;
uint64 n_pre_naive_;
uint64 n_recurse_;
public:
DualTreeDepthFirst() {}
~DualTreeDepthFirst();
/**
* Solves the GNP.
*
* Results are stored in q_results and in this->global_result.
* The datanode contains possible parameters, and records some
* recursion statistics when debugging is enabled.
* All the other arguments are the GNP input, and are not modified.
*/
void Doit(
const typename GNP::Param& param_in,
index_t q_root_index,
index_t q_node_end_index,
DistributedCache *q_points,
DistributedCache *q_nodes,
DistributedCache *r_points,
DistributedCache *r_nodes,
DistributedCache *q_results);
/**
* Gets the global result after computation.
*/
const typename GNP::GlobalResult& global_result() const {
return global_result_;
}
private:
void Begin_(index_t q_root_index);
void Pair_(
const typename GNP::QNode *q_node,
const typename GNP::RNode *r_node,
const typename GNP::Delta& delta,
const typename GNP::QSummaryResult& unvisited,
QMutables *q_node_mut);
void BaseCase_(
const typename GNP::QNode *q_node,
const typename GNP::RNode *r_node,
const typename GNP::QSummaryResult& unvisited,
QMutables *q_node_mut);
void PushDown_(index_t q_node_i, QMutables *q_node_mut);
};
template<typename GNP>
DualTreeDepthFirst<GNP>::~DualTreeDepthFirst() {
r_nodes_.StopRead(0);
}
template<typename GNP>
void DualTreeDepthFirst<GNP>::Doit(
const typename GNP::Param& param_in,
index_t q_root_index,
index_t q_end_index,
DistributedCache *q_points,
DistributedCache *q_nodes,
DistributedCache *r_points,
DistributedCache *r_nodes,
DistributedCache *q_results) {
param_.Copy(param_in);
q_nodes_.Init(q_nodes, BlockDevice::M_READ);
r_points_.Init(r_points, BlockDevice::M_READ);
r_nodes_.Init(r_nodes, BlockDevice::M_READ);
const typename GNP::QNode *q_root = q_nodes_.StartRead(q_root_index);
q_results_.Init(q_results, BlockDevice::M_OVERWRITE,
q_root->begin(), q_root->end());
q_points_.Init(q_points, BlockDevice::M_READ,
q_root->begin(), q_root->end());
q_nodes_.StopRead(q_root_index);
QMutables default_mutable;
default_mutable.summary_result.Init(param_);
default_mutable.postponed.Init(param_);
q_mutables_.Init(default_mutable, q_root_index, q_end_index);
global_result_.Init(param_);
r_root_ = r_nodes_.StartRead(0);
//datanode_ = datanode_in;
do_naive_ = false;
Begin_(q_root_index);
}
template<typename GNP>
void DualTreeDepthFirst<GNP>::Begin_(index_t q_root_index) {
typename GNP::Delta delta;
const typename GNP::QNode *q_root = q_nodes_.StartRead(q_root_index);
QMutables *q_root_mut = &q_mutables_[q_root_index];
//fx_timer_start(datanode_, "execute");
DEBUG_ONLY(n_naive_ = 0);
DEBUG_ONLY(n_pre_naive_ = 0);
DEBUG_ONLY(n_recurse_ = 0);
bool need_explore = GNP::Algorithm::ConsiderPairIntrinsic(
param_, *q_root, *r_root_, &delta,
&global_result_, &q_root_mut->postponed);
if (need_explore) {
typename GNP::QSummaryResult empty_summary_result;
empty_summary_result.Init(param_);
if (do_naive_) {
BaseCase_(q_root, r_root_, empty_summary_result, q_root_mut);
} else {
Pair_(q_root, r_root_, delta, empty_summary_result, q_root_mut);
}
PushDown_(q_root_index, q_root_mut);
}
q_nodes_.StopRead(q_root_index);
//fx_timer_stop(datanode_, "execute");
#warning we should collect statistics
/*DEBUG_ONLY(fx_format_result(datanode_, "naive_ratio", "%f",
1.0 * n_naive_ / q_root->count() / r_root_->count()));
DEBUG_ONLY(fx_format_result(datanode_, "naive_per_query", "%f",
1.0 * n_naive_ / q_root->count()));
DEBUG_ONLY(fx_format_result(datanode_, "pre_naive_ratio", "%f",
1.0 * n_pre_naive_ / q_root->count() / r_root_->count()));
DEBUG_ONLY(fx_format_result(datanode_, "pre_naive_per_query", "%f",
1.0 * n_pre_naive_ / q_root->count()));
DEBUG_ONLY(fx_format_result(datanode_, "recurse_ratio", "%f",
1.0 * n_recurse_ / q_root->count() / r_root_->count()));
DEBUG_ONLY(fx_format_result(datanode_, "recurse_per_query", "%f",
1.0 * n_recurse_ / q_root->count()));*/
/* if (fx_param_bool(datanode_, "print", 0)) {
ot::Print(q_results_);
}*/
}
template<typename GNP>
void DualTreeDepthFirst<GNP>::PushDown_(
index_t q_node_i, QMutables *q_node_mut) {
const typename GNP::QNode *q_node = q_nodes_.StartRead(q_node_i);
if (q_node->is_leaf()) {
for (index_t q_i = q_node->begin(); q_i < q_node->end(); q_i++) {
typename GNP::QResult *q_result = q_results_.StartWrite(q_i);
const typename GNP::QPoint *q_point = q_points_.StartRead(q_i);
q_result->ApplyPostponed(param_, q_node_mut->postponed, *q_point, q_i);
q_result->Postprocess(param_, *q_point, q_i, *r_root_);
global_result_.ApplyResult(param_, *q_point, q_i, *q_result);
q_results_.StopWrite(q_i);
q_points_.StopRead(q_i);
}
} else {
for (index_t k = 0; k < 2; k++) {
index_t q_child_i = q_node->child(k);
QMutables *q_child_mut = &q_mutables_[q_child_i];
q_child_mut->postponed.ApplyPostponed(param_, q_node_mut->postponed);
PushDown_(q_child_i, q_child_mut);
}
}
q_nodes_.StopRead(q_node_i);
}
template<typename GNP>
void DualTreeDepthFirst<GNP>::Pair_(
const typename GNP::QNode *q_node,
const typename GNP::RNode *r_node,
const typename GNP::Delta& delta,
const typename GNP::QSummaryResult& unvisited,
QMutables *q_node_mut) {
//printf("pair(%d:%d) at (%d:%d)\n", q_node->begin(), q_node->count(), r_node->begin(), r_node->count());
DEBUG_MSG(1.0, "Checking (%d,%d) x (%d,%d)",
q_node->begin(), q_node->end(),
r_node->begin(), r_node->end());
DEBUG_ONLY(n_recurse_++);
/* begin prune checks */
typename GNP::QSummaryResult mu(q_node_mut->summary_result);
mu.ApplyPostponed(param_, q_node_mut->postponed, *q_node);
mu.ApplySummaryResult(param_, unvisited);
mu.ApplyDelta(param_, delta);
if (!GNP::Algorithm::ConsiderQueryTermination(
param_, *q_node, mu, global_result_, &q_node_mut->postponed)) {
q_node_mut->summary_result.ApplyDelta(param_, delta);
DEBUG_MSG(1.0, "Termination prune");
} else if (!GNP::Algorithm::ConsiderPairExtrinsic(
param_, *q_node, *r_node, delta, mu, global_result_,
&q_node_mut->postponed)) {
DEBUG_MSG(1.0, "Extrinsic prune");
} else {
global_result_.UndoDelta(param_, delta);
if (q_node->is_leaf() && r_node->is_leaf()) {
DEBUG_MSG(1.0, "Base case");
BaseCase_(q_node, r_node, unvisited, q_node_mut);
} else if (r_node->is_leaf()
|| (q_node->count() >= r_node->count() && !q_node->is_leaf())) {
DEBUG_MSG(1.0, "Splitting Q");
// Phase 2: Explore children, and reincorporate their results.
q_node_mut->summary_result.StartReaccumulate(param_, *q_node);
for (index_t k = 0; k < 2; k++) {
typename GNP::Delta child_delta;
index_t q_child_i = q_node->child(k);
const typename GNP::QNode *q_child = q_nodes_.StartRead(q_child_i);
QMutables *q_child_mut = &q_mutables_[q_child_i];
q_child_mut->postponed.ApplyPostponed(
param_, q_node_mut->postponed);
child_delta.Init(param_);
if (GNP::Algorithm::ConsiderPairIntrinsic(
param_, *q_child, *r_node, &child_delta,
&global_result_, &q_child_mut->postponed)) {
Pair_(q_child, r_node, delta, unvisited, q_child_mut);
}
// We must VERY carefully apply both the horizontal and vertical join
// operators here for postponed results.
typename GNP::QSummaryResult tmp_result(q_child_mut->summary_result);
tmp_result.ApplyPostponed(param_, q_child_mut->postponed, *q_child);
q_node_mut->summary_result.Accumulate(param_, tmp_result, q_node->count());
q_nodes_.StopRead(q_child_i);
}
q_node_mut->summary_result.FinishReaccumulate(param_, *q_node);
q_node_mut->postponed.Reset(param_);
} else {
DEBUG_MSG(1.0, "Splitting R");
index_t r_child1_i = r_node->child(0);
index_t r_child2_i = r_node->child(1);
const typename GNP::RNode *r_child1 = r_nodes_.StartRead(r_child1_i);
const typename GNP::RNode *r_child2 = r_nodes_.StartRead(r_child2_i);
typename GNP::Delta delta1;
typename GNP::Delta delta2;
double heur1;
double heur2;
delta1.Init(param_);
delta2.Init(param_);
if (GNP::Algorithm::ConsiderPairIntrinsic(
param_, *q_node, *r_child1, &delta1,
&global_result_, &q_node_mut->postponed)) {
heur1 = GNP::Algorithm::Heuristic(param_, *q_node, *r_child1, delta1);
} else {
r_child1 = NULL;
heur1 = DBL_MAX;
}
if (GNP::Algorithm::ConsiderPairIntrinsic(
param_, *q_node, *r_child2, &delta2,
&global_result_, &q_node_mut->postponed)) {
heur2 = GNP::Algorithm::Heuristic(param_, *q_node, *r_child2, delta2);
} else {
r_child2 = NULL;
heur2 = DBL_MAX;
}
if (likely(heur1 <= heur2)) {
if (r_child1 != NULL) {
typename GNP::QSummaryResult unvisited_for_r1(
unvisited);
if (r_child2 != NULL) {
unvisited_for_r1.ApplyDelta(param_, delta2);
}
Pair_(q_node, r_child1, delta1, unvisited_for_r1, q_node_mut);
}
if (r_child2 != NULL) {
Pair_(q_node, r_child2, delta2, unvisited, q_node_mut);
}
} else {
if (r_child2 != NULL) {
typename GNP::QSummaryResult unvisited_for_r1(
unvisited);
if (r_child1 != NULL) {
unvisited_for_r1.ApplyDelta(param_, delta1);
}
Pair_(q_node, r_child2, delta2, unvisited_for_r1, q_node_mut);
}
if (r_child1 != NULL) {
Pair_(q_node, r_child1, delta1, unvisited, q_node_mut);
}
}
r_nodes_.StopRead(r_child1_i);
r_nodes_.StopRead(r_child2_i);
}
}
}
template<typename GNP>
void DualTreeDepthFirst<GNP>::BaseCase_(
const typename GNP::QNode *q_node,
const typename GNP::RNode *r_node,
const typename GNP::QSummaryResult& unvisited,
QMutables *q_node_mut) {
typename GNP::PairVisitor visitor;
DEBUG_ONLY(n_pre_naive_ += q_node->count() * r_node->count());
visitor.Init(param_);
q_node_mut->summary_result.StartReaccumulate(param_, *q_node);
CacheRead<typename GNP::QPoint> first_q_point(&q_points_, q_node->begin());
CacheWrite<typename GNP::QResult> first_q_result(&q_results_, q_node->begin());
CacheRead<typename GNP::RPoint> first_r_point(&r_points_, r_node->begin());
size_t q_point_stride = q_points_.n_elem_bytes();
size_t q_result_stride = q_results_.n_elem_bytes();
const typename GNP::QPoint *q_point = first_q_point;
typename GNP::QResult *q_result = first_q_result;
for (index_t q_i = q_node->begin(); q_i < q_node->end(); ++q_i) {
q_result->ApplyPostponed(param_, q_node_mut->postponed, *q_point, q_i);
if (visitor.StartVisitingQueryPoint(param_, *q_point, q_i, *r_node,
unvisited, q_result, &global_result_)) {
const typename GNP::RPoint *r_point = first_r_point;
size_t r_point_stride = r_points_.n_elem_bytes();
index_t r_end = r_node->end();
index_t r_i = r_node->begin();
for (;;) {
visitor.VisitPair(param_, *q_point, q_i, *r_point, r_i);
if (++r_i >= r_end) {
break;
}
r_point = mem::PointerAdd(r_point, r_point_stride);
}
visitor.FinishVisitingQueryPoint(param_, *q_point, q_i, *r_node,
unvisited, q_result, &global_result_);
DEBUG_ONLY(n_naive_ += r_node->count());
}
q_node_mut->summary_result.Accumulate(param_, *q_result);
q_point = mem::PointerAdd(q_point, q_point_stride);
q_result = mem::PointerAdd(q_result, q_result_stride);
}
q_node_mut->summary_result.FinishReaccumulate(param_, *q_node);
q_node_mut->postponed.Reset(param_);
}
// The old version -- doesn't allow delta re-use for heuristics
//
// double r_child1_h = GNP::Algorithm::Heuristic(
// param_, *q_node, *r_child1);
// double r_child2_h = GNP::Algorithm::Heuristic(
// param_, *q_node, *r_child2);
//
// if (unlikely(r_child2_h < r_child1_h)) {
// const typename GNP::RNode *r_child_t = r_child1;
// r_child1 = r_child2;
// r_child2 = r_child_t;
//
// index_t r_child_t_i = r_child1_i;
// r_child1_i = r_child2_i;
// r_child2_i = r_child_t_i;
// }
//
// typename GNP::Delta delta1;
// typename GNP::Delta delta2;
//
// delta1.Init(param_);
// delta2.Init(param_);
//
// bool do_r2 = GNP::Algorithm::ConsiderPairIntrinsic(
// param_, *q_node, *r_child2, &delta2,
// &global_result_, &q_node_mut->postponed);
//
// if (GNP::Algorithm::ConsiderPairIntrinsic(
// param_, *q_node, *r_child1, &delta1,
// &global_result_, &q_node_mut->postponed)) {
// typename GNP::QSummaryResult unvisited_for_r1(
// unvisited);
// if (do_r2) {
// unvisited_for_r1.ApplyDelta(param_, delta2);
// }
// Pair_(q_node, r_child1, delta1, unvisited_for_r1, q_node_mut);
// }
// if (do_r2) {
// Pair_(q_node, r_child2, delta2, unvisited, q_node_mut);
// }
#endif
+6 -19
View File
@@ -1,26 +1,13 @@
/*to-do
- Init functions
/- the protocol
/- nothing is initialized in my version yet
/- alloc() ?
- dynamic depth
/- the replacement policy
/- copy from old code (old-cache.c)
- use static width with tunable depth (that might be based on external
pressure)
/- think if it's possible to skip the fifo
/- no, not possible, no buffer size guarantees
/- how do we check items out of the n-way cache?
/- once we start using it, we can just leave a "hole" in the cache set
which can be filled later, like a victim cache
/- dirty marking needs to be improved
*/
#include "distribcache.h"
#include <stdio.h>
/*to-do
- dynamic depth
- use static width with tunable depth (that might be based on external
pressure)
*/
//-------------------------------------------------------------------------
//-- THE DISTRIBUTED CACHE ------------------------------------------------
+3
View File
@@ -1,6 +1,9 @@
#ifndef THOR_DISTRIBCACHE_H
#define THOR_DISTRIBCACHE_H
#include "col/arraylist.h"
#include "col/rangeset.h"
#include "rpc.h"
#include "cache.h"
#include "blockdev.h"
+2 -1
View File
@@ -1,7 +1,8 @@
#ifndef THOR_GNP_H
#define THOR_GNP_H
#include "fastlib/fastlib.h"
#include "base/otrav.h"
#include "fx/fx.h"
struct BlankDelta {
public:
+2 -1
View File
@@ -14,10 +14,11 @@
#include "thortree.h"
#include "cachearray.h"
#include "file/textfile.h"
#include "data/dataset.h"
#include "tree/bounds.h"
#include "base/common.h"
#include "col/arraylist.h"
#include "file/serialize.h"
#include "fx/fx.h"
/* Implementation */
+3 -3
View File
@@ -8,11 +8,11 @@
#define THOR_RPC_H
#include "blockdev.h"
#include "fastlib/fastlib_int.h"
#include "rpc_sock.h"
#include "base/common.h"
#include "col/arraylist.h"
/**
* A single remote procedure call.
*
+1 -3
View File
@@ -1,5 +1,3 @@
/**
* @file rpc_sock.cc
*
@@ -9,7 +7,7 @@
#include "rpc.h"
#include "rpc_sock.h"
#include "fastlib/fastlib.h"
#include "file/textfile.h"
#include <fcntl.h>
#include <errno.h>
+3 -3
View File
@@ -7,9 +7,9 @@
#ifndef RPC_SOCK_H
#define RPC_SOCK_H
#include "spbounds.h"
#include "fastlib/fastlib_int.h"
#include "col/arraylist.h"
#include "col/queue.h"
#include "math/math.h"
#include <sys/socket.h>
#include <sys/types.h>
+1 -1
View File
@@ -9,7 +9,7 @@
#include "cachearray.h"
#include "fastlib/fastlib.h"
#include "la/matrix.h"
#include "base/otrav.h"
/**
+5 -3
View File
@@ -10,9 +10,12 @@
#include "rpc.h"
#include "cache.h"
#include "cachearray.h"
#include "spnode.h"
#include "thortree.h"
#include "fastlib/fastlib_int.h"
#include "col/heap.h"
#include "col/arraylist.h"
#include "la/uselapack.h"
#include "tree/bounds.h"
//------------------------------------------------------------------------
@@ -172,7 +175,6 @@ void SimpleWorkQueue<Node>::AddWork_(
//------------------------------------------------------------------------
#include "spbounds.h"
template<typename Node>
class CentroidWorkQueue
+418 -226
View File
@@ -24,49 +24,107 @@
*/
struct DRange {
public:
/**
* The lower bound.
*/
double lo;
/**
* The upper bound.
*/
double hi;
OT_DEF_BASIC(DRange) {
OT_MY_OBJECT(lo);
OT_MY_OBJECT(hi);
}
public:
DRange() {}
/** Initializes to specified values. */
DRange(double lo_in, double hi_in)
: lo(lo_in), hi(hi_in)
{}
/** Initialize to an empty set, where lo > hi. */
void InitEmptySet() {
lo = DBL_MAX;
hi = -DBL_MAX;
}
/** Initializes to -infinity to infinity. */
void InitUniversalSet() {
lo = DBL_MAX;
hi = -DBL_MAX;
lo = -DBL_MAX;
hi = DBL_MAX;
}
/** Initializes to a range of values. */
void Init(double lo_in, double hi_in) {
lo = lo_in;
hi = hi_in;
}
/**
* Resets to a range of values.
*
* Since there is no dynamic memory this is the same as Init, but calling
* Reset instead of Init probably looks more similar to surrounding code.
*/
void Reset(double lo_in, double hi_in) {
lo = lo_in;
hi = hi_in;
}
/**
* Gets the span of the range, hi - lo.
*/
double width() const {
return hi - lo;
}
/**
* Gets the midpoint of this range.
*/
double mid() const {
return (hi + lo) / 2;
}
const DRange& operator |= (const DRange& other) {
if (unlikely(other.lo > lo)) {
lo = other.lo;
/**
* Interpolates (factor) * hi + (1 - factor) * lo.
*/
double interpolate(double factor) const {
return factor * width() + lo;
}
/**
* Simulate an union by growing the range if necessary.
*/
const DRange& operator |= (double d) {
if (unlikely(d < lo)) {
lo = d;
}
if (unlikely(other.hi < hi)) {
hi = other.hi;
if (unlikely(d > hi)) {
hi = d;
}
return *this;
}
const DRange& operator &= (const DRange& other) {
/**
* Sets this range to include only the specified value, or
* becomes an empty set if the range does not contain the number.
*/
const DRange& operator &= (double d) {
if (likely(d > lo)) {
lo = d;
}
if (likely(d < hi)) {
hi = d;
}
return *this;
}
/**
* Expands range to include the other range.
*/
const DRange& operator |= (const DRange& other) {
if (unlikely(other.lo < lo)) {
lo = other.lo;
}
@@ -76,34 +134,48 @@ struct DRange {
return *this;
}
/** Accumulates a bound difference. */
/**
* Shrinks range to be the overlap with another range, becoming an empty
* set if there is no overlap.
*/
const DRange& operator &= (const DRange& other) {
if (unlikely(other.lo > lo)) {
lo = other.lo;
}
if (unlikely(other.hi < hi)) {
hi = other.hi;
}
return *this;
}
/** Sums the upper and lower independently. */
const DRange& operator += (const DRange& other) {
lo += other.lo;
hi += other.hi;
return *this;
}
/** Reverses a bound difference. */
/** Subtracts from the upper and lower independently. */
const DRange& operator -= (const DRange& other) {
lo -= other.lo;
hi -= other.hi;
return *this;
}
/** Uniformly increases both lower and upper bounds. */
/** Adds to the upper and lower independently. */
const DRange& operator += (double d) {
lo += d;
hi += d;
return *this;
}
/** Uniformly decreases both upper and lower bounds. */
/** Subtracts from the upper and lower independently. */
const DRange& operator -= (double d) {
lo -= d;
hi -= d;
return *this;
}
friend DRange operator + (const DRange& a, const DRange& b) {
DRange result;
result.lo = a.lo + b.lo;
@@ -131,83 +203,176 @@ struct DRange {
result.hi = a.hi - b;
return result;
}
/**
* Takes the maximum of upper and lower bounds independently.
*/
void MaxWith(const DRange& range) {
if (unlikely(range.lo > lo)) {
lo = range.lo;
}
if (unlikely(range.hi > hi)) {
hi = range.hi;
}
}
/**
* Takes the minimum of upper and lower bounds independently.
*/
void MinWith(const DRange& range) {
if (unlikely(range.lo < lo)) {
lo = range.lo;
}
if (unlikely(range.hi < hi)) {
hi = range.hi;
}
}
/**
* Takes the maximum of upper and lower bounds independently.
*/
void MaxWith(double v) {
if (unlikely(v > lo)) {
lo = v;
if (unlikely(v > hi)) {
hi = v;
}
}
}
/**
* Takes the minimum of upper and lower bounds independently.
*/
void MinWith(double v) {
if (unlikely(v < hi)) {
hi = v;
if (unlikely(v < lo)) {
lo = v;
}
}
}
/**
* Compares if this is STRICTLY less than another range.
*/
friend bool operator < (const DRange& a, const DRange& b) {
return a.hi < b.lo;
}
/**
* Compares if this is STRICTLY equal to another range.
*/
friend bool operator == (const DRange& a, const DRange& b) {
return a.lo == b.lo && a.hi == b.hi;
}
DEFINE_ALL_COMPARATORS(DRange);
/**
* Compares if this is STRICTLY less than a value.
*/
friend bool operator < (const DRange& a, double b) {
return a.hi < b;
}
/**
* Compares if a value is STRICTLY less than this range.
*/
friend bool operator < (double a, const DRange& b) {
return a < b.lo;
}
DEFINE_INEQUALITY_COMPARATORS_HETERO(DRange, double);
/**
* Determines if a point is contained within the range.
*/
bool Contains(double d) const {
return d >= lo || d <= hi;
}
};
/**
* Hyper-rectangle bound.
* Hyper-rectangle bound for an L-metric.
*
* Template parameter t_pow is the metric to use; use 2 for Euclidean (L2).
*
* @experimental
*/
template<int t_pow = 2>
class DHrectBound {
public:
static const int PREFERRED_POWER = t_pow;
private:
DRange *bounds_;
//double diagonal_sq_;
index_t dim_;
OT_DEF(DHrectBound) {
OT_MY_OBJECT(dim_);
OT_MALLOC_ARRAY(bounds_, dim_);
}
public:
DHrectBound() {
DEBUG_POISON_PTR(bounds_);
DEBUG_ONLY(dim_ = BIG_BAD_NUMBER);
}
~DHrectBound() {
mem::Free(bounds_);
}
template<typename Deserializer>
void Deserialize(Deserializer *s) {
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
s->Get(&dim_);
bounds_ = mem::Alloc<DRange>(dim_);
s->Get(bounds_, dim_);
//ComputeDiagonal_();
}
template<typename Serializer>
void Serialize(Serializer *s) const {
s->Put(dim_);
s->Put(bounds_, dim_);
}
/**
* Initializes to specified dimensionality with each dimension the empty
* set.
*/
void Init(index_t dimension) {
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
//DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
bounds_ = mem::Alloc<DRange>(dimension);
for (index_t i = 0; i < dimension; i++) {
dim_ = dimension;
Reset();
}
/**
* Resets all dimensions to the empty set.
*/
void Reset() {
for (index_t i = 0; i < dim_; i++) {
bounds_[i].InitEmptySet();
}
dim_ = dimension;
//ComputeDiagonal_();
}
bool Belongs(const Vector& point) const {
/**
* Determines if a point is within this bound.
*/
bool Contains(const Vector& point) const {
for (index_t i = 0; i < point.length(); i++) {
const DRange *bound = &bounds_[i];
if (point[i] > bound->hi || point[i] < bound->lo) {
if (!bounds_[i].Contains(point[i])) {
return false;
}
}
return true;
}
double MinDistanceSqToPoint(const Vector& point) const {
DEBUG_ASSERT(point.length() == dim_);
return MinDistanceSqToPoint(point.ptr());
/** Gets the dimensionality */
index_t dim() const {
return dim_;
}
double MinDistanceSqToPoint(const double *mpoint) const {
/**
* Gets the range for a particular dimension.
*/
const DRange& get(index_t i) const {
DEBUG_BOUNDS(i, dim_);
return bounds_[i];
}
/** Calculates the midpoint of the range */
void CalculateMidpoint(Vector *centroid) const {
centroid->Init(dim_);
for (index_t i = 0; i < dim_; i++) {
(*centroid)[i] = bounds_[i].mid();
}
}
/**
* Calculates minimum bound-to-point squared distance,
* to the specified power.
*/
double MinDistanceSq(const Vector& point) const {
DEBUG_ASSERT(point.length() == dim_);
double sumsq = 0;
//index_t mdim = dim_;
const double *mpoint = point.ptr();
const DRange *mbound = bounds_;
index_t d = dim_;
@@ -222,64 +387,96 @@ class DHrectBound {
mbound++;
mpoint++;
sumsq += v * v;
sumsq += math::Pow<t_pow, 1>(v);
} while (--d);
return sumsq / 4;
return math::Pow<2, t_pow>(sumsq) / 4;
}
double MaxDistanceSqToPoint(const Vector& point) const {
/**
* Calculates closest-to-their-midpoint bounding box distance,
* i.e. calculates their midpoint and finds the minimum box-to-point
* distance.
*
* Equivalent to:
* <code>
* other.CalcMidpoint(&other_midpoint)
* return MinDistanceSqToPoint(other_midpoint)
* </code>
*/
double MinToMidSq(const DHrectBound& other) const {
double sumsq = 0;
const DRange *a = this->bounds_;
const DRange *b = other.bounds_;
DEBUG_ASSERT(dim_ == other.dim_);
for (index_t d = 0; d < dim_; d++) {
double v = b->mid();
double v1 = a->lo - v;
double v2 = v - a->hi;
v = (v1 + fabs(v1)) + (v2 + fabs(v2));
a++;
b++;
sumsq += math::Pow<t_pow, 1>(v);
}
return math::Pow<2, t_pow>(sumsq) / 4;
}
/**
* Calculates maximum bound-to-point squared distance,
* to the specified power.
*/
double MaxDistanceSq(const Vector& point) const {
double sumsq = 0;
DEBUG_ASSERT(point.length() == dim_);
for (index_t d = 0; d < dim_; d++) {
double v = max(point[d] - bounds_[d].lo,
bounds_[d].hi - point[d]);
sumsq += v * v;
sumsq += math::Pow<t_pow, 1>(
max(point[d] - bounds_[d].lo, bounds_[d].hi - point[d]));
}
return sumsq;
return math::Pow<2, t_pow>(sumsq);
}
double MinDistanceSqToBound(const DHrectBound& other) const {
/**
* Calculates minimum bound-to-point squared distance,
* to the specified power.
*
* Example: bound1.MinDistanceSq(other) for minimum squared distance.
*/
double MinDistanceSq(const DHrectBound& other) const {
double sumsq = 0;
const DRange *a = this->bounds_;
const DRange *b = other.bounds_;
index_t mdim = dim_;
DEBUG_ASSERT(dim_ == other.dim_);
// We invoke the following:
// x + fabs(x) = max(x * 2, 0)
// (x * 2)^2 / 4 = x^2
DEBUG_SAME_INT(dim_, other.dim_);
for (index_t d = 0; d < mdim; d++) {
#if 0
double v = b[d].lo - a[d].hi;
if (v < 0) {
v = a[d].lo - b[d].hi;
}
if (likely(v > 0)) {
sumsq += v * v;
}
#else
double v1 = b[d].lo - a[d].hi;
double v2 = a[d].lo - b[d].hi;
// We invoke the following:
// x + fabs(x) = max(x * 2, 0)
// (x * 2)^2 / 4 = x^2
double v = (v1 + fabs(v1)) + (v2 + fabs(v2));
sumsq += v * v;
#endif
sumsq += math::Pow<t_pow, 1>(v);
}
return sumsq / 4;
return math::Pow<2, t_pow>(sumsq) / 4;
}
double MinDistanceSqToBoundFarEnd(const DHrectBound& other) const {
/**
* Computes minimax distance, where the other node is trying to avoid me,
* to the specified power.
*/
double MinimaxDistanceSq(const DHrectBound& other) const {
double sumsq = 0;
const DRange *a = this->bounds_;
const DRange *b = other.bounds_;
@@ -290,17 +487,19 @@ class DHrectBound {
for (index_t d = 0; d < mdim; d++) {
double v1 = b[d].hi - a[d].hi;
double v2 = a[d].lo - b[d].lo;
double v = max(v1, v2);
v = (v + fabs(v)); /* truncate negative */
sumsq += v * v;
v = (v + fabs(v)); /* truncate negatives to zero */
sumsq += math::Pow<t_pow, 1>(v);
}
return sumsq / 4;
return math::Pow<2, t_pow>(sumsq) / 4;
}
double MaxDistanceSqToBound(const DHrectBound& other) const {
/**
* Computes maximum distance,
* to the specified power.
*/
double MaxDistanceSq(const DHrectBound& other) const {
double sumsq = 0;
const DRange *a = this->bounds_;
const DRange *b = other.bounds_;
@@ -308,15 +507,18 @@ class DHrectBound {
DEBUG_ASSERT(dim_ == other.dim_);
for (index_t d = 0; d < dim_; d++) {
double v = max(b[d].hi - a[d].lo, a[d].hi - b[d].lo);
sumsq += v * v;
sumsq += math::Pow<t_pow, 1>(
max(b[d].hi - a[d].lo, a[d].hi - b[d].lo));
}
return sumsq;
return math::Pow<2, t_pow>(sumsq);
}
double MidDistanceSqToBound(const DHrectBound& other) const {
/**
* Calculates midpoint-to-midpoint bounding box distance,
* to the specified power.
*/
double MidDistanceSq(const DHrectBound& other) const {
double sumsq = 0;
const DRange *a = this->bounds_;
const DRange *b = other.bounds_;
@@ -324,133 +526,123 @@ class DHrectBound {
DEBUG_ASSERT(dim_ == other.dim_);
for (index_t d = 0; d < dim_; d++) {
double v = (a[d].hi + a[d].lo - b[d].hi - b[d].lo) * 0.5;
sumsq += v * v;
sumsq += math::PowAbs<t_pow, 1>(a[d].hi + a[d].lo - b[d].hi - b[d].lo);
}
return sumsq;
return math::Pow<2, t_pow>(sumsq) / 4;
}
void Update(const Vector& vector) {
DEBUG_ASSERT(vector.length() == dim_);
/**
* Expands this region to include a new point.
*/
DHrectBound& operator |= (const Vector& vector) {
DEBUG_SAME_INT(vector.length(), dim_);
for (index_t i = 0; i < dim_; i++) {
DRange* bound = &bounds_[i];
double d = vector[i];
if (unlikely(d > bound->hi)) {
bound->hi = d;
}
if (unlikely(d < bound->lo)) {
bound->lo = d;
}
bounds_[i] |= vector[i];
}
return *this;
}
const DRange& get(index_t i) const {
return bounds_[i];
}
//double diagonal_sq() const {
// return diagonal_sq_;
//}
FORBID_COPY(DHrectBound);
private:
//void ComputeDiagonal_() {
// diagonal_sq_ = 0;
// for (index_t d = 0; d < dim_; d++) {
// double v = bounds_[d].lo - bounds_[d].hi;
// diagonal_sq_ += v*v;
// }
//}
};
/**
* Euclidean metric for use with ball bounds.
*
* @experimental
*/
class DEuclideanMetric {
public:
static double CalculateMetric(const Vector& a, const Vector& b) {
return sqrt(la::DistanceSqEuclidean(a.length(), a.ptr(), b.ptr()));
/**
* Expands this region to encompass another bound.
*/
DHrectBound& operator |= (const DHrectBound& other) {
DEBUG_SAME_INT(other.dim_, dim_);
for (index_t i = 0; i < dim_; i++) {
bounds_[i] |= other.bounds_[i];
}
return *this;
}
};
/**
* Bound of a ball tree.
*
* @experimental
*/
template<class TPoint, class TMetric>
class BallBound {
FORBID_COPY(BallBound);
public:
typedef TMetric Metric;
typedef TPoint Point;
private:
Point center_;
double radius_;
public:
BallBound() {}
const Point& center() const {
return center;
}
Point& center() {
return center;
}
double radius() const {
return radius;
}
void set_radius(double d) {
radius = d;
}
double DistanceToCenter(const Point& point) {
return Metric::CalculateMetric(point, center_);
}
bool Belongs(const Point& point) {
return DistanceToCenter(point) <= radius_;
}
double MinDistanceToPoint(const Point& point) {
return max(0.0, DistanceToCenter(point) - radius_);
}
double MaxDistanceToPoint(const Point& point) {
return DistanceToCenter(point) + radius_;
}
double MinDistanceToBound(const BallBound& ball) {
return max(0,
DistanceToCenter(ball.center_) - (radius_ + ball.radius_));
}
double MaxDistanceToBound(const BallBound& ball) {
return DistanceToCenter(ball.center_) + (radius_ + ball.radius_);
}
double MidDistanceToBound(const BallBound& other) {
return DistanceToCenter(other.center_);
}
double MidDistanceToPoint(const Point& point) {
return DistanceToCenter(point);
}
};
typedef BallBound<Vector, DEuclideanMetric> DEuclideanBallBound;
// Here's an idea of what ball-trees might look like.
// /**
// * Euclidean metric for use with ball bounds.
// *
// * @experimental
// */
// class DEuclideanMetric {
// public:
// static double CalculateMetric(const Vector& a, const Vector& b) {
// return sqrt(la::DistanceSqEuclidean(a.length(), a.ptr(), b.ptr()));
// }
// };
//
// /**
// * Bound of a ball tree.
// *
// * @experimental
// */
// template<class TPoint, class TMetric>
// class BallBound {
// FORBID_COPY(BallBound);
//
// public:
// typedef TMetric Metric;
// typedef TPoint Point;
//
// private:
// Point center_;
// double radius_;
//
// public:
// BallBound() {}
//
// const Point& center() const {
// return center;
// }
//
// Point& center() {
// return center;
// }
//
// double radius() const {
// return radius;
// }
//
// void set_radius(double d) {
// radius = d;
// }
//
// double DistanceToCenter(const Point& point) {
// return Metric::CalculateMetric(point, center_);
// }
//
// bool Belongs(const Point& point) {
// return DistanceToCenter(point) <= radius_;
// }
//
// double MinDistanceToPoint(const Point& point) {
// return max(0.0, DistanceToCenter(point) - radius_);
// }
//
// double MaxDistanceToPoint(const Point& point) {
// return DistanceToCenter(point) + radius_;
// }
//
// double MinDistanceToBound(const BallBound& ball) {
// return max(0,
// DistanceToCenter(ball.center_) - (radius_ + ball.radius_));
// }
//
// double MaxDistanceToBound(const BallBound& ball) {
// return DistanceToCenter(ball.center_) + (radius_ + ball.radius_);
// }
//
// double MidDistanceToBound(const BallBound& other) {
// return DistanceToCenter(other.center_);
// }
//
// double MidDistanceToPoint(const Point& point) {
// return DistanceToCenter(point);
// }
// };
//
// typedef BallBound<Vector, DEuclideanMetric> DEuclideanBallBound;
#endif
+5 -63
View File
@@ -19,7 +19,6 @@
#include "base/common.h"
#include "col/arraylist.h"
#include "file/serialize.h"
#include "fx/fx.h"
/* Implementation */
@@ -80,8 +79,8 @@ namespace tree_kdtree_private {
left_vector.SwapValues(&right_vector);
left_bound->Update(left_vector);
right_bound->Update(right_vector);
*left_bound |= left_vector;
*right_bound |= right_vector;
if (old_from_new) {
index_t t = old_from_new[left];
@@ -217,44 +216,6 @@ namespace tree {
}
// TODO: Perhaps move this into a "util.h" file
/** Serializes a KD tree to a serializer. @experimental */
template<typename TKdTree, typename Serializer>
void SerializeKdTree(const TKdTree *tree,
const Matrix& matrix,
const ArrayList<index_t>& old_from_new,
Serializer *s) {
s->PutMagic(file::CreateMagic("kdtree"));
tree->SerializeAll(matrix, s);
old_from_new.Serialize(s);
}
/** Deserializes a KD tree from a serializer. @experimental */
template<typename TKdTree, typename Deserializer>
void DeserializeKdTree(TKdTree *uninit_tree,
Matrix* uninit_matrix,
ArrayList<index_t>* uninit_old_from_new,
Deserializer *s) {
s->AssertMagic(file::CreateMagic("kdtree"));
uninit_tree->DeserializeAll(uninit_matrix, s);
if (uninit_old_from_new) {
uninit_old_from_new->Deserialize(s);
}
}
/** Reads a KD tree from a file in the SERIALIZED format. @experimental */
template<typename TKdTree>
void LoadKdTreeFromFile(const char *fname,
TKdTree *uninit_tree,
Matrix* uninit_matrix,
ArrayList<index_t>* uninit_old_from_new) {
NativeFileDeserializer ds;
ASSERT_PASS(ds.Init(fname));
DeserializeKdTree(uninit_tree, uninit_matrix, uninit_old_from_new,
&ds);
}
/**
* Loads a KD tree from a command-line parameter,
* creating a KD tree if necessary.
@@ -283,8 +244,6 @@ namespace tree {
* @code
* ./main --q=foo.txt # load from csv format
* ./main --q=foo.txt --q/leaflen=20 # leaf length
* ./main --q=foo.kd --q/type=native # load from serialized format
* ./main --q=foo.txt --q/save=foo.kd # serialize the tree too
* @endcode
*
* @param module the module to get parameters from
@@ -304,12 +263,7 @@ namespace tree {
success_t success = SUCCESS_PASS;
fx_timer_start(module, "load");
if (strcmp(type, "native") == 0) {
fx_timer_start(module, "deserialize");
*tree_pp = new TKdTree();
tree::LoadKdTreeFromFile(fname, *tree_pp, matrix, old_from_new);
fx_timer_stop(module, "deserialize");
} else if (strcmp(type, "text") == 0) {
if (strcmp(type, "text") == 0) {
int leaflen = fx_param_int(module, "leaflen", 20);
fx_timer_start(module, "load_matrix");
@@ -322,26 +276,14 @@ namespace tree {
*tree_pp = MakeKdTreeMidpoint<TKdTree>(
*matrix, leaflen, old_from_new);
fx_timer_stop(module, "make_tree");
} else {
FATAL("Uknown file type: %s", type);
}
fx_timer_stop(module, "load");
if (fx_param_exists(module, "save")) {
const char *save_fname = fx_param_str_req(module, "save");
fx_timer_start(module, "save");
NativeArraySerializer serializer;
serializer.Init();
SerializeKdTree(*tree_pp, *matrix, *old_from_new, &serializer);
serializer.WriteFile(save_fname);
fx_timer_stop(module, "save");
}
return success;
}
};
/** Basic KD tree structure. @experimental */
typedef BinarySpaceTree<DHrectBound, Matrix> BasicKdTree;
typedef BinarySpaceTree<DHrectBound<2>, Matrix> BasicKdTree;
#endif
+4 -75
View File
@@ -12,7 +12,6 @@
#define TREE_SPACETREE_H
#include "base/cc.h"
#include "file/serialize.h"
#include "statistic.h"
/**
@@ -34,7 +33,7 @@ class BinarySpaceTree {
typedef TBound Bound;
typedef TDataset Dataset;
typedef TStatistic Statistic;
private:
Bound bound_;
BinarySpaceTree *left_;
@@ -42,7 +41,7 @@ class BinarySpaceTree {
index_t begin_;
index_t count_;
Statistic stat_;
public:
BinarySpaceTree() {
DEBUG_ONLY(begin_ = BIG_BAD_NUMBER);
@@ -50,7 +49,6 @@ class BinarySpaceTree {
DEBUG_POISON_PTR(left_);
DEBUG_POISON_PTR(right_);
}
~BinarySpaceTree() {
if (!is_leaf()) {
@@ -62,7 +60,7 @@ class BinarySpaceTree {
DEBUG_POISON_PTR(left_);
DEBUG_POISON_PTR(right_);
}
void Init(index_t begin_in, index_t count_in) {
DEBUG_ASSERT(begin_ == BIG_BAD_NUMBER);
DEBUG_POISON_PTR(left_);
@@ -70,7 +68,7 @@ class BinarySpaceTree {
begin_ = begin_in;
count_ = count_in;
}
/**
* Find a node in this tree by its begin and count.
*
@@ -123,75 +121,6 @@ class BinarySpaceTree {
}
}
/**
* Serializes the tree _structure_ only.
* Statistics are not stored (this allows you to re-load the tree
* for problems that require different statistics).
*/
template<typename Serializer>
void Serialize(Serializer *s) const {
bound_.Serialize(s);
s->Put(begin_);
s->Put(count_);
bool children = !is_leaf();
s->Put(children);
if (children) {
left_->Serialize(s);
right_->Serialize(s);
}
}
/**
* Deserializes the tree from its structure, and re-calculates bottom-up
* statistics.
*/
template<typename Deserializer>
void Deserialize(const Dataset& data, Deserializer *s) {
DEBUG_ASSERT(begin_ == BIG_BAD_NUMBER);
bound_.Deserialize(s);
s->Get(&begin_);
s->Get(&count_);
bool children;
s->Get(&children);
BinarySpaceTree *l = NULL;
BinarySpaceTree *r = NULL;
if (children) {
l = new BinarySpaceTree();
l->Deserialize(data, s);
r = new BinarySpaceTree();
r->Deserialize(data, s);
}
set_children(data, l, r);
}
template<typename Serializer>
void SerializeAll(const Dataset& data, Serializer *s) const {
// can't use BinarySpaceTree as a magic number, because we want to be
// able to deserialize this class with another statistic
s->PutMagic(file::CreateMagic("spacetree")
+ MAGIC_NUMBER(TDataset) + MAGIC_NUMBER(TBound));
data.Serialize(s);
Serialize(s);
}
template<typename Deserializer>
void DeserializeAll(Dataset* data, Deserializer *s) {
// can't use BinarySpaceTree as a magic number, because we want to be
// able to deserialize this class with another statistic
s->AssertMagic(file::CreateMagic("spacetree")
+ MAGIC_NUMBER(TDataset) + MAGIC_NUMBER(TBound));
data->Deserialize(s);
Deserialize(*data, s);
}
// TODO: Not const correct
/**
+2 -6
View File
@@ -101,7 +101,7 @@ struct AffinityCommon {
void Init(datanode *module) {
dim = -1;
pref = fx_param_double_req(module, "pref");
lambda = fx_param_double(module, "lambda", 0.9);
lambda = fx_param_double(module, "lambda", 0.6);
}
void InitPointExtras(int tag, Point *point) const {
@@ -115,11 +115,7 @@ struct AffinityCommon {
point->info().alpha.max1 = 0;
point->info().alpha.max2 = pref;
point->info().alpha.max1_index = index;
if (math::RandInt(4096) == 0) {
point->info().rho = -pref / 2;
} else {
point->info().rho = 0;
}
point->info().rho = 0;
}
void Bootstrap(int tag, index_t dim_in, index_t count) {
-4
View File
@@ -378,10 +378,6 @@ class DistributedCache : public BlockDevice {
}
public:
void Copy(const Position& other) {
*this = other;
}
bool operator < (const Position& other) const {
if (unlikely(block == other.block)) {
return offset < other.offset;
+3 -3
View File
@@ -8,8 +8,8 @@
* @experimental
*/
#ifndef TREE_KDTREE_H
#define TREE_KDTREE_H
#ifndef THOR_KDTREE_H
#define THOR_KDTREE_H
#include "spnode.h"
#include "spbounds.h"
@@ -733,7 +733,7 @@ void ThorKdTree<TParam, TPoint, TNode>::Init(Param **parampp, int param_tag,
Config config;
MasterLoadData_(&config, *parampp, param_tag, module);
MasterBuildTree_(&config, *parampp, param_tag, module);
config.param = *parampp;
config.param = new Param(**parampp);
config_broadcaster_.SetData(config);
} else {
CacheArray<Point>::InitDistributedCacheWorker(points_channel_,
+4 -2
View File
@@ -432,15 +432,17 @@ struct DataGetterRequest {
template<typename T>
class DataGetterBackend
: public RemoteObjectBackend<DataGetterRequest, T> {
FORBID_COPY(DataGetterBackend);
private:
T data_;
public:
void Init(const T& data_in) {
ot::Copy(data_in, &data);
ot::Copy(data_in, &data_);
}
void Init(const T* data_in) {
ot::Copy(*data_in, &data);
ot::Copy(*data_in, &data_);
}
virtual void HandleRequest(const DataGetterRequest& request, T *response);
+5 -294
View File
@@ -11,8 +11,8 @@
* @experimental
*/
#ifndef TREE_SPBOUNDS_H
#define TREE_SPBOUNDS_H
#ifndef THOR_BOUNDS_H
#define THOR_BOUNDS_H
#include "la/matrix.h"
#include "la/la.h"
@@ -109,15 +109,12 @@ class MinMaxVal {
public:
/** The underlying value. */
Value val;
OT_DEF_BASIC(MinMaxVal) {
OT_MY_OBJECT(val);
}
public:
MinMaxVal(Value val_in) : val(val_in) {}
MinMaxVal() {}
public:
/**
* Converts implicitly to the value.
*/
@@ -155,282 +152,6 @@ class MinMaxVal {
}
};
class HiBound {
};
/**
* Simple real-valued range.
*
* @experimental
*/
struct DRange {
public:
/**
* The lower bound.
*/
double lo;
/**
* The upper bound.
*/
double hi;
OT_DEF_BASIC(DRange) {
OT_MY_OBJECT(lo);
OT_MY_OBJECT(hi);
}
public:
/** Doesn't initialize anything. */
DRange() {}
/** Initializes to specified values. */
DRange(double lo_in, double hi_in)
: lo(lo_in), hi(hi_in)
{}
/** Initialize to an empty set, where lo > hi. */
void InitEmptySet() {
lo = DBL_MAX;
hi = -DBL_MAX;
}
/** Initializes to -infinity to infinity. */
void InitUniversalSet() {
lo = -DBL_MAX;
hi = DBL_MAX;
}
/** Initializes to a range of values. */
void Init(double lo_in, double hi_in) {
lo = lo_in;
hi = hi_in;
}
/**
* Resets to a range of values.
*
* Since there is no dynamic memory this is the same as Init, but calling
* Reset instead of Init probably looks more similar to surrounding code.
*/
void Reset(double lo_in, double hi_in) {
lo = lo_in;
hi = hi_in;
}
/**
* Gets the span of the range, hi - lo.
*/
double width() const {
return hi - lo;
}
/**
* Gets the midpoint of this range.
*/
double mid() const {
return (hi + lo) / 2;
}
/**
* Interpolates (factor) * hi + (1 - factor) * lo.
*/
double interpolate(double factor) const {
return factor * width() + lo;
}
/**
* Simulate an union by growing the range if necessary.
*/
const DRange& operator |= (double d) {
if (unlikely(d < lo)) {
lo = d;
}
if (unlikely(d > hi)) {
hi = d;
}
return *this;
}
/**
* Sets this range to include only the specified value, or
* becomes an empty set if the range does not contain the number.
*/
const DRange& operator &= (double d) {
if (likely(d > lo)) {
lo = d;
}
if (likely(d < hi)) {
hi = d;
}
return *this;
}
/**
* Expands range to include the other range.
*/
const DRange& operator |= (const DRange& other) {
if (unlikely(other.lo < lo)) {
lo = other.lo;
}
if (unlikely(other.hi > hi)) {
hi = other.hi;
}
return *this;
}
/**
* Shrinks range to be the overlap with another range, becoming an empty
* set if there is no overlap.
*/
const DRange& operator &= (const DRange& other) {
if (unlikely(other.lo > lo)) {
lo = other.lo;
}
if (unlikely(other.hi < hi)) {
hi = other.hi;
}
return *this;
}
/** Sums the upper and lower independently. */
const DRange& operator += (const DRange& other) {
lo += other.lo;
hi += other.hi;
return *this;
}
/** Subtracts from the upper and lower independently. */
const DRange& operator -= (const DRange& other) {
lo -= other.lo;
hi -= other.hi;
return *this;
}
/** Adds to the upper and lower independently. */
const DRange& operator += (double d) {
lo += d;
hi += d;
return *this;
}
/** Subtracts from the upper and lower independently. */
const DRange& operator -= (double d) {
lo -= d;
hi -= d;
return *this;
}
friend DRange operator + (const DRange& a, const DRange& b) {
DRange result;
result.lo = a.lo + b.lo;
result.hi = a.hi + b.hi;
return result;
}
friend DRange operator - (const DRange& a, const DRange& b) {
DRange result;
result.lo = a.lo - b.lo;
result.hi = a.hi - b.hi;
return result;
}
friend DRange operator + (const DRange& a, double b) {
DRange result;
result.lo = a.lo + b;
result.hi = a.hi + b;
return result;
}
friend DRange operator - (const DRange& a, double b) {
DRange result;
result.lo = a.lo - b;
result.hi = a.hi - b;
return result;
}
/**
* Takes the maximum of upper and lower bounds independently.
*/
void MaxWith(const DRange& range) {
if (unlikely(range.lo > lo)) {
lo = range.lo;
}
if (unlikely(range.hi > hi)) {
hi = range.hi;
}
}
/**
* Takes the minimum of upper and lower bounds independently.
*/
void MinWith(const DRange& range) {
if (unlikely(range.lo < lo)) {
lo = range.lo;
}
if (unlikely(range.hi < hi)) {
hi = range.hi;
}
}
/**
* Takes the maximum of upper and lower bounds independently.
*/
void MaxWith(double v) {
if (unlikely(v > lo)) {
lo = v;
if (unlikely(v > hi)) {
hi = v;
}
}
}
/**
* Takes the minimum of upper and lower bounds independently.
*/
void MinWith(double v) {
if (unlikely(v < hi)) {
hi = v;
if (unlikely(v < lo)) {
lo = v;
}
}
}
/**
* Compares if this is STRICTLY less than another range.
*/
friend bool operator < (const DRange& a, const DRange& b) {
return a.hi < b.lo;
}
/**
* Compares if this is STRICTLY equal to another range.
*/
friend bool operator == (const DRange& a, const DRange& b) {
return a.lo == b.lo && a.hi == b.hi;
}
DEFINE_ALL_COMPARATORS(DRange);
/**
* Compares if this is STRICTLY less than a value.
*/
friend bool operator < (const DRange& a, double b) {
return a.hi < b;
}
/**
* Compares if a value is STRICTLY less than this range.
*/
friend bool operator < (double a, const DRange& b) {
return a < b.lo;
}
DEFINE_INEQUALITY_COMPARATORS_HETERO(DRange, double);
/**
* Determines if a point is contained within the range.
*/
bool Contains(double d) const {
return d >= lo || d <= hi;
}
};
/**
* Hyper-rectangle bound for an L-metric.
*
@@ -458,8 +179,7 @@ class ThorHrectBound {
* set.
*/
void Init(index_t dimension) {
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
//DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
bounds_ = mem::Alloc<DRange>(dimension);
dim_ = dimension;
@@ -475,15 +195,6 @@ class ThorHrectBound {
}
}
/**
* Initializes as a copy of another.
*/
void Copy(const ThorHrectBound& other) {
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
bounds_ = mem::Dup(other.bounds_, other.dim_);
dim_ = other.dim_;
}
/**
* Determines if a point is within this bound.
*/
+11 -12
View File
@@ -66,7 +66,6 @@ class ThorNode {
}
void set_range(index_t begin_in, index_t count_in) {
DEBUG_ASSERT(begin_ == BIG_BAD_NUMBER);
begin_ = begin_in;
count_ = count_in;
}
@@ -151,8 +150,6 @@ class ThorNode {
*/
template<typename TNode, typename TInfo>
class ThorSkeletonNode {
FORBID_COPY(ThorSkeletonNode); // TODO: otrav might provide a copy constructor
public:
typedef TNode Node;
typedef TInfo Info;
@@ -307,12 +304,12 @@ struct TreeGrain {
/** One past the last point. */
index_t point_end_index;
TreeGrain()
: node_index(-1)
, node_end_index(-1)
, point_begin_index(-1)
, point_end_index(-1)
{}
void InitBlank() {
node_index = -1;
node_end_index = -1;
point_begin_index = -1;
point_end_index = -1;
}
bool is_valid() const {
return node_index >= 0;
@@ -338,8 +335,6 @@ struct TreeGrain {
*/
template<typename TNode>
class ThorTreeDecomposition {
FORBID_COPY(ThorTreeDecomposition);
public:
typedef TNode Node;
struct Info {
@@ -380,7 +375,11 @@ class ThorTreeDecomposition {
void Init(DecompNode *root_in) {
root_ = root_in;
DEBUG_ASSERT(root_->info().begin_rank == 0);
grain_by_owner_.Init(root_->info().end_rank);
int n = root_->info().end_rank;
grain_by_owner_.Init(n);
for (int i = 0; i < n; i++) {
grain_by_owner_[i].InitBlank();
}
FillInfo_(root_);
}