Skip to content

Releases: soulverteam/SoulverCore

3.2.1

14 Aug 18:06

Choose a tag to compare

Improvements

  • Support for expressions like "USD1K"
  • Tweaks to the behaviour of "K": "10K" represents "10,000". For units of kelvin, add a space: "10 K".
  • "kilo" is now supported as a synonym for "kg"

LineCollectionEditingHelper (breaking change)

  • This class is now open source and available from the Simple Soulver repository (instead of from SoulverCore)

Additional context

  • The LineCollectionEditingHelper is a glue object that acts as a controller layer between a text editing view (typically, but not limited to, UITextView or NSTextView), and a SoulverCore LineCollection model object (that handles calculation)
  • It has been removed from SoulverCore in this release, as it depends on the TextActions package and this violates our design goal of having no dependencies in SoulverCore

3.2.0

12 Aug 11:56

Choose a tag to compare

Date & Time Calculations

  • Added an additional 'time from now' syntax: "time in 4 hours", "time in 4 hours in San Francisco"
  • Supported adding a clock time to expressions like "3 days from now at 4:39pm", "1 week ago @ 19:30"
  • Supported ISO8601 date stamps formatted in UTC (Zulu time) with trailing Z
  • Supported clock intervals in the form "5:55pm - 7"
  • Fixed an issue with using the minus operator to determine the difference between two clock times in named time zones (e.g., "6:50pm PST − 6:30am MST")
  • Fixed an issue with "oct" clashing with the octal conversion function in expressions like "oct 1 2024 to jun 1 2025"

Percentages

Percentage Ratios

Given one number and its percentage of a whole, determine the percentage of another number:

  • "20% is 500, what is 750" (= 30%)

Also calculate another percentage of the whole:

  • "if 20 is 30%, what is 60%" (= 40)

Percentage Elapsed in Calendar Unit

These functions help quickly get the amount of time passed in a day, week, month, or year as a percentage of the whole (i.e., what % of the year has elapsed):

  • "day percentage", "week %", "month percent", "year percentage"

Units

Fiat Currencies

  • Updated currency codes for Mauritanian Ouguiya (MRO → MRU) and Venezuelan Bolívar (VEF → VES)

Shorthand Units

  • "mo" is now accepted as a synonym for months (commonly used in rates, like "$30/mo")
  • "yr" is now accepted as a synonym for years (commonly used in rates, like "$20k/yr")
  • "deg" is now supported as a synonym for degrees

Other

  • Support added for units without spaces in the form (number)(scalar)(unit), e.g., "1kUSD"

Arithmetic

  • Expressions like "sqrt(2) - 2^0.5" now equal exactly "0" instead of a very small number caused by slight precision loss when converting from Decimal to Double
  • "1e100 + 1 - 1e100" now produces an error, indicating this calculation cannot be performed while retaining accuracy

API

  • EngineCustomization and LineCollection now conform to Sendable
  • City has a new airportCodes property to get a list of airport codes in the city
  • Calculator's calculateInBackground function now supports auto-converting answers into other forms
  • The seeksFutureDate property on DateParsingOptions has been split into two separate properties (seeksDate and preferFutureForAmbiguousDates) for greater granularity in customizing date parsing behaviour
  • A new option (useDefaultRatesForUnhandledCurrencies) is available on EngineFeatureFlags to fall back on a default rate when a CurrencyRateProvider fails to provide a rate for a particular currency

3.1.0

28 Jan 18:28

Choose a tag to compare

Calculation Features

Non-decimal bases

  • Do unit calculations using non-base 10 numbers, like "0xF days in μs"
  • Added support for converting into other bases using the converter "as base x", like "0b101101 as base 16" (= 0x2D)
    • Base 2, 8, 10, and 16 are supported
  • Support for hex(), bin() and oct() and int() functions (matching the format supported by Python)
  • Support for "as oct" as a synonym for "as octal"

Rounding up/down to nearest x phrase functions

  • "round 310 up to nearest hundred" (= 400)
  • "round 390 down to nearest hundred" (= 300)

Time zone calculations

  • Support for the use of "time" as a comment word, like "3pm Sydney time to London time"
  • Implicit interpretation of "from here" in certain cases: "3pm to Chicago" (assumes a conversion of 3pm here to Chicago)
  • Support for "time now" and "date today" phrases
  • Added "Tampa, Florida" as a built-in timezone city

