{"id":20858490,"url":"https://github.com/tylermorganwall/spacefillr","last_synced_at":"2025-05-12T08:31:21.164Z","repository":{"id":56934014,"uuid":"338888486","full_name":"tylermorganwall/spacefillr","owner":"tylermorganwall","description":"R Package for Space-Filling Random and Quasi-Random Sequences","archived":false,"fork":false,"pushed_at":"2024-05-22T02:32:52.000Z","size":25115,"stargazers_count":7,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-28T17:24:07.568Z","etag":null,"topics":["halton-sequence","quasi-random-generator","sobol-sequence"],"latest_commit_sha":null,"homepage":"http://www.spacefillr.com","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tylermorganwall.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-14T19:51:05.000Z","updated_at":"2024-10-16T06:02:58.000Z","dependencies_parsed_at":"2024-05-22T03:43:47.689Z","dependency_job_id":null,"html_url":"https://github.com/tylermorganwall/spacefillr","commit_stats":{"total_commits":26,"total_committers":2,"mean_commits":13.0,"dds":0.07692307692307687,"last_synced_commit":"6f820c7eb7a9535a9820f01469956fbea4ea0ca3"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylermorganwall%2Fspacefillr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylermorganwall%2Fspacefillr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylermorganwall%2Fspacefillr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylermorganwall%2Fspacefillr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tylermorganwall","download_url":"https://codeload.github.com/tylermorganwall/spacefillr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225130756,"owners_count":17425506,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["halton-sequence","quasi-random-generator","sobol-sequence"],"created_at":"2024-11-18T04:46:11.978Z","updated_at":"2025-05-12T08:31:21.116Z","avatar_url":"https://github.com/tylermorganwall.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\neditor_options: \n  chunk_output_type: console\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  fig.width = 8,\n  fig.height = 6,\n  out.width = \"100%\"\n)\n```\n\n# spacefillr\n\n\u003c!-- badges: start --\u003e\n[![R build status](https://github.com/tylermorganwall/spacefillr/workflows/R-CMD-check/badge.svg)](https://github.com/tylermorganwall/spacefillr/actions)\n[![R-CMD-check](https://github.com/tylermorganwall/spacefillr/workflows/R-CMD-check/badge.svg)](https://github.com/tylermorganwall/spacefillr/actions)\n[![R-CMD-check](https://github.com/tylermorganwall/spacefillr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tylermorganwall/spacefillr/actions/workflows/R-CMD-check.yaml)\n\u003c!-- badges: end --\u003e\n\nspacefillr is a package for generating random and quasi-random space-filling sequences. Supports the following sequences: 'Halton', 'Sobol', 'Owen'-scrambled 'Sobol', 'Owen'-scrambled 'Sobol' with errors distributed as blue noise, progressive jittered, progressive multi-jittered ('PMJ'), 'PMJ' with blue noise, 'PMJ02', and 'PMJ02' with blue noise. Includes a 'C++' 'API'. Methods derived from \"Constructing Sobol sequences with better two-dimensional projections\" (2012) S. Joe and F. Y. Kuo, and \"Progressive Multi‐Jittered Sample Sequences\" (2018) Christensen, P., Kensler, A. and Kilpatrick, C, and \"A Low-Discrepancy Sampler that Distributes Monte Carlo Errors as a Blue Noise in Screen Space\" (2019) E. Heitz, B. Laurent, O. Victor, C. David and I. Jean-Claude. \n\n## Installation\n\nYou can install the released version of spacefillr from Github with the following:\n\n``` r\nremotes::install_github(\"tylermorganwall/spacefillr\")\n```\n\n## Example\n\nGenerating random sequences is an important topic when trying to solve problems using Monte Carlo methods. Careful choice of the correct random (or quasi-random) sequence can result in much faster convergence to the final answer. Let's take the problem of solving for the value of Pi by counting the number of values that fall within the unit circle. If we generate random values between 0 and 1, count how many fall within the unit circle, multiply by 4 and divide by the number of samples, we will get an estimate for Pi.\n\nLet's first try this with purely uniform random numbers:\n\n```{r example, warning=FALSE,message=FALSE}\nlibrary(ggplot2)\nlibrary(dplyr)\nset.seed(1)\nresults_rand = as.data.frame(matrix(runif(2000),ncol=2))\ncolnames(results_rand) = c(\"x\",\"y\")\n\nresults_rand %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1) %\u003e% \n  ggplot() + \n  geom_point(aes(x=x,y=y,color=inside)) +\n  coord_fixed()\n```\n\nWe can plot the convergence:\n\n```{r convergence1}\nresults_rand_convergence = results_rand %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1, iteration = 1:n()) %\u003e% \n  mutate(pi_estimate = 4*cumsum(inside)/iteration) \n\nggplot(results_rand_convergence) +\n  geom_hline(yintercept = pi, alpha=0.25,color=\"black\",size=2) +\n  geom_line(aes(x=iteration,y=pi_estimate))\n```\n\nUniform random numbers, however, have poor convergence properties. We can do better by using spacefillr to generate sequences that are more evenly distributed throughout space, which helps these Monte Carlo integrals converge more quickly.\n\nWe'll first start with a Halton sequence:\n\n```{r halton}\nlibrary(spacefillr)\n\nresults_halton = as.data.frame(generate_halton_random_set(1000,2,seed=1))\ncolnames(results_halton) = c(\"x\",\"y\")\n\nresults_halton %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1) %\u003e% \n  ggplot() + \n  geom_point(aes(x=x,y=y,color=inside)) +\n  coord_fixed()\n```\n\nThese samples are much more evenly distributed. Let's compare the convergence of this sequence to random uniform numbers:\n\n```{r convergence2}\nresults_halton_convergence = results_halton %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1, iteration = 1:n()) %\u003e% \n  mutate(pi_estimate = 4*cumsum(inside)/iteration) \n\nggplot() +\n  geom_hline(yintercept = pi, alpha=0.25,color=\"black\",linewidth=2) +\n  geom_line(data=results_rand_convergence,aes(x=iteration,y=pi_estimate), color=\"red\") +\n  geom_line(data=results_halton_convergence,aes(x=iteration,y=pi_estimate), color=\"black\")\n```\n\nWe can see this set of quasi-random numbers converges significantly faster than random uniform. Let's now use the gold-standard quasi-random sequence: Owen-scrambled Sobol. (note: another function `generate_sobol_owen_fast_set()` is also included in the package that outputs near-ideal Owen scrambled Sobol numbers, but is much faster).\n\n```{r sobol}\nresults_owen_sobol = as.data.frame(generate_sobol_owen_set(1000,2,seed=1))\ncolnames(results_owen_sobol) = c(\"x\",\"y\")\n\nresults_owen_sobol %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1) %\u003e% \n  ggplot() + \n  geom_point(aes(x=x,y=y,color=inside)) +\n  coord_fixed()\n```\n\nLet's look at the convergence properties of this set.\n\n```{r convergence3}\nresults_owen_sobol_convergence = results_owen_sobol %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1, iteration = 1:n()) %\u003e% \n  mutate(pi_estimate = 4*cumsum(inside)/iteration) \n\nggplot() +\n  geom_hline(yintercept = pi, alpha=0.25,color=\"black\",linewidth=2) +\n  geom_line(data=results_rand_convergence,aes(x=iteration,y=pi_estimate), color=\"red\") +\n  geom_line(data=results_halton_convergence,aes(x=iteration,y=pi_estimate), color=\"black\") + \n  geom_line(data=results_owen_sobol_convergence,aes(x=iteration,y=pi_estimate), color=\"green\") +\n  scale_y_continuous(limits=c(3,4))\n```\n\nOwen-scrambled Sobol converges the fastest out of all of the sequences. Also included are the progressive multijittered sequences, of which pmj02 has similar convergence properties to Owen-scrambled Sobol.\n\n```{r pmj02}\nresults_owen_pmj02 = as.data.frame(generate_pmj02_set(1000,seed=1))\ncolnames(results_owen_pmj02) = c(\"x\",\"y\")\n\nresults_owen_pmj02 %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1) %\u003e% \n  ggplot() + \n  geom_point(aes(x=x,y=y,color=inside)) +\n  coord_fixed()\n```\n\nWe can compare this to Owen-scrambled Sobol:\n\n```{r convergence4}\nresults_owen_pmj02_convergence = results_owen_pmj02 %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1, iteration = 1:n()) %\u003e% \n  mutate(pi_estimate = 4*cumsum(inside)/iteration) \n\nggplot() +\n  geom_hline(yintercept = pi, alpha=0.25,color=\"black\",linewidth=2) +\n  geom_line(data=results_owen_pmj02_convergence,aes(x=iteration,y=pi_estimate), color=\"purple\") +\n  geom_line(data=results_owen_sobol_convergence,aes(x=iteration,y=pi_estimate), color=\"green\") +\n  scale_y_continuous(limits=c(2.4,3.6))\n```\n\nAn interesting properties of pmj02 sequences (absent from Sobol sequences) is that they can be generated with blue noise properties.\n\n```{r pmj02bn}\nresults_owen_pmj02bn = as.data.frame(generate_pmj02bn_set(1000,seed=1))\ncolnames(results_owen_pmj02bn) = c(\"x\",\"y\")\n\nresults_owen_pmj02bn %\u003e% \n  mutate(inside = x^2 + y^2 \u003c 1) %\u003e% \n  ggplot() + \n  geom_point(aes(x=x,y=y,color=inside)) +\n  coord_fixed()\n```\n\nThis does not help convergence, but has some applications in some types of Monte Carlo problems.\n\n## C++ API\n\nThis package also includes a C++ API for accessing Halton and Sobol sequences, which allows you to generate these sequences quickly in your C++ code. You can access a halton sequence by creating a Halton object:\n\n```{c capi_halton, eval=FALSE}\n#include \"halton_sampler.h\"\n\nspacefillr::Halton_sampler hs;\nhs.init_faure();\n//This generates the 10th value of the 2nd dimension of the Halton sequence\ndouble val = hs.sample(10,2);\n//This generates a 3D point in space\ndouble val[3] = {hs.sample(1,1), hs.sample(1,2), hs.sample(1,3)};\n```\n\nTo access Sobol values, call the following functions (no object is needed):\n\n```{c capi_sobol, eval=FALSE}\n#include \"sobol.h\"\n\n//Sobol, no Owen-scrambling: 1st value, 10th dimension\ndouble val1 = spacefillr::sobol_single(1, 10)\n\n//Fast generator: 1st value, 10th dimension,  setting the random seed for that sequence to 1234\ndouble val3 = spacefillr::sobol_owen_single(1, 10, 1234)\n\n//This generates a 3D point in space\ndouble val[3] = {spacefillr::sobol_owen_single(1,1, 10),\n                 spacefillr::sobol_owen_single(1,2, 10), \n                 spacefillr::sobol_owen_single(1,3, 10)};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylermorganwall%2Fspacefillr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftylermorganwall%2Fspacefillr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylermorganwall%2Fspacefillr/lists"}