Skip to content

Commit 993b622

Browse files
authored
Merge pull request #363 from apache/density_sketch
Density sketch
2 parents 4778e3a + db4dc00 commit 993b622

15 files changed

Lines changed: 1517 additions & 0 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ add_subdirectory(tuple)
116116
add_subdirectory(req)
117117
add_subdirectory(quantiles)
118118
add_subdirectory(count)
119+
add_subdirectory(density)
119120

120121
if (WITH_PYTHON)
121122
add_subdirectory(python)

common/include/memory_operations.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <exception>
2525
#include <iostream>
2626
#include <string>
27+
#include <cstring>
2728

2829
namespace datasketches {
2930

density/CMakeLists.txt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
add_library(density INTERFACE)
19+
20+
add_library(${PROJECT_NAME}::DENSITY ALIAS density)
21+
22+
if (BUILD_TESTS)
23+
add_subdirectory(test)
24+
endif()
25+
26+
target_include_directories(density
27+
INTERFACE
28+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
29+
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
30+
)
31+
32+
target_link_libraries(density INTERFACE common)
33+
target_compile_features(density INTERFACE cxx_std_11)
34+
35+
install(TARGETS density
36+
EXPORT ${PROJECT_NAME}
37+
)
38+
39+
install(FILES
40+
include/density_sketch.hpp
41+
include/density_sketch_impl.hpp
42+
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/DataSketches")

density/include/density_sketch.hpp

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#ifndef DENSITY_SKETCH_HPP_
21+
#define DENSITY_SKETCH_HPP_
22+
23+
#include <type_traits>
24+
#include <vector>
25+
#include <functional>
26+
#include <numeric>
27+
#include <cmath>
28+
29+
#include "common_defs.hpp"
30+
31+
/*
32+
* Based on the following paper:
33+
* Zohar Karnin, Edo Liberty "Discrepancy, Coresets, and Sketches in Machine Learning"
34+
* https://proceedings.mlr.press/v99/karnin19a/karnin19a.pdf
35+
*
36+
* Inspired by the following implementation:
37+
* https://github.com/edoliberty/streaming-quantiles/blob/f688c8161a25582457b0a09deb4630a81406293b/gde.py
38+
*/
39+
40+
namespace datasketches {
41+
42+
template<typename T>
43+
struct gaussian_kernel {
44+
T operator()(const std::vector<T>& v1, const std::vector<T>& v2) const {
45+
return exp(-std::inner_product(v1.begin(), v1.end(), v2.begin(), 0.0, std::plus<T>(), [](T a, T b){return (a-b)*(a-b);}));
46+
}
47+
};
48+
49+
template<
50+
typename T,
51+
typename Kernel = gaussian_kernel<T>,
52+
typename Allocator = std::allocator<T>
53+
>
54+
class density_sketch {
55+
static_assert(std::is_floating_point<T>::value, "Floating point type expected");
56+
57+
public:
58+
using Vector = std::vector<T, Allocator>;
59+
using Level = std::vector<Vector, typename std::allocator_traits<Allocator>::template rebind_alloc<Vector>>;
60+
using Levels = std::vector<Level, typename std::allocator_traits<Allocator>::template rebind_alloc<Level>>;
61+
62+
/**
63+
* Constructor
64+
* @param k controls the size and error of the sketch.
65+
* @param dim dimension of the input domain
66+
* @param kernel to use by this instance
67+
* @param allocator to use by this instance
68+
*/
69+
density_sketch(uint16_t k, uint32_t dim, const Kernel& kernel = Kernel(), const Allocator& allocator = Allocator());
70+
71+
/**
72+
* Returns configured parameter K
73+
* @return parameter K
74+
*/
75+
uint16_t get_k() const;
76+
77+
/**
78+
* Returns configured dimensions
79+
* @return dimensions
80+
*/
81+
uint32_t get_dim() const;
82+
83+
/**
84+
* Returns true if this sketch is empty.
85+
* @return empty flag
86+
*/
87+
bool is_empty() const;
88+
89+
/**
90+
* Returns the length of the input stream (number of points observed by this sketch).
91+
* @return stream length
92+
*/
93+
uint64_t get_n() const;
94+
95+
/**
96+
* Returns the number of retained points in the sketch.
97+
* @return number of retained points
98+
*/
99+
uint32_t get_num_retained() const;
100+
101+
/**
102+
* Returns true if this sketch is in estimation mode.
103+
* @return estimation mode flag
104+
*/
105+
bool is_estimation_mode() const;
106+
107+
/**
108+
* Updates this sketch with a given point.
109+
* @param point given point
110+
*/
111+
template<typename FwdVector>
112+
void update(FwdVector&& point);
113+
114+
/**
115+
* Merges another sketch into this one.
116+
* @param other sketch to merge into this one
117+
*/
118+
template<typename FwdSketch>
119+
void merge(FwdSketch&& other);
120+
121+
T get_estimate(const std::vector<T>& point) const;
122+
123+
/**
124+
* Returns an instance of the allocator for this sketch.
125+
* @return allocator
126+
*/
127+
Allocator get_allocator() const;
128+
129+
/**
130+
* This method serializes the sketch into a given stream in a binary form
131+
* @param os output stream
132+
*/
133+
void serialize(std::ostream& os) const;
134+
135+
using vector_bytes = std::vector<uint8_t, typename std::allocator_traits<Allocator>::template rebind_alloc<uint8_t>>;
136+
137+
/**
138+
* This method serializes the sketch as a vector of bytes.
139+
* An optional header can be reserved in front of the sketch.
140+
* It is an uninitialized space of a given size.
141+
* This header is used in Datasketches PostgreSQL extension.
142+
* @param header_size_bytes space to reserve in front of the sketch
143+
*/
144+
vector_bytes serialize(unsigned header_size_bytes = 0) const;
145+
146+
/**
147+
* This method deserializes a sketch from a given stream.
148+
* @param is input stream
149+
* @param kernel the kernel function to use for this sketch
150+
* @param allocator the memory allocator to use with this sketch
151+
* @return an instance of the sketch
152+
*/
153+
static density_sketch deserialize(std::istream& is,
154+
const Kernel& kernel=Kernel(), const Allocator& allocator = Allocator());
155+
156+
/**
157+
* This method deserializes a sketch from a given array of bytes.
158+
* @param bytes pointer to the array of bytes
159+
* @param size the size of the array
160+
* @param kernel the kernel function to use for this sketch
161+
* @param allocator the memory allocator to use with this sketch
162+
* @return an instance of the sketch
163+
*/
164+
static density_sketch deserialize(const void* bytes, size_t size,
165+
const Kernel& kernel=Kernel(), const Allocator& allocator = Allocator());
166+
167+
/**
168+
* Prints a summary of the sketch.
169+
* @param print_levels if true include information about levels
170+
* @param print_items if true include sketch data
171+
*/
172+
string<Allocator> to_string(bool print_levels = false, bool print_items = false) const;
173+
174+
class const_iterator;
175+
const_iterator begin() const;
176+
const_iterator end() const;
177+
178+
private:
179+
enum flags { RESERVED0, RESERVED1, IS_EMPTY };
180+
static const uint8_t PREAMBLE_INTS_SHORT = 3;
181+
static const uint8_t PREAMBLE_INTS_LONG = 6;
182+
static const uint8_t FAMILY_ID = 19;
183+
static const uint8_t SERIAL_VERSION = 1;
184+
static const size_t LEVELS_ARRAY_START = 5;
185+
186+
Allocator allocator_;
187+
Kernel kernel_;
188+
uint16_t k_;
189+
uint32_t dim_;
190+
uint32_t num_retained_;
191+
uint64_t n_;
192+
Levels levels_;
193+
194+
void compact();
195+
void compact_level(unsigned height);
196+
197+
static void check_k(uint16_t k);
198+
static void check_serial_version(uint8_t serial_version);
199+
static void check_family_id(uint8_t family_id);
200+
static void check_header_validity(uint8_t preamble_ints, uint8_t flags_byte, uint8_t serial_version);
201+
202+
density_sketch(uint16_t k, uint32_t dim, uint32_t num_retained, uint64_t n, Levels&& levels,
203+
const Kernel& kernel = Kernel());
204+
};
205+
206+
template<typename T, typename K, typename A>
207+
class density_sketch<T, K, A>::const_iterator {
208+
public:
209+
using Vector = density_sketch<T, K, A>::Vector;
210+
using iterator_category = std::input_iterator_tag;
211+
using value_type = std::pair<const Vector&, const uint64_t>;
212+
using difference_type = void;
213+
using pointer = return_value_holder<value_type>;
214+
using reference = const value_type;
215+
const_iterator& operator++();
216+
const_iterator& operator++(int);
217+
bool operator==(const const_iterator& other) const;
218+
bool operator!=(const const_iterator& other) const;
219+
const value_type operator*() const;
220+
const return_value_holder<value_type> operator->() const;
221+
private:
222+
using LevelsIterator = typename density_sketch<T, K, A>::Levels::const_iterator;
223+
using LevelIterator = typename density_sketch<T, K, A>::Level::const_iterator;
224+
LevelsIterator levels_it_;
225+
LevelsIterator levels_end_;
226+
LevelIterator level_it_;
227+
unsigned height_;
228+
friend class density_sketch<T, K, A>;
229+
const_iterator(LevelsIterator begin, LevelsIterator end);
230+
};
231+
232+
} /* namespace datasketches */
233+
234+
#include "density_sketch_impl.hpp"
235+
236+
#endif

0 commit comments

Comments
 (0)