Unix timestamps

  • Support for millisecond timestamps, like "1733823083000 ms to date"
  • An expression like "1733823083000 to date" will also be interpreted as a ms (rather than second) timestamp, because this makes more sense.

Units

  • Added barrels (bbl) unit, defined as 158.987 liters

Bug fixes

  • Fixed a crash when inputting "1s + 1970 in date"
  • Fixed a crash with the "moon phase" astrological function
  • Fixed an issue where an expression like "523 bits/s ÷ 5 bits" was returning a bps/bits rate instead of resolving into hertz

API

New API: TokenListSemantics

Supports syntax coloring expressions

  • A new TokenListSemantics class provides a semantic analysis layer on top of TokenList that tags the parts of a math expression with a semantic type (number, unit, timezone, etc)
  • Get a semantics object from the metadata on a TokenList object (tokenList.metadata.semantics) and use it to enumerate through the semantic tokens in an expression (with ranges)
  • We've built this API to make doing syntax coloring in a calculator or Soulver-like app easy. You might have been be tempted to use TokenList for this in the past, but its tree-like structure is optimized for evaluation (not syntax coloring), and concrete token types change between releases without notice
  • In contrast, you can rely on the semantic token types from TokenListSemantics to remain fairly consistent across releases, and any changes to its semantic token types will be documented
    See the Simple Soulver sample app for an example of how to use TokenListSemantics for syntax coloring expressions.

Formatting API

  • The unformatted static property on FormattingPreferences can be used for when you want most unformatted result (no thousands separator, rounding, and currency codes (USD) instead of symbols ($))

(Unlikely) breaking changes

  • Much of the conversion system in SoulverCore has been rewritten in this release to be more flexible and powerful
  • There have been been many changes to TokenType and TokenSubType as a result (for example, type name and converter subtypes are no longer available)

3.0.0

22 Nov 03:39

Choose a tag to compare

Dynamic place queries

  • A new placeDataProvider property on EngineCustomization supports natural language functions that include places that are dynamically resolved over the internet.

  • Ensure the dynamicPlaceQueries flag is enabled on EngineFeatureFlags to enable this feature (the default is off)

  • Dynamic places are supported in natural language functions, for example:

    • "time in Ubud, Bali"
    • "distance between Bellingen & Nowra"
    • "weather in Assisi, Perugia"
    • "temperature in Narva, Estonia"

A PlaceDataProvider implementation asynchronously geocodes a string query. You can optionally also enable distance calculations between by implementing another function.

protocol PlaceDataProvider {
    
    /// Geocode a given string request
    /// - For example, this might be a place like "Spoleto, Umbria, Italy"
    /// - On Apple platforms, you can use Core Location's `CLGeocoder/geocodeAddressString` class for this
    func placeDataFor(request: String) async throws -> PlaceData?
    
    /// Calculate the distance between two GPS locations
    /// On Apple platforms, you can use Core Location's `CLLocation/distance(from:)` function to calculate this
    /// - This is a synchronous call, because network access is not required to calculate this
    /// - Implement this function to enable "distance from (place) to (place)" style word functions
    /// - Return a unit expression of length (miles or km, up to you)
    func distanceBetween(location1: PlaceData.Coordinates, location2: PlaceData.Coordinates) -> UnitExpression?
    
}

Historical currency conversions

  • The CurrencyRateProvider protocol offers a new function to fetch historical currency rates:
func fetchRateInBackgroundFor(request: CurrencyRateRequest) async -> Decimal?
  • Get the conversion date from the request's new date property and dispatch a query to a web-based data source that supports historical currency conversions (like CurrencyLayer).
  • The synchronous variant rateFor(request: CurrencyRateRequest) -> Decimal? is polled first, to let you return a cached historical rate if available.
  • Ensure the historicalCurrencyQueries flag is enabled on EngineFeatureFlags to enable this feature (the default is off)

Historical weather queries

  • WeatherDataRequest now includes an optional datestamp property.
  • Ensure the historicalWeatherQueries flag is enabled on EngineFeatureFlags to enable this feature (the default is off)

Alternative Result Generator

  • A new AlternativeResultGenerator class can intelligently convert a given CalculationResult into relevant alternative forms
  • For example, a decimal number might be converted into hex, binary and octal, or if below zero, into a fraction, and if above a certain threshold, into scientific notation
  • A unit of time will be converted into a laptime (hh:mm:ss) and timespan (days, hours, minutes, seconds)
  • A date will be converted into ISO8601 format, and a unix timestamp

