1 | #pragma once |
2 | |
3 | #include <DataTypes/DataTypesNumber.h> |
4 | #include <Columns/ColumnsNumber.h> |
5 | #include <Common/FieldVisitors.h> |
6 | #include <IO/ReadHelpers.h> |
7 | #include <IO/WriteHelpers.h> |
8 | #include <AggregateFunctions/Helpers.h> |
9 | #include <AggregateFunctions/IAggregateFunction.h> |
10 | #include <Common/assert_cast.h> |
11 | |
12 | |
13 | namespace DB |
14 | { |
15 | |
16 | namespace ErrorCodes |
17 | { |
18 | extern const int BAD_ARGUMENTS; |
19 | } |
20 | |
21 | /** Tracks the leftmost and rightmost (x, y) data points. |
22 | */ |
23 | struct AggregateFunctionBoundingRatioData |
24 | { |
25 | struct Point |
26 | { |
27 | Float64 x; |
28 | Float64 y; |
29 | }; |
30 | |
31 | bool empty = true; |
32 | Point left; |
33 | Point right; |
34 | |
35 | void add(Float64 x, Float64 y) |
36 | { |
37 | Point point{x, y}; |
38 | |
39 | if (empty) |
40 | { |
41 | left = point; |
42 | right = point; |
43 | empty = false; |
44 | } |
45 | else if (point.x < left.x) |
46 | { |
47 | left = point; |
48 | } |
49 | else if (point.x > right.x) |
50 | { |
51 | right = point; |
52 | } |
53 | } |
54 | |
55 | void merge(const AggregateFunctionBoundingRatioData & other) |
56 | { |
57 | if (empty) |
58 | { |
59 | *this = other; |
60 | } |
61 | else |
62 | { |
63 | if (other.left.x < left.x) |
64 | left = other.left; |
65 | if (other.right.x > right.x) |
66 | right = other.right; |
67 | } |
68 | } |
69 | |
70 | void serialize(WriteBuffer & buf) const |
71 | { |
72 | writeBinary(empty, buf); |
73 | |
74 | if (!empty) |
75 | { |
76 | writePODBinary(left, buf); |
77 | writePODBinary(right, buf); |
78 | } |
79 | } |
80 | |
81 | void deserialize(ReadBuffer & buf) |
82 | { |
83 | readBinary(empty, buf); |
84 | |
85 | if (!empty) |
86 | { |
87 | readPODBinary(left, buf); |
88 | readPODBinary(right, buf); |
89 | } |
90 | } |
91 | }; |
92 | |
93 | |
94 | class AggregateFunctionBoundingRatio final : public IAggregateFunctionDataHelper<AggregateFunctionBoundingRatioData, AggregateFunctionBoundingRatio> |
95 | { |
96 | private: |
97 | /** Calculates the slope of a line between leftmost and rightmost data points. |
98 | * (y2 - y1) / (x2 - x1) |
99 | */ |
100 | Float64 NO_SANITIZE_UNDEFINED getBoundingRatio(const AggregateFunctionBoundingRatioData & data) const |
101 | { |
102 | if (data.empty) |
103 | return std::numeric_limits<Float64>::quiet_NaN(); |
104 | |
105 | return (data.right.y - data.left.y) / (data.right.x - data.left.x); |
106 | } |
107 | |
108 | public: |
109 | String getName() const override |
110 | { |
111 | return "boundingRatio" ; |
112 | } |
113 | |
114 | AggregateFunctionBoundingRatio(const DataTypes & arguments) |
115 | : IAggregateFunctionDataHelper<AggregateFunctionBoundingRatioData, AggregateFunctionBoundingRatio>(arguments, {}) |
116 | { |
117 | const auto x_arg = arguments.at(0).get(); |
118 | const auto y_arg = arguments.at(0).get(); |
119 | |
120 | if (!x_arg->isValueRepresentedByNumber() || !y_arg->isValueRepresentedByNumber()) |
121 | throw Exception("Illegal types of arguments of aggregate function " + getName() + ", must have number representation." , |
122 | ErrorCodes::BAD_ARGUMENTS); |
123 | } |
124 | |
125 | DataTypePtr getReturnType() const override |
126 | { |
127 | return std::make_shared<DataTypeFloat64>(); |
128 | } |
129 | |
130 | void add(AggregateDataPtr place, const IColumn ** columns, const size_t row_num, Arena *) const override |
131 | { |
132 | /// NOTE Slightly inefficient. |
133 | const auto x = columns[0]->getFloat64(row_num); |
134 | const auto y = columns[1]->getFloat64(row_num); |
135 | data(place).add(x, y); |
136 | } |
137 | |
138 | void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override |
139 | { |
140 | data(place).merge(data(rhs)); |
141 | } |
142 | |
143 | void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override |
144 | { |
145 | data(place).serialize(buf); |
146 | } |
147 | |
148 | void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override |
149 | { |
150 | data(place).deserialize(buf); |
151 | } |
152 | |
153 | void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override |
154 | { |
155 | assert_cast<ColumnFloat64 &>(to).getData().push_back(getBoundingRatio(data(place))); |
156 | } |
157 | }; |
158 | |
159 | } |
160 | |