├── .gitignore ├── LICENSE ├── README.md ├── TextMarkovChain.sln ├── TextMarkovChain.vcxproj ├── TextMarkovChain.vcxproj.filters ├── data ├── lastquestion.txt ├── projbluenoise.txt ├── psychreport.txt ├── readme.txt └── telltale.txt ├── main.cpp └── out ├── generated.txt └── stats.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | x64 3 | *.user -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alan Wolfe 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 | # TextMarkovChain 2 | Simple Nth order markov chain for text. Learns from text files, generates new text files. 3 | -------------------------------------------------------------------------------- /TextMarkovChain.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2019 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextMarkovChain", "TextMarkovChain.vcxproj", "{2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Debug|x64.ActiveCfg = Debug|x64 17 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Debug|x64.Build.0 = Debug|x64 18 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Debug|x86.ActiveCfg = Debug|Win32 19 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Debug|x86.Build.0 = Debug|Win32 20 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Release|x64.ActiveCfg = Release|x64 21 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Release|x64.Build.0 = Release|x64 22 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Release|x86.ActiveCfg = Release|Win32 23 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {8E99867D-788D-4CAD-B011-561E46FFD3EA} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /TextMarkovChain.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {2CD18025-FF06-4BFE-A6DA-1EB51717AFFD} 24 | TextMarkovChain 25 | 10.0.17134.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | Level3 84 | Disabled 85 | true 86 | true 87 | 88 | 89 | 90 | 91 | Level3 92 | MaxSpeed 93 | true 94 | true 95 | true 96 | true 97 | 98 | 99 | true 100 | true 101 | 102 | 103 | 104 | 105 | Level3 106 | MaxSpeed 107 | true 108 | true 109 | true 110 | true 111 | 112 | 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /TextMarkovChain.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/lastquestion.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atrix256/TextMarkovChain/c23d309d9a689169b447aa891b9604177839b111/data/lastquestion.txt -------------------------------------------------------------------------------- /data/projbluenoise.txt: -------------------------------------------------------------------------------- 1 | DOI: 10.1111/cgf.12725 COMPUTER GRAPHICS forum 2 | Volume 00 (2015), number 0 pp. 1–12 3 | Projective Blue-Noise Sampling 4 | Bernhard Reinert1, Tobias Ritschel1,2, Hans-Peter Seidel1 and Iliyan Georgiev3 5 | 1MPI Informatik, Saarbrucken, Germany ¨ 6 | {breinert, ritschel, hpseidel}@mpi-inf.mpg.de 2Saarland University, Saarbrucken, Germany ¨ 3Solid Angle, London, United Kingdom 7 | iliyan@solidangle.com 8 | Abstract 9 | We propose projective blue-noise patterns that retain their blue-noise characteristics when undergoing one or multiple projections 10 | onto lower dimensional subspaces. These patterns are produced by extending existing methods, such as dart throwing and Lloyd 11 | relaxation, and have a range of applications. For numerical integration, our patterns often outperform state-of-the-art stochastic 12 | and low-discrepancy patterns, which have been specifically designed only for this purpose. For image reconstruction, our method 13 | outperforms traditional blue-noise sampling when the variation in the signal is concentrated along one dimension. Finally, we 14 | use our patterns to distribute primitives uniformly in 3D space such that their 2D projections retain a blue-noise distribution. 15 | Keywords: sampling, blue-noise, Monte Carlo rendering, image reconstruction, primitive placement 16 | ACM CCS:I.3.3 [Computer Graphics]: Picture/Image Generation—Antialiasing; I.4.1 [Image Processing and Computer Vision]: 17 | Digitization and Image Capture—Sampling 18 | 1. Introduction 19 | Producing ‘good’ sampling patterns is an important task in many 20 | computer graphics applications, including simulation, rendering, 21 | image reconstruction and primitive placement. But what makes a 22 | good pattern depends on the application. For Monte Carlo (MC) rendering, low integration error is important [Coo86], [Shi91], which 23 | is usually achieved by stratified Latin hypercube (LH) or lowdiscrepancy point sets that have well-distributed low-dimensional 24 | projections. For digital half-toning [Uli87], stippling [KCODL06] 25 | and object placement [HHD03], blue-noise point sets with maximized minimum distance are preferred, as their structure closely 26 | resembles the photoreceptor arrangement in the eye retina [Yel83]. 27 | Such patterns are also desirable for image reconstruction [DW85] 28 | where low-discrepancy patterns can lead to spurious aliasing artefacts [Mit87]. At the same time, it has been shown that blue-noise 29 | patterns are not as competitive for numerical integration [Shi91]. 30 | All these applications call for point sets that are uniformly distributed in the sampling domain, though research in each area has 31 | focused on optimizing the distribution for its slightly different definition of uniformity. It has remained an open question whether there 32 | exist distributions that meet the requirements of a wide range of 33 | applications. 34 | In this paper, we propose projective blue-noise point distributions, in an attempt to give a positive answer to the above question. 35 | A key property of these distributions is that they retain their bluenoise characteristics when undergoing one or multiple projections 36 | to lower dimensional subspaces (Figure 1a). We show how the classic dart throwing and Lloyd relaxation algorithms can be extended 37 | to produce such point sets, and demonstrate the usefulness of their 38 | projective blue-noise properties in various applications. For MC 39 | rendering (Figure 1b) and image reconstruction (Figure 1c), our 40 | patterns often outperform existing distributions for functions with 41 | variations concentrated along one dimension, where the resulting 42 | sampling quality is dominated by a projection of the pattern. Furthermore, while common blue-noise patterns are useful for placing 43 | primitives in 3D space, our patterns preserve the good visual distribution when the arrangement is viewed from different angles 44 | (Figure 1d). 45 | The rest of this paper is organized as follows. After reviewing 46 | relevant prior work in the next section, in Section 3 we describe 47 | c 2015 The Authors 48 | Computer Graphics Forum c 2015 The Eurographics Association and 49 | John Wiley & Sons Ltd. Published by John Wiley & Sons Ltd. 1 50 | 2 Reinert et al. / Projective Blue-Noise Sampling 51 | 1D 52 | 2D 53 | 2D 54 | 1D 55 | (a) (b) (c) (d) Blue noise Projective blue noise 56 | Pattern Spectrum 57 | Figure 1: Our projective blue-noise distributions (a, bottom) have blue-noise spectra in 2D as well as in their 1D projections, while classic 58 | 2D blue noise (a, top) has an almost white-noise spectrum in 1D. Applications include Monte Carlo rendering (b), reconstruction (c), as well 59 | as placement of primitives (d) such that they are well distributed both in 3D and when projected to 2D. 60 | the construction of projective blue-noise patterns and discuss some 61 | practical considerations. In Section 4, we analyse the properties of 62 | our point sets and the performance of our construction algorithms. In 63 | Section 5, we demonstrate the versatility of our method in practical 64 | applications, followed by final conclusions in Section 6. 65 | 2. Previous Work 66 | Sampling is a key component in many computer graphics problems 67 | that arise in rendering, imaging, geometry processing and object 68 | distribution. Coined by Ulichney [Uli87], the term blue noise refers 69 | to the spectral properties of uniform and isotropic, yet structureless 70 | point distributions. Originally developed for the purposes of digital half-toning [Uli87], blue-noise distributions have been found 71 | useful in many other applications due to their resemblance of the 72 | photoreceptor arrangement in the eye retina [Yel83]. 73 | One way to generate a blue-noise point set is to insert the points 74 | one by one, maintaining a minimum interpoint distance along the 75 | way. The most common approach for doing this is dart throwing [Coo86], which ensures that points are tightly packed but no 76 | closer than a specified minimum distance, producing a so-called 77 | Poisson-disk distribution. This algorithm can be made progressive 78 | by adaptively shrinking the disk radius after a certain number of 79 | failed insertion attempts [MF92]. Alternatively, a new point can 80 | be inserted at the location farthest from the existing set [Mit91, 81 | ELPZ97]. 82 | Another approach to produce high-quality blue-noise distributions is to take an initial, e. g. random, point set and maximize 83 | the minimum interpoint distance using an iterative optimization 84 | scheme. The popular Lloyd relaxation algorithm [Llo82] is based 85 | on centroidal Voronoi tessellation (CVT). The quality of the resulting patterns has been recently improved by Balzer et al. [BSD09], 86 | and some further developments have addressed anisotropic sampling [LWSF10] and improving efficiency [dGBOD12, CYC*12]. 87 | Using uniform but irregular sample patterns can also reduce 88 | aliasing [DW85] and noise [Coo86] in MC rendering. Such applications have traditionally relied on stratified pseudo-random 89 | sampling, which places one sample in every stratum of the uniformly subdivided sampling domain [PH10]. One instance of this 90 | idea is jittering, where each sample on a regular grid is displaced 91 | randomly. Stratification can often increase the error convergence 92 | rate of the MC estimator over pure random sampling [Mit92]. 93 | LH, or N-rooks, sampling enforces stratification along each axis 94 | of a high-dimensional point set. Stratified and LH sampling have 95 | been combined to produce high-quality numerical integration patterns [CSW94, Ken13]. 96 | The quality of a pattern for numerical integration can be measured by its discrepancy [Shi91, Mit92]. Low-discrepancy point 97 | sets have seen wide adoption in physically based rendering, as they 98 | are relatively simple to implement and possess excellent stratification and LH properties [KK02, PH10, KPR12]. However, most 99 | low-discrepancy sampling methods achieve good stratification only 100 | for a restricted number of points (e. g. powers of two), depending on 101 | the construction method [KPR12]. Our approach does not have this 102 | limitation and performs on par with or better than such methods. 103 | Even though blue-noise point sets have very uniform distribution 104 | and lack regularity, their application in image synthesis has so far 105 | been mostly restricted to image anti-aliasing [Mit87, PH10]. Reports 106 | on their performance for estimating illumination integrals have been 107 | controversial [Shi91, SHD11, MBR*13]. We hypothesize that the 108 | main reason for their suboptimal performance is the poor uniformity in their low-dimensional projections, and aim to produce point 109 | sets with both blue-noise and LH properties. Research in numerical 110 | integration has shown that the quality of a pattern can be improved 111 | by ‘latinizing’ either the initial values for Lloyd relaxation or the 112 | final result [RBGP06, SGB07]. However, to our knowledge no attempt has been made to achieve both LH and blue-noise properties 113 | simultaneously. 114 | Some of the aforementioned works have demonstrated the utility of blue-noise sampling for procedural primitive placement. This 115 | application also benefits from the real-time performance of tilebased sampling [ODJ04, KCODL06]. Computational placement of 116 | extended primitives in 2D [HHD03, RRS13] has applications in 117 | automated generation of layouts in print, on screens and for fabrication. 118 | While producing images using projections, e. g. shadows [MP09], 119 | has been addressed in computer graphics, no prior work has considered the spectral properties of projections of primitive layouts. This 120 | c 2015 The Authors 121 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 122 | Reinert et al. / Projective Blue-Noise Sampling 3 123 | b1 124 | r r1 125 | r2 126 | r2 127 | r3 r3 128 | b3 b2 129 | x y x y 130 | Classic dart throwing 131 | Projective 132 | dart throwing 133 | Figure 2: Classic dart throwing (left) accepts both the orange and 134 | the blue candidate points, as no existing point in the set is within 135 | the rejection radius r (pink circle). Projective dart throwing (right) 136 | accepts the orange candidate, but not the blue one, as its projection 137 | onto b3, with radius r3 (pink box), conflicts with an existing point. 138 | becomes important when placing (fabricated) objects in 3D space, 139 | i. e. in a physical exhibition or a collaborative virtual environment. 140 | Typically used patterns do not produce layouts with blue-noise distribution when observed from different viewpoints. Our approach 141 | can reduce clutter and occlusion by optimizing both the spatial and 142 | the projected arrangement. 143 | 3. Our Approach 144 | The basic idea of projective blue noise is to extend existing sampling methods to not only operate in the full d-dimensional sample 145 | space, but also in multiple lower dimensional projective subspaces 146 | simultaneously. While classic dart throwing and Lloyd relaxation 147 | test candidates or move points only in the full-dimensional space, 148 | our extensions additionally check candidates, respectively, move 149 | points, in the projection subspaces. We specify all spaces via a set 150 | of m projection vectors 151 | B = 152 | bj ∈ {0, 1} 153 | d m 154 | j=1 . (1) 155 | The vectors bj can be used with the Hadamard product (i. e. 156 | the element-wise vector multiplication) to project points and vectors onto the (sub)spaces specified by those vectors. Classic, 157 | non-projective blue noise is the special case with B = {{1}d }. 158 | In our projective extension, for 2D point sets we use B = 159 | {(1, 1), (1, 0), (0, 1)}. 160 | In the following subsections, we extend the dart throwing and 161 | Lloyd relaxation algorithms to projective blue-noise sampling. For 162 | each method, we first review its classic, non-projective variant, before presenting our projective extension. 163 | 3.1. Dart throwing 164 | Classic. Dart throwing (Figure 2, left) starts with an empty point set 165 | and iteratively generates random candidate points x that are added 166 | to the set only if their distance to every other point xi is larger than 167 | a certain threshold r, called Poisson-disk radius [Coo86]: 168 | min 169 | i=1,...,n 170 | x − xi > r, (2) 171 | where n < n is the number of the already accepted points. For 172 | tiled patterns, the distance is computed on a toroidally wrapped 173 | domain. In its most basic form, the algorithm terminates if no new 174 | points can be added after a certain number of successive failed 175 | attempts. Alternatively, instead of terminating, the radius can be 176 | shrunk by a constant factor, which makes the sampling method 177 | progressive [MF92]. Our implementation operates on a toroidal 178 | domain and also incorporates this shrinkage. 179 | Projective. Our dart throwing extension (Figure 2, right) accepts a 180 | candidate point x only if its distance to every other point xi in the 181 | full d-dimensional space and in every projection space is larger than 182 | a certain threshold: 183 | min 184 | i=1,...,n 185 |  186 | bj ◦ (x − xi) 187 |  188 |  > rj ∀j ∈ 1, . . . , m, (3) 189 | where rj is the desired radius (i. e. minimum distance) in the j th 190 | space, and ◦ is the aforementioned Hadamard product. 191 | Radii. Since the distances between points are smaller in lower 192 | dimensional subspaces, the radii for these spaces should be smaller 193 | than the ones for higher dimensional spaces. We derive the radius 194 | for a space from the radius of the tightest known lattice sphere 195 | packing in the corresponding dimension. For 1D through 4D, these 196 | maximum radii are given, respectively, by [LD06, KZ77] 197 | rmax 198 | 1 = 1 199 | 2n 200 | , rmax 201 | 2 = 202 |  203 | 1 204 | 2 205 | √3n 206 | , rmax 207 | 3 = 3 208 |  209 | 1 210 | 4 211 | √2n 212 | , rmax 213 | 4 = 4 214 |  1 215 | 8n 216 | . 217 | For higher dimensions d, the maximum radius is found by solving 218 | Vd = ηd /n for the radius rmax 219 | d of a d-dimensional sphere, where Vd 220 | is the sphere volume and ηd is the best lattice disk packing density. 221 | Given the maximum packing radii, we compute the Poisson-disk 222 | radii as 223 | rj = r · 224 | rmax 225 | dj 226 | rmax 227 | d 228 | , (4) 229 | where dj = bj 1 is the dimension of space j and d is the dimension 230 | of the full space. The algorithm is now controlled via a single 231 | parameter r ∈ [0, 1], which we set to r = 0.15. 232 | 3.2. Lloyd relaxation 233 | Classic The Lloyd optimization algorithm (Figure 3, left) constructs a point arrangement that is a CVT. In a CVT, each point, or 234 | site, xi is also the centre of its associated Voronoi cell—the subset 235 | of the domain that is closer to xi than to any other site. To obtain 236 | such a set X = {x1,..., xn}, Lloyd relaxation minimizes the cost 237 | c(X) = n 238 | i=1 239 |  240 | i 241 | xi − x2 242 | dx, (5) 243 | c 2015 The Authors 244 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 245 | 4 Reinert et al. / Projective Blue-Noise Sampling 246 | Δ 247 | b2 b3 248 | xi 249 | Δ3 250 | Δ2 251 | Ω2 252 | Ω3 253 | Ω 254 | xi 255 | Ω Δ1 1 256 | b1 257 | Classic 258 | Lloyd relaxation 259 | Projective 260 | Lloyd relaxation 261 | Figure 3: Classic Lloyd relaxation (left) moves each point xi (orange) to the centre (blue) of its Voronoi cell (pink). Our projective 262 | extension (right) tries to move each point xi to the centre of its 263 | Voronoi cell in the full space b1 as well as in the two subspaces 264 | specified by b2 and b3. 265 | where i is the ith cell in the Voronoi tessellation of X. Conceptually, this cost measures how far the sites are from the centre of mass 266 | of their Voronoi cells. As with dart throwing, for tiled patterns the 267 | distances are computed on a toroidally wrapped domain. 268 | The relaxation algorithm starts with a random set of sites X which 269 | is refined iteratively in three steps. First, a Voronoi tessellation of 270 | X is built, mapping every location in the domain to its closest 271 | site. Secondly, the centroid of every Voronoi cell is computed by 272 | averaging the locations in the cell. Finally, every site is moved to 273 | the centroid of its associated cell. Practical implementations often 274 | discretize the domain into a finite set of locations, turning the integral 275 | in Eq. (5) into a sum. 276 | Projective. In our case, we want to distribute the sites uniformly 277 | not only in the full-dimensional space, but also in multiple lower 278 | dimensional projection subspaces (Figure 3, right). Similarly to 279 | our dart throwing extension, we specify all spaces via a set of 280 | m projection vectors bj . We build m Voronoi tessellations, one for 281 | each space, and aim to optimize the sites such that they coincide with 282 | centroids of their corresponding Voronoi cells in all tessellations. 283 | Note that for any site, its associated cells are different in the different 284 | spaces. The cost of each site is computed by summing m weighted 285 | norms, and the total cost reads 286 | cp(X) = m 287 | j=1 288 | wj 289 | n 290 | i=1 291 |  292 | i,j 293 |  294 | bj ◦ xi − x 295 |  296 | 2 297 | dx, (6) 298 | where ◦ is the Hadamard product,{wj } 299 | m 300 | j=1 is a set of scalar projection 301 | weights that sum up to one, and i,j is the Voronoi cell of the ith 302 | site after projection onto the j th space. Note that the dimension of 303 | the points x above depends on j . 304 | Our relaxation scheme seeks to minimize Eq. (6). We start with 305 | the same initial point set as the classic Lloyd method, but we perform 306 | the optimization steps in m spaces simultaneously as follows. For 307 | each site xi, we compute m correction vectors i,j , one from the 308 | Voronoi tessellation in each space. Each vector i,j would move 309 | xi to the centre of Voronoi cell i,j . These vectors are generally 310 | different for the different projections j , and each individual site can 311 | be moved to exactly fulfil only one constraint locally. We instead try 312 | to partially fulfil all constraints by applying all correction vectors 313 | i,j to site xi, each scaled by a corresponding weight wj . After 314 | moving all sites, the m Voronoi tessellations are recomputed and 315 | the process is iterated. 316 | Note that the projective correction vectors are heuristically chosen 317 | and not proven to be optimal as the non-projective vectors are, but 318 | work well in practice as shown by our analysis. 319 | Weights. Ideally, we want all spaces to have equal importance in 320 | the total cost in Eq. (6). However, since distances between points 321 | in lower dimensional spaces are shorter, the relative contribution 322 | of such spaces is smaller than that of higher dimensional spaces. 323 | We equalize all contributions by making each weight wj inversely 324 | proportional to the tightest sphere packing radius in dimension dj : 325 | wj = 1/rmax 326 | dj 327 | m 328 | k=1 1/rmax 329 | dk 330 | . (7) 331 | Additional optimizations. Due to the increased number of constraints, the straightforward implementation of the above scheme 332 | may converge much slower than the classic Lloyd relaxation algorithm. We propose two enhancements to improve both the speed and 333 | the quality of the resulting patterns. 334 | First, in early iterations, the different correction vectors contradict heavily, making the process susceptible to local minima and 335 | slow convergence. To remedy this, the weights wj for the lower 336 | dimensional spaces are faded in linearly from 0 for 50 iterations. 337 | This is done for each dimension successively, i. e. first the weights 338 | of the d − 1-dimensional subspaces are faded in, then the d − 2- 339 | dimensional ones, etc. 340 | Secondly, the convergence speed can be further increased by exploiting the fact that in 1D the best point arrangement that maximizes 341 | the mutual minimum distance is the regular distribution [RAMN12], 342 | which is the global minimum of the Lloyd cost in 1D (Eq. 5). Thus, to 343 | satisfy a single 1D projection, the pattern can simply be ‘snapped’ 344 | to a regular grid along the corresponding axis [SGB07]. So instead of building 1D Voronoi tessellations, we directly compute 345 | the correction vectors as the differences between the regular grid 346 | {(0.5 + i)/n} 347 | n−1 348 | i=0 and the sorted point coordinates along each axis. 349 | Note that this closed-form solution works only for 1D projections, 350 | and minimizing the cost in multiple dimensions simultaneously still 351 | requires iterative optimization. 352 | 4. Analysis 353 | In this section, we compare the quality of our patterns to existing methods in terms of their spectral and projective properties, 354 | Poisson-disk radii and discrepancy. We also compare our method to 355 | latinization [SGB07] and analyse the convergence and the computational performance of our projective Lloyd relaxation. 356 | 4.1. Projective analysis 357 | We begin with an analysis of the spectral and spatial properties of our 358 | projective patterns. We follow the recommendations of Schlomer ¨ 359 | c 2015 The Authors 360 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 361 | Reinert et al. / Projective Blue-Noise Sampling 5 362 | Regular Random Jittered MJ Latin hypercube 363 | CMJ 364 | Sobol SLP 365 | Dart 366 | throwing 367 | Lloyd 368 | relaxation 369 | Latinized 370 | dart throwing 371 | Latinized 372 | Lloyd relaxation 373 | Our projective 374 | dart throwing 375 | Our projective 376 | Lloyd relaxation 377 | Sample pattern 2D Power spectrum Spectrum radial avg. Spectrum anisotropy 1D power spectrum Sample pattern 2D Power spectrum Spectrum radial avg. Spectrum anisotropy 1D power spectrum 378 | 0.04301 379 | 0.93060 380 | 0.00674 381 | 0.31614 382 | 0.05478 383 | 0.01663 384 | 0.01852 385 | 0.07106 386 | 0.01358 387 | 0.07417 388 | 0.00970 389 | 0.20471 390 | 0.01733 391 | 0.72556 392 | 0.01221 393 | 0.76699 394 | 0.00914 395 | 0.73271 396 | 0.00923 397 | 0.10658 398 | 0.02875 399 | 0.05623 400 | 0.01512 401 | 0.63878 402 | 0.01120 403 | 0.70742 404 | 0.01503 405 | 0.57221 406 | 1 407 | 0 408 | 0 f 204 c 409 | 25 410 | -250 f 204 c 411 | 1 412 | 0 413 | 0 3025 414 | 1 415 | 0 416 | 0 f 204 c 417 | 25 418 | -250 f 204 c 419 | 1 420 | 0 421 | 0 3025 422 | ρ 423 | L∞ 424 | * 425 | ρ 426 | L∞ 427 | * 428 | Figure 4: Spectral analysis of 14 different 2D point sets and their 1D axis projections (shown as red and blue bars and graphs, respectively), 429 | discussed in Section 4. Note that the horizontal (frequency) scale is different for the 1D power spectrum plots and the radial average and 430 | anisotropy plots. The last rows report the star discrepancy L∞ 431 | ∗ and Poisson-disk radius ρ of each point set. 432 | c 2015 The Authors 433 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 434 | 6 Reinert et al. / Projective Blue-Noise Sampling 435 | 0 436 | 1 437 | 0 438 | 1 439 | 0 440 | 000 f 167 238 1024 c f 441 | c 442 | 1 443 | XYZ XY XZ YZ XYZ 444 | Frequency Frequency Frequency 445 | 3D spectrum 446 | 3D 3D+2D 3D+2D+1D 447 | 2D spectra 1D spectra 448 | Figure 5: The 3D, 2D and 1D power spectra (columns) of 1024- 449 | sample patterns, averaged from 10 periodograms, produced by 450 | our projective Lloyd relaxation with different projections enabled 451 | (rows). The spectra of the different same-dimensional projections 452 | are colour-coded. 453 | 0 22 f 454 | c 455 | 4D 3D 2D 1D 456 | 0 59 f 0 c 0 256 457 | 0 458 | 1 459 | f 460 | c 13 461 | Figure 6: The power spectra of a 256-sample 4D projective bluenoise point distribution, averaged from 10 periodograms. Each plot 462 | shows the radial averages for all subspaces of the same dimensionality: 1 in 4D, 4 in 3D, 6 in 2D and 4 in 1D. 463 | et al. [SHD11] on reporting spectral data for point sets, including 464 | the critical frequency fc and anisotropy reference levels in Figures 465 | 1, 4, 5 and 6. For the 1D, 3D and 4D power spectrum plots, we 466 | generalize the relevant frequency ranges using the respective rmax 467 | d 468 | (see Section 3.1). 469 | 2D analysis. In Figure 4, we compare various 2D patterns in 470 | terms of their Fourier power spectra as well as their star discrepancy and Poisson-disk radii. The patterns we consider are: 471 | (1) regular, (2) Sobol, (3) scrambled Larcher-Pillichshammer (SLP) 472 | [KK02], (4) uniform random, (5) jittered, (6) LH, (7) multijittered (MJ) [CSW94], (8) correlated multi-jittered (CMJ) [Ken13], 473 | (9) dart throwing, (10) Lloyd relaxation, (11) latinized dart throwing [SGB07], (12) latinized Lloyd relaxation [SGB07], (13) our 474 | projective dart throwing and (14) our projective Lloyd relaxation. 475 | All plotted patterns consist of 25 samples. The spectral power plots 476 | have been computed as the average of the periodograms of 100 477 | random instances of each pattern with 3025 samples. The star discrepancy L∞ 478 | ∗ and Poisson-disk radii ρ (i. e. the normalized global 479 | minimum intersample distance [LD08]) have been computed for 480 | sample patterns of size 529. 481 | A characteristic feature of 2D blue-noise distributions is their 482 | isotropic Fourier power spectrum with a black disk in the centre 483 | indicating the absence of low-frequency content, surrounded by 484 | an energy-peak ring around the principal frequency [LD08]. Such 485 | distributions are produced by maximizing the minimum distance 486 | between the points in the set. As discussed in Section 3.2, in 1D the 487 | regular distribution achieves the maximum point separation, and 488 | its Fourier power spectrum is zero except at frequencies that are 489 | multiples of n (the number of points). As a consequence, in Figure 490 | 4 patterns with good 1D axis projections, such as LH, MJ as well as 491 | the latinized and our projective patterns, have black crosses in their 492 | 2D power spectra. This is because the interesting power spectrum 493 | features of such distributions occur at different scales in 1D and 2D. 494 | For the sake of visual clarity, we clamp the 2D spectrum plots to 495 | the frequency range [0; 204], and show the 1D-projection slices of 496 | these spectra as separate plots in the range [0; 3025]. Note also that 497 | the black crosses in the 2D spectra cause a slight artificial increase 498 | in 2D anisotropy. 499 | The Sobol and SLP low-discrepancy patterns achieve regular 1D 500 | axis projections for sample counts that are powers of two. For other 501 | sample counts however, gaps remain along at least one axis. In 502 | our 25-sample example in Figure 4, only the x-axis of the SLP 503 | pattern has a uniform distribution. Furthermore, both methods fail 504 | to produce blue-noise 2D spectra. 505 | Uniform random, regular and jittered sampling all fail to produce high-quality 2D blue-noise distribution and 1D projections. 506 | The regular 2D pattern has very poor projection distributions with 507 | multiple points sharing the same coordinates on each axis, causing 508 | spikes in the 1D power spectra. LH sampling has good projection 509 | properties but poor 2D uniformity. 510 | MJ sampling [CSW94], as a combination of jittered and LH sampling, produces a 2D power spectrum that shares the features of 511 | both methods. MJ patterns have acceptable projections, but like 512 | other jittered patterns do not guarantee a minimal intersample distance, which is reflected in the smooth low-frequency ramps in both 513 | the 2D and the projected 1D power spectra. CMJ [Ken13] results in 514 | identical 1D spectra but a much less uniform 2D spectrum. 515 | Classic Lloyd relaxation produces excellent blue-noise distributions but only in 2D. Latinizing the pattern improves the 1D projections but at the cost of increasing the 2D anisotropy and decreasing 516 | the Poisson-disk radius. Our projective Lloyd distribution combines 517 | a good 2D spectrum with well-distributed 1D projections, and has a 518 | larger Poisson-disk radius than the latinized variant. Improving the 519 | 1D projections of a blue-noise pattern also decreases its discrepancy [SGB07], where our projective method once again comes on 520 | top of latinization. 521 | Finally, dart throwing produces inferior blue-noise distributions 522 | compared to Lloyd relaxation, as confirmed by both the 2D and the 523 | projected 1D spectral plots. This is not unexpected, as this method 524 | is highly sensitive to the order in which the samples are inserted. 525 | The additional constraints introduced by our projective extension 526 | further reduce the probability of successfully inserting a candidate 527 | point. As a result, the 2D blue-noise spectrum of projective dart 528 | throwing suffers more from the imposed constraints than that of 529 | Lloyd relaxation, and some low-frequency components appear— 530 | the dark circle in the centre of the spectrum is grey, not black. On 531 | the other hand, latinized dart throwing produces good projective and 532 | non-projective spectra but also higher anisotropy. 533 | 3D analysis. In Figure 5, we compare the power spectra of classic 534 | 3D blue-noise patterns to the projective distributions produced by 535 | c 2015 The Authors 536 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 537 | Reinert et al. / Projective Blue-Noise Sampling 7 538 | our extended Lloyd relaxation. We see that classic, non-projective 539 | patterns (top row) have inferior 2D spectral properties and almost 540 | white-noise 1D distributions. Our approach (middle and bottom 541 | rows) retains good quality in all specified projection subspaces, 542 | although this comes at the cost of slight quality degradation in the 543 | 3D spectrum. 544 | 4D analysis. Finally, in Figure 6 we plot the power spectra of 545 | the 4D patterns produced by our extended Lloyd relaxation with 546 | projective blue-noise properties imposed on all lower dimensional 547 | subspaces. The characteristic blue-noise spectrum shape in all projections demonstrates that our method generalizes to higher dimensions. Note the different frequency scale of each plot, indicating a 548 | quality improvement in the corresponding dimension over classic 549 | 4D blue noise, as also seen in Figure 5. However, imposing this 550 | many constraints leads to a more noticeable overall deterioration in 551 | blue-noise quality compared to the 3D case. The noise in the plots 552 | is due to the relatively low number of periodograms averaged (10). 553 | 4.2. Comparison to latinization 554 | Having analysed the spectral properties of our projective Lloyd 555 | relaxation and the latinization method of Saka et al. [SGB07] in 556 | Section 4.1, we now conduct a closer comparison between these 557 | two approaches. On a high level, our notion is a non-greedy, highdimensional generalization of latinization: Instead of first creating a 558 | blue-noise pattern and latinizing it as a post-process, we interleave 559 | these two steps. Note that while our method handles arbitrary dimensions, latinization only considers 2D patterns and their 1D axis 560 | projections. We look the average projective Poisson-disk radius with 561 | respext to vector b: 562 | ρ˜b = 1 563 | n 564 |  565 | x∈X 566 | min 567 | y∈X b ◦ (x − y)/dmax 568 | b , (8) 569 | which is the projective generalization of the average Poisson-disk 570 | radius measure [SHD11]. The minimal intersample distance is normalized by the optimal packing distance dmax 571 | b in subspace b, i. e. 572 | dmax 573 | b = 2rmax 574 | b1 575 | . In the following, we will use ˜ρ, ˜ρx and ˜ρy to denote 576 | the average radii in 2D and in the x- and y-axis projections, respectively, corresponding to projection the vectors (1, 1), (1, 0) and 577 | (0, 1). 578 | For patterns with 512 samples, latinized dart throwing 579 | and our projective variant achieve ( ˜ρ, ρ˜x, ρ˜y) = (0.801, 1, 1) 580 | and ( ˜ρ, ρ˜x, ρ˜y) = (0.806, 0.917, 0.921), respectively. Latinized 581 | Lloyd relaxation produces ( ˜ρ, ρ˜x, ρ˜y) = (0.873, 1, 1), whereas 582 | our projective variant gives the best balance with ( ˜ρ, ρ˜x, ρ˜y) = 583 | (0.909, 0.998, 0.999). In summary, latinization produces perfect 1D 584 | stratification, but at the cost of decreasing the uniformity in 2D. Our 585 | approach optimizes for both measures simultaneously. 586 | The above measures indicate that in 2D latinized dart throwing 587 | outperforms our projective variant. However, latinization has a negative effect on the progressiveness of the algorithm, which is one 588 | of its strengths. We analyse this in Figure 7 by comparing the average Poisson-disk radii for classical, latinized and our projective 589 | dart throwing and the Sobol low-discrepancy sequence [Sob94]. We 590 | 64 512 # of samples 591 | .85 592 | 64 # of samples 512 64 512 # of samples 593 | Classical 594 | .55 595 | 1 596 | .4 597 | Latinized Our projective Sobol 598 | ρ˜ ρ˜ x ρ˜ y 599 | Figure 7: Average Poisson-disk radii in 2D and along the x- and 600 | y-axis projections (left to right) as functions of increasing sample 601 | subset size for three dart throwing variants and the Sobol sequence. 602 | Please see Section 4.2 for details. 603 | (a) (b) (c) 604 | Figure 8: Projection axis rotation. (a) Original pattern. (b) Tiled 605 | and rotated pattern. (c) Resulting power spectrum. 606 | plot the radii as functions of the first n points in 512-sample sets, 607 | where the latinized pattern is computed from the classical one after generating all samples. The plots reveal that our projective dart 608 | throwing has the most consistent progressive performance in 1D 609 | and 2D, while the latinized variant has good properties only for 610 | sample counts close to the maximum. The classical dart throwing 611 | performs well in 2D, but its 1D projections are consistently poor. In 612 | contrast, the Sobol pattern is perfectly latinized for power-of-two 613 | sample counts, but its 2D radius is significantly worse than those of 614 | the dart throwing patterns. 615 | 4.3. Rotation 616 | Our approach supports rotating the canonical coordinate axes, as 617 | long as they remain orthogonal. Since our methods operate on a 618 | toroidal domain, this can be trivially achieved by optimizing the 619 | pattern for the canonical axes (Figure 8a) and then rotating it by the 620 | desired amount (Figure 8b). The black cross in the resulting power 621 | spectrum is oriented according to the rotation angle (Figure 8c). 622 | The same approach can also be used in higher dimensions, as the 623 | patterns tile in all directions. 624 | 4.4. Sample warping 625 | MC rendering and primitive placement often require warping samples according to a specified importance function. In Figure 9, we 626 | compare the warping quality of our projective Lloyd patterns against 627 | other patterns on a thin 2D curve, which can represent, e.g. an environment light source for rendering or a path on a plane for primitive 628 | placement. To produce the warped patterns, we first create samples 629 | as described before, i. e. using a uniform importance. We then warp 630 | c 2015 The Authors 631 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 632 | 8 Reinert et al. / Projective Blue-Noise Sampling 633 | Importance SLP CMJ Lloyd 634 | Projective 635 | Lloyd 636 | Figure 9: Importance-driven warping of different 25-sample 2D 637 | patterns. Our projective Lloyd pattern produces the best distribution, thanks to its good projections along both axes. 638 | 0.16 639 | 0.18 640 | 1 100 641 | 7x10-8 642 | 1 100 Iterations Iterations 0 0 643 | Classic Lloyd 644 | Cost 645 | Cost 646 | Latinization 647 | No fade, 1D snap Fade, 1D snap 648 | No fade, no 1D snap Fade, no 1D snap 649 | 2D cost Projective 1D cost 650 | Figure 10: 2D and projective 1D cost plots at different iterations 651 | of classic and latinized Lloyd relaxation as well as four different 652 | variants of our projective extension for a pattern with 2048 samples 653 | (see Section 4.5). Different weight fading strategies are shown in 654 | different colours, while solid and dashed lines denote the use of 1D 655 | grid snapping (Section 3.2). 656 | these samples to follow a new importance function (Figure 9, left) 657 | using the common approach of tabulating conditional and marginal 658 | distributions along the x- and y-axis, respectively [Dev86, p. 555]. 659 | Our pattern achieves the most uniform warped distribution, which 660 | in rendering translates to a low integration error. This is due to its 661 | well-distributed projections along both axes, a property that no other 662 | pattern in the comparison has. 663 | 4.5. Lloyd convergence 664 | We now analyse the convergence of different variants of our projective Lloyd optimization on a 2D point set X. In Figure 10, we 665 | plot the classic 2D cost c(X) (Eq. (5)) and the projective 1D part 666 | cp(X) − w1 · c(X) of the generalized cost (Eq. (6)), where w1 is 667 | the full (2D) space weight, over an increasing number of iterations. 668 | We consider five variants of our algorithm: classic non-projective 669 | as well as variants with and without the weight fading and 1D grid 670 | snapping optimizations from Section 3.2. A sixth graph shows the 671 | effect of latinizing the pattern after 50 optimization iterations. 672 | We see that all non-latinized variants minimize the classic 2D 673 | cost, though with slightly different speeds. Our projective variants 674 | achieve a final 2D cost only 0.76% worse than that of the classical 675 | method (note the small [0.16; 0.18] vertical range in the left plot), 676 | while also minimizing the 1D costs. On the other hand, latinization 677 | brings excellent projective properties but at the expense of increasing 678 | the total cost. 679 | Unsurprisingly, the projective 1D cost is not minimized by the 680 | classic Lloyd relaxation. The weight fading increases the projective cost initially, but ultimately achieves a substantially faster convergence. The 1D grid snapping adds a further constant runtime 681 | improvement. 682 | 4.6. Performance 683 | The GPU implementation of our projective Lloyd relaxation performs slower than classic Lloyd relaxation by a factor slightly 684 | smaller than m (the number of projection spaces). While the performance of the 1D relaxation is improved by the grid snapping 685 | optimization, its computational cost is insignificant compared to the 686 | higher dimensional Voronoi tessellations. Our na¨ıve implementation of projective dart throwing is about 3× slower than the classic 687 | method. 688 | 5. Applications 689 | In this section, we demonstrate the utility of our projective bluenoise patterns in rendering, image reconstruction and primitive 690 | placement—applications that have traditionally relied on specialized distributions. 691 | 5.1. Rendering 692 | In Figure 11, we compare several patterns for MC rendering of 693 | direct illumination from three different types of extended light 694 | sources. The light sources used to produce the renderings are (a) an 695 | anisotropic area light with a colour gradient, 21 samples per pixel 696 | (spp); (b) an importance-sampled environment light (see inset in 697 | Figure 11b, Section 4.4), 25 spp and (c) a square area light, 25 spp. 698 | We decorrelate the pixel estimators for all but the SLP and CMJ 699 | patterns via Cranley-Patterson rotation [CP76]. We use (1) Hammersley [KK02], (2) CMJ [Ken13], (3) SLP [KK02], (4) classic 700 | Lloyd relaxation (which was slightly better than dart throwing) and 701 | (5) our projective Lloyd relaxation (again, slightly better than our 702 | projective dart throwing) to sample the rectangluar domains of the 703 | area and environment light sources. 704 | The visual and numerical results in Figure 11 indicate that our 705 | projective blue-noise patterns outperform all others on thin area 706 | lights. SLP is the closest competitor on all scenes and even slightly 707 | outperforms our patterns on the environment map scene. However, 708 | the pattern exhibits pixel correlation which is clearly visible in both 709 | the first and the second scenes, as also observed by Kensler [Ken13]. 710 | The environment map in the second scene features thin curved lights 711 | that are importance sampled as described in Section 4.4. In Figure 712 | 11(c), we see that the blue-noise patterns perform slightly better 713 | than the classical optimal methods on a square area light source. 714 | To analyse the effect of light source anisotropy, in Figure 12 topleft we plot the Root Mean Square (RMS) reference error of three 715 | patterns on a simple scene for varying numbers of samples. Classic 716 | Lloyd relaxation (green) and SLP (blue) exhibit strong variation in 717 | quality. For power-of-two sample counts, SLP is on par with our 718 | projective Lloyd pattern (red) which otherwise outperforms consis- 719 | c 2015 The Authors 720 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 721 | Reinert et al. / Projective Blue-Noise Sampling 9 722 | Ground truth Hammersley CMJ SLP Lloyd Projective Lloyd 723 | a) Thin area light c) Square area light b) Environment light 724 | 2.1x10-2 2.1x10-2 1.7x10-2 2.0x10-2 1.6x10-2 725 | 2.4x10-2 2.4x10-2 2.4x10-3 2.2x10-3 2.2x10-3 726 | 4.1x10-2 4.0x10-2 3.5x10-3 4.4x10-3 3.8x10-3 727 | Figure 11: Rendering comparison of five sample patterns on three scenes with different light sources, discussed in Section 5.1. 728 | 0 729 | 0.05 730 | 0 731 | 0.1 732 | 0% 100% 733 | 0 734 | 0.15 735 | 8 16 25 32 Anisotropy 736 | # of samples 737 | Error 738 | Error 739 | Error 8 16 25 32 740 | # of samples 0 741 | 0.1 742 | 0% Anisotropy 100% 743 | Error 744 | Thin light 745 | Lloyd 746 | SLP 747 | Our Lloyd 748 | Square light 749 | 25 samples 750 | 16 samples 751 | Figure 12: RMS error plots of the renderings of a scene using three 752 | different sample patterns. We plot the error as a function of sample 753 | count (left) and area light source anisotropy (right). 754 | tently better. We speculate that classic Lloyd spuriously achieves 755 | the same quality as ours when it randomly produces patterns with 756 | good 1D projections. For a square area light source (Figure 12, 757 | bottom-left), the differences are smaller, though our approach again 758 | consistently outperforms classic Lloyd relaxation. Finally, in Figure 12 right we plot the RMS error as a function of the light source 759 | anisotropy. 760 | 5.2. Image reconstruction 761 | In Figure 13, we compare the performance of classic Lloyd relaxation and our projective extension for reconstructing 2D images. 762 | We test a 2D zone plate function with a 4-pixel-wide Lanczos filter (512×512 pixels = 262 144 samples) as well as a modified 763 | anisotropic variant (512×16 pixels = 16 384 samples). On the 764 | isotropic zone plate (left), the two patterns perform similarly. However, our pattern significantly outperforms classic blue noise on the 765 | anisotropic variant (right), demonstrating the importance of having 766 | well-distributed 1D projections. 767 | 5.3. Primitive placement 768 | We finally demonstrate the utility of our three-dimensional projective blue-noise patterns for primitive placement. Our approach 769 | enables arranging objects in 3D in a way that is artistically pleasant [HHD03], has semantic structure along its axes [RRS13] and 770 | fills multiple 2D projection subspaces uniformly. Figure 14 shows 771 | one such arrangement where primitives are sorted by size, brightness and orientation (direction of the primitive’s first principal 772 | c 2015 The Authors 773 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 774 | 10 Reinert et al. / Projective Blue-Noise Sampling 775 | Isotropic 776 | Classic Lloyd Projective Lloyd 777 | Anisotropic 778 | Classic Lloyd 779 | Ground truth 780 | Projective Lloyd 781 | Figure 13: Reconstructions of an isotropic (left) and an anisotropic 782 | (right) 2D zone plate functions using a classic blue-noise pattern 783 | and our projective blue-noise pattern. 784 | Projective 3D blue noise 2D blue noise 3D blue noise 785 | Free view XY projection YZ projection XZ projection 786 | Brightness 787 | Size 788 | Orientation 789 | Size 790 | Brightness 791 | Orientation 792 | Figure 14: Using 3D, 2D and our projective 3D blue-noise patterns 793 | for distributing primitives ordered by brightness, size and orientation along the x-, y- and z-axis, respectively. 794 | component) along the x-, y- and z-axis, respectively. The distances 795 | in the projective Lloyd cost (Eq. (6)) have been computed on a 796 | non-toroidal domain by taking the spatial extent of the objects into 797 | account [RRS13]. When looking at the 2D projection along an axis, 798 | the distribution remains uniform and shows one aspect of the data, 799 | e. g. size and brightness when looking down the z-axis. 800 | 6. Conclusion 801 | We proposed a simple extension to blue-noise sampling that produces patterns with good spectral properties when projected onto 802 | lower dimensional subspaces. Our extension is easy to implement 803 | and likely orthogonal to many ways of generating patterns, as we 804 | demonstrated for two popular methods—dart throwing and Lloyd 805 | relaxation. For MC rendering, we showed that the resulting patterns 806 | perform better than classic blue-noise patterns and on par with or 807 | better than low-discrepancy patterns which have been specifically 808 | designed for the purpose of numerical integration. For primitive 809 | placement, we showed arrangements with uniform distribution in 810 | both 3D space and multiple 2D viewing projections. We believe 811 | our approach is a step towards a single universal multi-dimensional 812 | pattern with a wide range of applications. 813 | Compared to low-discrepancy sequences, our patterns are much 814 | more costly to construct. Compared to the cost of common bluenoise sampling approaches, however, the overhead is small and 815 | the produced patterns are of almost the same quality in the fulldimensional space. For numerical integration, we have found our 816 | projective 2D Lloyd relaxation to perform consistently better than 817 | most other patterns in all our experiments. Nevertheless, our patterns 818 | can be slightly outperformed by low-discrepancy sequences that 819 | achieve perfect 1D stratification for certain sample counts. We have 820 | only demonstrated our method for up to four dimensions; however 821 | our results indicate that it generalizes to higher dimensions, which 822 | are required in full global illumination rendering. 823 | Our implementation is currently limited to rectangular domains 824 | and allows consequently to (optionally rotated) axis-aligned projections, although this is not a limitation of our theoretical formulation. 825 | Extensions to non-orthogonal and non-linear projections is an interesting avenue for further research, which requires a more in-depth 826 | analysis of how such projections and the toroidal tiling influence 827 | each other. Other pertinent future work includes the extension of our 828 | and other sampling algorithms, e.g. capacity-constrained Lloyd relaxation [BSD09] or farthest point optimization [ELPZ97, SHD11], 829 | to projective blue noise and non-linear projections. 830 | References 831 | [BSD09] BALZER M., SCHLOMER ¨ T., DEUSSEN O.: Capacityconstrained point distributions: A variant of Lloyd’s method. 832 | ACM Transactions on Graphics 28, 3 (2009), 86:1–86:8. 833 | [Coo86] COOK R. L.: Stochastic sampling in computer graphics. 834 | ACM Transactions on Graphics 5, 1 (1986), 51–72. 835 | [CP76] CRANLEY R., PATTERSON T.: Randomization of number theoretic methods for multiple integration. SIAM Journal of Numerical Analysis 13, 6 (1976), 904–914. 836 | [CSW94] CHIU K., SHIRLEY P., WANG C.: Multi-jittered sampling. 837 | In Graphics Gems IV (San Diego, CA, USA, 1994), Academic 838 | Press, Professional, Inc., pp. 370–374. 839 | [CYC*12] CHEN Z., YUAN Z., CHOI Y.-K., LIU L., WANG W.: Variational blue noise sampling. IEEE Transactions on Visualization 840 | and Computer Graphics 18, 10 (2012), 1784–1796. 841 | [Dev86] DEVROYE L.: Non-Uniform Random Variate Generation. 842 | Springer-Verlag, New York, 1986. 843 | c 2015 The Authors 844 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. 845 | Reinert et al. / Projective Blue-Noise Sampling 11 846 | [dGBOD12] DE GOES F., BREEDEN K., OSTROMOUKHOV V., DESBRUN 847 | M.: Blue noise through optimal transport. ACM Transactions on 848 | Graphics 31, 6 (2012), 171:1–171:11. 849 | [DW85] DIPPE´ M. A., WOLD E. H.: Antialiasing through stochastic 850 | sampling. ACM SIGGRAPH Computer Graphics 19, 3 (1985), 851 | 69–78. 852 | [ELPZ97] ELDAR Y., LINDENBAUM M., PORAT M., ZEEVI Y. Y.: The farthest point strategy for progressive image sampling. IEEE Transactions on Image Processing 6, 9 (1997), 1305–1315. 853 | [HHD03] HILLER S., HELLWIG H., DEUSSEN O.: Beyond stippling— 854 | Methods for distributing objects in the plane. In Proceedings of 855 | Eurographics (Granada, 2003), vol. 22, pp. 515–522. 856 | [KCODL06] KOPF J., COHEN-OR D., DEUSSEN O., LISCHINSKI D.: 857 | Recursive Wang tiles for real-time blue noise (New York, NY, 858 | USA, 2006), SIGGRAPH ’06, ACM 25, 509–518. 859 | [Ken13] KENSLER A.: Correlated multi-jittered sampling. Pixar 860 | Technical Memo 13-01, 2013. 861 | [KK02] KOLLIG T., KELLER A.: Efficient multidimensional sampling. 862 | In Proceedings of Eurographics(Saarbrucken, 2002), vol. 21, pp. ¨ 863 | 557–563. 864 | [KPR12] KELLER A., PREMOZE S., RAAB M.: Advanced (quasi) Monte 865 | Carlo methods for image synthesis. In ACM SIGGRAPH 2012 866 | Courses (2012), pp. 21:1–21:46. 867 | [KZ77] KORKIN A., ZOLOTAREV G.: Sur les formes quadratiques positives. Mathematische Annalen 11 (1877), 242–292. 868 | [LD06] LAGAE A., DUTRE´ P.: Poisson sphere distributions. In Proceedings of Vision, Modeling, and Visualization 2006 (Aachen, 869 | November 2006), pp. 373–379. 870 | [LD08] LAGAE A., DUTRE´ P.: A comparison of methods for generating Poisson disk distributions. Computer Graphics Forum 27, 1 871 | (2008), 114–129. 872 | [Llo82] LLOYD S.: Least squares quantization in PCM. IEEE Transactions on Information Theory 28, 2 (1982), 129–137. 873 | [LWSF10] LI H.,WEIL.-Y., SANDER P. V., FU C.-W.: Anisotropic blue 874 | noise sampling. In Proceedings of SIGGRAPH (Los Angeles, 875 | 2010), vol. 29, ACM, p. 167. 876 | [MBR*13] MARQUES R., BOUVILLE C., RIBARDIERE M., SANTOS L. P., BOUATOUCH K.: Spherical Fibonacci point sets 877 | for illumination integrals. Computer Graphics Forum 32, 878 | 8 (2013), 134–143. 879 | [MF92] MCCOOL M., FIUME E.: Hierarchical Poisson disk sampling 880 | distributions. In Proceedings of GI (Vancouver, 1992). 881 | [Mit87] MITCHELL D. P.: Generating antialiased images at low sampling densities. SIGGRAPH Computer Graphics 21, 4 (1987), 882 | 65–72. 883 | [Mit91] MITCHELL D. P.: Spectrally optimal sampling for distribution 884 | ray tracing. ACM SIGGRAPH Computer Graphics 25, 4 (1991), 885 | 157–164. 886 | [Mit92] MITCHELL D.: Ray tracing and irregularities of distribution. 887 | In Proceedings of EGWR (Pisa, 1992), pp. 61–69. 888 | [MP09] MITRA N. J., PAULY M.: Shadow art. In Proceedings of 889 | SIGGRAPH (New Orleans, 2009), vol. 28, pp. 156:1–156:7. 890 | [ODJ04] OSTROMOUKHOV V., DONOHUE C., JODOIN P.-M.: Fast hierarchical importance sampling with blue noise properties. In 891 | Proceedings of SIGGRAPH (Los Angeles, 2004), vol. 23, pp. 892 | 488–495. 893 | [PH10] PHARR M., HUMPHREYS G.: Physically Based Rendering: 894 | From Theory to Implementation (San Francisco, CA, USA, 895 | 2010), Morgan Kaufmann. 896 | [RAMN12] RAMAMOORTHI R., ANDERSON J., MEYER M., 897 | NOWROUZEZAHRAI D.: A theory of Monte Carlo visibility sampling. ACM Transactions on Graphics 31, 5 (2012), 121:1– 898 | 121:16. 899 | [RBGP06] ROMERO V. J., BURKARDT J. V., GUNZBURGER M. D., PETERSON J. S.: Initial evaluation of pure and Latinized centroidal 900 | Voronoi tessellation for non-uniform statistical sampling. Rel. 901 | Eng. & Sys. Safety 91, 10 (2006), 1266–1280. 902 | [RRS13] REINERT B., RITSCHEL T., SEIDEL H.-P.: Interactive byexample design of artistic packing layouts. In Proceedings of 903 | SIGGRAPH Asia (Hong Kong, 2013), vol. 32, p. 218. 904 | [SGB07] SAKA Y., GUNZBURGER M., BURKHARDT J.: Latinized, improved LHS, and CVT point sets in hypercubes. International 905 | Journal of Numerical Analysis and Modeling 4, 3–4 (2007), 729– 906 | 743. 907 | [SHD11] SCHLOMER ¨ T., HECK D., DEUSSEN O.: Farthest-point optimized point sets with maximized minimum distance. In Proceedings of HPG (Vancouver, 2011), pp. 135–142. 908 | [Shi91] SHIRLEY P.: Discrepancy as a quality measure for sample 909 | distributions. In Proceedings of Eurographics (Vienna, 1991), 910 | vol. 91, pp. 183–194. 911 | [Sob94] SOBOL I. M.: A Primer for the Monte Carlo Method (1st 912 | edition). Boca Raton, CRC Press, Florida, May 1994. 913 | [Uli87] ULICHNEY R.: Digital Halftoning. MIT Press, Cambridge, 914 | MA, 1987. 915 | [Yel83] YELLOTT J.: Spectral consequences of photoreceptor sampling in the Rhesus retina. Science 221, 4608 (1983), 382–385. 916 | Supporting Information 917 | Additional Supporting Information may be found in the online version of this article at the publisher’s web site: 918 | Images S1 919 | Video S1 920 | c 2015 The Authors 921 | Computer Graphics Forum c 2015 The Eurographics Association and John Wiley & Sons Ltd. -------------------------------------------------------------------------------- /data/psychreport.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atrix256/TextMarkovChain/c23d309d9a689169b447aa891b9604177839b111/data/psychreport.txt -------------------------------------------------------------------------------- /data/readme.txt: -------------------------------------------------------------------------------- 1 | projbluenoise.txt 2 | This is the text from this paper about projective blue noise. 3 | http://resources.mpi-inf.mpg.de/ProjectiveBlueNoise/ProjectiveBlueNoise.pdf 4 | 5 | psychreport.txt 6 | a template psych report 7 | 8 | lastquestion.txt 9 | The last question, by asimov. 10 | http://hell.pl/szymon/Baen/The%20best%20of%20Jim%20Baens%20Universe/The%20World%20Turned%20Upside%20Down/0743498747__18.htm 11 | 12 | telltale.txt 13 | the tell tale heart by Poe 14 | https://poestories.com/read/telltaleheart -------------------------------------------------------------------------------- /data/telltale.txt: -------------------------------------------------------------------------------- 1 | TRUE! -- nervous -- very, very dreadfully nervous I had been and am; but why will you say that I am mad? The disease had sharpened my senses -- not destroyed -- not dulled them. Above all was the sense of hearing acute. I heard all things in the heaven and in the earth. I heard many things in hell. How, then, am I mad? Hearken! and observe how healthily -- how calmly I can tell you the whole story. 2 | 3 | It is impossible to say how first the idea entered my brain; but once conceived, it haunted me day and night. Object there was none. Passion there was none. I loved the old man. He had never wronged me. He had never given me insult. For his gold I had no desire. I think it was his eye! yes, it was this! He had the eye of a vulture --a pale blue eye, with a film over it. Whenever it fell upon me, my blood ran cold; and so by degrees -- very gradually --I made up my mind to take the life of the old man, and thus rid myself of the eye forever. 4 | 5 | Now this is the point. You fancy me mad. Madmen know nothing. But you should have seen me. You should have seen how wisely I proceeded --with what caution --with what foresight --with what dissimulation I went to work! I was never kinder to the old man than during the whole week before I killed him. And every night, about midnight, I turned the latch of his door and opened it --oh so gently! And then, when I had made an opening sufficient for my head, I put in a dark lantern, all closed, closed, so that no light shone out, and then I thrust in my head. Oh, you would have laughed to see how cunningly I thrust it in! I moved it slowly --very, very slowly, so that I might not disturb the old man's sleep. It took me an hour to place my whole head within the opening so far that I could see him as he lay upon his bed. Ha! --would a madman have been so wise as this? And then, when my head was well in the room, I undid the lantern cautiously --oh, so cautiously --cautiously (for the hinges creaked) --I undid it just so much that a single thin ray fell upon the vulture eye. And this I did for seven long nights --every night just at midnight --but I found the eye always closed; and so it was impossible to do the work; for it was not the old man who vexed me, but his Evil Eye. And every morning, when the day broke, I went boldly into the chamber, and spoke courageously to him, calling him by name in a hearty tone, and inquiring how he has passed the night. So you see he would have been a very profound old man, indeed, to suspect that every night, just at twelve, I looked in upon him while he slept. 6 | 7 | Upon the eighth night I was more than usually cautious in opening the door. A watch's minute hand moves more quickly than did mine. Never before that night had I felt the extent of my own powers --of my sagacity. I could scarcely contain my feelings of triumph. To think that there I was, opening the door, little by little, and he not even to dream of my secret deeds or thoughts. I fairly chuckled at the idea; and perhaps he heard me; for he moved on the bed suddenly, as if startled. Now you may think that I drew back --but no. His room was as black as pitch with the thick darkness, (for the shutters were close fastened, through fear of robbers,) and so I knew that he could not see the opening of the door, and I kept pushing it on steadily, steadily. 8 | 9 | I had my head in, and was about to open the lantern, when my thumb slipped upon the tin fastening, and the old man sprang up in bed, crying out --"Who's there?" 10 | 11 | I kept quite still and said nothing. For a whole hour I did not move a muscle, and in the meantime I did not hear him lie down. He was still sitting up in the bed listening; --just as I have done, night after night, hearkening to the death watches in the wall. 12 | 13 | Presently I heard a slight groan, and I knew it was the groan of mortal terror. It was not a groan of pain or of grief --oh, no! --it was the low stifled sound that arises from the bottom of the soul when overcharged with awe. I knew the sound well. Many a night, just at midnight, when all the world slept, it has welled up from my own bosom, deepening, with its dreadful echo, the terrors that distracted me. I say I knew it well. I knew what the old man felt, and pitied him, although I chuckled at heart. I knew that he had been lying awake ever since the first slight noise, when he had turned in the bed. His fears had been ever since growing upon him. He had been trying to fancy them causeless, but could not. He had been saying to himself --"It is nothing but the wind in the chimney --it is only a mouse crossing the floor," or "It is merely a cricket which has made a single chirp." Yes, he had been trying to comfort himself with these suppositions: but he had found all in vain. All in vain; because Death, in approaching him had stalked with his black shadow before him, and enveloped the victim. And it was the mournful influence of the unperceived shadow that caused him to feel --although he neither saw nor heard --to feel the presence of my head within the room. 14 | 15 | When I had waited a long time, very patiently, without hearing him lie down, I resolved to open a little --a very, very little crevice in the lantern. So I opened it --you cannot imagine how stealthily, stealthily --until, at length a single dim ray, like the thread of the spider, shot from out the crevice and fell full upon the vulture eye. 16 | 17 | It was open --wide, wide open --and I grew furious as I gazed upon it. I saw it with perfect distinctness --all a dull blue, with a hideous veil over it that chilled the very marrow in my bones; but I could see nothing else of the old man's face or person: for I had directed the ray as if by instinct, precisely upon the damned spot. 18 | 19 | And have I not told you that what you mistake for madness is but over acuteness of the senses? --now, I say, there came to my ears a low, dull, quick sound, such as a watch makes when enveloped in cotton. I knew that sound well, too. It was the beating of the old man's heart. It increased my fury, as the beating of a drum stimulates the soldier into courage. 20 | 21 | But even yet I refrained and kept still. I scarcely breathed. I held the lantern motionless. I tried how steadily I could maintain the ray upon the eye. Meantime the hellish tattoo of the heart increased. It grew quicker and quicker, and louder and louder every instant. The old man's terror must have been extreme! It grew louder, I say, louder every moment! --do you mark me well? I have told you that I am nervous: so I am. And now at the dead hour of the night, amid the dreadful silence of that old house, so strange a noise as this excited me to uncontrollable terror. Yet, for some minutes longer I refrained and stood still. But the beating grew louder, louder! I thought the heart must burst. And now a new anxiety seized me --the sound would be heard by a neighbor! The old man's hour had come! With a loud yell, I threw open the lantern and leaped into the room. He shrieked once --once only. In an instant I dragged him to the floor, and pulled the heavy bed over him. I then smiled gaily, to find the deed so far done. But, for many minutes, the heart beat on with a muffled sound. This, however, did not vex me; it would not be heard through the wall. At length it ceased. The old man was dead. I removed the bed and examined the corpse. Yes, he was stone, stone dead. I placed my hand upon the heart and held it there many minutes. There was no pulsation. He was stone dead. His eye would trouble me no more. 22 | 23 | If still you think me mad, you will think so no longer when I describe the wise precautions I took for the concealment of the body. The night waned, and I worked hastily, but in silence. First of all I dismembered the corpse. I cut off the head and the arms and the legs. 24 | 25 | I then took up three planks from the flooring of the chamber, and deposited all between the scantlings. I then replaced the boards so cleverly, so cunningly, that no human eye -- not even his --could have detected any thing wrong. There was nothing to wash out --no stain of any kind --no blood-spot whatever. I had been too wary for that. A tub had caught all --ha! ha! 26 | 27 | When I had made an end of these labors, it was four o'clock --still dark as midnight. As the bell sounded the hour, there came a knocking at the street door. I went down to open it with a light heart, --for what had I now to fear? There entered three men, who introduced themselves, with perfect suavity, as officers of the police. A shriek had been heard by a neighbor during the night; suspicion of foul play had been aroused; information had been lodged at the police office, and they (the officers) had been deputed to search the premises. 28 | 29 | I smiled, --for what had I to fear? I bade the gentlemen welcome. The shriek, I said, was my own in a dream. The old man, I mentioned, was absent in the country. I took my visitors all over the house. I bade them search --search well. I led them, at length, to his chamber. I showed them his treasures, secure, undisturbed. In the enthusiasm of my confidence, I brought chairs into the room, and desired them here to rest from their fatigues, while I myself, in the wild audacity of my perfect triumph, placed my own seat upon the very spot beneath which reposed the corpse of the victim. 30 | 31 | The officers were satisfied. My manner had convinced them. I was singularly at ease. They sat, and while I answered cheerily, they chatted of familiar things. But, ere long, I felt myself getting pale and wished them gone. My head ached, and I fancied a ringing in my ears: but still they sat and still chatted. The ringing became more distinct: --it continued and became more distinct: I talked more freely to get rid of the feeling: but it continued and gained definiteness --until, at length, I found that the noise was not within my ears. 32 | 33 | No doubt I now grew very pale; --but I talked more fluently, and with a heightened voice. Yet the sound increased --and what could I do? It was a low, dull, quick sound --much such a sound as a watch makes when enveloped in cotton. I gasped for breath -- and yet the officers heard it not. I talked more quickly --more vehemently; but the noise steadily increased. I arose and argued about trifles, in a high key and with violent gesticulations; but the noise steadily increased. Why would they not be gone? I paced the floor to and fro with heavy strides, as if excited to fury by the observations of the men -- but the noise steadily increased. Oh God! what could I do? I foamed --I raved --I swore! I swung the chair upon which I had been sitting, and grated it upon the boards, but the noise arose over all and continually increased. It grew louder --louder --louder! And still the men chatted pleasantly, and smiled. Was it possible they heard not? Almighty God! --no, no! They heard! --they suspected! --they knew! --they were making a mockery of my horror! --this I thought, and this I think. But anything was better than this agony! Anything was more tolerable than this derision! I could bear those hypocritical smiles no longer! I felt that I must scream or die! --and now --again! --hark! louder! louder! louder! louder! -- 34 | 35 | "Villains!" I shrieked, "dissemble no more! I admit the deed! --tear up the planks! --here, here! --it is the beating of his hideous heart!" -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // array hasher 10 | namespace std 11 | { 12 | template 13 | struct hash > 14 | { 15 | typedef array argument_type; 16 | typedef size_t result_type; 17 | 18 | result_type operator()(const argument_type& a) const 19 | { 20 | hash hasher; 21 | result_type h = 0; 22 | for (result_type i = 0; i < N; ++i) 23 | { 24 | h = h * 31 + hasher(a[i]); 25 | } 26 | return h; 27 | } 28 | }; 29 | } 30 | 31 | template 32 | class MarkovChain 33 | { 34 | public: 35 | 36 | MarkovChain() 37 | : m_rd("dev/random") 38 | , m_fullSeed{ m_rd(), m_rd(), m_rd(), m_rd(), m_rd(), m_rd(), m_rd(), m_rd() } 39 | , m_rng(m_fullSeed) 40 | { 41 | 42 | } 43 | 44 | typedef std::array Observations; 45 | 46 | typedef std::unordered_map TObservedCounts; 47 | 48 | struct ObservedProbability 49 | { 50 | TType observed; 51 | float cumulativeProbability; 52 | }; 53 | 54 | typedef std::vector TObservedProbabilities; 55 | 56 | struct ObservationContext 57 | { 58 | ObservationContext() 59 | { 60 | std::fill(m_hasObservation.begin(), m_hasObservation.end(), false); 61 | } 62 | 63 | Observations m_observations; 64 | std::array m_hasObservation; 65 | }; 66 | 67 | ObservationContext GetObservationContext() 68 | { 69 | return ObservationContext(); 70 | } 71 | 72 | // learning stage 73 | void RecordObservation(ObservationContext& context, const TType& next) 74 | { 75 | // if this observation has a full set of data observed, record this observation 76 | if (context.m_hasObservation[ORDER_N - 1]) 77 | m_counts[context.m_observations][next]++; 78 | 79 | // move all observations down 80 | for (size_t index = ORDER_N - 1; index > 0; --index) 81 | { 82 | context.m_observations[index] = context.m_observations[index - 1]; 83 | context.m_hasObservation[index] = context.m_hasObservation[index - 1]; 84 | } 85 | 86 | // put in the new observation 87 | context.m_observations[0] = next; 88 | context.m_hasObservation[0] = true; 89 | } 90 | 91 | void FinalizeLearning() 92 | { 93 | // turn the sums into cumulative probabilities 94 | for (auto observed : m_counts) 95 | { 96 | size_t sum = 0; 97 | for (auto nextState : observed.second) 98 | sum += nextState.second; 99 | 100 | float probabilitySum = 0.0f; 101 | for (auto nextState : observed.second) 102 | { 103 | float probability = float(nextState.second) / float(sum); 104 | probabilitySum += probability; 105 | m_probabilities[observed.first].push_back(ObservedProbability{ nextState.first, probabilitySum }); 106 | } 107 | } 108 | } 109 | 110 | // data generation stage 111 | Observations GetInitialObservations() 112 | { 113 | // select a starting state entirely at random 114 | std::uniform_int_distribution dist(0, m_probabilities.size()); 115 | size_t index = dist(m_rng); 116 | auto it = m_probabilities.begin(); 117 | std::advance(it, index); 118 | return it->first; 119 | } 120 | 121 | void GetNextObservations(Observations& observations) 122 | { 123 | // get the next state by choosing a weighted random next state. 124 | std::uniform_real_distribution distFloat(0.0f, 1.0f); 125 | TObservedProbabilities& probabilities = m_probabilities[observations]; 126 | if (probabilities.size() == 0) 127 | return; 128 | 129 | float nextStateProbability = distFloat(m_rng); 130 | int nextStateIndex = 0; 131 | while (nextStateIndex < probabilities.size() - 1 && probabilities[nextStateIndex].cumulativeProbability < nextStateProbability) 132 | ++nextStateIndex; 133 | 134 | // move all observations down 135 | for (size_t index = ORDER_N - 1; index > 0; --index) 136 | observations[index] = observations[index - 1]; 137 | 138 | // put the new observation in 139 | observations[0] = probabilities[nextStateIndex].observed; 140 | } 141 | 142 | // random number generation storage 143 | std::random_device m_rd; 144 | std::seed_seq m_fullSeed; 145 | std::mt19937 m_rng; 146 | 147 | // data storage 148 | std::unordered_map m_counts; 149 | std::unordered_map m_probabilities; 150 | }; 151 | 152 | // file output. If you change what type the markov chain works with, you'll have to implement something that handles that type 153 | // like this, for being able to print out the stats file. 154 | template 155 | void fprintf(FILE* file, const Observations& observations) 156 | { 157 | bool first = true; 158 | for (int i = int(observations.size()) - 1; i >= 0; --i) 159 | { 160 | if (first) 161 | ::fprintf(file, "%s", observations[i].c_str()); 162 | else 163 | ::fprintf(file, " %s", observations[i].c_str()); 164 | first = false; 165 | } 166 | } 167 | 168 | MarkovChain g_markovChain; 169 | 170 | bool IsAlphaNumeric(char c) 171 | { 172 | if (c >= 'a' && c <= 'z') 173 | return true; 174 | 175 | if (c >= 'A' && c <= 'Z') 176 | return true; 177 | 178 | if (c >= '0' && c <= '9') 179 | return true; 180 | 181 | if (c == '\'') 182 | return true; 183 | 184 | return false; 185 | } 186 | 187 | bool IsPunctuation(char c) 188 | { 189 | if (c == '.') 190 | return true; 191 | 192 | if (c == ',') 193 | return true; 194 | 195 | if (c == ';') 196 | return true; 197 | 198 | //if (c == '\"') 199 | // return true; 200 | 201 | if (c == ':') 202 | return true; 203 | 204 | if (c == '-') 205 | return true; 206 | 207 | return false; 208 | } 209 | 210 | bool GetWord(unsigned char* contents, size_t size, size_t& position, std::string& word) 211 | { 212 | // skip ignored characters to start 213 | while (position < size && !IsAlphaNumeric(contents[position]) && !IsPunctuation(contents[position])) 214 | position++; 215 | 216 | // exit if there is no word 217 | if (position >= size) 218 | { 219 | word = ""; 220 | return false; 221 | } 222 | 223 | // go until bad character, or end of data 224 | size_t startPosition = position; 225 | if (IsPunctuation(contents[position])) 226 | { 227 | while (position < size && IsPunctuation(contents[position])) 228 | position++; 229 | } 230 | else 231 | { 232 | while (position < size && IsAlphaNumeric(contents[position])) 233 | position++; 234 | } 235 | 236 | // copy the word into the string 237 | word = std::string(&contents[startPosition], &contents[position]); 238 | 239 | // make lowercase for consistency 240 | std::transform(word.begin(), word.end(), word.begin(), ::tolower); 241 | 242 | return true; 243 | } 244 | 245 | bool ProcessFile(const char* fileName) 246 | { 247 | // read the file into memory 248 | FILE* file = nullptr; 249 | fopen_s(&file, fileName, "rt"); 250 | if (!file) 251 | return false; 252 | std::vector contents; 253 | fseek(file, 0, SEEK_END); 254 | contents.resize(ftell(file)); 255 | fseek(file, 0, SEEK_SET); 256 | fread(contents.data(), 1, contents.size(), file); 257 | fclose(file); 258 | 259 | // get an observation context 260 | auto context = g_markovChain.GetObservationContext(); 261 | 262 | // process the file 263 | size_t position = 0; 264 | size_t size = contents.size(); 265 | std::string nextWord; 266 | while(GetWord(contents.data(), size, position, nextWord)) 267 | g_markovChain.RecordObservation(context, nextWord); 268 | 269 | return true; 270 | } 271 | 272 | bool GenerateStatsFile(const char* fileName) 273 | { 274 | FILE* file = nullptr; 275 | fopen_s(&file, fileName, "w+t"); 276 | if (!file) 277 | return false; 278 | 279 | // show the data we have 280 | fprintf(file, "\n\nWord Counts:"); 281 | for (auto& wordCounts : g_markovChain.m_counts) 282 | { 283 | fprintf(file, "\n[+] "); 284 | fprintf(file, wordCounts.first); 285 | fprintf(file, "\n"); 286 | 287 | for (auto& wordCount : wordCounts.second) 288 | fprintf(file, "[++] %s - %zu\n", wordCount.first.c_str(), wordCount.second); 289 | } 290 | 291 | fprintf(file, "\n\nWord Probabilities:"); 292 | for (auto& wordCounts : g_markovChain.m_probabilities) 293 | { 294 | fprintf(file, "\n[-] "); 295 | fprintf(file, wordCounts.first); 296 | fprintf(file, "\n"); 297 | 298 | float lastProbability = 0.0f; 299 | for (auto& wordCount : wordCounts.second) 300 | { 301 | fprintf(file, "[--] %s - %i%%\n", wordCount.observed.c_str(), int((wordCount.cumulativeProbability - lastProbability)*100.0f)); 302 | lastProbability = wordCount.cumulativeProbability; 303 | } 304 | } 305 | 306 | // show the ignored letters 307 | fprintf(file, "\n\nIgnored Letters:\n"); 308 | for (int i = 1; i < 256; ++i) 309 | { 310 | if (IsAlphaNumeric(char(i)) || IsPunctuation(char(i))) 311 | continue; 312 | 313 | fprintf(file, "%c (%i)\n", char(i), i); 314 | } 315 | 316 | return true; 317 | } 318 | 319 | template 320 | bool GenerateFile(const char* fileName, size_t wordCount, MARKOVCHAIN& markovChain) 321 | { 322 | FILE* file = nullptr; 323 | fopen_s(&file, fileName, "w+t"); 324 | if (!file) 325 | return false; 326 | 327 | // get the initial starting state 328 | auto observations = markovChain.GetInitialObservations(); 329 | std::string word = observations[0]; 330 | word[0] = toupper(word[0]); 331 | fprintf(file, "%s", word.c_str()); 332 | 333 | bool capitalizeFirstLetter = false; 334 | 335 | for (size_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) 336 | { 337 | markovChain.GetNextObservations(observations); 338 | 339 | std::string nextWord = observations[0]; 340 | if (capitalizeFirstLetter) 341 | { 342 | nextWord[0] = toupper(nextWord[0]); 343 | capitalizeFirstLetter = false; 344 | } 345 | 346 | if (nextWord == "." || nextWord == "," || nextWord == ";" || nextWord == ":") 347 | fprintf(file, "%s", nextWord.c_str()); 348 | else 349 | fprintf(file, " %s", nextWord.c_str()); 350 | 351 | if (nextWord == ".") 352 | capitalizeFirstLetter = true; 353 | } 354 | 355 | fclose(file); 356 | return true; 357 | } 358 | 359 | int main(int argc, char** argv) 360 | { 361 | std::vector inputFiles = 362 | { 363 | //"data/projbluenoise.txt", 364 | //"data/psychreport.txt", 365 | "data/lastquestion.txt", 366 | "data/telltale.txt", 367 | }; 368 | 369 | // process input 370 | for (const char* inputFile : inputFiles) 371 | { 372 | printf("processing %s...\n", inputFile); 373 | if (!ProcessFile(inputFile)) 374 | { 375 | printf("could not open file %s!\n", inputFile); 376 | return 1; 377 | } 378 | } 379 | 380 | // make probabilities 381 | printf("Calculating probabilities...\n"); 382 | g_markovChain.FinalizeLearning(); 383 | 384 | // make statistics file 385 | if (!GenerateStatsFile("out/stats.txt")) 386 | { 387 | printf("Could not generate stats file!\n"); 388 | return 1; 389 | } 390 | 391 | // make output 392 | if (!GenerateFile("out/generated.txt", 1000, g_markovChain)) 393 | { 394 | printf("Could not generate output file!\n"); 395 | return 1; 396 | } 397 | 398 | return 0; 399 | } 400 | 401 | /* 402 | 403 | Next: try with images? 404 | * maybe just have a "N observed states = M possible outputs" general markov chain. Maybe try it with more than images? letters? audio? i dunno 405 | 406 | Note: all sorts of copies and ineficiencies in code. Runs fast enough for this usage case, and was fast to write, so good enough. 407 | Note: try 0th order (purely random selection of words), 2nd order, 3rd order, etc. Show how it limits options. Need more data i guess. 408 | Note: hitting situations where there is nothing to transition to next? actually i dont think this is an issue 409 | 410 | */ -------------------------------------------------------------------------------- /out/generated.txt: -------------------------------------------------------------------------------- 1 | Before him. I've half a mind to take it into account. I get it, said jerrodine. It was the sense of loss overwhelmed him even so. His thin hands clamped tightly behind his back and lose itself among the blurred pin points. He had never seen this one before. Would he ever see them all in being the original galaxy of man the universal ac how may stars be kept from dying dee sub wun said, on which one i cannot imagine. Nor could anyone, for in a way, man, mentally, was one. He had never seen this one before. Would he ever see them all so many hundreds of billions of years. The energy we could ever use, forever and forever and forever. Lupov cocked his head sideways. He consisted of a spaceship. Jerrodd shrugged. Now, honeys. I'll ask microvac. Don't worry, he'll tell us. He was still left and sipped gently at his small ac - contact on the table before him. I had been answered, and space grew black after ten trillion years and then, am i mad hearken and observe how healthily -- how calmly i can tell you, it's time for bed. Ha -- would a madman have been a universe and brooded over what was now chaos. Step by step, it did all right. Who says they won't you did, you poor sap. You should have seen how wisely i proceeded -- with what caution -- with what dissimulation i went to work i was singularly at ease. They had no desire. I fairly chuckled at heart. It was adell's turn to be able to phrase the necessary data to answer deeper questions more fundamentally, and flipped the switch that connected all of universal ac kept itself aloof. Zee prime knew of only one star for every thousand white dwarfs might yet be built. Man looked about at the visiplate. I went down to open it with perfect suavity, as in such cases was constructed for their physical bodies in time. Yes, he had been the answer. Man said, the energy we could ever use for free. Enough energy, if we wanted to see the opening so far that i drew back -- but i found the eye forever. Now look what you've done, the real essence of men was to relax in the visiplate. I fairly chuckled at the present rate of expansion. Both seemed in their lives and were self - correcting. It was as black as pitch with the great galactic ac. It took me an hour to place my whole head within the room. When i had directed the ray upon the eye forever. Till the sun will last twenty billion, maybe. Are you sure, jerrodd what is wrong the stars are the power - units, dear. Once they're gone, our bodies will finally die, and those would come to a preordered destination; of feeding on energies from the flooring of the heart and held it there many minutes, the real essence of men was to be but sure asked jerrodd, glancing up at the end. Our energy requirements are going up in a dark lantern, when he thought that his own galaxy. One of them, and desired them here to rest from their fatigues, while i answered cheerily, they knew what lay behind the cold, clicking, flashing face miles and miles of face of that old house, so cautiously -- oh, say, there came to pass that ac learned how to turn the stars were white dwarfs might yet be built. Man said, the heart and held it there many minutes, the other, and he reported only a mouse crossing the floor to and fro with heavy strides, as he lay upon his bed. We'll just have to face someday. He was stone, stone dead. They had brought a bottle with them. Above all was the sense of hearing acute. I then replaced the boards, but could not see the two, plagued with throbbing head and the boys appreciated that. They must all die. Why not but when all the good they are. But you should have seen me. He was part of his ac - contact, can entropy not be reversed vj - 23x said, man's original star of man. But how can the net amount of entropy. We ought to ask multivac. I took for the concealment of the mighty forces so released, new stars out of galaxies. In the original star is dead. His eye yes, of disturbing it. Whenever it fell upon the heart and held it there many minutes, the giants won't last forever. You fancy me mad, you will think so no longer, there came a knocking at the idea; and so i am nervous: so i knew the sound of the mighty buried body of multivac. I tried how steadily i could see nothing else of the victim. The energy we could ever use, forever and forever. All the time. Even the stars must someday die, at a time, said jerrodine sharply. Are you two hundred. But, for many minutes, the two, plagued with throbbing head and cottony mouth, had earned its vacation and the arms and the legs. I had been the answer. Will there -------------------------------------------------------------------------------- /out/stats.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atrix256/TextMarkovChain/c23d309d9a689169b447aa891b9604177839b111/out/stats.txt --------------------------------------------------------------------------------