Date Interval Parsing from String

  • A new dateIntervalFor(_ expression: String) -> DateInterval on Calculator offers intelligent date interval (start and end date) parsing that might be used to power a natural language event scheduling feature

Loading engine content from an external bundle

SoulverCore now supports loading its content files (containing places, units & functions, etc) from an externally located bundle directory. Previous versions always loaded resources included in the framework's resource folder.
To load resources from an external source:

  • First make a resources bundle ResourceBundle(url: URL)? with a URL pointing to your resources bundle.
  • This initializer is failable to ensure that your resources bundle is valid
  • Use the dedicated initializer on EngineCustomization that takes a ResourcesBundle: init(resourcesBundle: ResourceBundle, locale: Locale)

Breaking API changes

In connection with allowing an EngineCustomization to be loaded from an external bundle, we've moved away from all singletons in the framework, including CurrencyList and StaticResources.

  • Functions for getting lists of content primitives (currencies & places) formally provided by these objects are now available on EngineCustomization

Minor features

  • Additional percentage shorthand: "5 of 50" (as a shorthand of "5 as a % of 50")
  • Convert time to decimal: "10:45 to decimal" (= 10.75)
  • Support for interpreting sub-zero numbers like 0.001 as 0,001in an EU locale (with MisplacedThousandsSeparatorBehavior set to interpretAsDecimalPoint)

Bug fixes

  • Fixed a crash when doing fact(99999.999)
  • Fixed a bug with auto converting a conversion in parentheses while using answer auto conversion mode
  • Fixed a bug where you couldn't convert rates of fluid oz/acre into mL/ha (because the first rate was being converted into meters)

2.7.1

15 Oct 05:39

Choose a tag to compare

Time & Date Calculations

  • Support for adding timespans with the form hh:mm with more than 24 hours in the hour component
  • Added phrases to get day of month and week of month date components from the current day or a particular date

Bug fixes

  • Fixed an issue with the automatic result conversion mode incorrectly invoking with a single phrase function
  • Fixed an issue affecting stale variable dependencies in rare cases in LineCollection

2.7.0

25 Sep 11:16

Choose a tag to compare

This version of SoulverCore has been built for Swift 6 with Xcode 16

New Functions

Data Transfer Functions

New function makes it easier to work out how long files will take to download or upload.

  • "time to 3GB at 10 MB/s" (= 300 s)
  • Or specify an explicit unit: "minutes to 35GB at 200MB/s" (= 2.92 min)

Speeding Up Time Functions

New function to speed up time by a multiplier:

  • "1 hour 30 minutes at 1.5x" (= 1 hour)

You can also calculate the time saved:

  • "time saved 1 hour 30 minutes at 1.5x" (= 30 minutes)

Financial Functions

Added a new function for working out how much money you need in the bank to ensure a certain amount of interest:

  • "deposit needed for $42k/year at 7.5%" (= $560k)
  • "savings required for $10k/month @ 5.6% (=$2.143M)

Added additional variants for compounding monthly and quarterly:

  • "interest on $100 after 3 years at 10% compounding monthly"
  • "interest on $100 for 3 years at 10% compounding quarterly"

Percentage functions

New functions to display the percentage change from one number by an amount

  • "3k on 50k" (= 6%)
  • "50 off 150" (= 33%)

Lunar day

  • Get the current lunar day: "lunar day" or "moon day"
  • Or the lunar day on a particular date: "lunar day on March 12, 2025"

Units

  • Added support for unit expressions with a fractional value, like "1 1/2 pounds"
  • Added cubic micrometer & square nanometer units
  • Improved behaviour of certain unit multiplications, where they would not return in the most relevant form: "3 min × 15 mph" now returns "0.75 mi" rather than 1,207 m

Currencies

  • Polygon symbol (formally MATIC) updated to POL
  • Added sub-domination ETH currencies: Wei and Gwei

Conversions

  • Support for automatic conversion of units without explicit value: "usd eur" will be interpreted as "1 usd in eur"
  • More flexible unit conversion for ostensibly incompatible units: "3 mph to minutes" (convert to miles/minute), "10 cubic centimeters to meters" (convert to cubic meters)
  • Support for conversion from & into imperial volume units explicitly, like "1 liter in imperial pints"

Other

