From eb97ff828538874dac3faec8e6b9cfe44388c548 Mon Sep 17 00:00:00 2001 From: Garry Boyer Date: Tue, 7 Aug 2007 20:36:01 +0000 Subject: [PATCH] thor moved into the main line -- tree code experiences radical changes --- fastlib/Doxyfile | 2 +- fastlib/base/ccmem.cc | 27 +- fastlib/base/ccmem.h | 64 +-- fastlib/base/otrav.h | 465 ++++++++++++-------- fastlib/col/arraylist.h | 27 +- fastlib/col/build.py | 4 +- fastlib/col/heap.h | 43 +- fastlib/col/intmap.h | 47 +- fastlib/col/queue.h | 2 + fastlib/col/rangeset.h | 4 +- fastlib/col/string.h | 15 +- fastlib/data/build.py | 2 +- fastlib/data/dataset.h | 23 - fastlib/fastlib/build.py | 2 +- fastlib/fastlib/fastlib_int.h | 1 - fastlib/fastlib/otrav_test.cc | 14 +- fastlib/file/build.py | 6 +- fastlib/file/serialize.cc | 79 ---- fastlib/file/serialize.h | 257 ----------- fastlib/la/build.py | 4 +- fastlib/la/matrix.h | 42 +- fastlib/la/uselapack_test.cc | 3 +- fastlib/math/build.py | 2 +- fastlib/math/kernel.h | 20 +- fastlib/math/math.h | 59 +++ fastlib/math/math_test.cc | 4 +- fastlib/par/build.py | 7 - fastlib/par/mpigrain.h | 398 ----------------- fastlib/thor/blockdev.h | 8 +- fastlib/thor/cache.h | 33 ++ fastlib/thor/dfs.h | 439 +++++++++++++++++++ fastlib/thor/distribcache.cc | 25 +- fastlib/thor/distribcache.h | 3 + fastlib/thor/gnp.h | 3 +- fastlib/thor/kdtree.h | 3 +- fastlib/thor/rpc.h | 6 +- fastlib/thor/rpc_sock.cc | 4 +- fastlib/thor/rpc_sock.h | 6 +- fastlib/thor/thortree.h | 2 +- fastlib/thor/work.h | 8 +- fastlib/tree/bounds.h | 644 ++++++++++++++++++---------- fastlib/tree/kdtree.h | 68 +-- fastlib/tree/spacetree.h | 79 +--- fastlib/u/garryb/nbr/affinity.cc | 8 +- fastlib/u/garryb/nbr/distribcache.h | 4 - fastlib/u/garryb/nbr/kdtree.h | 6 +- fastlib/u/garryb/nbr/rpc.h | 6 +- fastlib/u/garryb/nbr/spbounds.h | 299 +------------ fastlib/u/garryb/nbr/spnode.h | 23 +- 49 files changed, 1424 insertions(+), 1876 deletions(-) delete mode 100644 fastlib/file/serialize.cc delete mode 100644 fastlib/file/serialize.h delete mode 100644 fastlib/par/mpigrain.h create mode 100644 fastlib/thor/cache.h create mode 100644 fastlib/thor/dfs.h diff --git a/fastlib/Doxyfile b/fastlib/Doxyfile index 58305d07d7..66742fe55d 100644 --- a/fastlib/Doxyfile +++ b/fastlib/Doxyfile @@ -97,7 +97,7 @@ EXCLUDE_PATTERNS = */auton/* \ *_impl.h \ *_impl.cc \ */u/* \ - *test.cc + *_test.cc EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO diff --git a/fastlib/base/ccmem.cc b/fastlib/base/ccmem.cc index 68b0680e48..5c5cd39bf5 100644 --- a/fastlib/base/ccmem.cc +++ b/fastlib/base/ccmem.cc @@ -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(a_lp_in); char *b_cp = reinterpret_cast(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); + } +} diff --git a/fastlib/base/ccmem.h b/fastlib/base/ccmem.h index a30112f1bb..1e829f97cb 100644 --- a/fastlib/base/ccmem.h +++ b/fastlib/base/ccmem.h @@ -68,7 +68,7 @@ namespace mem { * @param elems number of *elements* */ template - 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* dest, const char* src, size_t elems) { - ::memcpy(dest, src, elems); return dest; - } +#define BASE_CCMEM__FAST_COPY(T) \ + template<> inline T* CopyConstruct(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 inline T* DupConstruct(const T* src, size_t elems = 1) { return CopyConstruct(Alloc(elems), src, elems); } - inline void SwapBytes__Chars(long *a_lp_in, long *b_lp_in, size_t remaining) { - char *a_cp = reinterpret_cast(a_lp_in); - char *b_cp = reinterpret_cast(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 void SwapBytes(T* a, T* b, size_t bytes) { - long *a_lp = reinterpret_cast(a); - long *b_lp = reinterpret_cast(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(a), reinterpret_cast(b), + bytes); } template diff --git a/fastlib/base/otrav.h b/fastlib/base/otrav.h index 020eed96ac..a04d90b3b4 100644 --- a/fastlib/base/otrav.h +++ b/fastlib/base/otrav.h @@ -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 #include -// 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 \ + friend void TraverseObject(AClass *obj_OT, Visitor *v_OT) { \ + obj_OT->TraverseObject__OT_(v_OT); \ + } \ + private: \ + template \ + 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 - * OT_MY_OBJECT(num_extra_data) must come before the subsequent - * line that uses num_extra_data as an array length. If deserialization is - * occuring, each OT_... call is actually deserializing each - * member, so num_extra_data is uninitialized until OT_MY_OBJECT - * is called on it. + * The OT_DEF is used to declare a class's members, and its pointers. + * Notice that OT_MY_OBJECT(num_extra_data) must come before + * the subsequent line that uses num_extra_data as an array length. If + * deserialization is occuring, each OT_... call is actually + * deserializing each member, so num_extra_data is uninitialized until + * OT_MY_OBJECT 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 \ - friend void TraverseObject(AClass *obj_OT, Visitor *v_OT) { \ - obj_OT->TraverseObject__OT_(v_OT); \ - } \ - private: \ - template \ - 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 - void OTPrinter_Primitive( - const char *name, T& x, Printer* printer) { - DefaultPrinter::Print(name, x, printer); - } - template - inline void OTPrinter_Primitive( - const char *name, const char* x, Printer* printer) { - printer->Write("%s : string = %s", name, x); - } - template - 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 - inline void OTPrinter_Primitive( - const char *name, short x, Printer* printer) { - printer->Write("%s : short = %d", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, int x, Printer* printer) { - printer->Write("%s : int = %d", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, long x, Printer* printer) { - printer->Write("%s : long = %ld", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, unsigned char x, Printer* printer) { - printer->Write("%s : uchar = %u", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, unsigned short x, Printer* printer) { - printer->Write("%s : ushort = %u", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, unsigned int x, Printer* printer) { - printer->Write("%s : uint = %u", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, unsigned long x, Printer* printer) { - printer->Write("%s : ulong = %lu", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, float x, Printer* printer) { - printer->Write("%s : float = %f", name, x); - } - template - inline void OTPrinter_Primitive( - const char *name, double x, Printer* printer) { - printer->Write("%s : double = %f", name, x); - } -*/ + template - 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 \ - struct OTPrinter_Primitive { \ + struct OTPrinter_Dispatcher { \ 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 struct DefaultPrimitivePrinter { @@ -361,10 +373,11 @@ namespace ot_private { public: template - 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(&x), this); + name_ = ""; + Object(const_cast(&x), false, ""); } /** Stores the name of the object going to come in. */ @@ -373,7 +386,7 @@ namespace ot_private { } template void Primitive(T& x) { - OTPrinter_Primitive< DefaultPrimitivePrinter, OTPrinter, T > + OTPrinter_Dispatcher< DefaultPrimitivePrinter, 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, OTPrinter, T > + OTPrinter_Dispatcher< DefaultObjectPrinter, OTPrinter, T > ::Print(name_, *obj, this); } } - template 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 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 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 void MallocArray(T*& source_region, index_t len, - bool nullable) { - Array(source_region, len, nullable); + template 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 - 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(block_), &x); // we must cast away const due to TraverseObject's limitations TraverseObject(const_cast(&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 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 void Array(T*& source_region, index_t len, - bool nullable); + template void Array(T*& source_region, index_t len); /** Visits an array pointed to, allocated with malloc */ - template void MallocArray(T*& source_region, index_t len, - bool nullable) { - Array(source_region, len, nullable); + template void MallocArray(T*& source_region, index_t len) { + Array(source_region, len); } - + private: template /** @@ -603,8 +611,8 @@ namespace ot_private { } template 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 - void InitBegin(const T& obj) { + void Doit(const T& obj) { pos_ = sizeof(T); TraverseObject(const_cast(&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 void Primitive(T& x) {} /** visits an internal object */ @@ -657,7 +665,7 @@ namespace ot_private { template void MyArray(T* x, index_t len) { TraverseArray(x, len, this); } - + /** visits an object pointed to, allocated with new */ template 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 void Array(T*& x, index_t len, bool nullable) { - if (!nullable || x != NULL) { + template void Array(T*& x, index_t len) { + if (len != 0) { PretendLayout_(len); TraverseArray(x, len, this); } } /** visits an array pointed to, allocated with malloc */ - template void MallocArray(T*& x, index_t len, bool nullable) { - Array(x, len, nullable); + template 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 - T* InitBegin(ptrdiff_t offset_in, char *data) { + T* Doit(ptrdiff_t offset_in, char *data) { offset_ = offset_in; T* dest = reinterpret_cast(data); MyObject(*dest); return dest; } - + template - T* InitBegin(char *data) { - return InitBegin(data, reinterpret_cast(data)); + T* Doit(char *data) { + return Doit(data, reinterpret_cast(data)); } /** Receives the nanme of the upcoming object -- we ignore this. */ void Name(const char *s) {} - + /** visits an object with no OT implementation */ template void Primitive(T& x) {} /** visits an internal object */ @@ -726,15 +734,15 @@ namespace ot_private { } } /** visits an array pointed to, allocated with new[] */ - template void Array(T*& x, index_t len, bool nullable) { - if (!nullable || x != NULL) { + template 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 void MallocArray(T*& x, index_t len, bool nullable) { - Array(x, len, nullable); + template 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 - 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 void Array(T*& x, index_t len, bool nullable) { - if (!nullable || x != NULL) { + template 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 void MallocArray(T*& x, index_t len, bool nullable) { - Array(x, len, nullable); + template 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 void Primitive(T& x) {} + /** visits an internal object */ + template void MyObject(T& x) { + TraverseObject(&x, this); + } + /** visits an array */ + template void MyArray(T* x, index_t len) { + TraverseArray(x, len, this); + } + /** visits an object pointed to, allocated with new */ + template void Ptr(T*& x, bool nullable) { + if (!nullable || x != NULL) { + x = new T(*x); + } + } + /** visits an array pointed to, allocated with new[] */ + template void Array(T*& x, index_t len) { + x = mem::CopyConstruct(new T[len], x, len); + } + /** visits an array pointed to, allocated with malloc */ + template void MallocArray(T*& x, index_t len) { + x = mem::CopyConstruct(mem::Alloc(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 void Primitive(T& x) {} + /** visits an internal object */ + template void MyObject(T& x) { + // C++ will automatically chain this + } + /** visits an array */ + template void MyArray(T* x, index_t len) { + // C++ will automatically chain this + } + /** visits an object pointed to, allocated with new */ + template 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 void Array(T*& x, index_t len, bool nullable) { + delete[] x; + DEBUG_POISON_PTR(x); + } + /** visits an array pointed to, allocated with malloc */ + template void MallocArray(T*& x, index_t len) { + T *tmpx = x; + mem::DestructAll(tmpx, len); + mem::Free(tmpx); + DEBUG_POISON_PTR(x); + } + }; + + template + void DestructorImplementation(T *dest) { + ot_private::OTDestructor d; + TraverseObject(dest, &d); + // can't poison this because of destructor chanining + } + + template + 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 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 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 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 void PointerRefreeze(T* obj) { ot_private::OTPointerRelocator fixer; - fixer.InitBegin( + fixer.Doit( 0, -mem::PointerAbsoluteAddress(obj), reinterpret_cast(obj)); } @@ -875,7 +964,7 @@ namespace ot { template void PointerRefreeze(const T* src, char* dest) { ot_private::OTPointerRelocator fixer; - fixer.InitBegin( + fixer.Doit( mem::PointerDiff(dest, src), -mem::PointerAbsoluteAddress(src), reinterpret_cast(dest)); } @@ -890,7 +979,7 @@ namespace ot { template T* PointerThaw(char *block) { ot_private::OTPointerThawer fixer; - return fixer.InitBegin( + return fixer.Doit( mem::PointerAbsoluteAddress(block), block); } @@ -903,11 +992,19 @@ namespace ot { template void PointerRelocate(const char *old_location, char *new_location) { ot_private::OTPointerRelocator fixer; - fixer.InitBegin( + fixer.Doit( mem::PointerDiff(new_location, old_location), mem::PointerDiff(new_location, old_location), reinterpret_cast(new_location)); } + + /** + * Deep-copy initializer for OT-compliant classes. + */ + template + void Copy(const T& src, T* dest) { + new(dest)T(src); + } }; #endif diff --git a/fastlib/col/arraylist.h b/fastlib/col/arraylist.h index d239f7de93..97c4984707 100644 --- a/fastlib/col/arraylist.h +++ b/fastlib/col/arraylist.h @@ -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 - void Serialize(Serializer *s) const { - s->Put(size_); - s->Put(ptr_, size_); - } - - /** - * Initializes this list, deserializing from the given source. - */ - template - void Deserialize(Deserializer *s) { - s->Get(&size_); - cap_ = size_; - ptr_ = mem::Alloc(cap_); - s->Get(ptr_, size_); - } - /** * Use this to shrink the ArrayList. */ diff --git a/fastlib/col/build.py b/fastlib/col/build.py index b4e1ffbe6d..acb7d56b80 100644 --- a/fastlib/col/build.py +++ b/fastlib/col/build.py @@ -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"]) diff --git a/fastlib/col/heap.h b/fastlib/col/heap.h index d57d605f27..f8755c2b98 100644 --- a/fastlib/col/heap.h +++ b/fastlib/col/heap.h @@ -35,22 +35,11 @@ class MinHeap { ArrayList 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 - void Serialize(Serializer *s) const { - entries_.Serialize(s); - } - - /** - * Initializes this heap, deserializing from the given source. - * - * @deprecated Use otrav instead. - */ - template - 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; diff --git a/fastlib/col/intmap.h b/fastlib/col/intmap.h index 2ad00af8a6..7d1035b126 100644 --- a/fastlib/col/intmap.h +++ b/fastlib/col/intmap.h @@ -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 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 diff --git a/fastlib/col/queue.h b/fastlib/col/queue.h index 63ea058988..f4b0124204 100644 --- a/fastlib/col/queue.h +++ b/fastlib/col/queue.h @@ -3,6 +3,8 @@ template class Queue { + FORBID_COPY(Queue); // No copy constructor defined (yet) + private: struct Node { T data; diff --git a/fastlib/col/rangeset.h b/fastlib/col/rangeset.h index 0075bbdf2f..b897671607 100644 --- a/fastlib/col/rangeset.h +++ b/fastlib/col/rangeset.h @@ -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& ranges() const { return ranges_; } diff --git a/fastlib/col/string.h b/fastlib/col/string.h index f7328f469a..efac5bd778 100644 --- a/fastlib/col/string.h +++ b/fastlib/col/string.h @@ -30,19 +30,11 @@ class String { private: ArrayList 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. diff --git a/fastlib/data/build.py b/fastlib/data/build.py index cca237b062..7fe453933c 100644 --- a/fastlib/data/build.py +++ b/fastlib/data/build.py @@ -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"]) diff --git a/fastlib/data/dataset.h b/fastlib/data/dataset.h index 49ce718f68..b86298df24 100644 --- a/fastlib/data/dataset.h +++ b/fastlib/data/dataset.h @@ -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 features_; @@ -184,9 +179,6 @@ class DatasetInfo { } public: - DatasetInfo() {} - ~DatasetInfo() {} - /** Gets a mutable list of all features. */ ArrayList& 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. * diff --git a/fastlib/fastlib/build.py b/fastlib/fastlib/build.py index 4c73c6f254..771a33960f 100644 --- a/fastlib/fastlib/build.py +++ b/fastlib/fastlib/build.py @@ -21,4 +21,4 @@ librule( binrule( name = "otrav_test", sources = ["otrav_test.cc"], - linkables = [":fastlib_int"]) + deplibs = [":fastlib_int"]) diff --git a/fastlib/fastlib/fastlib_int.h b/fastlib/fastlib/fastlib_int.h index 055e0ef38d..c4af1f04ff 100644 --- a/fastlib/fastlib/fastlib_int.h +++ b/fastlib/fastlib/fastlib_int.h @@ -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" diff --git a/fastlib/fastlib/otrav_test.cc b/fastlib/fastlib/otrav_test.cc index 3bbea1bd88..acbb988639 100644 --- a/fastlib/fastlib/otrav_test.cc +++ b/fastlib/fastlib/otrav_test.cc @@ -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) diff --git a/fastlib/file/build.py b/fastlib/file/build.py index 347077c112..8f8295108b 100644 --- a/fastlib/file/build.py +++ b/fastlib/file/build.py @@ -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"] ) diff --git a/fastlib/file/serialize.cc b/fastlib/file/serialize.cc deleted file mode 100644 index 66b149e5dc..0000000000 --- a/fastlib/file/serialize.cc +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file serialize.cc - * - * Definitions for serialization methods. - */ - -#include "serialize.h" - -#include -#include -#include -#include - -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(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; -} diff --git a/fastlib/file/serialize.h b/fastlib/file/serialize.h deleted file mode 100644 index 7e4c152719..0000000000 --- a/fastlib/file/serialize.h +++ /dev/null @@ -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 - -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 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 - 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 - 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 - 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 - 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 - 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 - 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(ptr())); - } - - /** - * Initializes by reading the entire file into memory. - */ - success_t Init(const char *fname); -}; - -#endif diff --git a/fastlib/la/build.py b/fastlib/la/build.py index dcab8fbe31..cf6a08587c 100644 --- a/fastlib/la/build.py +++ b/fastlib/la/build.py @@ -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"]) diff --git a/fastlib/la/matrix.h b/fastlib/la/matrix.h index 411fa4509f..4e760ee541 100644 --- a/fastlib/la/matrix.h +++ b/fastlib/la/matrix.h @@ -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 - void Serialize(Serializer *s) const { - s->Put(length_); - s->Put(ptr_, length_); - } - - template - void Deserialize(Deserializer *s) { - DEBUG_ONLY(AssertUninitialized_()); - s->Get(&length_); - ptr_ = mem::Alloc(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 - void Serialize(Serializer *s) const { - s->Put(n_rows_); - s->Put(n_cols_); - s->Put(ptr_, n_elements()); - } - - template - void Deserialize(Deserializer *s) { - DEBUG_ONLY(AssertUninitialized_()); - s->Get(&n_rows_); - s->Get(&n_cols_); - ptr_ = mem::Alloc(n_elements()); - s->Get(ptr_, n_elements()); - should_free_ = true; - } - + /** * Make a matrix that is an alias of a particular slice of my columns. * diff --git a/fastlib/la/uselapack_test.cc b/fastlib/la/uselapack_test.cc index 4191329e5b..984144e1cd 100644 --- a/fastlib/la/uselapack_test.cc +++ b/fastlib/la/uselapack_test.cc @@ -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); diff --git a/fastlib/math/build.py b/fastlib/math/build.py index 0888360511..ee995eb304 100644 --- a/fastlib/math/build.py +++ b/fastlib/math/build.py @@ -8,5 +8,5 @@ librule( binrule( name = "math_test", sources = ["math_test.cc"], - linkables = [":math"]) + deplibs = [":math"]) diff --git a/fastlib/math/kernel.h b/fastlib/math/kernel.h index 01215307e3..c807b034bd 100644 --- a/fastlib/math/kernel.h +++ b/fastlib/math/kernel.h @@ -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. diff --git a/fastlib/math/math.h b/fastlib/math/math.h index cc61d61c2f..4aca9d06ad 100644 --- a/fastlib/math/math.h +++ b/fastlib/math/math.h @@ -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 +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" diff --git a/fastlib/math/math_test.cc b/fastlib/math/math_test.cc index 291e6838c0..017a66cf38 100644 --- a/fastlib/math/math_test.cc +++ b/fastlib/math/math_test.cc @@ -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); } diff --git a/fastlib/par/build.py b/fastlib/par/build.py index e3318b546f..f4826f83f5 100644 --- a/fastlib/par/build.py +++ b/fastlib/par/build.py @@ -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"]) - diff --git a/fastlib/par/mpigrain.h b/fastlib/par/mpigrain.h deleted file mode 100644 index fb3a0119fa..0000000000 --- a/fastlib/par/mpigrain.h +++ /dev/null @@ -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 - -/** - * 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 -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 *queue_; - - public: - Dispatcher() {} - ~Dispatcher() {} - - void Init(MPIGrainRunner *runner_in) { - queue_ = NULL; - runner_ = runner_in; - } - - void set_queue(GrainQueue *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 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 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 diff --git a/fastlib/thor/blockdev.h b/fastlib/thor/blockdev.h index 47ca82d0c9..ab6524ce92 100644 --- a/fastlib/thor/blockdev.h +++ b/fastlib/thor/blockdev.h @@ -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); diff --git a/fastlib/thor/cache.h b/fastlib/thor/cache.h new file mode 100644 index 0000000000..8047d4a154 --- /dev/null +++ b/fastlib/thor/cache.h @@ -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* data) const = 0; + /** Initialize from state. */ + virtual void Deserialize(const ArrayList& 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 diff --git a/fastlib/thor/dfs.h b/fastlib/thor/dfs.h new file mode 100644 index 0000000000..f0ffef052f --- /dev/null +++ b/fastlib/thor/dfs.h @@ -0,0 +1,439 @@ +#ifndef THOR_DFS_H +#define THOR_DFS_H + +#include "gnp.h" +#include "cachearray.h" + +/** + * Depth-first dual-tree solver. + */ +template +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 q_points_; + CacheArray q_nodes_; + CacheArray q_results_; + SubsetArray q_mutables_; + + CacheArray r_points_; + CacheArray 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 +DualTreeDepthFirst::~DualTreeDepthFirst() { + r_nodes_.StopRead(0); +} + +template +void DualTreeDepthFirst::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 +void DualTreeDepthFirst::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 +void DualTreeDepthFirst::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 +void DualTreeDepthFirst::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 +void DualTreeDepthFirst::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 first_q_point(&q_points_, q_node->begin()); + CacheWrite first_q_result(&q_results_, q_node->begin()); + CacheRead 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 diff --git a/fastlib/thor/distribcache.cc b/fastlib/thor/distribcache.cc index 4f6558933d..3a49a56127 100644 --- a/fastlib/thor/distribcache.cc +++ b/fastlib/thor/distribcache.cc @@ -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 +/*to-do + +- dynamic depth + - use static width with tunable depth (that might be based on external + pressure) +*/ //------------------------------------------------------------------------- //-- THE DISTRIBUTED CACHE ------------------------------------------------ diff --git a/fastlib/thor/distribcache.h b/fastlib/thor/distribcache.h index 710c381dfe..038d526084 100644 --- a/fastlib/thor/distribcache.h +++ b/fastlib/thor/distribcache.h @@ -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" diff --git a/fastlib/thor/gnp.h b/fastlib/thor/gnp.h index c8831978f2..f5772ad038 100644 --- a/fastlib/thor/gnp.h +++ b/fastlib/thor/gnp.h @@ -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: diff --git a/fastlib/thor/kdtree.h b/fastlib/thor/kdtree.h index 376d524b32..d240a5e895 100644 --- a/fastlib/thor/kdtree.h +++ b/fastlib/thor/kdtree.h @@ -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 */ diff --git a/fastlib/thor/rpc.h b/fastlib/thor/rpc.h index 6445418d6d..6df545fa12 100644 --- a/fastlib/thor/rpc.h +++ b/fastlib/thor/rpc.h @@ -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. * diff --git a/fastlib/thor/rpc_sock.cc b/fastlib/thor/rpc_sock.cc index fa25ff30c8..003a9d1084 100644 --- a/fastlib/thor/rpc_sock.cc +++ b/fastlib/thor/rpc_sock.cc @@ -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 #include diff --git a/fastlib/thor/rpc_sock.h b/fastlib/thor/rpc_sock.h index 24cfaa4edf..eca8f2b814 100644 --- a/fastlib/thor/rpc_sock.h +++ b/fastlib/thor/rpc_sock.h @@ -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 #include diff --git a/fastlib/thor/thortree.h b/fastlib/thor/thortree.h index 7ae4013091..34498a1ced 100644 --- a/fastlib/thor/thortree.h +++ b/fastlib/thor/thortree.h @@ -9,7 +9,7 @@ #include "cachearray.h" -#include "fastlib/fastlib.h" +#include "la/matrix.h" #include "base/otrav.h" /** diff --git a/fastlib/thor/work.h b/fastlib/thor/work.h index 8e4c897980..7f3a6e1438 100644 --- a/fastlib/thor/work.h +++ b/fastlib/thor/work.h @@ -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::AddWork_( //------------------------------------------------------------------------ -#include "spbounds.h" template class CentroidWorkQueue diff --git a/fastlib/tree/bounds.h b/fastlib/tree/bounds.h index 07be479c5b..4db36b66fc 100644 --- a/fastlib/tree/bounds.h +++ b/fastlib/tree/bounds.h @@ -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 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 - void Deserialize(Deserializer *s) { - DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized"); - - s->Get(&dim_); - bounds_ = mem::Alloc(dim_); - s->Get(bounds_, dim_); - - //ComputeDiagonal_(); - } - - template - 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(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(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: + * + * other.CalcMidpoint(&other_midpoint) + * return MinDistanceSqToPoint(other_midpoint) + * + */ + 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(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( + 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(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(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( + 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(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 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 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 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 DEuclideanBallBound; #endif diff --git a/fastlib/tree/kdtree.h b/fastlib/tree/kdtree.h index 73ecbd9514..3b5d0071dd 100644 --- a/fastlib/tree/kdtree.h +++ b/fastlib/tree/kdtree.h @@ -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 - void SerializeKdTree(const TKdTree *tree, - const Matrix& matrix, - const ArrayList& 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 - void DeserializeKdTree(TKdTree *uninit_tree, - Matrix* uninit_matrix, - ArrayList* 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 - void LoadKdTreeFromFile(const char *fname, - TKdTree *uninit_tree, - Matrix* uninit_matrix, - ArrayList* 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( *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 BasicKdTree; +typedef BinarySpaceTree, Matrix> BasicKdTree; #endif diff --git a/fastlib/tree/spacetree.h b/fastlib/tree/spacetree.h index 13b9cd0c14..92ee9faa33 100644 --- a/fastlib/tree/spacetree.h +++ b/fastlib/tree/spacetree.h @@ -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 - 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 - 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 - 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 - 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 /** diff --git a/fastlib/u/garryb/nbr/affinity.cc b/fastlib/u/garryb/nbr/affinity.cc index 55f0ad941a..6410cd611a 100644 --- a/fastlib/u/garryb/nbr/affinity.cc +++ b/fastlib/u/garryb/nbr/affinity.cc @@ -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) { diff --git a/fastlib/u/garryb/nbr/distribcache.h b/fastlib/u/garryb/nbr/distribcache.h index 0125de4895..710c381dfe 100644 --- a/fastlib/u/garryb/nbr/distribcache.h +++ b/fastlib/u/garryb/nbr/distribcache.h @@ -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; diff --git a/fastlib/u/garryb/nbr/kdtree.h b/fastlib/u/garryb/nbr/kdtree.h index 3c798d441b..a1a5d36c50 100644 --- a/fastlib/u/garryb/nbr/kdtree.h +++ b/fastlib/u/garryb/nbr/kdtree.h @@ -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::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::InitDistributedCacheWorker(points_channel_, diff --git a/fastlib/u/garryb/nbr/rpc.h b/fastlib/u/garryb/nbr/rpc.h index 6d94bc98c6..6445418d6d 100644 --- a/fastlib/u/garryb/nbr/rpc.h +++ b/fastlib/u/garryb/nbr/rpc.h @@ -432,15 +432,17 @@ struct DataGetterRequest { template class DataGetterBackend : public RemoteObjectBackend { + 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); diff --git a/fastlib/u/garryb/nbr/spbounds.h b/fastlib/u/garryb/nbr/spbounds.h index d3d3e56b8c..3949016642 100644 --- a/fastlib/u/garryb/nbr/spbounds.h +++ b/fastlib/u/garryb/nbr/spbounds.h @@ -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(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. */ diff --git a/fastlib/u/garryb/nbr/spnode.h b/fastlib/u/garryb/nbr/spnode.h index 4490426814..cc583fd0c2 100644 --- a/fastlib/u/garryb/nbr/spnode.h +++ b/fastlib/u/garryb/nbr/spnode.h @@ -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 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 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_); }