Skip to content

Commit 8f44cb4

Browse files
committed
jngen::Hash introduced
1 parent df4e920 commit 8f44cb4

8 files changed

+232
-97
lines changed

array.h

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "common.h"
4+
#include "hash.h"
45
#include "printers.h"
56
#include "random.h"
67
#include "sequence_ops.h"
@@ -471,8 +472,17 @@ TArray<T> arrayCast(const TArray<U>& array) {
471472
return TArray<T>(array.begin(), array.end());
472473
}
473474

475+
template<typename T>
476+
struct Hash<TArray<T>> {
477+
uint64_t operator()(const TArray<T>& elements) const {
478+
return Hash<std::vector<T>>{}(elements);
479+
}
480+
};
481+
474482
} // namespace jngen
475483

484+
JNGEN_DEFINE_STD_HASH_TEMPLATE(T, jngen::TArray<T>);
485+
476486
using jngen::makeArray;
477487
using jngen::zip;
478488
using jngen::arrayCast;

common.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ inline void checkLargeParameter(int n) {
141141
}
142142

143143
// Some type traits helpers. Based on ideas from TCPPPL v4.
144-
template<bool B, typename T>
144+
template<bool B, typename T = void>
145145
using enable_if_t = typename std::enable_if<B, T>::type;
146146