General

  • Added power phrase functions like: "3 to the power of 9", "4 raised to 5"
  • Support for min/max functions with percentages
  • Combination and permutation functions now support numerically larger parameters
  • Added additional trigonometry functions that take their parameter in degrees: "asind", "acosd", "atand" and "tand"
  • Added (sample) standard deviation function: "standard deviation of 10, 20, 30 and 40"
    • You can also use "std dev of …" as a shorthand

Time zones

  • Support for "Korea" as an alias of "South Korea"

Bug fixes

  • Fixed a date parsing issue where a number like "1.003.020" was being misinterpreted as a date ("01.03.20")
  • Fixed a lexing issue with feet units that are written with a trailing apostrophe, like 30.334'
  • Fixed an issue with min/max list functions and negative currencies

API

Breaking changes

  • We're working towards only depending on API available in the modern Swift FoundationEssentials & FoundationInternationalization,
  • This version takes the first step in this direction by weaning off uses of NS prefixed classes (NSNumber, NSString, NSRegularExpression etc).
  • For our public API, this change only affects the range property on Token:
    • It is now typed to a similar Token.Range struct, rather NSRange.
    • You can still get an NSRange for a token if needed using token.range.nsRange
  • ECBCurrencyRateProvider now uses swift async/await for rate updates, rather than a closure.

Parsing options

  • Added a DateParsingOptions to EngineFeatureFlags that lets you specify the default time for dates without times (either midday or midnight)

Places

  • Cites, airports and countries now offer a 2-letter ISO country code property

2.6.3

26 Apr 08:20

Choose a tag to compare

Percentage functions

  • New percentage function: "3 as % with 7, 8 and 9" (= 11.11%)
  • This function gets the percentage of one number of a whole (including the number), a shorthand for "3 as % of (3 + 7 + 8 + 9)".

Future date seeking mode

  • Compound units of time are now supported in date seeking mode (for example "in 1 hour 20 minutes" will return a date 1 hour and 20 minutes from now)

Automatic conversion mode

  • Added a case for nanoseconds to automatically convert into milliseconds

Bug fixes & improvements:

  • Fixed a crash introduced in the previous build when doing certain date interval calculations
  • Fixed a rare issue with fractions potentially being incorrectly formatted
  • Fixed an issue with pitch to hz conversion not enough precision for rounded results in some cases

2.6.2

09 Apr 09:56

Choose a tag to compare

Improvements

  • Support for rates in lists (like "mean of 0.09615 $/kWh and 0.10965 $/kWh")
  • The base unit for volume units is now cubic meters (rather than liters). This enables SoulverCore to return a result of meters for expressions like "200000 L / 125 m^2"
  • Support for "dec" as a synonym of "decimal"
  • Fixed a hang related to using 0 as in a list with the lcm function
  • Fixed a bug with the future date seeking mode, for dates in the past that had a specified time of day

2.6.1

26 Mar 21:06

Choose a tag to compare

Places

  • Added new properties country and city on Place. These will return the associated country for a City, and the capital city of a Country. It will also return the associated city with an Airport place
  • Added some additional places: Mauritius, French Guiana, Martinique, La Réunion, & Guadeloupe

Units

  • Support for generic custom units (defined not in terms of an existing unit)
  • Use undefined as your equivalentUnitIdentifier

Linear growth functions

  • Linear growth functions can now omit the starting quantity (it will be assumed to be 0)
  • For instance "time to $100 at $4 every hour" (= 25 hours)

Misc

  • CSS units (em, rem & px) will now always be formatted using a standard US decimal character (.) so they can be immediately pasted into CSS files.
  • Phrases like "days left in 2024" now use round numbers
  • Fixed an issue with a spaceless compound quantity of time not being correctly recognized, like "2hr1min"
  • You can now convert timespans into "months and days"

2.6.0

15 Mar 11:26

Choose a tag to compare

Currency symbols

  • New CurrencySymbolSettings enum on EngineCustomization
  • Set to .automatic (the default) for the most logical currency symbol settings for the current locale
  • Added "tenges" as a synonym for Kazakhstani Tenges

Bug fixes

  • "tonne" now maps to metric ton, rather than short tons.
  • iso8601 time stamps with sub-second components and negative timezone offsets are now recognized correctly.
  • Fixed an issue with hex/binary/octal numbers not working with log functions
  • Fixed an issue where raising area and volume units to fractional powers would not perform the correct operation
  • Fixed an issued where single letter prefix currency symbols were not parsing correctly (like "R100", used in South Africa)