├── License ├── README.md ├── array.h ├── build.py ├── chaining_traits.h ├── common.h ├── config.h ├── doc ├── array.md ├── config.md ├── drawer.md ├── generic_graph.md ├── geometry.md ├── getopt.md ├── getting_started.md ├── graph.md ├── library_build.md ├── math.md ├── overview.md ├── pics │ ├── img1.png │ ├── img1.svg │ ├── img2.png │ ├── img2.svg │ ├── img3.png │ ├── img3.svg │ ├── src1.cpp │ ├── src2.cpp │ └── src3.cpp ├── printers.md ├── random.md ├── strings.md └── tree.md ├── drawer ├── drawer.h ├── drawing_engine.h ├── svg_engine.h └── svg_engine_inl.h ├── dsu.h ├── examples ├── 786D.cpp ├── even-odd.cpp ├── folding.cpp ├── jumps.cpp └── some_random_graph_problem.cpp ├── footer.h ├── gcc_primes_list.h ├── generic_graph.h ├── geometry.h ├── graph.h ├── graph_builder_proxy.h ├── hash.h ├── header.h ├── impl ├── generic_graph_inl.h ├── geometry_inl.h ├── graph_inl.h ├── pattern_inl.h ├── random_inl.h ├── rnds_inl.h └── tree_inl.h ├── jngen.h ├── lib.cpp ├── math_jngen.h ├── options.h ├── pattern.h ├── printers.h ├── query_builder.h ├── random.h ├── range_option.h ├── repr.h ├── rnda.h ├── rnds.h ├── sequence_ops.h ├── suites ├── base_suite.h ├── graph.h ├── suites.h └── tree.h ├── testcases.h ├── tests ├── Makefile ├── antihashset.cpp ├── array.cpp ├── dsu.cpp ├── exact.cpp ├── generic_graph.cpp ├── geometry.cpp ├── graph.cpp ├── main.cpp ├── math.cpp ├── options.cpp ├── printers.cpp ├── random.cpp ├── repr.cpp ├── rnds.cpp └── tree.cpp ├── tree.h ├── util └── generate_prime_rehash_policy.cpp ├── variant.h ├── variant_array.h └── weight.h /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2018 Ivan Smirnov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Jngen: preparing tests made simpler 2 | 3 | [DOWNLOAD](https://raw.githubusercontent.com/ifsmirnov/jngen/master/jngen.h) 4 | 5 | * [Overview](#overview) 6 | * [Reference](#reference) 7 | * [Compatibility note](#compatibility-note) 8 | * [Examples](#examples) 9 | * [Why not testlib.h?](#why-not-testlibh) 10 | * [What does Jngen mean?](#what-does-jngen-mean) 11 | 12 | ### Overview 13 | 14 | Jngen is a C++ library for generating testss for various competitive programming problems. 15 | It is written in pure C++ (compliant with C++11 standard) and distributed as a single header. 16 | 17 | Among its features there are: 18 | * random number generator with uniform and off-center distribution (known as wnext); 19 | * command-line options parser, supporting named and positional arguments; 20 | * wrapper for *std::vector* which makes sorting, printing and generating random sequences easier; 21 | * printers for all standard types (no more trailing spaces and pain with 1-indexing!); 22 | * various random and not-so graphs and trees generators, manipulation with graphs and trees; 23 | * generating random geometrical primitives (including large convex polygons) and built-in drawing geometry in SVG; 24 | * random primes, partitions, anti-hash and anti-hashset tests; 25 | * and more. 26 | 27 | Check out the larger [overview](/doc/overview.md) to see more capabilities and examples 28 | or see [Getting started](/doc/getting_started.md) section to learn the simplest usecases immediately. 29 | 30 | ### Reference 31 | * [[random.h] Random numbers generation](/doc/random.md) 32 | * [[options.h] Parsing command-line options](/doc/getopt.md) 33 | * [[array.h] Array: wrapper for std::vector](/doc/array.md) 34 | * [[repr.h, printers.h] Printers and output modifiers](/doc/printers.md) 35 | * [[generic_graph.h] Graphs and trees: basics](/doc/generic_graph.md) 36 | * [[graph.h] Graphs generation](/doc/graph.md) 37 | * [[tree.h] Trees generation](/doc/tree.md) 38 | * [[math.h] Math: primes and partitions](/doc/math.md) 39 | * [[rnds.h] Strings](/doc/strings.md) 40 | * [[geometry.h] Geometric primitives](/doc/geometry.md) 41 | * [[drawer/drawer.h] Drawing figures in SVG](/doc/drawer.md) 42 | * [[config.h] Internal library options](/doc/config.md) 43 | 44 | ### Compatibility note 45 | * **This is not a standard "provided as-is" legal warning!** Opposite to testlib.h, which is already well-tested and pretty stable, Jngen is only yet being developed. First, not everything was properly tested and there may be bugs. Second and more important: there is no backward compatibility at the moment. It means that if you download Jngen tomorrow and run the same code then it may produce different result. Do not blindly update Jngen header if you need that tests for your problem remain exactly the same. 46 | 47 | ### Examples 48 | Find some real-world examples [here](/examples). 49 | 50 | Generate a random tree on *n* vertices with a 3-letter string assigned to each edge: 51 | ```cpp 52 | Tree t = Tree::random(5); 53 | t.setEdgeWeights(TArray::random(t.m(), "[a-z]{%d}", 3)); 54 | cout << t.add1().printN() << endl; 55 | --- 56 | 5 57 | 1 2 rqi 58 | 1 3 slv 59 | 1 4 foi 60 | 4 5 eju 61 | ``` 62 | 63 | Output a random permutation and its inverse: 64 | ```cpp 65 | setMod().add1(); 66 | 67 | auto a = Array::id(10).shuffled(); 68 | cout << a.size() << endl; 69 | cout << a << endl; 70 | cout << a.inverse() << endl; 71 | --- 72 | 10 73 | 3 8 5 7 2 4 1 10 9 6 74 | 7 5 1 6 3 10 4 2 9 8 75 | ``` 76 | 77 | Output a bamboo on *n* vertices connected to a star on *m* vertices, probably shuffled: 78 | ```cpp 79 | int main(int argc, char *argv[]) { 80 | parseArgs(argc, argv); 81 | int n, m; 82 | getPositional(n, m); 83 | 84 | Tree t = Tree::bamboo(n).link(n - 1, Tree::star(m), 0); 85 | if (getOpt("shuffled", false)) { 86 | t.shuffle(); 87 | } 88 | 89 | cout << t.printN().add1() << endl; 90 | } 91 | ``` 92 | 93 | Generate a connected graph with multi-edges: 94 | ```cpp 95 | cout << Graph::random(n, m).connected().allowMulti() << endl; 96 | ``` 97 | 98 | ### Why not testlib.h? 99 | testlib.h is a wonderful library which has already saved hundreds of hours for contest writers. However, there are reasons why I did not build Jngen on top of existing testlib.h code. 100 | 101 | * Testlib is multi-purpose. It also supports validators, checkers and interactors, while Jngen does not need it. 102 | * There are not many things to borrow from testlib. *rnd*, pattern generation, maybe some internal helper functions. 103 | * Testlib random is not very good. std::mt19937, which is used in Jngen under the hood, has much better distribution than hand-written linear congruential generator from testlib (though it is a bit slower). 104 | * Also, it would be harder to introduce new features in *rnd* than to code it from scratch. 105 | * I don't really like the code style of testlib, particularly naming convention and not using namespaces. 106 | * Being dependant on testlib, Jngen would compile even longer than it does now. 107 | 108 | ### What does Jngen mean? 109 | I don't know. 110 | 111 | It sounds similar to Jinotega, my ACM-ICPC team, maybe that's the way how it (unconsciously) came to my mind. Also it is similar to Jungen – "Young" in German. Or "Just 'Nother GENerator library". Well, who the hell cares. 112 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | 4 | import re, os 5 | 6 | HEADER_REGEX = re.compile('#include "(.*)"') 7 | 8 | # This list may contain not all headers directly, but each jngen header 9 | # must be among the dependencies of some file from here. 10 | LIBRARY_HEADERS = [ 11 | "array.h", 12 | "random.h", 13 | "common.h", 14 | "tree.h", 15 | "graph.h", 16 | "geometry.h", 17 | "math_jngen.h", 18 | "rnda.h", 19 | "rnds.h", 20 | "testcases.h", 21 | "options.h", 22 | "printers.h", 23 | "repr.h", 24 | "query_builder.h", 25 | "drawer/drawer.h", 26 | "suites/suites.h", 27 | ] 28 | 29 | 30 | def posix_path_to_native(posix_path): 31 | return os.path.join(*posix_path.split('/')) 32 | 33 | 34 | def extract_header(line): 35 | res = HEADER_REGEX.match(line) 36 | if res: 37 | return res.groups()[0] 38 | 39 | 40 | def extract_direct_deps(posix_filename): 41 | dir = os.path.dirname(posix_filename) # check explicitly on win 42 | 43 | res = set() 44 | with open(posix_path_to_native(posix_filename)) as fin: 45 | for line in fin.readlines(): 46 | t = extract_header(line) 47 | if t and not t.endswith("_inl.h"): 48 | res.add(dir + '/' + t if dir else t) 49 | 50 | return res 51 | 52 | 53 | deps = {} 54 | 55 | 56 | def extract_deps(posix_filename): 57 | posix_filename = os.path.normpath(posix_filename) 58 | if posix_filename in deps: 59 | return deps[posix_filename] 60 | deps[posix_filename] = set((posix_filename,)) 61 | 62 | for dep in extract_direct_deps(posix_filename): 63 | deps[posix_filename].update(extract_deps(dep)) 64 | return deps[posix_filename] 65 | 66 | 67 | def write_file(filename, stream): 68 | dir = os.path.dirname(filename) # check explicitly on win 69 | with open(posix_path_to_native(filename)) as fin: 70 | for line in fin.readlines(): 71 | include_or_not = HEADER_REGEX.match(line) 72 | if include_or_not: 73 | if include_or_not.groups()[0].endswith("_inl.h"): 74 | t = include_or_not.groups()[0] 75 | write_file(dir + '/' + t if dir else t, stream) 76 | elif '#pragma once' not in line: 77 | stream.write(line) 78 | 79 | 80 | headers = set() 81 | for h in LIBRARY_HEADERS: 82 | headers.update(extract_deps(h)) 83 | headers = ['header.h'] + sorted(headers) 84 | deps['footer.h'] = set(headers + ['footer.h']) 85 | headers += ['footer.h'] 86 | deps['header.h'] = set(('header.h',)) 87 | 88 | headers_in_order = [] 89 | while headers: 90 | for h in headers: 91 | if len(deps[h]) == 1: 92 | headers_in_order.append(h) 93 | for other in deps: 94 | deps[other].discard(h) 95 | del deps[h] 96 | headers.remove(h) 97 | break 98 | 99 | with open("jngen.h", "w") as fout: 100 | for filename in headers_in_order: 101 | write_file(filename, fout) 102 | 103 | -------------------------------------------------------------------------------- /chaining_traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, name) \ 4 | int _ ## name = 0; \ 5 | Class& name(int val = 1) { _ ## name = val; return *this; } 6 | 7 | #define JNGEN_CHAINING_TRAITS_INNER_0(Class) 8 | #define JNGEN_CHAINING_TRAITS_INNER_1(Class, arg) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) 9 | #define JNGEN_CHAINING_TRAITS_INNER_2(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_1(Class, __VA_ARGS__) 10 | #define JNGEN_CHAINING_TRAITS_INNER_3(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_2(Class, __VA_ARGS__) 11 | #define JNGEN_CHAINING_TRAITS_INNER_4(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_3(Class, __VA_ARGS__) 12 | #define JNGEN_CHAINING_TRAITS_INNER_5(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_4(Class, __VA_ARGS__) 13 | #define JNGEN_CHAINING_TRAITS_INNER_6(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_5(Class, __VA_ARGS__) 14 | #define JNGEN_CHAINING_TRAITS_INNER_7(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_6(Class, __VA_ARGS__) 15 | #define JNGEN_CHAINING_TRAITS_INNER_8(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_7(Class, __VA_ARGS__) 16 | #define JNGEN_CHAINING_TRAITS_INNER_9(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_8(Class, __VA_ARGS__) 17 | #define JNGEN_CHAINING_TRAITS_INNER_10(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_9(Class, __VA_ARGS__) 18 | #define JNGEN_CHAINING_TRAITS_INNER_11(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_10(Class, __VA_ARGS__) 19 | #define JNGEN_CHAINING_TRAITS_INNER_12(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_11(Class, __VA_ARGS__) 20 | #define JNGEN_CHAINING_TRAITS_INNER_13(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_12(Class, __VA_ARGS__) 21 | #define JNGEN_CHAINING_TRAITS_INNER_14(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_13(Class, __VA_ARGS__) 22 | #define JNGEN_CHAINING_TRAITS_INNER_15(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_14(Class, __VA_ARGS__) 23 | #define JNGEN_CHAINING_TRAITS_INNER_16(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_15(Class, __VA_ARGS__) 24 | #define JNGEN_CHAINING_TRAITS_INNER_17(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_16(Class, __VA_ARGS__) 25 | #define JNGEN_CHAINING_TRAITS_INNER_18(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_17(Class, __VA_ARGS__) 26 | #define JNGEN_CHAINING_TRAITS_INNER_19(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_18(Class, __VA_ARGS__) 27 | #define JNGEN_CHAINING_TRAITS_INNER_20(Class, arg, ...) JNGEN_DEFINE_CHAINING_TRAITS_FIELD(Class, arg) JNGEN_CHAINING_TRAITS_INNER_19(Class, __VA_ARGS__) 28 | 29 | #define JNGEN_GET_CHAINING_TRAITS_INNER_IMPL(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, x, ...) x 30 | 31 | #define JNGEN_GET_CHAINING_TRAITS_INNER(...) JNGEN_GET_CHAINING_TRAITS_INNER_IMPL(\ 32 | __VA_ARGS__,\ 33 | JNGEN_CHAINING_TRAITS_INNER_20,\ 34 | JNGEN_CHAINING_TRAITS_INNER_19,\ 35 | JNGEN_CHAINING_TRAITS_INNER_18,\ 36 | JNGEN_CHAINING_TRAITS_INNER_17,\ 37 | JNGEN_CHAINING_TRAITS_INNER_16,\ 38 | JNGEN_CHAINING_TRAITS_INNER_15,\ 39 | JNGEN_CHAINING_TRAITS_INNER_14,\ 40 | JNGEN_CHAINING_TRAITS_INNER_13,\ 41 | JNGEN_CHAINING_TRAITS_INNER_12,\ 42 | JNGEN_CHAINING_TRAITS_INNER_11,\ 43 | JNGEN_CHAINING_TRAITS_INNER_10,\ 44 | JNGEN_CHAINING_TRAITS_INNER_9,\ 45 | JNGEN_CHAINING_TRAITS_INNER_8,\ 46 | JNGEN_CHAINING_TRAITS_INNER_7,\ 47 | JNGEN_CHAINING_TRAITS_INNER_6,\ 48 | JNGEN_CHAINING_TRAITS_INNER_5,\ 49 | JNGEN_CHAINING_TRAITS_INNER_4,\ 50 | JNGEN_CHAINING_TRAITS_INNER_3,\ 51 | JNGEN_CHAINING_TRAITS_INNER_2,\ 52 | JNGEN_CHAINING_TRAITS_INNER_1,\ 53 | JNGEN_CHAINING_TRAITS_INNER_0) 54 | 55 | #define JNGEN_CHAINING_TRAITS(Class, ...) \ 56 | struct Class { JNGEN_GET_CHAINING_TRAITS_INNER(__VA_ARGS__)(Class, __VA_ARGS__) }; 57 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "config.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef JNGEN_DECLARE_ONLY 15 | #define JNGEN_EXTERN extern 16 | #else 17 | #define JNGEN_EXTERN 18 | #endif 19 | 20 | namespace jngen { 21 | 22 | class Exception : public std::runtime_error { 23 | public: 24 | explicit Exception(const std::string& s) : 25 | std::runtime_error("Assertion `" + s + "' failed.") 26 | { } 27 | 28 | Exception(const std::string& assertMsg, const std::string& expl) : 29 | std::runtime_error(expl + " (assertion `" + assertMsg + "' failed).") 30 | { } 31 | }; 32 | 33 | class InternalException : public Exception { 34 | public: 35 | explicit InternalException(const std::string& s) : Exception(s) {} 36 | 37 | InternalException(const std::string& assertMsg, const std::string& expl) : 38 | Exception(assertMsg, expl) 39 | { } 40 | }; 41 | 42 | } // namespace jngen 43 | 44 | #define JNGEN_ENSURE1(exType, cond)\ 45 | do\ 46 | if (!(cond)) {\ 47 | throw exType(#cond);\ 48 | }\ 49 | while (false) 50 | 51 | #define JNGEN_ENSURE2(exType, cond, msg)\ 52 | do\ 53 | if (!(cond)) {\ 54 | throw exType(#cond, msg);\ 55 | }\ 56 | while (false) 57 | 58 | #define JNGEN_GET_MACRO(_1, _2, NAME, ...) NAME 59 | 60 | #define ensure(...) JNGEN_GET_MACRO(__VA_ARGS__, JNGEN_ENSURE2, JNGEN_ENSURE1)\ 61 | (jngen::Exception, __VA_ARGS__) 62 | #define ENSURE(...) JNGEN_GET_MACRO(__VA_ARGS__, JNGEN_ENSURE2, JNGEN_ENSURE1)\ 63 | (jngen::InternalException, __VA_ARGS__) 64 | 65 | namespace jngen { 66 | 67 | template 68 | std::string format(const std::string& fmt, Args... args) { 69 | constexpr static char BUF_SIZE = 64; 70 | static char BUFFER[BUF_SIZE]; 71 | 72 | int bufSize = BUF_SIZE; 73 | char *buf = BUFFER; 74 | 75 | while (true) { 76 | int ret = std::snprintf(buf, bufSize, fmt.c_str(), args...); 77 | if (ret < bufSize) { 78 | break; 79 | } 80 | 81 | if (bufSize != BUF_SIZE) { 82 | delete[] buf; 83 | } 84 | 85 | bufSize *= 2; 86 | buf = new char[bufSize]; 87 | } 88 | 89 | std::string result(buf); 90 | 91 | if (bufSize != BUF_SIZE) { 92 | delete[] buf; 93 | } 94 | 95 | return result; 96 | } 97 | 98 | class ContextTimer { 99 | public: 100 | ContextTimer(const std::string& name) : name_(name) { 101 | start_ = std::chrono::steady_clock::now(); 102 | } 103 | 104 | ContextTimer() : ContextTimer("") {} 105 | 106 | ContextTimer(const ContextTimer&) = delete; 107 | ContextTimer& operator=(const ContextTimer&) = delete; 108 | ContextTimer(ContextTimer&&) = delete; 109 | ContextTimer& operator=(ContextTimer&&) = delete; 110 | 111 | ~ContextTimer() { 112 | auto dif = std::chrono::steady_clock::now() - start_; 113 | auto ms = std::chrono::duration_cast(dif); 114 | if (!name_.empty()) { 115 | std::cerr << "[" << name_ << "] "; 116 | } 117 | std::cerr << ms.count() << " ms\n"; 118 | } 119 | 120 | private: 121 | std::string name_; 122 | std::chrono::steady_clock::time_point start_; 123 | }; 124 | 125 | template 126 | auto distribution(int n, F&& f) -> std::map { 127 | std::map dist; 128 | for (int i = 0; i < n; ++i) { 129 | ++dist[f()]; 130 | } 131 | return dist; 132 | } 133 | 134 | inline void checkLargeParameter(int n) { 135 | if (!config.generateLargeObjects) { 136 | constexpr static int BOUND = 5e6; 137 | ensure( 138 | n <= BOUND, 139 | "If you want to generate an object of size > 5'000'000, please set " 140 | "'config.generateLargeObjects = true'."); 141 | } 142 | } 143 | 144 | // Some type traits helpers. Based on ideas from TCPPPL v4. 145 | template 146 | using enable_if_t = typename std::enable_if::type; 147 | 148 | template 149 | using decay_t = typename std::decay::type; 150 | 151 | namespace util { 152 | 153 | inline long long gcd(long long a, long long b) { 154 | if (a < 0) { 155 | a = -a; 156 | } 157 | if (b < 0) { 158 | b = -b; 159 | } 160 | 161 | while (a && b) { 162 | if (a > b) { 163 | a %= b; 164 | } else { 165 | b %= a; 166 | } 167 | } 168 | return a + b; 169 | } 170 | 171 | inline std::vector split(std::string s, char delimiter) { 172 | auto strip = [](std::string s) { 173 | size_t l = 0; 174 | while (l < s.size() && s[l] == ' ') { 175 | ++l; 176 | } 177 | s = s.substr(l); 178 | while (!s.empty() && s.back() == ' ') { 179 | s.pop_back(); 180 | } 181 | return s; 182 | }; 183 | 184 | std::vector result; 185 | s += delimiter; 186 | std::string cur; 187 | 188 | for (char c: s) { 189 | if (c == delimiter) { 190 | result.push_back(strip(cur)); 191 | cur.clear(); 192 | } else { 193 | cur += c; 194 | } 195 | } 196 | 197 | return result; 198 | } 199 | 200 | } // namespace util 201 | 202 | } // namespace jngen 203 | 204 | using jngen::format; 205 | using jngen::ContextTimer; 206 | using jngen::distribution; 207 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace jngen { 4 | 5 | struct Config { 6 | bool generateLargeObjects = false; 7 | bool largeOptionIndices = false; 8 | bool normalizeEdges = true; 9 | }; 10 | 11 | #ifdef JNGEN_DECLARE_ONLY 12 | extern 13 | #endif 14 | Config config; 15 | 16 | } // namespace jngen 17 | 18 | using jngen::config; 19 | -------------------------------------------------------------------------------- /doc/array.md: -------------------------------------------------------------------------------- 1 | ## Arrays 2 | 3 | Jngen provides a template class *TArray<T>* which is derived from *std::vector<T>* and implements all its functionality... and some more handy things like single-argument sorting (*a.sort()*) , in-place generating of random arrays (*Array::random(n, maxValue)*) and more. 4 | 5 | There are several typedefs for convenience: 6 | ```cpp 7 | typedef TArray Array; 8 | typedef TArray Array64; 9 | typedef TArray Arrayf; 10 | typedef TArray> Arrayp; 11 | typedef TArray> Array2d; 12 | ``` 13 | In this document *Array* will be mostly used instead of *TArray<T>*. Usually it means that corresponding method works for arrays of any type; if not, it will be mentioned explicitly. 14 | 15 | ### Generators 16 | #### template<typename ...Args>
static Array Array::random(size_t size, Args... args) 17 | #### template<typename ...Args>
static Array Array::randomUnique(size_t size, Args... args) 18 | #### template<typename ...Args>
static Array Array::randomAll(Args... args) 19 | * Returns: array of *size* random elements generated as *rnd.tnext<T>(args...)*. In the second version all generated elements are distinct. In the third version generation runs until no new elements appear with high probability. 20 | * Note: *randomUnique* and *randomAll* assume uniform distribution on data. I.e. if your method returns 1 with probability 0.999 and 2 with probability 0.001, *randomUnique(2, ...)* will most likely terminate saying that there are not enough distinct elements. 21 | * Complexity: 22 | * *random*: *size* calls of *rnd.tnext*; 23 | * *randomUnique*: approximately *O(size log size)* calls of *rnd.tnext*; 24 | * *randomAll*: approximately *O(size log size)* calls of *rnd.tnext*, where *size* is the number of generated elements. 25 | * Examples: 26 | ```cpp 27 | Array::randomUnique(10, 10) 28 | ``` 29 | yields a random permutation on 10 elements (though more optimal way is *Array::id(10).shuffled()*); 30 | 31 | ```cpp 32 | Arrayp::random(20, 10, 10, dpair) 33 | ``` 34 | yields edges of a random graph with 10 vertices and 20 edges, possibly containing multi-edges, but without loops. 35 | 36 | #### template<typename F, typename ...Args>
static Array Array::randomf(size_t size, F func, Args... args) 37 | #### template<typename F, typename ...Args>
static Array Array::randomfUnique(size_t size, F func, Args... args) 38 | #### template<typename F, typename ...Args>
static Array Array::randomfAll(F func, Args... args) 39 | * Same as *Array::random*, but *func(args...)* is called instead of *rnd.tnext*. 40 | * Example: 41 | ```cpp 42 | TArray::randomf( 43 | 10, 44 | [](const char* pattern) { return rnd.next(pattern); }, 45 | "[a-z]{5}") 46 | ``` 47 | yields an array of 10 strings of 5 letters each. 48 | 49 | #### Array Array::id(size_t size, T start = T()) 50 | * Generates an array of *size* elements: *start*, *start + 1*, ... 51 | * Note: defined only for integer types. 52 | 53 | ### Modifiers 54 | Most of modifiers have two versions: the one which modifies the object itself and the one which returns the modified copy. They are usually named as *verb* and *verb-ed*, e.g. *shuffle* and *shuffled*. 55 | 56 | #### Array& shuffle() 57 | #### Array shuffled() const 58 | * Shuffle the array. The source of randomness is *rnd*. 59 | 60 | #### Array& reverse() 61 | #### Array reversed() const 62 | * Reverse the array. 63 | 64 | #### Array& sort() 65 | #### Array sorted() const 66 | * Sort the array in non-decreasing order. 67 | 68 | #### template<typename Comp>
Array& sort(Comp&& comp) 69 | #### template<typename Comp>
Array sorted(Comp&& comp) const 70 | * Sort the array in non-decreasing order using *comp* as a comparator. 71 | 72 | #### Array& unique() 73 | #### Array uniqued() const 74 | * Remove consequent duplicates in the array. Equivalent to *std::erase(std::unique(a.begin(), a.end()), a.end())*. 75 | * Note: as *std::unique*, this method doesn not remove all duplicated elements if the array is not sorted. 76 | 77 | #### Array inverse() const 78 | * Returns: inverse permutation of the array. 79 | * Note: defined only for integer types. Terminates if the array is not a permutation of \[0, n). 80 | 81 | #### void extend(size_t requiredSize); 82 | * Equivalent to *resize(max(size(), requiredSize))*. 83 | 84 | ### Selectors 85 | #### template<typename Integer>
Array subseq(const std::vector& indices) const; 86 | #### template<typename Integer>
Array subseq(const std::initializer_list& indices) const; 87 | * Returns: subsequence of the array denoted by *indices*. 88 | * Example: 89 | ```cpp 90 | a = a.subseq(Array::id(a.size()).shuffled()); 91 | ``` 92 | effectively shuffles *a*. For example, this may be used to shuffle several arrays with the same permutation. 93 | 94 | #### T choice() const; 95 | * Returns: random element of the array. 96 | 97 | #### Array choice(size_t count) const; 98 | * Returns: an array of *count* elements of the array **without repetition**. 99 | * Note: obviously, *count* should be not greater than *array.size()*. 100 | 101 | #### Array choiceWithRepetition(size_t count) const; 102 | * Returns: an array of *count* elements of the array, possibly repeating. 103 | 104 | ### Operators 105 | #### Array& operator+=(const Array& other); 106 | #### Array operator+(const Array& other) const; 107 | * Inserts *other* to the end of the array. 108 | 109 | #### Array& operator*=(int k); 110 | #### Array operator*(int k) const; 111 | * Repeats the array *k* times. 112 | 113 | #### operator std::string() const; 114 | * Casts TArray<char> to std::string. 115 | * Note: defined only for TArray<char>. 116 | -------------------------------------------------------------------------------- /doc/config.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | Jngen has some built-in "sanity checks": if you want to generate an array of size 481927184, likely you have an uninitialize variable. Jngen will gracefully terminate and report it to you (instead of causing OOM error and possibly hanging the machine). 4 | 5 | However, sometimes you know better and may want to turn these checks off. To do it, simply put a line at the beginning of *main*: 6 | ```cpp 7 | config.optionName = true/false; 8 | ``` 9 | 10 | ### List of configurable options (default value) 11 | #### generateLargeObjects (false) 12 | * Allow generating arrays, graphs and so of size exceeding 5 million. 13 | 14 | #### largeOptionIndices (false) 15 | * Allow calling *getOpt(n)* for *n >= 32*. This check is created to report if you accidentally call *getOpt('C')* (that is, with char instead of string). 16 | 17 | #### normalizeEdges (true) 18 | * If this option is set, edges of newly generated graphs are printed in sorted order to make output more human-readable. You may turn it off if you care about performance rather than presentation. 19 | -------------------------------------------------------------------------------- /doc/drawer.md: -------------------------------------------------------------------------------- 1 | ## Drawer 2 | Have you ever wanted to visualize tests for geometry problems? Jngen gives you a convenient way to do so. It gives an instrument for drawing 3 | basic geometric primitives (points, circles, segments and polygons) in SVG format. 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | Here is a usage example. 12 | 13 | ```cpp 14 | // Create an instance of a Drawer class 15 | Drawer d; 16 | 17 | // Use Point or Pointf from jngen or your own point class. 18 | // In the latter case it must have two fields named x and y. 19 | // Both integers and reals are supported. 20 | Point p1(3, 14); 21 | Point p2(15, 92); 22 | 23 | d.point(p1); 24 | // Second argument is radius 25 | d.circle(p1, 5); 26 | d.segment(p1, p2); 27 | // d.polygon takes vector or initializer list of points as its argument 28 | d.polygon(vector{p1, p2, Point{1, 2}, Point{5, 6}}); 29 | 30 | // You can also use pairs: 31 | d.point(pair(0.5, 1.1)); 32 | d.circle(pair(5, 6), 10); 33 | d.segment(make_pair(1, 2), make_pair(3, 4)); 34 | d.polygon(vector>{ {0, 0}, {0, 10}, {10, 0} }); 35 | 36 | // Or even specify coordinates by hand for point, circle and segment: 37 | d.point(1, 2); 38 | d.circle(5, 10, 3.3); 39 | // Here the order is x1, y1, x2, y2 40 | d.segment(0, 0, 10, 10); 41 | 42 | // Style of figures can be altered. Any style change only applies 43 | // to figures which were drawn after. 44 | 45 | // You can change the color of your figures... 46 | d.setColor("green"); 47 | // and deal with stroke and fill separately: 48 | d.setStroke("red"); 49 | d.setFill("blue"); 50 | // Both stroke and fill can be set to none passing an empty string: 51 | d.setFill(""); 52 | // You can use any color which is supported by HTML/SVG. If the color 53 | // has adequate name it is likely on the list. 54 | 55 | // It is possible to set line width (default is 1): 56 | d.setWidth(2.5); 57 | // And opacity (ranging from 0 to 1, 0 is invisible, 1 is solid): 58 | d.setOpacity(0.5); 59 | 60 | // By default Jngen draws a cool grid with coordinates. I find it 61 | // very handy, however, if you don't like it it is easy do disable: 62 | d.enableGrid(false); 63 | 64 | // Finally, you should save your piece of art to the SVG file: 65 | d.dumpSvg("name.svg"); 66 | ``` 67 | -------------------------------------------------------------------------------- /doc/generic_graph.md: -------------------------------------------------------------------------------- 1 | ## Graphs and trees: common interface 2 | 3 | * [Documentation](#document) 4 | * [Weights](#weights) 5 | * [Labeling](#labeling) 6 | 7 | Jngen provides a *GenericGraph* class. You will mostly use its two subclasses: *Graph* and *Tree*. They have different generators and methods, though there is a common generic part. 8 | 9 | Graph vertices are always numbered from 0 to n-1, where n is the number of vertices. Other numerations will be supported later. Currently can output a graph in 1-numeration using *.add1()* output modifier. 10 | 11 | You can assign weights to edges and vertices of a graph. Weight is implemented as (self-written, waiting for C++17) kinda *std::variant* with some predefined types: *int*, *double*, *string*, *pair<int, int>*. However, you can add your own types. To do it define a macro `JNGEN_EXTRA_WEIGHT_TYPES` containing comma-separated extra types you want to use. 12 | 13 | ```cpp 14 | #define JNGEN_EXTRA_WEIGHT_TYPES std::vector, std::pair 15 | #include "jngen.h" 16 | ``` 17 | 18 | Note that if you use precompiled library and compile your code with `JNGEN_DECLARE_ONLY`, you must precompile the library with the same `JNGEN_EXTRA_WEIGHT_TYPES` as well. 19 | 20 | Like all containers in jngen, graphs support pretty-printing and output modifiers. 21 | 22 | ```cpp 23 | Graph g; 24 | g.addEdge(0, 1); 25 | g.addEdge(1, 2); 26 | g.setVertexWeights({"v1", "v2", "v3"}); 27 | g.setEdgeWeights({10, 20}); 28 | 29 | cout << g.printN().printM().add1() << endl; 30 | --- 31 | 3 2 32 | v1 v2 v3 33 | 1 2 10 34 | 2 3 20 35 | ``` 36 | 37 | Graphs and trees are printed as following. If *.printN()* and *.printM()* modifiers are set, on the first line *n* and *m* are printed (you can set any of modifiers independently). If vertex weights are present, they are then printed on a separate line. After *m* lines with edges follow. Two endpoints of the edge are printed, optionally followed by edge weight. 38 | 39 | **Output modifiers do not apply to vertex/edge weights**. When you set edge length to 10, you probably don't want it to increase to 11 when you switch to 1-numeration, right? 40 | 41 | By default, edges of a newly generated graph are printed in sorted order, because it makes tests more human-readable. If you generate large graphs and care about performance rather than presentation, sorting may be disabled using [config](config.md). Simply add this line at the top of *main*: 42 | 43 | ```cpp 44 | config.normalizeEdges = false; 45 | ``` 46 | 47 | Of course, edges are not sorted anymore after the graph is shuffled. 48 | 49 | ### Documentation 50 | 51 | #### int n() const 52 | * Returns: the number of vertices in the graph. 53 | #### int m() const 54 | * Returns: the number of edges in the graph. 55 | #### bool directed() const 56 | * Returns: true if and only the graph is directed. 57 | #### void addEdge(int u, int v, const Weight& w = Weight{}) 58 | * Add an edge *(u, v)*, possbly, with weight *w*, to a graph. 59 | #### bool isConnected() const 60 | * Returns: true if and only if the graph is connected. 61 | #### int vertexByLabel(int label) const 62 | * Returns: the internal id of the vertex identified by *label*. See [*labeling*](#labeling) section at the end of this part. Most likely you'll never need this and the next method. 63 | #### int vertexLabel(int v) const 64 | * Returns: the label of the vertex with internal id *v*. 65 | #### Array edges(int v) const 66 | * Returns: array of vertices incident to *v*. 67 | #### Arrayp edges() const 68 | * Returns: array of all edges of the graph. 69 | #### void setVertexWeights(const WeightArray& weights) 70 | * Set weight of *i*-th vertex to *weights[i]*. Size of *weights* must be equal to *n*. 71 | #### void setVertexWeight(int v, const Weight& weight) 72 | * Set weight of a vertex *v* to *weight*. 73 | #### void setEdgeWeights(const WeightArray& weights) 74 | * Set weight of *i*-th edge to *weights[i]*. Size of *weights* must be equal to *m*. 75 | #### void setEdgeWeight(size_t index, const Weight& weight) 76 | * Set weight of an edge with index *index* to *weight*. 77 | #### Weight vertexWeight(int v) const 78 | * Returns: weight of the vertex *v*. 79 | #### Weight edgeWeight(size_t index) const 80 | * Returns: weight of an edge with index *index*. 81 | #### bool operator==(const GenericGraph& other) const 82 | #### bool operator!=(const GenericGraph& other) const 83 | #### bool operator<(const GenericGraph& other) const 84 | #### bool operator>(const GenericGraph& other) const 85 | #### bool operator<=(const GenericGraph& other) const 86 | #### bool operator>=(const GenericGraph& other) const 87 | * 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. 88 | * Note: weights have no any effect on comparison result. 89 | * Note: two identical graphs with shuffled adjacency lists are equal. 90 | 91 | ### Weights 92 | All things you will probably ever do with *Weight* or *WeightArray* are shown in this snippet. 93 | 94 | ```cpp 95 | Graph g(3); // construct an empty graph on 3 vertices 96 | 97 | graph.setVertexWeight(1, 123); 98 | int v = graph.vertexWeight(1); // v = 123 99 | string s = graph.vertexWeight(1); // s = "" because weight holds int now. 100 | cout << graph.vertexWeight(1) << endl; // 123. Value which is now held is printed. 101 | graph.setVertexWeight(2, graph.vertexWeight(1)); // Weight is copyable as wwell. 102 | 103 | Array a{1, 2, 3}; 104 | graph.setVertexWeights(a); // implicit cast from std::vector to WeightArray 105 | // is supported for each T which can be held by Weight. 106 | std::vector vs{"hello", "world", "42"}; 107 | graph.setVertexWeights(vs); 108 | ``` 109 | 110 | *Weight* type is implemented as a *jngen::Variant* class. Basically it is a type-safe union which can store the value of any of the predefined types. *jngen::Variant* is a bit different from *boost::variant* and *std::variant*. The first notable exception is that valueless state is valid, i.e. variant can be empty. The second is that *jngen::Variant* allows implicit casts to any of containing types which allows you writing something like 111 | 112 | ```cpp 113 | int w = graph.vertexWeight(1); 114 | string s = graph.edgeWeight(2); 115 | ``` 116 | 117 | Still, it may have some flaws (I'm far not Antony Polukhin), and I'll be happy to know about them. 118 | 119 | ### Labeling 120 | Internally graph nodes are stored as integers from 0 to n-1. However, sometimes you need to change numeration (e.g. to shuffle the graph). That's why each vertex is assigned with a *label*, and end-user does all operations with vertices using their labels. Currently labels are always a permutation of [0, n-1]. Later Jngen is going to support arbitrary labeling. 121 | -------------------------------------------------------------------------------- /doc/geometry.md: -------------------------------------------------------------------------------- 1 | ## Geometry 2 | 3 | Jngen provides two point classes: *Point* with *long long* coordinates and *Pointf* with *long double* coordinates. Standard operations like addition, subtraction, dot and cross products are supported. Similarly, classes *Polygon* and *Polygonf* are provided. A special class *GeometryRandom* is used for generating objects, all interaction goes via its global instance *rndg*. 4 | 5 | *Point* is basically a structure with two fields: *x* and *y*. *Polygon* is basically an *Array* of *Points*. 6 | 7 | Like most Jngen objects, *Point* and *Polygon* can be printed to streams and modified with [output modifiers](printers.md). 8 | 9 | If you are looking for an SVG drawing tool, please refer to [this](drawer.md) page. 10 | 11 | ### Generators (*rndg* static methods) 12 | #### Point point(long long C) 13 | #### Pointf pointf(long double C) 14 | * Returns: random point with coordinates between 0 and C, inclusive. 15 | 16 | #### Point point(long long min, long long max) 17 | #### Pointf pointf(long double min, long double max) 18 | * Returns: random point with coordinates between *min* and *max*, inclusive. 19 | 20 | #### Point point(long long x1, long long y1, long long x2, long long y2) 21 | #### Pointf pointf(long double x1, long double y1, long double x2, long double y2) 22 | * Returns: random point with x-coordinate between *x1* and *x2* and y-coordinate between *y1* and *y2*, inclusive. 23 | 24 | #### Polygon convexPolygon(int n, long long C) 25 | #### Polygon convexPolygon(int n, long long min, long long max) 26 | #### Polygon convexPolygon(int n, long long x1, long long y1, long long x2, long long y2) 27 | * Returns: random convex polygon with *n* vertices and coordinates lying in specified range. 28 | * No three consecutive vertices lie on the same line, no two points coincide. 29 | * Polygon is generated like following: convex hull of *10n* random points on an ellipse is taken, 30 | then *n* points are randomly selected from it. 31 | * Throws if the are less than *n* points on the above convex hull. 32 | 33 | #### TArray<Point> pointsInGeneralPosition(int n, long long C) 34 | #### TArray<Point> pointsInGeneralPosition(int n, long long min, long long max) 35 | #### TArray<Point> pointsInGeneralPosition(int n, long long x1, long long y1, long long x2, long long y2) 36 | * Returns: *n* random points such that no two coincide and no three lie on the same line. 37 | * Complexity: *O(n2 log n)*. 38 | 39 | ### Point and Pointf operators 40 | Here is the list of operators supported for *Point* and *Pointf*. All of them are declared *const*, excluding those which explicitly modify their arguments. 41 | 42 | * _p1 + p2_, _p1 += p2_: coordinate-wise addition; 43 | * _p1 - p2_, _p1 -= p2_: coordinate-wise subtraction; 44 | * _p * x_, _p *= x_: coordinate-wise multiplication with scalar value; 45 | * _p1 * p2_: dot product (_p1.x * p2.x + p1.y * p2.y_); 46 | * _p1 % p2_: cross product (_p1.x * p2.y - p1.y * p2.x_); 47 | * _p1 == p2_, _p1 != p2_: coordinate-wise equality comparison; 48 | * _p1 < p2_: lexicographical coordinate-wise ordering. 49 | 50 | For *Pointf* comparisons of floating point values are done with *eps* presision. The default value is *10-9*. It can be overridden with *setEps* function. 51 | 52 | ### Polygon and Polygonf methos 53 | *Polygon* inherits *TArray<Point>* so has it supports standard Array methods like *.sort()*, *.choice()* and so on. However, it provides a couple of additional methods. 54 | 55 | #### Polygon& shift(const Point& vector) 56 | #### Polygon shifted(const Point& vector) const 57 | * Shift the polygon by given *vector*, i.e. add *vector* to each vertex of a polygon. 58 | 59 | #### Polygon& reflect() 60 | #### Polygon reflected() const 61 | * Reflect the polygon across the *x = -y* line, i.e. replace point *(x, y)* with *(-x, -y)*. 62 | -------------------------------------------------------------------------------- /doc/getopt.md: -------------------------------------------------------------------------------- 1 | ## Parsing command-line options 2 | Jngen provides a parser of command-line options. It supports both positional and named arguments. Here is the comprehensive example of usage. 3 | 4 | ```cpp 5 | // ./main 10 -pi=3.14 20 -hw hello-world randomseedstring 6 | int main(int argc, char *argv[]) { 7 | parseArgs(argc, argv); 8 | int n, m; 9 | double pi; 10 | string hw; 11 | 12 | n = getOpt(0); // n = 10 13 | pi = getOpt("pi"); // pi = 3.14 14 | 15 | n = getOpt(5, 100); // n = 100 as there is no option #5 16 | pi = getOpt("PI", 3.1415); // pi = 3.1415 as there is no option "PI" 17 | 18 | getPositional(n, m); // n = 10, m = 20 19 | getNamed(hw, pi); // hw = "hello-world", pi = 3.14 20 | 21 | cout << (int)getOpt("none", 10) << endl; // 10 as there is no "none" option 22 | } 23 | ``` 24 | 25 | ### Options format 26 | * Any option not starting with "-" sign is a positional option; 27 | * positional options are numbered from 0 sequentially (e.g. if there is a positional option, then named, then again positional, two positional options will have indices 0 and 1); 28 | * named options can have form "-name=value" and "-name value", though the second is allowed if *value* does not start with a hyphen; 29 | * if an option name immediately follows another option name (e.g. "-first -second ..." than the value of *first* is set to 1; 30 | * single "-" sign is ignored; 31 | * anything after "‐‐" (two minus signs) is ignored; 32 | 33 | ### Documentation 34 | 35 | #### void parseArgs(int argc, char *argv) 36 | * Parse arguments and prepare variable map. Required to be called before any *getOpt...* calls. 37 | 38 | #### *unspecified_type* getOpt(size_t index) 39 | #### *unspecified_type* getOpt(const std::string& name) 40 | * Reads an option denoted by *index* (positional, 0-indexed) or *name*. Throws if the option does not exist. 41 | * Return type can be casted to any other type. See the expected usage: 42 | ```cpp 43 | int n = getOpt(0), m = getOpt(1); 44 | double h = getOpt("height"); 45 | ``` 46 | * Note: if the cast fails (e.g. you try to interpret "adsfasd" as int) the function throws. 47 | 48 | #### template<typename T>
*unspecified_type* getOpt(size_t index, T def) 49 | #### template<typename T>
*unspecified_type* getOpt(const std::string& name, T def) 50 | * Same as *getOpt(index)* and *getOpt(name)*, but if the option doens't exist then *def* is returned. 51 | * Note: the function still throws if the option exists but the cast fails. 52 | 53 | #### bool hasOpt(size_t index) 54 | #### bool hasOpt(const std::string& name) 55 | * Checks if the option denoted by *index* or *name* is present. Its value is not examined. 56 | 57 | #### int getPositional(Args&... args) 58 | * Reads positional options to *args...* in order. Arguments which could not be read are not modified. 59 | * Returns: number of succesfully read arguments. 60 | 61 | #### int getNamed(Args&... args) 62 | * Reads named arguments. Variable *x* is interpreted as having name *x*. Arguments which could not be read are not modified. 63 | * Returns: number of succesfully read arguments. 64 | * Note: this function is implemented with a define and may be not noticed by your autocompletion tool. 65 | -------------------------------------------------------------------------------- /doc/getting_started.md: -------------------------------------------------------------------------------- 1 | ## Getting started with Jngen 2 | 3 | ### Installation 4 | Jngen is a single-header library. You only have to download the [jngen.h](https://raw.githubusercontent.com/ifsmirnov/jngen/master/jngen.h) 5 | file and put it somewhere on your machine. `/usr/include` or the directory with your problem must work. And, of course, don't forget to include it 6 | in your source file. 7 | 8 | #### Note on compilers 9 | Jngen is known to work with g++ of versions 4.8, 4.9, 5.3 and 6.2 and Clang of version 3.5. You should enable C++11 support (`-std=c++11`) 10 | to work with it. C++14 is also fine. 11 | 12 | MS Visual Studio is not supported at the moment, and it is known that Jngen fails to compile under it. Nothing is known about MinGW. 13 | 14 | ### Migrating from testlib.h 15 | So let's write our first generator for an "A+B" problem! 16 | 17 | ```cpp 18 | #include "jngen.h" 19 | #include 20 | using namespace std; 21 | 22 | int main(int argc, char *argv[]) { 23 | registerGen(argc, argv); 24 | parseArgs(argc, argv); 25 | 26 | int maxc = getOpt(0); 27 | 28 | int a = rnd.next(0, maxc); 29 | int b = rnd.next(0, maxc); 30 | 31 | cout << a << " " << b << endl; 32 | } 33 | ``` 34 | 35 | At the first glance there is not much difference from testlib.h. The only new functions are *parseArgs* and *getOpt*. 36 | They are for options parsing. *parseArgs* initializes the parser. *getOpt(0)* reads the first option and casts it to int 37 | (or to any other type, whatever you want). Options parser is described in details [here](getopt.md). 38 | 39 | *rnd.next(0, maxc)* returns a random integer from 0 to *maxc*, exactly the same as in testlib. 40 | 41 | ### The basic Jngen 42 | My favorite and very common example is generating a permutation. I would expect to see something like this: 43 | 44 | ```cpp 45 | int n = getOpt(0); 46 | vector a; 47 | for (int i = 0; i < n; ++i) { 48 | a.push_back(i); 49 | } 50 | shuffle(a.begin(), a.end()); 51 | cout << n << "\n"; 52 | for (int i = 0; i < n; ++i) { 53 | cout << a[i] + 1; 54 | if (i+1 == n) { 55 | cout << "\n"; 56 | } else { 57 | cout << " "; 58 | } 59 | } 60 | ``` 61 | 62 | Freaking 14 lines of code! Now see Jngen version. 63 | 64 | ```cpp 65 | cout << Array::id(getOpt(0)).shuffled().printN().add1() << endl; 66 | ``` 67 | 68 | Such wow, very short. Here we see many Jngen features at once. 69 | 70 | * [Arrays](array.md). With *Array::something* you can generate various arrays (like permutations and random ones). 71 | After you can shuffle, sort and do anything else calling a method on the same object. 72 | * Chaining. Syntax *object.doThis().doThat().andThat()* is very common in Jngen. You will see it when modifying objects 73 | (like sorting the array), dealing with output format (*printN* and *add1* here) or setting constraints for graphs generation. 74 | * [Printing](printers.md). All containers can be put to *cout* and usually are printed in a least-surprising way. For vector 75 | and Array it is just space-separated elements. Or newline-separated for 2D; it is smart! With chaining you can print your 76 | object in 1-numeration and prepend its size to it. 77 | 78 | ### On the margins 79 | You want [trees](tree.md)? [graphs](graph.md)? [convex polygons](geometry.md)? We have some, but this margin is too narrow to 80 | contain all of the examples. 81 | 82 | ```cpp 83 | int h, w; 84 | getPositional(h, w); // also a getOpt-like function 85 | auto a = Tree::bamboo(h); 86 | auto b = Tree::star(w); 87 | cout << a.link(0, b, 0).shuffled() << endl; 88 | 89 | cout << Graph::random(n, m).connected().allowMulti().printN().printM() << endl; 90 | 91 | Drawer d; 92 | d.polygon(rndg.convexPolygon(n, maxc)); 93 | d.dumpSvg("image.svg"); 94 | ``` 95 | 96 | I hope that this description and pieces of code helped you to understand how Jngen is supposed to be used. 97 | -------------------------------------------------------------------------------- /doc/graph.md: -------------------------------------------------------------------------------- 1 | ## Graph generation 2 | 3 | * [Generators](#generators) 4 | * [Modifiers](#modifiers) 5 | * [Graph methods](#graph-methods) 6 | 7 | This page is about *Graph* class and graph generators. To see the list of generic graphs methods please visit [this page](/generic_graph.md). 8 | 9 | The *Graph* class has several static methods to generate random and special graphs, like *random(n, m)* or *complete(n)*. The source of randomness is *rnd*. 10 | 11 | After calling a method you can add modifiers to allow or disallow loops, make graph connected etc. As you can see from the following example, *chaining* semantics is used. To support this semantics generation methods return not *Graph* itself but a special proxy class. To get a *Graph* itself, you may do one of the following: 12 | * call *.g()* method after modifiers chain: 13 | * cast the returned object to *Graph*; 14 | * or directly print the proxy class to the stream, in this case the generated graph will be printed. 15 | 16 | See the example for further clarifications. 17 | 18 | ```cpp 19 | auto g = Graph::random(10, 20).connected().allowMulti().g().shuffled(); 20 | Graph g2 = Graph::randomStretched(100, 200, 2, 5); 21 | cout << Graph::complete(5).allowLoops() << endl; 22 | ``` 23 | 24 | All graph generators return graph with sorted edges to make tests more human-readable. If you want to have your graph shuffled, use *.shuffle()* method, as in the example. 25 | 26 | ### Generators 27 | #### random(int n, int m) 28 | * Returns: a random graph with *n* vertices and *m* edges. 29 | * Available modifiers: *connected*, *allowLoops*, *allowMulti*, *directed*, *allowAntiparallel*, *acyclic*. 30 | 31 | #### complete(int n) 32 | * Returns: a complete graph with *n* vertices. If *directed* is specified, the direction of each edge is selected randomly, taking into account *allowAntiparallel* and *acyclic* flags. 33 | * Available modifiers: *allowLoops*, *directed*, *allowAntiparallel*, *acyclic*. 34 | 35 | #### cycle(int n) 36 | * Returns: a cycle with *n* vertices, connected in order. 37 | * Available modifiers: *directed*. 38 | 39 | #### empty(int n) 40 | * Returns: an empty graph with *n* vertices. 41 | * Available modifiers: *directed*. 42 | 43 | #### randomStretched(int n, int m, int elongation, int spread) 44 | * Returns: a connected stretched graph with *n* vertices and *m* vertices. 45 | * Available modifiers: *allowLoops*, *allowMulti*, *directed*, *allowAntiparallel*, *acyclic*. 46 | * Description: first a random tree on *n* vertices with given *elongation* (see [tree docs](/doc/tree.md)) is generated. Then remaining *m*-*n*+*1* edges are added. One endpoint of an edge is selected at random. The second is a result of jumping to a tree parent of the first endoint a random number of times, from 0 to *spread*, inclusive. 47 | * If the graph is directed, the direction of each edge is selected at random, unless it is acyclic: in this case the direction of all edges is down the tree. 48 | 49 | #### randomBipartite(int n1, int n2, int m) 50 | * Returns: a random bipartite graph with *n1* vertices in one part, *n2* vertices in another part and *m* edges. Vertices from *1* to *n1* belong to the first part. 51 | * Available modifiers: *connected*, *allowMulti*. 52 | 53 | #### completeBipartite(int n1, int n2) 54 | * Returns: a complet bipartite graph with *n1* vertices in one part and *n2* vertices in another part. Vertices from *1* to *n1* belong to the first part. 55 | * Available modifiers: none. 56 | 57 | ### Modifiers 58 | All options are unset by default. If the generator contradicts some option (like *randomStretched*, which always produces a connected graph), it is ignored. 59 | #### connected(bool value = true) 60 | * Action: force the generated graph to be connected. 61 | #### allowMulti(bool value = true) 62 | * Action: allow multiple edges in the generated graph (i.e. several edges with the same endpoints). 63 | #### allowLoops(bool value = true) 64 | * Action: allow loops in the generated graph (i.e. edges from a vertex to itself). 65 | #### directed(bool value = true) 66 | * Action: create a directed graph. 67 | #### allowAntiparallel(bool value = true) 68 | * Action: allow antiparallel edges (that is, edges u-v and v-u) in a directed graph. Ignored if *directed* is unset. 69 | #### acyclic(bool value = true) 70 | * Action: make the directed graph acyclic (DAG). Ignored if *directed* is unset. 71 | 72 | ### Graph methods 73 | #### Graph(int n) 74 | * Construct an empty graph with *n* vertices. 75 | #### void setN(int n) 76 | * Set the number of vertices of the graph to *n*. 77 | * Note: this operation cannot lessen the number of vertices. 78 | 79 | #### Graph& shuffle() 80 | #### Graph shuffled() const 81 | * Shuffle the graph. This means: 82 | * relabel vertices in random order; 83 | * shuffle edges; 84 | * randomly swap egdes' endpoints (for undirected graphs only). 85 | 86 | #### Graph& shuffleAllBut(const Array& except) 87 | #### Graph shuffledAllBut(const Array& except) 88 | * Same as *shuffle*, but vertices from *except* do not change their numbers. 89 | * Possible usecase: we may generate a graph where *s-t* path is supposed to be found. Then shuffle the graph in such a way that path endpoints are still *1* and *n*: 90 | ```cpp 91 | g = Graph::random(n, m)...; 92 | g.shuffleAllBut({0, n-1}); 93 | ``` 94 | -------------------------------------------------------------------------------- /doc/library_build.md: -------------------------------------------------------------------------------- 1 | ## Accelerating Jngen build 2 | 3 | Jngen is distributed as a single header. As the header is sufficiently large, compilation lasts fairly long. To speed it up you may use `JNGEN_DECLARE_ONLY` macro. 4 | 5 | Many functions in the library look like this: 6 | 7 | ```cpp 8 | #ifdef JNGEN_DECLARE_ONLY 9 | void doSomething(); 10 | #else 11 | void doSomething() { 12 | // crunching numbers 13 | } 14 | #endif 15 | ``` 16 | 17 | If `JNGEN_DECLARE_ONLY` is defined, the compiler expects to find the definitions in some other translation unit, otherwise the header is used standalone. When working with Jngen locally, you may create a static library which includes *jngen.h* and does nothing else, compile it with *g++ lib.cpp -c*, and then link your *main.cpp* with generated *lib.o*. If you add `#define JNGEN_DECLARE_ONLY` to the top of your *main.cpp* or specify `-DJNGEN_DECLARE_ONLY` flag in compiler options, function definitions will be taken from the static library and thus will be not recompiled every time. 18 | 19 | ```sh 20 | $ echo '#include "jngen.h"' > lib.cpp 21 | $ g++ -O2 -std=c++11 -Wall lib.cpp -c 22 | $ g++ -O2 -std=c++11 -Wall -DJNGEN_DECLARE_ONLY main.cpp lib.o 23 | ``` 24 | 25 | On the author's laptop this trick reduces compilation time by approximately 2.5 times. 26 | 27 | Note that if you use some other Jngen defines, like `JNGEN_EXTRA_WEIGHT_TYPES`, the library and your program must be compiled with the same set of defines. 28 | 29 | -------------------------------------------------------------------------------- /doc/math.md: -------------------------------------------------------------------------------- 1 | ## Math-ish primitives 2 | 3 | Jngen provides several free functions and a generator class *MathRandom* to help generating numbers and combinatorial primitives. All interaction with *MathRandom* goes via its global instance called *rndm*. The source of randomness is *rnd*. 4 | 5 | ### Standalone functions 6 | 7 | #### bool isPrime(long long n) 8 | * Returns: true if *n* is prime, false otherwise. 9 | * Supported for all *n* from 1 to 3.8e18. 10 | * Implemented with deterministic variation of the Miller-Rabin primality test so should work relatively fast (exact benchmark here). 11 | 12 | ### MathRandom methods 13 | 14 | #### long long randomPrime(long long n) 15 | #### long long randomPrime(long long l, long long r) 16 | * Returns: random prime in range *[2, n)* or *[l, r]* respectively. 17 | * Throws if no prime is found on the interval. 18 | 19 | #### long long nextPrime(long long n) 20 | #### long long previousPrime(long long n) 21 | * Returns: the first prime larger (or smaller) than *n*, including *n*. 22 | 23 | #### Array partition(int n, int numParts, int minSize = 0, int maxSize = -1) 24 | * Returns: a random ordered partition of *n* into *numParts* parts, where the size of each part is between *minSize* and *maxSize*. If *maxSize* is *-1* (the default value) then sizes can be arbitrary large. 25 | 26 | #### template<typename T>
TArray<TArray<T>> partition(TArray<T> elements, int numParts, int minSize = 0, int maxSize = -1) 27 | * Returns: a random partition of the array *elements* into *numParts* parts. 28 | 29 | #### template<typename T>
TArray<TArray<T>> partition(TArray<T> elements, const Array& sizes) 30 | * Returns: a random partition of the array *elements* into parts, where the size of each part is specified. 31 | * Note: sum(*sizes*) must be equal to *elements.size()*. 32 | -------------------------------------------------------------------------------- /doc/overview.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | Jngen is a library which helps you to generate standard objects for competitive problems: trees, graphs, strings and so. For some objects it defines classes (like *Array*, *Graph* or *Point*), for others STL is used (*std::string*). 4 | 5 | 6 | 7 | There are two ways of generating objects. The first is with static methods of the class. 8 | 9 | ```cpp 10 | auto a = Array::random(n, maxSize); 11 | auto t = Tree::bamboo(n); 12 | ``` 13 | 14 | [Arrays](array.md), [trees](tree.md) and [graphs](graph.md) are generated like this. 15 | 16 | The second uses helper objects. 17 | 18 | 19 | ```cpp 20 | auto polygon = rndg.convexPolygon(n, maxCoordinate); 21 | auto stringPair = rnds.antiHash({{1000000007, 101}, {1000000009, 211}}, "a-z", 10000); 22 | int p = rndm.randomPrime(100, int(1e9)); 23 | ``` 24 | 25 | [Strings](strings.md), [geometric primitives](geometry.md), [primes and partitions](math.md) and simply [random numbers](random.md) are generated with such helpers. 26 | 27 | For each Jngen object there are operators for printing to streams. There are modifiers which allow, for example, to switch between 0- and 1-indexation. Also Jngen allows printing standard containers like vectors and pairs. See section [printers](printers.md). 28 | 29 | ```cpp 30 | cout << std::vector{1, 2, 3} << endl; 31 | cout << Array::id(5).shuffled().printN().add1() << endl; 32 | --- 33 | 1 2 3 34 | 5 35 | 5 2 4 3 1 36 | ``` 37 | 38 | The library also supplies a [command-line arguments parser](getopt.md) and a [tool for drawing geometric primitives](drawer.md). 39 | 40 | Jngen is large, its compilation lasts for several seconds. It is possible to make it faster with precompiling a part of it. See [this chapter](library_build.md) for manual. 41 | 42 | If you want to learn more about Jngen, please see all the docs listed at the [reference](/README.md#reference) section. Good luck! 43 | -------------------------------------------------------------------------------- /doc/pics/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifsmirnov/jngen/8d1e33be29d6c38d7e0777c54fc380d5084e6105/doc/pics/img1.png -------------------------------------------------------------------------------- /doc/pics/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifsmirnov/jngen/8d1e33be29d6c38d7e0777c54fc380d5084e6105/doc/pics/img2.png -------------------------------------------------------------------------------- /doc/pics/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifsmirnov/jngen/8d1e33be29d6c38d7e0777c54fc380d5084e6105/doc/pics/img3.png -------------------------------------------------------------------------------- /doc/pics/img3.svg: -------------------------------------------------------------------------------- 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 | 0 40 | 50 41 | 100 42 | 150 43 | 0 44 | 50 45 | 100 46 | 150 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /doc/pics/src1.cpp: -------------------------------------------------------------------------------- 1 | // #define JNGEN_DECLARE_ONLY 2 | #include "drawer/drawer.h" 3 | #include "geometry.h" 4 | #include "options.h" 5 | #include 6 | #include 7 | using namespace std; 8 | #define forn(i, n) for (int i = 0; i < int(n); ++i) 9 | 10 | int main(int argc, char *argv[]) { 11 | (void)argc, (void)argv; 12 | parseArgs(argc, argv); 13 | 14 | Drawer d; 15 | 16 | int n = 6; 17 | double R = 10; 18 | TArray pts; 19 | double pi = acos(-1.0); 20 | for (int i = 0; i < n; ++i) { 21 | double sina = sin(2 * pi * i / n); 22 | double cosa = cos(2 * pi * i / n); 23 | pts.emplace_back(cosa * R, sina * R); 24 | } 25 | 26 | pts.shuffle(); 27 | 28 | for (int i = 0; i < n; ++i) { 29 | for (int j = 0; j < n; ++j) { 30 | if (i < 3 && j < 3) { 31 | d.setWidth(2); 32 | d.setColor("red"); 33 | } else { 34 | d.setWidth(1); 35 | d.setColor(rnd.next(2) ? "red" : "blue"); 36 | } 37 | d.segment(pts[i], pts[j]); 38 | } 39 | } 40 | 41 | d.setFill("green"); 42 | d.setStroke("black"); 43 | d.setWidth(1); 44 | 45 | for (auto pt: pts) { 46 | d.circle(pt, 1); 47 | } 48 | 49 | d.dumpSvg("image.svg"); 50 | } 51 | -------------------------------------------------------------------------------- /doc/pics/src2.cpp: -------------------------------------------------------------------------------- 1 | // #define JNGEN_DECLARE_ONLY 2 | #include "drawer/drawer.h" 3 | #include "geometry.h" 4 | #include "options.h" 5 | #include 6 | #include 7 | using namespace std; 8 | #define forn(i, n) for (int i = 0; i < int(n); ++i) 9 | 10 | int main(int argc, char *argv[]) { 11 | (void)argc, (void)argv; 12 | parseArgs(argc, argv); 13 | 14 | Drawer d; 15 | 16 | int n = 40; 17 | 18 | d.setStroke("blue"); 19 | 20 | for (int i = 0; i < n; ++i) { 21 | d.setOpacity(1.0 * i / n); 22 | d.circle(i * 2, 0, i); 23 | } 24 | 25 | d.dumpSvg("image.svg"); 26 | } 27 | -------------------------------------------------------------------------------- /doc/pics/src3.cpp: -------------------------------------------------------------------------------- 1 | // #define JNGEN_DECLARE_ONLY 2 | #include "drawer/drawer.h" 3 | #include "geometry.h" 4 | #include "options.h" 5 | #include "rnda.h" 6 | #include 7 | #include 8 | using namespace std; 9 | #define forn(i, n) for (int i = 0; i < int(n); ++i) 10 | 11 | int main(int argc, char *argv[]) { 12 | (void)argc, (void)argv; 13 | parseArgs(argc, argv); 14 | 15 | Drawer d; 16 | 17 | int k = 5; 18 | int n = 8; 19 | int C = 150; 20 | int sz = 45; 21 | 22 | auto polygons = rnda.randomf(k, [n, C, sz] () { 23 | auto pt = rndg.point(C, C); 24 | auto poly = rndg.convexPolygon(n, sz, sz).shifted(pt); 25 | return poly; 26 | }); 27 | 28 | for (const auto& t: polygons) { 29 | d.setFill(choice({"green", "red", "blue"})); 30 | d.polygon(t); 31 | } 32 | 33 | d.dumpSvg("image.svg"); 34 | } 35 | -------------------------------------------------------------------------------- /doc/printers.md: -------------------------------------------------------------------------------- 1 | ## Printing to ostreams 2 | 3 | Tired of writing `cout << a[i] << " \n"[i+1 == n]`? We have a solution! Jngen declares ostream operators for all standard containers. Moreover, for Jngen containers there is a bunch of output modifiers which can toggle 0/1 numeration, automatically print the size of the array and something else. 4 | 5 | ### Outline 6 | As a quick start, try to write something like 7 | ```cpp 8 | cout << Array::random(5, 5) << endl; 9 | cout << Arrayp::random(2, 10) << endl; 10 | --- 11 | 3 1 1 0 4 12 | 5 9 13 | 8 8 14 | ``` 15 | 16 | Or even 17 | ```cpp 18 | vector a{0, 1, 2}; 19 | pair p{"hello", 4.2}; 20 | cout << a << endl; 21 | cout << p << endl; 22 | --- 23 | 0 1 2 24 | hello 4.2 25 | ``` 26 | Containers are printed in a least surprising way: sequences are separated with single spaces, sequences of pairs -- with line breaks, sequences of sequences are formatted as matrices. If you print a graph, it first prints *n* and *m* on the first line (if corresponding modifiers are set, see later), then, if present, a line of vertex weights, then *m* lines with edges in a most standard format. 27 | 28 | Now a word about modifiers. C++ programmers are used to 0-indexing, while in problem statements usually arises 1-indexing. There is a *quick fix*, which at first glance looks as a dirty hack but later appears to be very convenient. Look how to output a random 1-indexed permutation: 29 | ```cpp 30 | cout << Array::id(5).shuffled().add1().printN() << endl; 31 | --- 32 | 5 33 | 1 4 2 5 3 34 | ``` 35 | These *add1()* and *printN()* are called *output modifiers*. These modifiers can be applied to any container provided by Jngen, such as Array, Graph and Tree. If you want to use modifiers with other types (like std::vector or even int), you can do it like this: 36 | ```cpp 37 | vector a{1, 2, 3}; 38 | cout << repr(a).endl() << endl; 39 | --- 40 | 1 41 | 2 42 | 3 43 | ``` 44 | 45 | ### Global modifier 46 | Sometimes it may be more convenient to set modifiers once for the entire program. This can be done as following: 47 | ```cpp 48 | setMod().printN().add1(); 49 | // now printN() and add1() modifiers apply to everything being printed 50 | setMod().reset(); 51 | // global modifier has returned to default state, you should specify local modifiers manually 52 | ``` 53 | 54 | Note that Jngen does not interact with stl-defined operators. That mean that writing `cout << 123 << endl;` will print *123* regardless of which global modifiers are set. However, printing a std::vector **will** use global modifiers. 55 | 56 | ### Modifiers 57 | #### add1(bool value = true) 58 | * Action: adds 1 to each integer being output, **except for vertex/edge weights in graphs**. 59 | * Default: unset. 60 | #### printN(bool value = true) 61 | * Action: print array size on a separate line before the array. Print number of vertices of a graph. 62 | * Default: unset. 63 | #### printM(bool value = true) 64 | * Action: print number of edges of a graph. 65 | * Default: unset. 66 | #### printEdges(bool value = true) 67 | * Action: when printing a tree, print a list of edges. 68 | * Default: set. 69 | #### printParents(int value = -1) 70 | * Action: when printing a tree, print a parent of each vertex. Opposite to *printEdges*. 71 | * Arguments: *value* stands for the root of the tree. If *value* is *0* or greater, then the parent of each vertex is printed, having root's parent as 72 | *-1* (*0* if *add1()* is present). *value = -1* is a special value: in this case tree is rooted at *0* and its parent is not printed (printing *n-1* values in total). 73 | * Note: this option and *printEdges* cancel each other. 74 | #### endl(bool value = true) 75 | * Action: separate elements of the array with line breaks instead of spaces. 76 | * Default: unset. 77 | -------------------------------------------------------------------------------- /doc/random.md: -------------------------------------------------------------------------------- 1 | ## Random numbers generation 2 | 3 | Jngen provides a class *Random* whose behavior is similar to *rnd* from testlib.h. E.g. you may write *rnd.next(100)*, *rnd.next("[a-z]{%d}", n)*, and so on. Most of interaction with *Random* happens via its global instance of *Random* called *rnd*. 4 | 5 | Default initialized *Random* is seeded with some hardware-generated random value, so subsequent executions of the program will produce different tests. This may be useful for local stress-testing, for example. If you want to fix the seed, use *registerGen(argc, argv)* at the beginning of your *main*. 6 | 7 | ### Generation 8 | 9 | #### uint32_t next() 10 | * Returns: random integer in range [0, 2^32). 11 | #### uint64_t next64() 12 | * Returns: random integer in range [0, 2^64). 13 | #### double nextf() 14 | * Returns: random real in range [0, 1). 15 | #### int next(int n) // also for long long, size\_t, double 16 | * Returns: random integer in range [0, n). 17 | #### int next(int l, int r) // also for long long, size\_t, double 18 | * Returns: random integer in range [l, r]. 19 | #### int wnext(int n, int w) // also for long long, size\_t, double 20 | * If w > 0, returns max(next(n), ..., next(n)) (w times). If w < 0, returns min(next(n), ..., next(n)) (-w times). If w = 0, same as next(n). 21 | #### int wnext(int l, int r, int w) // also for long long, size\_t, double 22 | * Same as wnext(n, w), but the range is [l, r]. 23 | #### std::string next(const std::string& pattern) 24 | * Should be compatible with testlib.h. 25 | * Returns: random string matching regex *pattern*. 26 | * Regex has the following features: 27 | * any single character yields itself; 28 | * a set of characters inside square braces (*[abc123]*) yields random of them; 29 | * character ranges are allowed inside square braces (*[a-z1-9]*); 30 | * pattern followed by *{n}* is the same as the pattern repeated *n* times; 31 | * pattern followed by *{l,r}* is the same as the pattern repeated random number of times from *l* to *r*, inclusive; 32 | * "|" character yields either a pattern to its left or the pattern to its right equiprobably; 33 | * several "|" characters between patterns yield any pattern between them equiprobably, e.g. *(a|b|c|z){100}* yields a string of length 100 with almost equal number of *a*'s, *b*'s, *c*'s and *z*'s; 34 | * parentheses "()" are used for grouping. 35 | * examples: 36 | * `rnd.next("[1-9][0-9]{1,2}")`: random 2- or 3-digit number (note that the distribution on numbers is not uniform); 37 | * `rnd.next("a{10}{10}{10}")`: 1000 *a*'s; 38 | * `rnd.next("(ab|ba){10}|c{15}")`: either 15 *c*'s or a string of length 20 consisting of *ab*'s and *ba*'s. 39 | #### std::string next(const std::string& pattern, ...) 40 | * Same as rnd.next(pattern), but pattern interpreted as printf-like format string. 41 | #### template<typename T, typename ...Args>
tnext(Args... args) 42 | * Calls *next(args...)*, forcing the return type to be *T* and casting arguments appropriately. E.g. *tnext<int>(2.5, 10.1)* is equivalent to *rnd.next(2, 10)*, where both arguments are ints. 43 | * Name origin: *typed* next. 44 | #### std::pair<int, int> nextp(int n, [RandomPairTraits]) 45 | #### std::pair<int, int> nextp(int l, int r, [RandomPairTraits]) 46 | * Returns: random pair of integers, where both of them are in range [0, *n*) or [*l*, *r*] respectively. 47 | * RandomPairTraits denotes if the pair should be ordered (first element is less than or equal to second one) and if its two elements should be distinct. Several global constants are defined: 48 | * *opair*: ordered pair (first <= second) 49 | * *dpair*: distinct pair (first != second) 50 | * *odpair*, *dopair*: ordered distinct pair 51 | * Example of usage: *rnd.nextp(1, 10, odpair)* yields a pair of random integers from 1 to 10 where first is strictly less than second. *rnd.nextp(1, 10)* returns any pair of integers from 1 to 10 (note that the *RandomPairTraits* argument is optional). 52 | #### template<typename Iterator>
Iterator::value_type choice(Iterator begin, Iterator end) 53 | #### template<typename Container>
Container::value_type choice(const Container& container) 54 | * Returns: random element of a range or of a container, respectively. 55 | * Note: *Container* may be *any* STL container, including *std::set*. In general case the runtime of this function is *O(container.size())*. However, if *Iterator* is a random-access iterator, the runtime is constant. 56 | 57 | #### template<typename N>
size_t nextByDistribution(const std::vector<N>& distribution) 58 | * Returns: a random integer from *0* to *distribution.size() - 1*, where probability of *i* is proportional to *distribution[i]. 59 | * Example: *rnd.nextByDistribution({1, 1, 100})* will likely return 2, but roughly each 50-th iteration will return 0 or 1. 60 | 61 | ### Seeding 62 | #### void seed(uint32_t seed) 63 | #### void seed(const std::vector<uint32_t>& seed) 64 | * Seed the generator with appropriate values. It is guaranteed that after identical *seed* calls the generator produces the same sequence of values. 65 | 66 | ### Related free functions 67 | #### void registerGen(int argc, char* argv[], [int version]) 68 | * Seed the generator using command-line options. Different options will likely result in different generator states. The behavior is similar to the one of testlib.h. 69 | * Note: parameter *version* is optional and is introduced only for compatibility with testlib.h. 70 | -------------------------------------------------------------------------------- /doc/strings.md: -------------------------------------------------------------------------------- 1 | ## Strings 2 | 3 | Strings are generated with the help of *StringRandom* class. As usual, you should interact with it via its global instance *rnds*. 4 | 5 | ### Generators (*rnds* static methods) 6 | #### std::string random(int len, const std::string& alphabet = "a-z") 7 | * Returns: random string of length *len* made of characters from *alphabet*. 8 | * Note: *alphabet* can contain single chars and groups of form *A-Z*. For example, *"0-9abcdefA-F"* includes all hexadecimal characters. 9 | 10 | #### std::string random(const std::string& pattern, ...) 11 | * Returns: a random string generated by *pattern*. 12 | * Equivalent to *rnd.next(pattern, ...)*; see [docs on Random](random.md) for detailed description. 13 | 14 | #### std::string thueMorse(int len, char first = 'a', char second = 'b') 15 | * Returns: a prefix of length *n* of the Thue-Morse string made of *first* and *second* characters. 16 | * Description: Thue-Morse string is a string of kind 0110100110010110.... That is, start from 0 and on each step concatenate the string to itself exchanging zeroes and ones. 17 | * Note: this string is useful for breaking hashes modulo 264. Strings *thueMorse(n, x, y)* and *thueMorse(n, y, x)* will have identical polynomial hash for any base for *n* ≥ 2048. 18 | 19 | #### std::string abacaba(int len, char first = 'a') 20 | * Returns: a prefix of length *n* of the string of form *abacabadabacaba...* starting with character *first*. 21 | 22 | #### std::pair<std::string, std::string> antiHash(
  const std::vector<std::pair<long long, long long>>& bases,
  const std::string& alphabet = "a-z",
  int length = -1) 23 | * Returns: a pair of different strings of length *length* (or minimal found if *length* is -1) with the same polynomial hash for specified bases. 24 | * Parameters: 25 | * *bases*: vector of pairs (mod, base); 26 | * *alphabet*: the same as in *random(len, alphabet)*; 27 | * *length*: length of resulting strings, or *-1* if the shortest found result is needed. 28 | * Note: mod must not exceed 2\*109. Also, you cannot specify more than two pairs (mod, base). 29 | * Complexity and result size: for two mods around 2\*109 generation runs for about 3 seconds and produces strings of length approximately 100-200. A faster version of the algorithm will be presented later. 30 | * Example: 31 | ```cpp 32 | int mod1 = rndm.randomPrime(1999000000, 2000000000); 33 | int mod2 = rndm.randomPrime(1999000000, 2000000000); 34 | int base1 = rnd.next(2000, 10000) * 2 + 1; 35 | int base2 = rnd.next(2000, 10000) * 2 + 1; 36 | 37 | auto res = rnds.antiHash( {{mod1, base1}, {mod2, base2}}, "a-z", -1); 38 | cout << res.first << "\n" << res.second << "\n"; 39 | 40 | // or simply 41 | cout << rnds.antiHash({{1000000007, 107}, {1000000009, 109}}) << "\n"; 42 | ``` 43 | -------------------------------------------------------------------------------- /doc/tree.md: -------------------------------------------------------------------------------- 1 | ## Trees generation 2 | 3 | Jngen provides a *Tree* class. It offers some methods to manipulate with trees and static generators. As other Jngen objects, *Tree* can be printed to *std::ostream*. Here is a standard way to use generators: 4 | 5 | ```cpp 6 | cout << Tree::random(100).shuffled() << endl; 7 | ``` 8 | 9 | ### Generators 10 | Note that all generators return trees with sorted edges to make tests more human-readable. More, numbering is not always random for same reason. Particularly, *Tree::random(size, elongation)* always returns a tree rooted at 0. You can always use *tree.shuffle()* to renumerate vertices and shuffle edges. 11 | 12 | #### random(int size) 13 | * Returns: a completely random tree, selected uniformly over all nn-2 trees. Name comes from the fact that this generator exploits Prüfer sequences. 14 | 15 | #### randomPrim(int size, int elongation = 0) 16 | * Returns: a random tree with given elongation built with Prim-like process. The most classical tree generator ever. 17 | * Description: first, vertex no. 0 is selected as a root. Next, for each vertex from 1 to n-1 its parent is selected as *wnext(i, elongation)*. With *elongation = -1000000* you will likely get a star, with *elongation = 1000000* -- a bamboo (a path). 18 | 19 | #### randomKruskal(int size) 20 | * Returns: a random tree built with a Kruskal-like process. 21 | * Description: uniformly random edges are added one by one. The edge is added if it doesn't introduce a cycle. 22 | 23 | #### bamboo(int size) 24 | * Returns: a bamboo (or a path) of a kind 0 -- 1 -- ... -- n-1. 25 | 26 | #### star(int size) 27 | * Returns: a star graph with *size* vertices and vertex no. 0 in the center. Central vertex is counted, i.e. there are *size - 1* leaf vertices in general case. 28 | 29 | #### caterpillar(int size, int length) 30 | * Returns: a caterpillar tree with *size* vertices based on a path of length *length*. 31 | * Description: first, a path of length *length* is generated. Vertices of the path are numbered in order. Next, other *size - length* vertices are connected to random vertices of the path. 32 | 33 | #### Tree binary(int size) 34 | * Returns: a complete binary tree with *size* vertices. 35 | * Numeration: parent of vertex *i* is *(i-1)/2*, *0* is root. 36 | 37 | #### Tree kary(int size, int k) 38 | * Returns: a complete *k*-ary tree with *size* vertices. 39 | * Numeration: parent of vertex *i* is *(i-1)/k*, *0* is root. 40 | 41 | #### Tree fromPruferSequence(const Array& code) 42 | * Returns: a tree with given [Prüfer sequence](https://en.wikipedia.org/wiki/Pr%C3%BCfer_sequence). The tree contains *code.size() + 2* vertices. 43 | 44 | ### Tree methods 45 | 46 | #### Tree& shuffle() 47 | #### Tree shuffled() const 48 | * Shuffle the tree. This means: 49 | * relabel vertices in random order; 50 | * shuffle edges; 51 | * randomly swap egdes' endpoints. 52 | 53 | #### Tree& shuffleAllBut(const Array& except) 54 | #### Tree shuffledAllBut(const Array& except) 55 | * Same as *shuffle*, but vertices from *except* do not change their numbers. 56 | * Possible usecase: we may generate a rooted tree and shuffle it in such a way that root still has number *1*. 57 | ```cpp 58 | t = Tree::randomPrim(n, 1000); 59 | t.shuffleAllBut({0}); 60 | ``` 61 | 62 | #### Array parents(int root) const 63 | * Returns: array of size *n*, where *i*-th element is a parent of vertex *i* if the tree is rooted at *root*. Parent of *root* is *-1*. 64 | 65 | #### Tree link(int vInThis, const Tree& other, int vInOther) 66 | * Returns: a tree made of _*this_ and *other*, with an extra edge between two vertices with ids *vInThis* and *vInOther*, respectively. 67 | * Labeling: labels of the source tree are unchanged, labels of the other tree are increased by the number of vertices in source. Edges are ordered like "source edges, other edges, new edge". 68 | 69 | #### Tree glue(int vInThis, const Tree& other, int vInOther) 70 | * Returns: a tree made of _*this_ and *other*, where vertices *vInThis* and *vInOther* are glued into one. 71 | * Labeling: labels of the source tree are unchanged, vertices of the other tree are renumbered in order starting with the number of vertices in source, except for *vInOther*. 72 | -------------------------------------------------------------------------------- /drawer/drawing_engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace jngen { 9 | namespace drawing { 10 | 11 | using Color = std::string; 12 | 13 | struct DrawingEngineState { 14 | double width; 15 | Color stroke; 16 | Color fill; 17 | double opacity; 18 | }; 19 | 20 | class DrawingEngine { 21 | public: 22 | DrawingEngine() {} 23 | virtual ~DrawingEngine() {} 24 | 25 | virtual void drawPoint(double x, double y) = 0; 26 | virtual void drawCircle(double x, double y, double r) = 0; 27 | virtual void drawSegment(double x1, double y1, double x2, double y2) = 0; 28 | virtual void drawPolygon( 29 | const std::vector>& vertices) = 0; 30 | virtual void drawText( 31 | double x, double y, const std::string& s) = 0; 32 | 33 | virtual void setWidth(double width) = 0; 34 | virtual void setStroke(Color color) = 0; 35 | virtual void setFill(Color color) = 0; 36 | virtual void setOpacity(double opacity) = 0; 37 | 38 | virtual double width() const = 0; 39 | virtual Color stroke() const = 0; 40 | virtual Color fill() const = 0; 41 | virtual double opacity() const = 0; 42 | 43 | DrawingEngineState saveState() { 44 | return { width(), stroke(), fill(), opacity() }; 45 | } 46 | 47 | void restoreState(const DrawingEngineState& state) { 48 | setWidth(state.width); 49 | setStroke(state.stroke); 50 | setFill(state.fill); 51 | setOpacity(state.opacity); 52 | } 53 | }; 54 | 55 | }} // namespace jngen::drawing 56 | -------------------------------------------------------------------------------- /drawer/svg_engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "drawing_engine.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace jngen { 9 | namespace drawing { 10 | 11 | class SvgEngine : public DrawingEngine { 12 | public: 13 | SvgEngine(double x1 = 0, double y1 = 0, double x2 = 50, double y2 = 50); 14 | 15 | virtual ~SvgEngine() {} 16 | 17 | virtual void drawPoint(double x, double y) override; 18 | virtual void drawCircle(double x, double y, double r) override; 19 | virtual void drawSegment( 20 | double x1, double y1, double x2, double y2) override; 21 | virtual void drawPolygon( 22 | const std::vector>& vertices) override; 23 | virtual void drawText( 24 | double x, double y, const std::string& s) override; 25 | 26 | virtual void setWidth(double width) override; 27 | virtual void setStroke(Color color) override; 28 | virtual void setFill(Color color) override; 29 | virtual void setOpacity(double opacity) override; 30 | 31 | virtual double width() const override { return width_; } 32 | virtual Color stroke() const override { return strokeColor_; } 33 | virtual Color fill() const override { return fillColor_; } 34 | virtual double opacity() const override { return opacity_; } 35 | 36 | std::string serialize() const; 37 | 38 | private: 39 | double lerpX(double x) const; 40 | double lerpY(double y) const; 41 | double scaleSize(double size) const; 42 | 43 | std::string getStyle() const; 44 | 45 | std::ostringstream output_; 46 | 47 | double width_; 48 | Color strokeColor_; 49 | Color fillColor_; 50 | double opacity_; 51 | 52 | double x1_, y1_, x2_, y2_; // borders 53 | }; 54 | 55 | }} // namespace jngen::drawing 56 | 57 | #ifndef JNGEN_DECLARE_ONLY 58 | #define JNGEN_INCLUDE_SVG_ENGINE_INL_H 59 | #include "svg_engine_inl.h" 60 | #undef JNGEN_INCLUDE_SVG_ENGINE_INL_H 61 | #endif // JNGEN_DECLARE_ONLY 62 | -------------------------------------------------------------------------------- /drawer/svg_engine_inl.h: -------------------------------------------------------------------------------- 1 | #ifndef JNGEN_INCLUDE_SVG_ENGINE_INL_H 2 | #error File "svg_engine_inl.h" must not be included directly. 3 | #endif 4 | 5 | #include 6 | #include 7 | 8 | namespace jngen { 9 | namespace drawing { 10 | 11 | static char buf[10000]; 12 | constexpr static double WIDTH_SCALE = 8; 13 | constexpr static double CANVAS_SIZE = 2000; 14 | constexpr static int FONT_SIZE = 64; 15 | 16 | namespace { 17 | 18 | const char* colorToString(const Color& color) { 19 | const static char* NONE = "none"; 20 | if (color.empty()) { 21 | return NONE; 22 | } 23 | return color.c_str(); 24 | } 25 | 26 | // Given x \in [l, r], return linear interpolation to [L, R] 27 | double lerp(double x, double l, double r, double L, double R) { 28 | return L + (R - L) * ((x - l) / (r - l)); 29 | } 30 | 31 | } // namespace 32 | 33 | SvgEngine::SvgEngine(double x1, double y1, double x2, double y2) : 34 | width_(1.0), 35 | opacity_(1.0), 36 | x1_(x1), 37 | y1_(y1), 38 | x2_(x2), 39 | y2_(y2) 40 | { } 41 | 42 | void SvgEngine::drawPoint(double x, double y) { 43 | x = lerpX(x); 44 | y = lerpY(y); 45 | double w = width_ * WIDTH_SCALE * 1.5; 46 | std::sprintf( 47 | buf, 48 | "", 49 | x, y, w, colorToString(strokeColor_), opacity_ 50 | ); 51 | output_ << buf << "\n"; 52 | } 53 | 54 | void SvgEngine::drawCircle(double x, double y, double r) { 55 | x = lerpX(x); 56 | y = lerpY(y); 57 | r = scaleSize(r); 58 | std::sprintf( 59 | buf, 60 | "", 61 | x, y, r, getStyle().c_str() 62 | ); 63 | output_ << buf << "\n"; 64 | } 65 | 66 | void SvgEngine::drawPolygon( 67 | const std::vector>& points) 68 | { 69 | output_ << "\n"; 74 | } 75 | 76 | void SvgEngine::drawSegment( 77 | double x1, double y1, double x2, double y2) 78 | { 79 | x1 = lerpX(x1); 80 | y1 = lerpY(y1); 81 | x2 = lerpX(x2); 82 | y2 = lerpY(y2); 83 | if (std::fabs(x1 - x2) < 1e-9) { 84 | x1 = std::round(x1); 85 | x2 = std::round(x2); 86 | } 87 | if (std::fabs(y1 - y2) < 1e-9) { 88 | y1 = std::round(y1); 89 | y2 = std::round(y2); 90 | } 91 | std::sprintf( 92 | buf, 93 | "", 94 | x1, y1, x2, y2, getStyle().c_str() 95 | ); 96 | output_ << buf << "\n"; 97 | } 98 | 99 | void SvgEngine::drawText( 100 | double x, double y, const std::string& s) 101 | { 102 | x = std::round(lerpX(x)); 103 | y = std::round(lerpY(y)); 104 | std::sprintf( 105 | buf, 106 | "%s", 107 | x, y, FONT_SIZE, s.c_str() 108 | ); 109 | output_ << buf << "\n"; 110 | } 111 | 112 | void SvgEngine::setWidth(double width) { 113 | width_ = width; 114 | } 115 | 116 | void SvgEngine::setStroke(Color color) { 117 | strokeColor_ = color; 118 | } 119 | 120 | void SvgEngine::setFill(Color color) { 121 | fillColor_ = color; 122 | } 123 | 124 | void SvgEngine::setOpacity(double opacity) { 125 | opacity_ = opacity; 126 | } 127 | 128 | std::string SvgEngine::serialize() const { 129 | int offset = std::sprintf( 130 | buf, 131 | "\n", 133 | 0.0, 0.0, CANVAS_SIZE, CANVAS_SIZE * (y2_ - y1_) / (x2_ - x1_) 134 | ); 135 | std::sprintf( 136 | buf + offset, 137 | "\n", 138 | CANVAS_SIZE/2, CANVAS_SIZE/2, 139 | std::hypot(CANVAS_SIZE, CANVAS_SIZE * (y2_ - y1_) / (x2_ - x1_)) 140 | ); 141 | 142 | return buf + output_.str() + "\n"; 143 | } 144 | 145 | double SvgEngine::lerpX(double x) const { 146 | return lerp(x, x1_, x2_, 0., CANVAS_SIZE); 147 | } 148 | 149 | double SvgEngine::lerpY(double y) const { 150 | return lerp(y, y2_, y1_, 0., CANVAS_SIZE * (y2_ - y1_) / (x2_ - x1_)); 151 | } 152 | 153 | double SvgEngine::scaleSize(double size) const { 154 | return size * CANVAS_SIZE / (x2_ - x1_); 155 | } 156 | 157 | std::string SvgEngine::getStyle() const { 158 | static char buf[1024]; 159 | std::sprintf( 160 | buf, 161 | "stroke-width:%f;stroke:%s;fill:%s;opacity:%f", 162 | width_ * WIDTH_SCALE, 163 | colorToString(strokeColor_), 164 | colorToString(fillColor_), 165 | opacity_ 166 | ); 167 | return buf; 168 | } 169 | 170 | }} // namespace jngen::drawing 171 | 172 | -------------------------------------------------------------------------------- /dsu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace jngen { 7 | 8 | class Dsu { 9 | public: 10 | int getRoot(int x); 11 | 12 | bool unite(int x, int y); 13 | 14 | bool isConnected() const { return components <= 1; } 15 | 16 | int numComponents() const { return components; } 17 | 18 | void extend(size_t size); 19 | 20 | private: 21 | std::vector parent; 22 | std::vector rank; 23 | 24 | int components = 0; 25 | }; 26 | 27 | #ifndef JNGEN_DECLARE_ONLY 28 | 29 | int Dsu::getRoot(int x) { 30 | extend(x); 31 | 32 | return parent[x] == x ? x : (parent[x] = getRoot(parent[x])); 33 | } 34 | 35 | bool Dsu::unite(int x, int y) { 36 | extend(std::max(x, y) + 1); 37 | 38 | x = getRoot(x); 39 | y = getRoot(y); 40 | if (x == y) { 41 | return false; 42 | } 43 | 44 | if (rank[x] > rank[y]) { 45 | std::swap(x, y); 46 | } 47 | if (rank[y] == rank[x]) { 48 | ++rank[y]; 49 | } 50 | parent[x] = y; 51 | 52 | --components; 53 | 54 | return true; 55 | } 56 | 57 | void Dsu::extend(size_t x) { 58 | size_t last = parent.size() - 1; 59 | while (parent.size() < x) { 60 | ++components; 61 | parent.push_back(++last); 62 | rank.push_back(0); 63 | } 64 | } 65 | 66 | #endif // JNGEN_DECLARE_ONLY 67 | 68 | } // namespace jngen 69 | -------------------------------------------------------------------------------- /examples/786D.cpp: -------------------------------------------------------------------------------- 1 | #include "jngen.h" 2 | using namespace std; 3 | 4 | // http://codeforces.com/contest/786/problem/D 5 | // tree with a letter on each edge, then pairs of distinct vertices 6 | // run as ./main n, m [-elong=...] 7 | int main(int argc, char *argv[]) { 8 | registerGen(argc, argv); 9 | parseArgs(argc, argv); 10 | 11 | int n = getOpt(0); 12 | int q = getOpt(1); 13 | int elong = getOpt("elong", 0); 14 | 15 | cout << n << " " << q << "\n"; 16 | auto t = Tree::randomPrim(n, elong).shuffled(); 17 | t.setEdgeWeights(TArray::random(n - 1, 'a', 'z')); 18 | cout << t.add1() << "\n"; 19 | cout << Arrayp::random(q, 1, n, dpair) << "\n"; 20 | } 21 | -------------------------------------------------------------------------------- /examples/even-odd.cpp: -------------------------------------------------------------------------------- 1 | #include "jngen.h" 2 | #include 3 | using namespace std; 4 | #define forn(i, n) for (int i = 0; i < (int)(n); ++i) 5 | 6 | #define se second 7 | #define fi first 8 | 9 | Graph connectedBipartite(int n, int m) { 10 | Tree t = Tree::random(n); 11 | vector q{0}; 12 | vector col(n, -1); 13 | col[0] = 0; 14 | Array bc[2]; 15 | bc[0] = {0}; 16 | forn(i, n) { 17 | int v = q[i]; 18 | for (int to: t.edges(v)) { 19 | if (col[to] == -1) { 20 | col[to] = !col[v]; 21 | bc[col[to]].push_back(to); 22 | q.push_back(to); 23 | } 24 | } 25 | } 26 | m = min((long long)m, 1ll * bc[0].size() * bc[1].size()); 27 | auto treeEdges = t.edges(); 28 | Graph g(t); 29 | set> edges(treeEdges.begin(), treeEdges.end()); 30 | while ((int)edges.size() != m) { 31 | int u = bc[0].choice(); 32 | int v = bc[1].choice(); 33 | if (!edges.count({v, u}) && edges.emplace(u, v).second) { 34 | g.addEdge(u, v); 35 | } 36 | } 37 | return g.shuffled(); 38 | } 39 | 40 | Graph makeTreeOfGraphs(const std::vector& graphs, bool line = false) { 41 | Array shifts; 42 | int s = 0; 43 | int n = graphs.size(); 44 | forn(i, n) { 45 | shifts.push_back(s); 46 | s += graphs[i].n(); 47 | } 48 | 49 | jngen::Dsu dsu; 50 | dsu.getRoot(s - 1); 51 | 52 | auto t = line ? Tree::bamboo(n) : Tree::random(n); 53 | for (auto e: t.edges()) { 54 | int v1 = rnd.next(shifts[e.fi], shifts[e.fi] + graphs[e.fi].n() - 1); 55 | int v2 = rnd.next(shifts[e.se], shifts[e.se] + graphs[e.se].n() - 1); 56 | dsu.unite(v1, v2); 57 | } 58 | 59 | map id; 60 | forn(i, s) { 61 | int v = dsu.getRoot(i); 62 | if (!id.count(v)) { 63 | int t = id.size(); 64 | id[v] = t; 65 | } 66 | } 67 | 68 | Graph res(id.size()); 69 | set> edges; 70 | forn(i, n) for (auto e: graphs[i].edges()) { 71 | int v1 = e.first + shifts[i]; 72 | int v2 = e.second + shifts[i]; 73 | v1 = id[dsu.getRoot(v1)]; 74 | v2 = id[dsu.getRoot(v2)]; 75 | if (v1 != v2 && !edges.count({v1, v2}) && !edges.count({v2, v2})) { 76 | edges.emplace(v1, v2); 77 | res.addEdge(v1, v2); 78 | } 79 | } 80 | return res; 81 | } 82 | 83 | int main(int argc, char *argv[]) { 84 | registerGen(argc, argv); 85 | parseArgs(argc, argv); 86 | 87 | setMod().printN().printM().add1(); 88 | 89 | string type = getOpt("type", "random"); 90 | 91 | if (type == "random") { 92 | int n, m; 93 | ensure(getPositional(n, m) == 2); 94 | ensure(n >= 2); 95 | cout << Graph::random(n, m).connected().g().shuffled() << endl; 96 | } else if (type == "bipartite") { 97 | int n, m; 98 | ensure(getPositional(n, m) == 2); 99 | cout << connectedBipartite(n, m) << endl; 100 | } else if (type == "bipartite-tree") { 101 | int n, m; 102 | ensure(getPositional(n, m) == 2); 103 | int n_comps = getOpt("n_comps", 5); 104 | int n_bad = getOpt("n_bad", 0); 105 | Array vnums = rndm.partition(n, n_comps, /* min_size = */ 1); 106 | Array enums = vnums; 107 | for (int& x: enums) { 108 | --x; 109 | m -= x; 110 | } 111 | auto ePartition = rndm.partition(m, n_comps, /* min_size = */ 1); 112 | forn(i, n_comps) enums[i] += ePartition[i]; 113 | TArray parts; 114 | forn(i, n_comps) { 115 | if (rnd.next(n_comps - i) < n_bad) { 116 | --n_bad; 117 | parts.push_back(Graph::random( 118 | vnums[i], min(enums[i], 1ll * vnums[i] * (vnums[i] - 1) / 2)).connected() 119 | ); 120 | } else { 121 | parts.push_back(connectedBipartite(vnums[i], enums[i])); 122 | } 123 | } 124 | auto g = makeTreeOfGraphs(parts); 125 | // cout << Array::id(g.n()).endl().printN(false) << endl; 126 | // cout << g.printN(false).printM(false) << endl; 127 | cout << g.shuffled() << endl; 128 | } else if (type == "manual") { 129 | int n = getOpt(0); 130 | int id = getOpt("id"); 131 | if (id == 1) { 132 | const int k = 100; 133 | vector graphs; 134 | forn(i, k) { 135 | graphs.push_back(connectedBipartite(n / (k*2), n / k)); 136 | } 137 | auto g = makeTreeOfGraphs(graphs, true); 138 | cout << g.shuffled() << endl; 139 | } else if (id == 2) { 140 | const int k = 100; 141 | vector graphs; 142 | forn(i, k) { 143 | if (i%2 == 0) { 144 | graphs.push_back(connectedBipartite(n / (k*2), n / k)); 145 | } else { 146 | graphs.push_back(Graph::complete(3)); 147 | } 148 | } 149 | auto g = makeTreeOfGraphs(graphs, true); 150 | cout << g.shuffled() << endl; 151 | } else if (id == 3) { 152 | cout << Graph(Tree::bamboo(n)).shuffled() << endl; 153 | } else if (id == 4) { 154 | cout << Graph(Tree::star(n)).shuffled() << endl; 155 | } else { 156 | ensure(false, format("Incorrect manual test id: '%d'", id)); 157 | } 158 | } else { 159 | ensure(false, format("Type '%s' is not supported", type.c_str())); 160 | } 161 | 162 | return 0; 163 | } 164 | -------------------------------------------------------------------------------- /examples/folding.cpp: -------------------------------------------------------------------------------- 1 | #include "jngen.h" 2 | #include 3 | #define forn(i, n) for (int i = 0; i < (int)(n); ++i) 4 | using namespace std; 5 | 6 | Tree uniDepthTree(const vector& layers) { 7 | ensure(is_sorted(layers.begin(), layers.end())); 8 | 9 | Tree t; 10 | Array last{0}; 11 | int n = 1; 12 | for (int d: layers) { 13 | Array nxt = Array::id(d, n); 14 | n += d; 15 | Array cnt(last.size(), 1); 16 | forn(i, d - last.size()) ++cnt[rnd.next() % cnt.size()]; 17 | int ptr = 0; 18 | forn(i, cnt.size()) { 19 | forn(j, cnt[i]) { 20 | t.addEdge(last[i], nxt[ptr++]); 21 | } 22 | } 23 | last = nxt; 24 | } 25 | return t; 26 | } 27 | 28 | Array depthVector(int n, int depth) { 29 | ensure(n >= depth); 30 | 31 | Array a(depth, 1); 32 | n -= depth; 33 | 34 | while (n) { 35 | int k = rnd.next(1, min(depth, n)); 36 | forn(i, k) { 37 | ++a[depth - i - 1]; 38 | } 39 | n -= k; 40 | } 41 | return a; 42 | } 43 | 44 | Tree goodTree(int n, int a, int b) { 45 | int deg = rnd.next(1, int(sqrt(n))); 46 | 47 | Array sz(deg, 1); 48 | forn(i, n - deg - 1) ++sz[rnd.next(sz.size())]; 49 | 50 | Tree t; 51 | for (int x: sz) { 52 | int d; 53 | if (min(a, b) > x) { 54 | continue; 55 | } else if (max(a, b) > x) { 56 | d = min(a, b); 57 | } else { 58 | d = rnd.next(0, 1) ? a : b; 59 | } 60 | 61 | auto u = uniDepthTree(depthVector(x, d)); 62 | t = t.glue(0, u, 0); 63 | } 64 | 65 | return t; 66 | } 67 | 68 | Tree distort(Tree t, int cnt) { 69 | int n = t.n(); 70 | forn(i, cnt) { 71 | t.addEdge(rnd.next(n), n); 72 | ++n; 73 | } 74 | return t.shuffle(); 75 | } 76 | 77 | void genSpecial(int id) { 78 | if (id == 1) { 79 | cout << distort(Tree::bamboo(180001), 50).shuffled() << endl; 80 | } else if (id == 2) { 81 | cout << Tree::star(200000).shuffled() << endl; 82 | } else if (id == 3) { 83 | cout << distort(Tree::star(190000), 1000).shuffled() << endl; 84 | } else if (id == 4 || id == 5) { 85 | Tree a = Tree::bamboo(98000); 86 | Tree b = Tree::star(98000); 87 | a = a.link(0, b, 0); 88 | 89 | if (id == 5) { 90 | a = distort(a, 200); 91 | } 92 | 93 | cout << a.shuffled() << endl; 94 | } else if (id == 6) { 95 | cout << Tree::caterpillar(200000, 50000).shuffled() << endl; 96 | } else if (id == 7) { 97 | cout << Tree::caterpillar(20000, 150000).shuffled() << endl; 98 | } 99 | } 100 | 101 | int main(int argc, char *argv[]) { 102 | registerGen(argc, argv); 103 | parseArgs(argc, argv); 104 | 105 | setMod().printN().add1(); 106 | 107 | string type; 108 | int n, a = -1, b = -1; 109 | 110 | getPositional(type, n, a, b); 111 | 112 | if (a == -1) { 113 | cerr << "a = -1" << endl; 114 | a = rnd.next(1, int(sqrt(n))); 115 | } 116 | if (b == -1) { 117 | cerr << "b = -1" << endl; 118 | b = rnd.next(1, int(sqrt(n))); 119 | } 120 | 121 | if (type == "yes") { 122 | cout << goodTree(n, a, b).shuffled() << endl; 123 | } 124 | 125 | if (type == "no") { 126 | int bad = rnd.next(1, min(n, 10)); 127 | cout << distort(goodTree(n - bad, a, b).shuffled(), bad) << endl; 128 | } 129 | 130 | if (type == "bamboo") { 131 | cout << Tree::bamboo(n).shuffled() << endl; 132 | } 133 | 134 | if (type == "special") { 135 | genSpecial(n); 136 | } 137 | } 138 | 139 | -------------------------------------------------------------------------------- /examples/jumps.cpp: -------------------------------------------------------------------------------- 1 | #include "jngen.h" 2 | #include 3 | using namespace std; 4 | #define forn(i, n) for (int i = 0; i < (int)(n); ++i) 5 | 6 | int main(int argc, char *argv[]) { 7 | registerGen(argc, argv); 8 | parseArgs(argc, argv); 9 | setMod().printN(); 10 | 11 | int n; 12 | ensure(getOpt(0, n)); 13 | 14 | string type = getOpt("type", "random"); 15 | 16 | if (type == "random") { 17 | int min = 1, max = n-1; 18 | getNamed(min, max); 19 | 20 | auto a = Array::random(n, min, max); 21 | 22 | cout << a << "\n"; 23 | } else if (type == "manual") { 24 | int id; 25 | ensure(getNamed(id)); 26 | 27 | if (id == 1) { 28 | Array a(n, 1); 29 | a[0] = a[n-1] = n-1; 30 | cout << a << "\n"; 31 | } else if (id == 2) { 32 | cout << Array(n, 1) << "\n"; 33 | } else if (id == 3) { 34 | cout << Array(n, n-1) << "\n"; 35 | } else if (id == 4) { 36 | cout << Array{1, 2} * (n/2) << "\n"; 37 | } else { 38 | ensure(false, format("Incorrect manual test id: '%d'", id)); 39 | } 40 | } else if (type == "sides") { 41 | int sidelen = 0, smin = 1, smax = n-1, min = 1, max = n-1; 42 | getNamed(sidelen, smin, smax, min, max); 43 | ensure(2 * sidelen <= n); 44 | 45 | auto lhs = Array::random(rnd.wnext(1, sidelen, 3), smin, smax); 46 | auto rhs = Array::random(rnd.wnext(1, sidelen, 3), smin, smax); 47 | auto mid = Array::random(n - lhs.size() - rhs.size(), min, max); 48 | 49 | cout << lhs + mid + rhs << "\n"; 50 | } else if (type == "islands") { 51 | int cnt = 1, size = n, min = 1, max = n-1; 52 | getNamed(cnt, size, min, max); 53 | ensure(cnt * (size + 1) - 1 <= n); 54 | auto landSizes = rndm.partition(n - cnt*size, cnt+1, /* minSize = */ 1); 55 | Array a; 56 | forn(i, cnt) { 57 | a += Array(landSizes[i], n-1); 58 | a += Array::random(size, min, max); 59 | } 60 | a += Array(landSizes.back(), n-1); 61 | cout << a << "\n"; 62 | } else { 63 | ensure(false, format("Incorrect type: '%s'", type.c_str())); 64 | } 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /examples/some_random_graph_problem.cpp: -------------------------------------------------------------------------------- 1 | #include "jngen.h" 2 | #include 3 | using namespace std; 4 | #define forn(i, n) for (int i = 0; i < (int)(n); ++i) 5 | #define for2(cur, prev, a) for (auto _it1 = std::begin(a),\ 6 | _it2 = _it1 == std::end(a) ? _it1 : std::next(_it1);\ 7 | _it2 != std::end(a); ++_it1, ++_it2)\ 8 | for (bool _ = true; _;)\ 9 | for (auto &cur = *_it1, &prev = *_it2; _; _ = false) 10 | 11 | Array getw(int m) { 12 | int minc = 0, maxc = 9; 13 | getNamed(minc, maxc); 14 | return Array::random(m, minc, maxc); 15 | } 16 | 17 | int main(int argc, char *argv[]) { 18 | registerGen(argc, argv); 19 | parseArgs(argc, argv); 20 | 21 | setMod().printN().printM().add1(); 22 | 23 | if (int id = getOpt("manual", 0)) { 24 | int n = getOpt(0, -1); 25 | int m = getOpt(1, -1); 26 | (void)(n+m); 27 | 28 | if (id == 1) { 29 | cout << "2 1\n1 2 5\n"; 30 | } else if (id == 2) { 31 | cout << "2 1\n1 2 0\n"; 32 | } else if (id == 3) { 33 | Graph g = Tree::bamboo(n); 34 | g.setEdgeWeights(Array::random(n-1, 0, 9)); 35 | g.shuffleAllBut({0, n-1}); 36 | cout << g << endl; 37 | } else if (id == 4) { 38 | Graph g = Tree::bamboo(n); 39 | g.setEdgeWeights(Array::random(n-1, 0, 0)); 40 | g.shuffleAllBut({0, n-1}); 41 | cout << g << endl; 42 | } else if (id == 5) { 43 | Graph g = Tree::bamboo(n); 44 | g.setEdgeWeights(Array::random(n-1, 1, 9)); 45 | g.shuffleAllBut({0, n-1}); 46 | cout << g << endl; 47 | } else if (id == 6) { 48 | Graph g = Tree::star(n); 49 | g.setEdgeWeights(Array::random(n-1, 1, 9)); 50 | g.shuffle(); 51 | cout << g << endl; 52 | } else if (id == 7) { 53 | Graph g(n); 54 | forn(i, n-1) { 55 | g.addEdge(i, i+1); 56 | g.setEdgeWeight(g.m()-1, rnd.next(0, 9)); 57 | g.addEdge(i, i+1); 58 | g.setEdgeWeight(g.m()-1, rnd.next(0, 9)); 59 | } 60 | g.shuffleAllBut({0, n-1}); 61 | cout << g << endl; 62 | } else { 63 | ensure(false, format("manual test id unknown: %d", id)); 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int n = getOpt(0); 71 | int m = getOpt(1); 72 | 73 | string type = getOpt("type", "random"); 74 | 75 | if (type == "random") { 76 | auto g = Graph::random(n, m).connected().allowMulti(true).g(); 77 | g.setEdgeWeights(getw(m)); 78 | g.shuffle(); 79 | cout << g << endl; 80 | } else if (type == "stretched") { 81 | int elong = getOpt("elong", 10); 82 | int spread = getOpt("spread", 5); 83 | 84 | auto g = Graph::randomStretched(n, m, elong, spread). 85 | connected().allowMulti(true).g(); 86 | g.setEdgeWeights(getw(m)); 87 | g.shuffleAllBut({0, n-1}); 88 | 89 | cout << g << endl; 90 | } else if (type == "levels") { 91 | int mn = getOpt("min", 1); 92 | int mx = getOpt("max", 10); 93 | auto levels = rndm.partition(Array::id(n-2, 1), (n-2) / ((mn + mx)/2), mn, mx); 94 | levels.insert(levels.begin(), {0}); 95 | levels.push_back({n-1}); 96 | 97 | Graph g; 98 | 99 | for2(prev, cur, levels) { 100 | for (auto v: cur) { 101 | g.addEdge(v, prev.choice()); 102 | --m; 103 | } 104 | } 105 | while (m) { 106 | int l1 = rnd.next(1u, levels.size() - 1); 107 | int v = levels[l1-1].choice(); 108 | int to = levels[l1].choice(); 109 | g.addEdge(v, to); 110 | --m; 111 | } 112 | g.setEdgeWeights(getw(g.m())); 113 | 114 | cout << g << endl; 115 | } else { 116 | ensure(false, "Unknown test type"); 117 | } 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /footer.h: -------------------------------------------------------------------------------- 1 | #pragma GCC diagnostic pop // -Wconversion 2 | #if __clang__major >= 5 3 | #pragma GCC diagnostic pop // -Wunused-lambda-capture 4 | #endif 5 | -------------------------------------------------------------------------------- /gcc_primes_list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | namespace jngen { 6 | namespace impl { 7 | 8 | // Generated with util/generate_prime_rehash_policy.cpp 9 | // Necessary for anti-unordered_set test. 10 | extern const unsigned int primeList[] 11 | #ifndef JNGEN_DECLARE_ONLY 12 | = { 13 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 14 | 71, 73, 79, 83, 89, 97, 103, 109, 113, 127, 137, 139, 149, 157, 167, 179, 15 | 193, 199, 211, 227, 241, 257, 277, 293, 313, 337, 359, 383, 409, 439, 16 | 467, 503, 541, 577, 619, 661, 709, 761, 823, 887, 953, 1031, 1109, 1193, 17 | 1289, 1381, 1493, 1613, 1741, 1879, 2029, 2179, 2357, 2549, 2753, 2971, 18 | 3209, 3469, 3739, 4027, 4349, 4703, 5087, 5503, 5953, 6427, 6949, 7517, 19 | 8123, 8783, 9497, 10273, 11113, 12011, 12983, 14033, 15173, 16411, 17749, 20 | 19183, 20753, 22447, 24281, 26267, 28411, 30727, 33223, 35933, 38873, 21 | 42043, 45481, 49201, 53201, 57557, 62233, 67307, 72817, 78779, 85229, 22 | 92203, 99733, 107897, 116731, 126271, 136607, 147793, 159871, 172933, 23 | 187091, 202409, 218971, 236897, 256279, 277261, 299951, 324503, 351061, 24 | 379787, 410857, 444487, 480881, 520241, 562841, 608903, 658753, 712697, 25 | 771049, 834181, 902483, 976369, 1056323, 1142821, 1236397, 1337629, 1447153, 26 | 1565659, 1693859, 1832561, 1982627, 2144977, 2320627, 2510653, 2716249, 27 | 2938679, 3179303, 3439651, 3721303, 4026031, 4355707, 4712381, 5098259, 28 | 5515729, 5967347, 6456007, 6984629, 7556579, 8175383, 8844859, 9569143, 29 | 10352717, 11200489 30 | } 31 | #endif // JNGEN_DECLARE_ONLY 32 | ; 33 | 34 | } // namespace impl 35 | } // namespace jngen 36 | -------------------------------------------------------------------------------- /generic_graph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "array.h" 4 | #include "dsu.h" 5 | #include "printers.h" 6 | #include "weight.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace jngen { 16 | 17 | class GenericGraph { 18 | public: 19 | virtual ~GenericGraph() {} 20 | 21 | virtual int n() const { return adjList_.size(); } 22 | virtual int m() const { return numEdges_; } 23 | 24 | bool directed() const { return directed_; } 25 | 26 | // u, v: labels 27 | virtual void addEdge(int u, int v, const Weight& w = Weight{}); 28 | virtual bool isConnected() const { return dsu_.isConnected(); } 29 | 30 | virtual int vertexLabel(int v) const { return vertexLabel_.at(v); } 31 | virtual int vertexByLabel(int v) const { return vertexByLabel_.at(v); } 32 | 33 | // v: label 34 | // return: array