├── .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
--------------------------------------------------------------------------------