147147
namespace util {

doc/generic_graph.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ Graphs and trees are printed as following. If *.printN()* and *.printM()* modifi
7272
#### bool operator&gt;(const GenericGraph& other) const
7373
#### bool operator&lt;=(const GenericGraph& other) const
7474
#### bool operator&gt;=(const GenericGraph& other) const
75-
* Compare two graphs. If number of vertices in two grapgs is different then one with lesser vertices is less then the other. Otherwise adjacency lists of vertices are compared lexicographically in natural order of vertices.
75+
* Compare two graphs. If number of vertices in two graphs is different then one with lesser vertices is less than the other. Otherwise adjacency lists of vertices are compared lexicographicaly in natural order of vertices.
7676
* Note: weights have no any effect on comparison result.
77+
* Note: two identical graphs with shuffled adjacency lists are NOT equal. You may think of equality as of «having same representations when printed».
7778

7879
### Weights
7980
All things you will probably ever do with *Weight* or *WeightArray* are shown in this snippet.

generic_graph.h

+14-2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ class GenericGraph {
134134
WeightArray edgeWeights_;
135135
};
136136

137+
template<>
138+
struct Hash<GenericGraph> {
139+
uint64_t operator()(const GenericGraph& graph) const {
140+
uint64_t h = 0;
141+
for (int i = 0; i < graph.n(); ++i) {
142+
impl::hashCombine(h, Hash<Array>{}(graph.edges(i)));
143+
}
144+
return h;
145+
}
146+
};
147+
137148
#ifndef JNGEN_DECLARE_ONLY
138149

139150
Array GenericGraph::edges(int v) const {
@@ -371,8 +382,8 @@ int GenericGraph::compareTo(const GenericGraph& other) const {
371382
return n() < other.n() ? -1 : 1;
372383
}
373384
for (int i = 0; i < n(); ++i) {
374-
Array e1 = Array(edges(i)).sorted();
375-
Array e2 = Array(other.edges(i)).sorted();
385+
auto e1 = edges(i);
386+
auto e2 = other.edges(i);
376387
if (e1 != e2) {
377388
return e1 < e2 ? -1 : 1;
378389
}
@@ -384,3 +395,4 @@ int GenericGraph::compareTo(const GenericGraph& other) const {
384395

385396
} // namespace jngen
386397

398+
JNGEN_DEFINE_STD_HASH(jngen::GenericGraph);

geometry.h

+83-93
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
#include "array.h"
44
#include "common.h"
5+
#include "hash.h"
56
#include "printers.h"
67
#include "random.h"
7-
#include "random.h"
88
#include "repr.h"
99
#include "rnda.h"
1010

@@ -129,41 +129,16 @@ struct TPoint : public ReprProxy<TPoint<T>> {
129129
using Point = TPoint<long long>;
130130
using Pointf = TPoint<long double>;
131131

132-
} // namespace jngen
133-
134-
namespace std {
135-
136132
template<>
137-
struct hash<jngen::Point> {
138-
// Credits to boost::hash
139-
static void hash_combine_impl(uint64_t& h, uint64_t k) {
140-
const uint64_t m = 0xc6a4a7935bd1e995;
141-
const int r = 47;
142-
143-
k *= m;
144-
k ^= k >> r;
145-
k *= m;
146-
147-
h ^= k;
148-
h *= m;
149-
150-
// Completely arbitrary number, to prevent 0's
151-
// from hashing to 0.
152-
h += 0xe6546b64;
153-
}
154-
155-
size_t operator()(const jngen::Point& p) const {
133+
struct Hash<Point> {
134+
uint64_t operator()(const Point& point) const {
156135
uint64_t h = 0;
157-
hash_combine_impl(h, std::hash<long long>{}(p.x));
158-
hash_combine_impl(h, std::hash<long long>{}(p.y));
136+
impl::hashCombine(h, Hash<long long>{}(point.x));
137+
impl::hashCombine(h, Hash<long long>{}(point.y));
159138
return h;
160139
}
161140
};
162141

163-
} // namespace std
164-
165-
namespace jngen {
166-
167142
template<typename T>
168143
JNGEN_DECLARE_SIMPLE_PRINTER(TPoint<T>, 3) {
169144
(void)mod;
@@ -206,8 +181,15 @@ class TPolygon : public GenericArray<TPoint<T>> {
206181
using Polygon = TPolygon<long long>;
207182
using Polygonf = TPolygon<long double>;
208183

184+
template<>
185+
struct Hash<Polygon> {
186+
uint64_t operator()(const Polygon& p) const {
187+
return Hash<TArray<Point>>{}(p);
188+
}
189+
};
190+
209191
template<typename T>
210-
JNGEN_DECLARE_SIMPLE_PRINTER(TPolygon<T>, 5) {
192+
JNGEN_DECLARE_SIMPLE_PRINTER(TArray<TPoint<T>>, 5) {
211193
// I should avoid copy-paste from array printer here but need to output
212194
// points with '\n' separator. Maybe 'mod' should be made non-const?
213195
if (mod.printN) {
@@ -343,68 +325,7 @@ class GeometryRandom {
343325
}
344326

345327
static TArray<Point> pointsInGeneralPosition(
346-
int n, long long X, long long Y)
347-
{
348-
struct Line {
349-
long long A, B, C; // Ax + By + C = 0
350-
Line() {}
351-
Line(const Point& p1, const Point& p2) {
352-
A = p1.y - p2.y;
353-
B = p2.x - p1.x;
354-
C = -(p1.x * A + p1.y * B);
355-
356-
ENSURE(A != 0 || B != 0);
357-
358-
long long g = util::gcd(A, util::gcd(B, C));
359-
A /= g;
360-
B /= g;
361-
C /= g;
362-
if (A < 0 || (A == 0 && B < 0)) {
363-
A = -A;
364-
B = -B;
365-
C = -C;
366-
}
367-
}
368-
369-
bool operator<(const Line& other) const {
370-
return std::tie(A, B, C) < std::tie(other.A, other.B, other.C);
371-
}
372-
};
373-
374-
const long long LIMIT = 2e9;
375-
ensure(
376-
X <= LIMIT && Y <= LIMIT,
377-
"rndg.pointsInGeneralPosition must not be called with coordinates "
378-
"larger than 2e9");
379-
380-
std::set<Line> lines;
381-
std::unordered_set<Point> points;
382-
383-
TArray<Point> res;
384-
385-
while (static_cast<int>(res.size()) != n) {
386-
Point p = point(X, Y);
387-
388-
if (points.count(p)) {
389-
continue;
390-
}
391-
392-
if (std::none_of(
393-
res.begin(),
394-
res.end(),
395-
[&lines, &p] (const Point& q) {
396-
return lines.count(Line(p, q));
397-
}))
398-
{
399-
points.insert(p);
400-
for (const auto& q: res) {
401-
lines.emplace(p, q);
402-
}
403-
res.push_back(p);
404-
}
405-
}
406-
return res;
407-
}
328+
int n, long long X, long long Y);
408329

409330
static TArray<Point> pointsInGeneralPosition(int n, long long C) {
410331
return pointsInGeneralPosition(n, C, C);
@@ -415,6 +336,9 @@ JNGEN_EXTERN GeometryRandom rndg;
415336

416337
} // namespace jngen
417338

339+
JNGEN_DEFINE_STD_HASH(jngen::Point);
340+
JNGEN_DEFINE_STD_HASH(jngen::Polygon);
341+
418342
using jngen::Point;
419343
using jngen::Pointf;
420344

@@ -424,3 +348,69 @@ using jngen::Polygonf;
424348
using jngen::rndg;
425349

426350
using jngen::setEps;
351+
352+
#ifndef JNGEN_DECLARE_ONLY
353+
TArray<Point> jngen::GeometryRandom::pointsInGeneralPosition(
354+
int n, long long X, long long Y)
355+
{
356+
struct Line {
357+
long long A, B, C; // Ax + By + C = 0
358+
Line() {}
359+
Line(const Point& p1, const Point& p2) {
360+
A = p1.y - p2.y;
361+
B = p2.x - p1.x;
362+
C = -(p1.x * A + p1.y * B);
363+
364+
ENSURE(A != 0 || B != 0);
365+
366+
long long g = util::gcd(A, util::gcd(B, C));
367+
A /= g;
368+
B /= g;
369+
C /= g;
370+
if (A < 0 || (A == 0 && B < 0)) {
371+
A = -A;
372+
B = -B;
373+
C = -C;
374+
}
375+
}
376+
377+
bool operator<(const Line& other) const {
378+
return std::tie(A, B, C) < std::tie(other.A, other.B, other.C);
379+
}
380+
};
381+
382+
const long long LIMIT = 2e9;
383+
ensure(
384+
X <= LIMIT && Y <= LIMIT,
385+
"rndg.pointsInGeneralPosition must not be called with coordinates "
386+
"larger than 2e9");
387+
388+
std::set<Line> lines;
389+
std::unordered_set<Point> points;
390+
391+
TArray<Point> res;
392+
393+
while (static_cast<int>(res.size()) != n) {
394+
Point p = point(X, Y);
395+
396+
if (points.count(p)) {
397+
continue;
398+
}
399+
400+
if (std::none_of(
401+
res.begin(),
402+
res.end(),
403+
[&lines, &p] (const Point& q) {
404+
return lines.count(Line(p, q));
405+
}))
406+
{
407+
points.insert(p);
408+
for (const auto& q: res) {
409+
lines.emplace(p, q);
410+
}
411+
res.push_back(p);
412+
}
413+
}
414+
return res;
415+
}
416+
#endif // JNGEN_DECLARE_ONLY

graph.h

+9
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,19 @@ JNGEN_DECLARE_SIMPLE_PRINTER(graph_detail::BuilderProxy, 2) {
6464
JNGEN_PRINT(t.g());
6565
}
6666

67+
template<>
68+
struct Hash<Graph> {
69+
uint64_t operator()(const Graph& g) const {
70+
return Hash<GenericGraph>{}(g);
71+
};
72+
};
73+
6774
} // namespace jngen
6875

6976
using jngen::Graph;
7077

78+
JNGEN_DEFINE_STD_HASH(jngen::Graph);
79+
7180
#ifndef JNGEN_DECLARE_ONLY
7281
#define JNGEN_INCLUDE_GRAPH_INL_H
7382
#include "graph_inl.h"

0 commit comments

Comments
 (0)