{"id":16965000,"url":"https://github.com/propensive/abacist","last_synced_at":"2025-04-05T15:45:55.869Z","repository":{"id":220085155,"uuid":"749321575","full_name":"propensive/abacist","owner":"propensive","description":"Calculations with non-decimal units and mixed bases","archived":false,"fork":false,"pushed_at":"2025-02-12T18:46:13.000Z","size":3148,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-28T20:49:17.936Z","etag":null,"topics":["arithmetic","imperial-units","mixed-bases","scala"],"latest_commit_sha":null,"homepage":"https://soundness.dev/abacist/","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-28T08:23:55.000Z","updated_at":"2025-02-12T18:46:17.000Z","dependencies_parsed_at":"2024-04-10T17:59:52.691Z","dependency_job_id":"8531bc27-e980-4a64-b64e-4ab0254007c5","html_url":"https://github.com/propensive/abacist","commit_stats":null,"previous_names":["propensive/abacist"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fabacist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fabacist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fabacist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/propensive%2Fabacist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/propensive","download_url":"https://codeload.github.com/propensive/abacist/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247361598,"owners_count":20926642,"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":["arithmetic","imperial-units","mixed-bases","scala"],"created_at":"2024-10-13T23:44:48.544Z","updated_at":"2025-04-05T15:45:55.844Z","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/abacist/main.yml?style=for-the-badge\" height=\"24\"\u003e](https://github.com/propensive/abacist/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# Abacist\n\n__Calculations with non-decimal units and mixed bases__\n\nMany units of measurement in use today have not yet been decimalized, and work\nin non-decimal and mixed bases. Arithmetic using these units can be convoluted,\nrequiring either conversion or error-prone carrying. _Abacist_ builds upon the\nrepresentations of physical quantities provided by\n[Quantitative](https://github.com/propensive/quantitative/) to support compound\nunits in mixed bases.\n\n## Features\n\n- allows arbitrary constructions of cascading units of the same dimension, such as (miles, yards, feet and inches)\n- provides addition, subtraction and scalar multiplication operations on those units\n- allows conversion to and from decimal `Quantity` values\n- unit types are opaque aliases of `Long` for performance\n\n\n## Availability\n\n\n\n\n\n\n\n## Getting Started\n\nAll terms and types are defined in the `abacist` package, and are exported to\nthe `soundness` package, and build upon\ndefinitions in [Quantitative](https://github.com/propensive/quantitative/). You\ncan import from either:\n```amok\nsyntax scala\ntransform\n  before   selective imports\n  after    universal soundness import\n  replace  abacist.*, quantitative.*  soundness.*\n##\nimport abacist.*, quantitative.*\n```\n\n### Discrete Cascading Units\n\nPrior to the adoption of the metric system for quantities of mass and length, other systems based\non non-decimal (but exact) multiples of other units were widely used. These are commonly called\n\"the Imperial System\", particularly for lengths, and for masses, \"Avoirdupois\", but actually\nrepresent several different systems (often with units of the same name representing different\nphysical amounts, confusingly) adopted in various jurisdictions with varying degrees of\nofficiality.\n\nAbacist can accommodate all such systems through a single _type_ which defines a cascade of\nunits (of the same dimension), in a tuple. The unit types are defined in\nQuantitative, and Abacist makes it\npossible to use them in discrete multiples.\n\nFor example, one variant of the Imperial System measuring\nhuman heights could be defined as,\n```amok\nsyntax scala\n##\ntype ImperialHeight = (Feet[1], Inches[1])\n```\nor for longer distances,\n```amok\nsyntax scala\n##\ntype ImperialDistance = (Miles[1], Yards[1], Inches[1])\n```\nthat is, a number of miles, yards and inches, represented as a `Tuple` of these units' types\n(each raised to the power `1`). Another example for mass is,\n```amok\nsyntax scala\n##\ntype Avoirdupois = (Hundredweights[1], Stones[1], Pounds[1], Ounces[1], Drams[1])\n```\nor alternatively:\n```amok\nsyntax scala\n##\ntype SimpleAvoirdupois = (Pounds[1], Ounces[1])\n```\n\nEach type, a tuple of subtypes of `Measure`, statically represents a system of discrete cascading units,\nprovided that,\n- each element of the tuple has the same dimensionality (i.e. represents the same sort of physical quantity)\n- the elements are ordered by decreasing magnitude\nand furthermore, for most useful operations, that contextual `Ratio` instances exist between each unit and\nthe principal unit for their common dimension.\n\nWith a valid definition, such as one of the above, we can represent values in its units, called a `Count`\n(because it's a count of integer multiples of each of the units).\n\n### Construction\n\nTo construct a new `Count`, simply call its factory method with the appropriate tuple type, and as many\ninteger arguments as necessary. The rightmost `Int` argument will be interpreted as the multiple of the\nrightmost unit in the tuple, and additional arguments will represent (right-to-left) multiples of units of\nincreasing magnitude. For example, `Count[ImperialDistance](180, 24)` represents, \"180 yards and 24 inches\",\nwhile, `Count[ImperialDistance](1, 180, 24)` represents, \"1 mile, 180 yards and 24 inches\".\n\n### Extraction\n\nIndividual units from a `Count` may be extracted by applying the units value\nto extract, without its dimension, to the `Count` value, like so:\n```amok\nsyntax scala\n##\ntype Height = (Feet[1], Inches[1])\nval height: Count[Height] = Count(6, 4)\nval feet = height[Feet]\nval inches = height[Inches]\n```\n\nThe value `feet` will be set to `6`, and the value `inches` will be `4`.\n\n`Count`s of identical units may be added and subtracted, and multiplied and divided by numbers, but not\nby other quantities. They may be converted to `Quantity`s with the `quantity` method, much as a `Quantity` can\nbe converted, or constructed from a `Quantity` by calling `count` on the\n`Quantity`, e.g.\n```amok\nsyntax scala\n##\n(18*Kilo(Gram)).count[Avoirdupois]\n```\n\n### Rounding\n\nNote that in many cases, the discrete units of a `Count` will not be able to\nprecisely represent a `Quantity`. A `Quantity` will be rounded to the nearest\nwhole `Count` value. Converting back to a `Quantity` will include this\nrounding error.\n\nFor example, note how the error changes when more precise `Count` units are\nused:\n```amok\nsyntax scala\ntransform\n  before  Imprecise height\n  after   Precise height\n  replace  Inches[1]  Inches[1], Points[1]\n  replace  0.00460  0.0000139\n##\ntype Height = (Feet[1], Inches[1])\nval height: Quantity[Metres[1]] = Quantity(1.3)\nval error = height - height.count[Height].quantity\n\nassert(error == 0.00460)\n```\n\n\n### Underlying Representation\n\nA `Count` is an opaque type alias for a `Long`, meaning that operations involving `Count`s do not involve\nany heap objects. The underlying value of a count represents an integer\nmultiple of the smallest unit in the cascade. For example, a length of\n`1ft 3in` would be stored as `15`, being the sum of the 12 inches in one foot,\nplus 3 inches.\n\n\n## Status\n\nAbacist 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\nAbacist is designed to be _small_. Its entire source code currently consists\nof 319 lines of code.\n\n## Building\n\nAbacist 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 Abacist?\".\n\n1. *Copy the sources into your own project*\n   \n   Read the `fury` file in the repository root to understand Abacist'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 Abacist 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 `abacist`.\n   Run `wrath -F` in the repository root. This will download and compile the\n   latest version of Scala, as well as all of Abacist'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 Abacist are welcome and encouraged. New contributors may like\nto look for issues marked\n[beginner](https://github.com/propensive/abacist/labels/beginner).\n\nWe suggest that all contributors read the [Contributing\nGuide](/contributing.md) to make the process of contributing to Abacist\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\nAbacist 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\nAn _abacist_ is a person who operates an abacus, for counting and arithmetic.\nCounting of mixed-base units is the purpose of _Abacist_.\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 single bead on a rod of an abacus, the device an _abacist_ specializes in.\n\n## License\n\nAbacist 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%2Fabacist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpropensive%2Fabacist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpropensive%2Fabacist/lists"}