summaryrefslogtreecommitdiff
path: root/test/datastructures/monotonicConvexHull.cpp
blob: 9490d7edeee868313cd4bf6d244b78b4a4ff86e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "../util.h"
struct MCH {
	#include <datastructures/monotonicConvexHull.cpp>
};

struct Line {
	ll m, c;
	Line(ll m_, ll c_) : m(m_), c(c_) {}
	ll operator()(ll x) {return m*x+c;}
};

void stress_test(ll range) {
	ll queries = 0;
	for (int tries = 0; tries < 1000; tries++) {
		int n = Random::integer<int>(1, 100);
		auto ms = Random::integers<ll>(n, -range, range);
		sort(all(ms), greater<>{});
		auto cs = ms;
		for (int l = 0, r = 0; l < n;) {
			while (r < n && ms[l] == ms[r]) r++;
			auto tmp = Random::distinct<ll>(r - l, -range, range);
			sort(all(tmp), greater<>{});
			for (int c : tmp) {
				cs[l] = c;
				l++;
			}
		}

		auto xs = Random::integers<ll>(n*100, -range*n, range*n);
		sort(all(xs));
		int i = 0;

		vector<Line> naive;

		MCH mch;
		for (int k = 0; k < n; k++) {
			ll m = ms[k];
			ll c = cs[k];

			mch.add(m, c);
			naive.emplace_back(m, c);

			for (int j = i + 100; i < j; i++) {
				ll x = xs[i];

				ll got = mch.query(x);
				ll expected = naive[0](x);
				for (auto l : naive) expected = min(expected, l(x));

				if (got != expected) cerr << "got: " << got << ", expected: " << expected << FAIL;
				queries++;
			}
		}
	}
	cerr << "tested random queries: " << queries << endl;
}

void stress_test_independent(ll range) {
	ll queries = 0;
	for (int tries = 0; tries < 1000; tries++) {
		int n = Random::integer<int>(1, 100);
		auto ms = Random::integers<ll>(n, -range, range);
		sort(all(ms), greater<>{});
		auto cs = ms;
		for (int l = 0, r = 0; l < n;) {
			while (r < n && ms[l] == ms[r]) r++;
			auto tmp = Random::distinct<ll>(r - l, -range, range);
			sort(all(tmp), greater<>{});
			for (int c : tmp) {
				cs[l] = c;
				l++;
			}
		}

		vector<Line> naive;

		MCH mch;
		for (int i = 0; i < n; i++) {
			ll m = ms[i];
			ll c = cs[i];

			mch.add(m, c);
			naive.emplace_back(m, c);

			auto xs = Random::integers<ll>(100, -range, range);
			sort(all(xs));
			auto tmp = mch;

			for (auto x : xs) {
				ll got = tmp.query(x);
				ll expected = naive[0](x);
				for (auto l : naive) expected = min(expected, l(x));

				if (got != expected) cerr << "got: " << got << ", expected: " << expected << FAIL;
				queries++;
			}
		}
	}
	cerr << "tested random independent queries: " << queries << endl;
}

constexpr int N = 1'000'000;
void performance_test() {
	timer t;
	auto ms = Random::distinct<ll>(N, -1'000'000'000, 1'000'000'000);
	sort(all(ms), greater<>{});
	auto xs = Random::distinct<ll>(N, -1'000'000'000, 1'000'000'000);
	sort(all(xs));
	MCH mch;

	hash_t hash = 0;
	for (int operations = 0; operations < N; operations++) {
		ll c = Random::integer<ll>(-1'000'000'000, 1'000'000'000);
		ll m = ms[operations];
		ll x = xs[operations];
		
		t.start();
		mch.add(m, c);
		hash += mch.query(x);
		t.stop();
	}
	if (t.time > 100) cerr << "too slow: " << t.time << FAIL;
	cerr << "tested performance: " << t.time << "ms (hash: " << hash << ")" << endl;
}

int main() {
	stress_test(100);
	stress_test(1'000);
	stress_test(1'000'000);
	stress_test_independent(100);
	stress_test_independent(1'000);
	stress_test_independent(1'000'000);
	if (!sanitize) performance_test();
}