1.. 2 PLEASE DO NOT EDIT DIRECTLY. EDIT THE .rst.in FILE PLEASE. 3 4Cookbook part 2: Random things, and some math 5================================================================ 6 7Randomly selecting words from a list 8---------------------------------------------------------------- 9 10Given this `word list <https://github.com/johnkerl/miller/blob/master/docs/data/english-words.txt>`_, first take a look to see what the first few lines look like: 11 12:: 13 14 $ head data/english-words.txt 15 a 16 aa 17 aal 18 aalii 19 aam 20 aardvark 21 aardwolf 22 aba 23 abac 24 abaca 25 26Then the following will randomly sample ten words with four to eight characters in them: 27 28:: 29 30 $ mlr --from data/english-words.txt --nidx filter -S 'n=strlen($1);4<=n&&n<=8' then sample -k 10 31 thionine 32 birchman 33 mildewy 34 avigate 35 addedly 36 abaze 37 askant 38 aiming 39 insulant 40 coinmate 41 42Randomly generating jabberwocky words 43---------------------------------------------------------------- 44 45These are simple *n*-grams as `described here <http://johnkerl.org/randspell/randspell-slides-ts.pdf>`_. Some common functions are `located here <https://github.com/johnkerl/miller/blob/master/docs/ngrams/ngfuncs.mlr.txt>`_. Then here are scripts for `1-grams <https://github.com/johnkerl/miller/blob/master/docs/ngrams/ng1.mlr.txt>`_ `2-grams <https://github.com/johnkerl/miller/blob/master/docs/ngrams/ng2.mlr.txt>`_ `3-grams <https://github.com/johnkerl/miller/blob/master/docs/ngrams/ng3.mlr.txt>`_ `4-grams <https://github.com/johnkerl/miller/blob/master/docs/ngrams/ng4.mlr.txt>`_, and `5-grams <https://github.com/johnkerl/miller/blob/master/docs/ngrams/ng5.mlr.txt>`_. 46 47The idea is that words from the input file are consumed, then taken apart and pasted back together in ways which imitate the letter-to-letter transitions found in the word list -- giving us automatically generated words in the same vein as *bromance* and *spork*: 48 49:: 50 51 $ mlr --nidx --from ./ngrams/gsl-2000.txt put -q -f ./ngrams/ngfuncs.mlr -f ./ngrams/ng5.mlr 52 beard 53 plastinguish 54 politicially 55 noise 56 loan 57 country 58 controductionary 59 suppery 60 lose 61 lessors 62 dollar 63 judge 64 rottendence 65 lessenger 66 diffendant 67 suggestional 68 69Program timing 70---------------------------------------------------------------- 71 72This admittedly artificial example demonstrates using Miller time and stats functions to introspectively acquire some information about Miller's own runtime. The ``delta`` function computes the difference between successive timestamps. 73 74:: 75 76 $ ruby -e '10000.times{|i|puts "i=#{i+1}"}' > lines.txt 77 78 $ head -n 5 lines.txt 79 i=1 80 i=2 81 i=3 82 i=4 83 i=5 84 85 mlr --ofmt '%.9le' --opprint put '$t=systime()' then step -a delta -f t lines.txt | head -n 7 86 i t t_delta 87 1 1430603027.018016 1.430603027e+09 88 2 1430603027.018043 2.694129944e-05 89 3 1430603027.018048 5.006790161e-06 90 4 1430603027.018052 4.053115845e-06 91 5 1430603027.018055 2.861022949e-06 92 6 1430603027.018058 3.099441528e-06 93 94 mlr --ofmt '%.9le' --oxtab \ 95 put '$t=systime()' then \ 96 step -a delta -f t then \ 97 filter '$i>1' then \ 98 stats1 -a min,mean,max -f t_delta \ 99 lines.txt 100 t_delta_min 2.861022949e-06 101 t_delta_mean 4.077508505e-06 102 t_delta_max 5.388259888e-05 103 104Computing interquartile ranges 105---------------------------------------------------------------- 106 107For one or more specified field names, simply compute p25 and p75, then write the IQR as the difference of p75 and p25: 108 109:: 110 111 $ mlr --oxtab stats1 -f x -a p25,p75 \ 112 then put '$x_iqr = $x_p75 - $x_p25' \ 113 data/medium 114 x_p25 0.246670 115 x_p75 0.748186 116 x_iqr 0.501516 117 118For wildcarded field names, first compute p25 and p75, then loop over field names with ``p25`` in them: 119 120:: 121 122 $ mlr --oxtab stats1 --fr '[i-z]' -a p25,p75 \ 123 then put 'for (k,v in $*) { 124 if (k =~ "(.*)_p25") { 125 $["\1_iqr"] = $["\1_p75"] - $["\1_p25"] 126 } 127 }' \ 128 data/medium 129 i_p25 2501 130 i_p75 7501 131 x_p25 0.246670 132 x_p75 0.748186 133 y_p25 0.252137 134 y_p75 0.764003 135 i_iqr 5000 136 x_iqr 0.501516 137 y_iqr 0.511866 138 139Computing weighted means 140---------------------------------------------------------------- 141 142This might be more elegantly implemented as an option within the ``stats1`` verb. Meanwhile, it's expressible within the DSL: 143 144:: 145 146 $ mlr --from data/medium put -q ' 147 # Using the y field for weighting in this example 148 weight = $y; 149 150 # Using the a field for weighted aggregation in this example 151 @sumwx[$a] += weight * $i; 152 @sumw[$a] += weight; 153 154 @sumx[$a] += $i; 155 @sumn[$a] += 1; 156 157 end { 158 map wmean = {}; 159 map mean = {}; 160 for (a in @sumwx) { 161 wmean[a] = @sumwx[a] / @sumw[a] 162 } 163 for (a in @sumx) { 164 mean[a] = @sumx[a] / @sumn[a] 165 } 166 #emit wmean, "a"; 167 #emit mean, "a"; 168 emit (wmean, mean), "a"; 169 }' 170 a=pan,wmean=4979.563722,mean=5028.259010 171 a=eks,wmean=4890.381593,mean=4956.290076 172 a=wye,wmean=4946.987746,mean=4920.001017 173 a=zee,wmean=5164.719685,mean=5123.092330 174 a=hat,wmean=4925.533162,mean=4967.743946 175 176Generating random numbers from various distributions 177---------------------------------------------------------------- 178 179Here we can chain together a few simple building blocks: 180 181:: 182 183 $ cat expo-sample.sh 184 # Generate 100,000 pairs of independent and identically distributed 185 # exponentially distributed random variables with the same rate parameter 186 # (namely, 2.5). Then compute histograms of one of them, along with 187 # histograms for their sum and their product. 188 # 189 # See also https://en.wikipedia.org/wiki/Exponential_distribution 190 # 191 # Here I'm using a specified random-number seed so this example always 192 # produces the same output for this web document: in everyday practice we 193 # wouldn't do that. 194 195 mlr -n \ 196 --seed 0.25 \ 197 --opprint \ 198 seqgen --stop 100000 \ 199 then put ' 200 # https://en.wikipedia.org/wiki/Inverse_transform_sampling 201 func expo_sample(lambda) { 202 return -log(1-urand())/lambda 203 } 204 $u = expo_sample(2.5); 205 $v = expo_sample(2.5); 206 $s = $u + $v; 207 $p = $u * $v; 208 ' \ 209 then histogram -f u,s,p --lo 0 --hi 2 --nbins 50 \ 210 then bar -f u_count,s_count,p_count --auto -w 20 211 212Namely: 213 214* Set the Miller random-number seed so this webdoc looks the same every time I regenerate it. 215* Use pretty-printed tabular output. 216* Use pretty-printed tabular output. 217* Use ``seqgen`` to produce 100,000 records ``i=0``, ``i=1``, etc. 218* Send those to a ``put`` step which defines an inverse-transform-sampling function and calls it twice, then computes the sum and product of samples. 219* Send those to a histogram, and from there to a bar-plotter. This is just for visualization; you could just as well output CSV and send that off to your own plotting tool, etc. 220 221The output is as follows: 222 223:: 224 225 $ sh expo-sample.sh 226 bin_lo bin_hi u_count s_count p_count 227 0.000000 0.040000 [78]*******************#[9497] [353]#...................[3732] [20]*******************#[39755] 228 0.040000 0.080000 [78]******************..[9497] [353]*****...............[3732] [20]*******.............[39755] 229 0.080000 0.120000 [78]****************....[9497] [353]*********...........[3732] [20]****................[39755] 230 0.120000 0.160000 [78]**************......[9497] [353]************........[3732] [20]***.................[39755] 231 0.160000 0.200000 [78]*************.......[9497] [353]**************......[3732] [20]**..................[39755] 232 0.200000 0.240000 [78]************........[9497] [353]****************....[3732] [20]*...................[39755] 233 0.240000 0.280000 [78]**********..........[9497] [353]******************..[3732] [20]*...................[39755] 234 0.280000 0.320000 [78]**********..........[9497] [353]******************..[3732] [20]*...................[39755] 235 0.320000 0.360000 [78]*********...........[9497] [353]*******************.[3732] [20]#...................[39755] 236 0.360000 0.400000 [78]********............[9497] [353]*******************.[3732] [20]#...................[39755] 237 0.400000 0.440000 [78]*******.............[9497] [353]*******************#[3732] [20]#...................[39755] 238 0.440000 0.480000 [78]******..............[9497] [353]******************..[3732] [20]#...................[39755] 239 0.480000 0.520000 [78]*****...............[9497] [353]******************..[3732] [20]#...................[39755] 240 0.520000 0.560000 [78]*****...............[9497] [353]******************..[3732] [20]#...................[39755] 241 0.560000 0.600000 [78]****................[9497] [353]*****************...[3732] [20]#...................[39755] 242 0.600000 0.640000 [78]****................[9497] [353]*****************...[3732] [20]#...................[39755] 243 0.640000 0.680000 [78]****................[9497] [353]****************....[3732] [20]#...................[39755] 244 0.680000 0.720000 [78]***.................[9497] [353]****************....[3732] [20]#...................[39755] 245 0.720000 0.760000 [78]***.................[9497] [353]**************......[3732] [20]#...................[39755] 246 0.760000 0.800000 [78]**..................[9497] [353]**************......[3732] [20]#...................[39755] 247 0.800000 0.840000 [78]**..................[9497] [353]*************.......[3732] [20]#...................[39755] 248 0.840000 0.880000 [78]**..................[9497] [353]************........[3732] [20]#...................[39755] 249 0.880000 0.920000 [78]**..................[9497] [353]***********.........[3732] [20]#...................[39755] 250 0.920000 0.960000 [78]*...................[9497] [353]***********.........[3732] [20]#...................[39755] 251 0.960000 1.000000 [78]*...................[9497] [353]**********..........[3732] [20]#...................[39755] 252 1.000000 1.040000 [78]*...................[9497] [353]*********...........[3732] [20]#...................[39755] 253 1.040000 1.080000 [78]*...................[9497] [353]*********...........[3732] [20]#...................[39755] 254 1.080000 1.120000 [78]*...................[9497] [353]********............[3732] [20]#...................[39755] 255 1.120000 1.160000 [78]*...................[9497] [353]********............[3732] [20]#...................[39755] 256 1.160000 1.200000 [78]#...................[9497] [353]*******.............[3732] [20]#...................[39755] 257 1.200000 1.240000 [78]#...................[9497] [353]******..............[3732] [20]#...................[39755] 258 1.240000 1.280000 [78]#...................[9497] [353]*****...............[3732] [20]#...................[39755] 259 1.280000 1.320000 [78]#...................[9497] [353]*****...............[3732] [20]#...................[39755] 260 1.320000 1.360000 [78]#...................[9497] [353]*****...............[3732] [20]#...................[39755] 261 1.360000 1.400000 [78]#...................[9497] [353]****................[3732] [20]#...................[39755] 262 1.400000 1.440000 [78]#...................[9497] [353]****................[3732] [20]#...................[39755] 263 1.440000 1.480000 [78]#...................[9497] [353]***.................[3732] [20]#...................[39755] 264 1.480000 1.520000 [78]#...................[9497] [353]***.................[3732] [20]#...................[39755] 265 1.520000 1.560000 [78]#...................[9497] [353]***.................[3732] [20]#...................[39755] 266 1.560000 1.600000 [78]#...................[9497] [353]**..................[3732] [20]#...................[39755] 267 1.600000 1.640000 [78]#...................[9497] [353]**..................[3732] [20]#...................[39755] 268 1.640000 1.680000 [78]#...................[9497] [353]*...................[3732] [20]#...................[39755] 269 1.680000 1.720000 [78]#...................[9497] [353]*...................[3732] [20]#...................[39755] 270 1.720000 1.760000 [78]#...................[9497] [353]*...................[3732] [20]#...................[39755] 271 1.760000 1.800000 [78]#...................[9497] [353]*...................[3732] [20]#...................[39755] 272 1.800000 1.840000 [78]#...................[9497] [353]#...................[3732] [20]#...................[39755] 273 1.840000 1.880000 [78]#...................[9497] [353]#...................[3732] [20]#...................[39755] 274 1.880000 1.920000 [78]#...................[9497] [353]#...................[3732] [20]#...................[39755] 275 1.920000 1.960000 [78]#...................[9497] [353]#...................[3732] [20]#...................[39755] 276 1.960000 2.000000 [78]#...................[9497] [353]#...................[3732] [20]#...................[39755] 277 278Sieve of Eratosthenes 279---------------------------------------------------------------- 280 281The `Sieve of Eratosthenes <http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>`_ is a standard introductory programming topic. The idea is to find all primes up to some *N* by making a list of the numbers 1 to *N*, then striking out all multiples of 2 except 2 itself, all multiples of 3 except 3 itself, all multiples of 4 except 4 itself, and so on. Whatever survives that without getting marked is a prime. This is easy enough in Miller. Notice that here all the work is in ``begin`` and ``end`` statements; there is no file input (so we use ``mlr -n`` to keep Miller from waiting for input data). 282 283:: 284 285 $ cat programs/sieve.mlr 286 # ================================================================ 287 # Sieve of Eratosthenes: simple example of Miller DSL as programming language. 288 # ================================================================ 289 290 # Put this in a begin-block so we can do either 291 # mlr -n put -q -f name-of-this-file.mlr 292 # or 293 # mlr -n put -q -f name-of-this-file.mlr -e '@n = 200' 294 # i.e. 100 is the default upper limit, and another can be specified using -e. 295 begin { 296 @n = 100; 297 } 298 299 end { 300 for (int i = 0; i <= @n; i += 1) { 301 @s[i] = true; 302 } 303 @s[0] = false; # 0 is neither prime nor composite 304 @s[1] = false; # 1 is neither prime nor composite 305 # Strike out multiples 306 for (int i = 2; i <= @n; i += 1) { 307 for (int j = i+i; j <= @n; j += i) { 308 @s[j] = false; 309 } 310 } 311 # Print survivors 312 for (int i = 0; i <= @n; i += 1) { 313 if (@s[i]) { 314 print i; 315 } 316 } 317 } 318 319:: 320 321 $ mlr -n put -f programs/sieve.mlr 322 2 323 3 324 5 325 7 326 11 327 13 328 17 329 19 330 23 331 29 332 31 333 37 334 41 335 43 336 47 337 53 338 59 339 61 340 67 341 71 342 73 343 79 344 83 345 89 346 97 347 348Mandelbrot-set generator 349---------------------------------------------------------------- 350 351The `Mandelbrot set <http://en.wikipedia.org/wiki/Mandelbrot_set>`_ is also easily expressed. This isn't an important case of data-processing in the vein for which Miller was designed, but it is an example of Miller as a general-purpose programming language -- a test case for the expressiveness of the language. 352 353The (approximate) computation of points in the complex plane which are and aren't members is just a few lines of complex arithmetic (see the Wikipedia article); how to render them is another task. Using graphics libraries you can create PNG or JPEG files, but another fun way to do this is by printing various characters to the screen: 354 355:: 356 357 $ cat programs/mand.mlr 358 # Mandelbrot set generator: simple example of Miller DSL as programming language. 359 begin { 360 # Set defaults 361 @rcorn = -2.0; 362 @icorn = -2.0; 363 @side = 4.0; 364 @iheight = 50; 365 @iwidth = 100; 366 @maxits = 100; 367 @levelstep = 5; 368 @chars = "@X*o-."; # Palette of characters to print to the screen. 369 @verbose = false; 370 @do_julia = false; 371 @jr = 0.0; # Real part of Julia point, if any 372 @ji = 0.0; # Imaginary part of Julia point, if any 373 } 374 375 # Here, we can override defaults from an input file (if any). In Miller's 376 # put/filter DSL, absent-null right-hand sides result in no assignment so we 377 # can simply put @rcorn = $rcorn: if there is a field in the input like 378 # 'rcorn = -1.847' we'll read and use it, else we'll keep the default. 379 @rcorn = $rcorn; 380 @icorn = $icorn; 381 @side = $side; 382 @iheight = $iheight; 383 @iwidth = $iwidth; 384 @maxits = $maxits; 385 @levelstep = $levelstep; 386 @chars = $chars; 387 @verbose = $verbose; 388 @do_julia = $do_julia; 389 @jr = $jr; 390 @ji = $ji; 391 392 end { 393 if (@verbose) { 394 print "RCORN = ".@rcorn; 395 print "ICORN = ".@icorn; 396 print "SIDE = ".@side; 397 print "IHEIGHT = ".@iheight; 398 print "IWIDTH = ".@iwidth; 399 print "MAXITS = ".@maxits; 400 print "LEVELSTEP = ".@levelstep; 401 print "CHARS = ".@chars; 402 } 403 404 # Iterate over a matrix of rows and columns, printing one character for each cell. 405 for (int ii = @iheight-1; ii >= 0; ii -= 1) { 406 num pi = @icorn + (ii/@iheight) * @side; 407 for (int ir = 0; ir < @iwidth; ir += 1) { 408 num pr = @rcorn + (ir/@iwidth) * @side; 409 printn get_point_plot(pr, pi, @maxits, @do_julia, @jr, @ji); 410 } 411 print; 412 } 413 } 414 415 # This is a function to approximate membership in the Mandelbrot set (or Julia 416 # set for a given Julia point if do_julia == true) for a given point in the 417 # complex plane. 418 func get_point_plot(pr, pi, maxits, do_julia, jr, ji) { 419 num zr = 0.0; 420 num zi = 0.0; 421 num cr = 0.0; 422 num ci = 0.0; 423 424 if (!do_julia) { 425 zr = 0.0; 426 zi = 0.0; 427 cr = pr; 428 ci = pi; 429 } else { 430 zr = pr; 431 zi = pi; 432 cr = jr; 433 ci = ji; 434 } 435 436 int iti = 0; 437 bool escaped = false; 438 num zt = 0; 439 for (iti = 0; iti < maxits; iti += 1) { 440 num mag = zr*zr + zi+zi; 441 if (mag > 4.0) { 442 escaped = true; 443 break; 444 } 445 # z := z^2 + c 446 zt = zr*zr - zi*zi + cr; 447 zi = 2*zr*zi + ci; 448 zr = zt; 449 } 450 if (!escaped) { 451 return "."; 452 } else { 453 # The // operator is Miller's (pythonic) integer-division operator 454 int level = (iti // @levelstep) % strlen(@chars); 455 return substr(@chars, level, level); 456 } 457 } 458 459At standard resolution this makes a nice little ASCII plot: 460 461:: 462 463 $ mlr -n put -f ./programs/mand.mlr 464 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 465 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 466 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 467 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 468 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 469 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 470 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 471 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 472 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 473 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 474 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 475 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXX.XXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 476 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXooXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 477 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXX**o..*XXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 478 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXX*-....-oXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 479 @@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXX@XXXXXXXXXX*......o*XXXXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 480 @@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXX**oo*-.-........oo.XXXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 481 @@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXXXXX....................X..o-XXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 482 @@@@@@@@@@@@@@@@@@XXXXXXXXXXXXXXX*oo......................oXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 483 @@@@@@@@@@@@@@@@XXX*XXXXXXXXXXXX**o........................*X*X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 484 @@@@@@@@@@@@@XXXXXXooo***o*.*XX**X..........................o-XX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 485 @@@@@@@@@@@XXXXXXXX*-.......-***.............................oXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 486 @@@@@@@@@@XXXXXXXX*@..........Xo............................*XX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 487 @@XXXX@XXXXXXXX*o@oX...........@...........................oXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 488 .........................................................o*XXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 489 @@@@@@XXXXXXXXX*-.oX...........@...........................oXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 490 @@@@@@@XXXXXXXXXX**@..........*o............................*XXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 491 @@@@@@@XXXXXXXXXXXXX-........***.............................oXXXXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 492 @@@@@@@XXXXXXXXXXXXoo****o*.XX***@..........................o-XXXXXXXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@ 493 @@@@@@@@@@@@@@XXXXX*XXXX*XXXXXXX**-........................***XXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 494 @@@@@@@@@@@@@@@@@@@@XXXXXXXXXXXXX*o*.....................@o*XXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 495 @@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXXXX*....................*..o-XX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 496 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXX*ooo*-.o........oo.X*XXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 497 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXX**@.....*XXXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 498 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXX*o....-o*XXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 499 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXXo*o..*XXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 500 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXXXXX*o*XXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 501 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXXXX@XXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 502 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXX@@XXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 503 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XXXXX@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 504 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 505 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 506 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 507 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 508 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 509 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 510 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 511 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 512 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 513 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 514 515But using a very small font size (as small as my Mac will let me go), and by choosing the coordinates to zoom in on a particular part of the complex plane, we can get a nice little picture: 516 517:: 518 519 #!/bin/bash 520 # Get the number of rows and columns from the terminal window dimensions 521 iheight=$(stty size | mlr --nidx --fs space cut -f 1) 522 iwidth=$(stty size | mlr --nidx --fs space cut -f 2) 523 echo "rcorn=-1.755350,icorn=+0.014230,side=0.000020,maxits=10000,iheight=$iheight,iwidth=$iwidth" \ 524 | mlr put -f programs/mand.mlr 525 526.. image:: pix/mand.png 527