{"id":16965012,"url":"https://github.com/propensive/capricious","last_synced_at":"2025-10-23T19:03:51.405Z","repository":{"id":215415013,"uuid":"738884979","full_name":"propensive/capricious","owner":"propensive","description":"Controlled randomness in Scala","archived":false,"fork":false,"pushed_at":"2024-12-12T09:29:05.000Z","size":1868,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-12T10:27:15.450Z","etag":null,"topics":["arbitrary-data","monte-carlo","prng","randomness","rng","scala","test-data-generator"],"latest_commit_sha":null,"homepage":"https://soundness.dev/capricious/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/propensive.png","metadata":{"files":{"readme":".github/readme.md","changelog":null,"contributing":".github/contributing.md","funding":null,"license":null,"code_of_conduct":null,"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":"2024-01-04T09:16:38.000Z","updated_at":"2024-12-12T09:29:09.000Z","dependencies_parsed_at":"2024-01-14T11:50:09.087Z","dependency_job_id":"26c0ed96-970d-4255-a0f9-b92c8dc61fba","html_url":"https://github.com/propensive/capricious","commit_stats":null,"previous_names":["propensive/capricious"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fcapricious","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fcapricious/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fcapricious/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fcapricious/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/propensive","download_url":"https://codeload.github.com/propensive/capricious/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230347037,"owners_count":18212188,"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":["arbitrary-data","monte-carlo","prng","randomness","rng","scala","test-data-generator"],"created_at":"2024-10-13T23:44:49.760Z","updated_at":"2025-10-23T19:03:51.329Z","avatar_url":"https://github.com/propensive.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"[\u003cimg alt=\"GitHub Workflow\" src=\"https://img.shields.io/github/actions/workflow/status/propensive/capricious/main.yml?style=for-the-badge\" height=\"24\"\u003e](https://github.com/propensive/capricious/actions)\n[\u003cimg src=\"https://img.shields.io/discord/633198088311537684?color=8899f7\u0026label=DISCORD\u0026style=for-the-badge\" height=\"24\"\u003e](https://discord.com/invite/MBUrkTgMnA)\n\u003cimg src=\"/doc/images/github.png\" valign=\"middle\"\u003e\n\n# Capricious\n\n__Generation of random values__\n\nBeing able to calculate random values is useful for a variety of tasks, not least as test data.\n__Capricious__ provides a more convenient interface to the standard pseudorandom number generators \navailable on the JVM.\n\n## Features\n\n- generalized abstraction of random value generation\n- special support for generating random `Double`s in a user-specified distribution\n- parameterized uniform, Normal (Gaussian) and Gamma distributions are available\n- offers a choice of random sources: \"default\", secure and strongly secure, with optional seed values\n- generic derivation of product and sum types\n\n## Availability\n\n\n\n\n\n\n\n## Getting Started\n\nAll terms and types are defined in the `capricious` package:\n```scala\nimport capricious.*\n```\n\n### Generating random values\n\nA random instance of some type, `Type` can be constructed by calling,\n```scala\nval randomInt = random[Int]()\nval randomBoolean = random[Boolean]()\n```\nor, if the type can be inferred from the context, just,\n```scala\nval randomChar: Char = random()\n```\n\nRandom values can only be generated for certain types, but this includes most\nprimitive types, and any type for which an `Randomizable` typeclass instance\nexists.\n\nA value generated with `random` should be unpredictable, since it will be\ndetermined from a random 64-bit value provided by the JVM's default random\nnumber generator. This is, however, only a pseudorandom number generator, and\nthe sequence it produces will be deterministic, albeit difficult to predict.\n\n### Repeatability\n\nRandomness is useful, but it can undermine repeatability. So a more\nfine-grained mechanism is available for generating random values with the same\nprobability distribution, but using different random number generators (RNGs),\nincluding seeded RNGs which will produce a repeatable sequence of values each\ntime.\n\nThe code which will generate random values of this form must be delimited in a\n`stochastic` block. Within this block, new random values can be generated by\ncalling `arbitrary` in much the same way as we called `random` before.\n\nBut in order to construct a new `stochastic` block, a random number generator\nshould be specified, with a seed value if necessary. For now, we will used the\ndefault random number generator, with a specified seed value.\n\nFor example,\n```scala\ngiven Seed = Seed(12L)\nimport randomNumberGenerators.seeded\n\ndef main(): Unit = stochastic:\n  println(arbitrary[Int]())\n  println(arbitrary[Char]())\n```\n\n\nNote that the sequence of random values generated within a stochastic block\nwill be deterministic, so long as the code is deterministic. This is generally\ntrue for single-threaded code, but concurrency can introduce nondeterminism,\nsince multiple threads could cause random values to be generated in a different\norder across threads, each time the code is run.\n\nTherefore, it is important to\ninitiate a new `stochastic` block for each thread, using a seed generated from\nthe parent thread, like so:\n```scala\nimport parasite.*\n\ngiven Seed = Seed(42L)\nimport randomNumberGenerators.seeded\n\ndef main(): Unit =\n  stochastic:\n    val seed1: Seed = arbitrary()\n    val seed2: Seed = arbitrary()\n\n    val async1 = Async:\n      seed1.stochastic:\n        println(arbitrary[Int])\n\n    val async2 = Async:\n      seed2.stochastic:\n        println(arbitrary[Int])\n\n    async1.await()\n    async2.await()\n```\n\n### Generating random `Double`s\n\nRandom `Double`s can be generated only if a probability distribution is\nspecified. Since `Double`s are a 64-bit approximation of the set of real\nnumbers, which is an infinite set, there is no clear answer for what\nprobability each possible `Double` value should have of being chosen randomly.\nHence, several options are provided, which can be selected by importing them as\ncontextual values:\n\n- `import randomDistributions.gaussian` - the Gaussian distribution with mean,\n  `0`, and variance, `1`\n- `import randomDistributions.uniformUnitInterval` - uniform across the\n  interval `[0, 1]`\n- `import randomDistributions.uniformSymmetricUnitInterval` - uniform across\n  the interval `[-1, 1]`\n- `import randomDistributions.binary` - uniform across the 64-bit binary\n  representations of IEEE 754\n  double-precision values\n- `given Distribution = Gamma(shape, scale)` - a Gamma distribution with a\n  specified shape (k) and\n  scale (θ)\n- `given Distribution = Gaussian(mean, standardDeviation)` - a Gaussian\n  (normal) distribution with specified mean (x̄) and standard deviation (σ)\n- `given Distribution = UniformDistribution(start, end)` - a uniform\n  distribution in the range `[start, end]`\n\n### Random sources\n\nSeveral (pseudo-)random number generators are available, sometimes in seeded and unseeded variants:\n\n- `import randomNumberGenerators.unseeded` - a \"standard\" generator, with no seed\n- `import randomNumberGenerators.seeded` - a \"standard\" generator, requiring a contextual `Seed` instance\n- `import randomNumberGenerators.secureUnseeded` - a \"secure\" generator, with no seed\n- `import randomNumberGenerators.secureSeeded` - a \"secure\" generator, requiring a contextual `Seed` instance\n- `import randomNumberGenerators.stronglySecure` - a \"strongly secure\" generator, which cannot be seeded\n\nThose generators which require a seed value can define it, as a `Long` value, with:\n```scala\ngiven Seed = Seed(23956242374982L)\n```\nor as a byte array of arbitrary length, for example,\n```scala\ngiven Seed = Seed(Bytes(78, 124, 19, 3, 52, 99, 112, 89, 8, 7, 12))\n```\nthough different random number generators may only use as much of the seed value as they need.\n\n### The `Randomizable` Typeclass\n\nThe typeclass, `Randomizable`, will produce random instances of its type parameter. Given instances are\npredefined for a few basic types, but custom instances can be constructed by implementing the trait:\n```scala\ntrait Randomizable:\n  type Self\n  def from(random: Random): Self\n```\n\nWe can define a new instance for a type, say `Color`, with a simple `given`\ndefinition such as:\n```scala\ngiven Color is Randomizable = rnd =\u003e\n  Color(rnd[Byte](), rnd[Byte](), rnd[Byte]())\n```\n\nIn this example we generate three `Byte` values from the `Random` instance,\n`rnd`, supplied.\n\nAn implementation of `Randomizable`'s `from` method should call its `rnd`\nparameter's methods as many times as necessary to construct a new, arbitrary\ninstance of `Self`. Although random, the instance of `Self` should depend\ndeterministically on the values produced by `random` (and should not take\nrandomness from any other source).\n\n### Random sequences\n\nIf a type `ValueType` is `Randomizable`, then `List[ValueType]` and\n`IArray[ValueType]` are also `Randomizable`, provided a `RandomSize` instance\nis in scope, for example by importing,\n```scala\nimport randomization.sizes.uniformUpto1000\n```\n\nInstances of `RandomSize` exist for other powers of 10, up to `100000`.\n\nIt's also possible to construct random `Set[ValueType]`s in the same way, but\ntheir sizes may be smaller due to deduplication. For example, whatever the\nrange of `RandomSize`, a `Set[Boolean]` would never have more than two elements,\n`true` and `false`.\n\n### Product and Sum types\n\nCapricious can construct random instances of product types such as case classes\nand enumeration cases, and sum types like `enum`s and sealed traits, as long as\neach field of the product and variant of the sum has a valid `Randomizable`\ninstance.\n\nThis generic-derivation functionality works thanks to\n[Wisteria](https://soundness.dev/wisteria/).\n\n\n## Status\n\nCapricious is classified as __fledgling__. For reference, Soundness projects are\ncategorized into one of the following five stability levels:\n\n- _embryonic_: for experimental or demonstrative purposes only, without any guarantees of longevity\n- _fledgling_: of proven utility, seeking contributions, but liable to significant redesigns\n- _maturescent_: major design decisions broady settled, seeking probatory adoption and refinement\n- _dependable_: production-ready, subject to controlled ongoing maintenance and enhancement; tagged as version `1.0.0` or later\n- _adamantine_: proven, reliable and production-ready, with no further breaking changes ever anticipated\n\nProjects at any stability level, even _embryonic_ projects, can still be used,\nas long as caution is taken to avoid a mismatch between the project's stability\nlevel and the required stability and maintainability of your own project.\n\nCapricious is designed to be _small_. Its entire source code currently consists\nof 181 lines of code.\n\n## Building\n\nCapricious will ultimately be built by Fury, when it is published. In the\nmeantime, two possibilities are offered, however they are acknowledged to be\nfragile, inadequately tested, and unsuitable for anything more than\nexperimentation. They are provided only for the necessity of providing _some_\nanswer to the question, \"how can I try Capricious?\".\n\n1. *Copy the sources into your own project*\n   \n   Read the `fury` file in the repository root to understand Capricious's build\n   structure, dependencies and source location; the file format should be short\n   and quite intuitive. Copy the sources into a source directory in your own\n   project, then repeat (recursively) for each of the dependencies.\n\n   The sources are compiled against the latest nightly release of Scala 3.\n   There should be no problem to compile the project together with all of its\n   dependencies in a single compilation.\n\n2. *Build with [Wrath](https://github.com/propensive/wrath/)*\n\n   Wrath is a bootstrapping script for building Capricious and other projects in\n   the absence of a fully-featured build tool. It is designed to read the `fury`\n   file in the project directory, and produce a collection of JAR files which can\n   be added to a classpath, by compiling the project and all of its dependencies,\n   including the Scala compiler itself.\n   \n   Download the latest version of\n   [`wrath`](https://github.com/propensive/wrath/releases/latest), make it\n   executable, and add it to your path, for example by copying it to\n   `/usr/local/bin/`.\n\n   Clone this repository inside an empty directory, so that the build can\n   safely make clones of repositories it depends on as _peers_ of `capricious`.\n   Run `wrath -F` in the repository root. This will download and compile the\n   latest version of Scala, as well as all of Capricious's dependencies.\n\n   If the build was successful, the compiled JAR files can be found in the\n   `.wrath/dist` directory.\n\n## Contributing\n\nContributors to Capricious are welcome and encouraged. New contributors may like\nto look for issues marked\n[beginner](https://github.com/propensive/capricious/labels/beginner).\n\nWe suggest that all contributors read the [Contributing\nGuide](/contributing.md) to make the process of contributing to Capricious\neasier.\n\nPlease __do not__ contact project maintainers privately with questions unless\nthere is a good reason to keep them private. While it can be tempting to\nrepsond to such questions, private answers cannot be shared with a wider\naudience, and it can result in duplication of effort.\n\n## Author\n\nCapricious was designed and developed by Jon Pretty, and commercial support and\ntraining on all aspects of Scala 3 is available from [Propensive\nO\u0026Uuml;](https://propensive.com/).\n\n\n\n## Name\n\nSomething which is _capricious_ is determined by chance, whimsy or impulse.\n\nIn general, Soundness project names are always chosen with some rationale,\nhowever it is usually frivolous. Each name is chosen for more for its\n_uniqueness_ and _intrigue_ than its concision or catchiness, and there is no\nbias towards names with positive or \"nice\" meanings—since many of the libraries\nperform some quite unpleasant tasks.\n\nNames should be English words, though many are obscure or archaic, and it\nshould be noted how willingly English adopts foreign words. Names are generally\nof Greek or Latin origin, and have often arrived in English via a romance\nlanguage.\n\n## Logo\n\nThe logo shows a stylized pollen cell, the canonical body used to illustrate Brownian (i.e. random) motion.\n\n## License\n\nCapricious is copyright \u0026copy; 2025 Jon Pretty \u0026 Propensive O\u0026Uuml;, and\nis made available under the [Apache 2.0 License](/license.md).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpropensive%2Fcapricious","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpropensive%2Fcapricious","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpropensive%2Fcapricious/lists"}