diff --git a/stdlib/source/library/lux/abstract/equivalence.lux b/stdlib/source/library/lux/abstract/equivalence.lux index 24d6763fb..9f29911d8 100644 --- a/stdlib/source/library/lux/abstract/equivalence.lux +++ b/stdlib/source/library/lux/abstract/equivalence.lux @@ -57,8 +57,7 @@ (the .public (recursive sub) (for_any (_ it) - (-> (-> (Equivalence it) - (Equivalence it)) + (-> (Change (Equivalence it)) (Equivalence it))) (implementation (the (= left right) diff --git a/stdlib/source/library/lux/math/algebra/equation.lux b/stdlib/source/library/lux/math/algebra/equation.lux new file mode 100644 index 000000000..296239185 --- /dev/null +++ b/stdlib/source/library/lux/math/algebra/equation.lux @@ -0,0 +1,116 @@ +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +(.using + [library + [lux (.except function) + [math + [number + [/64 + ["[0]" natural]]]] + [data + ["[0]" product] + ["[0]" text] + [collection + ["[0]" list (.use "[1]#[0]" functor) + ["?[1]" \\projection]] + ["[0]" set (.only Set)]]] + [abstract + ["[0]" monad]] + [macro + ["[0]" template] + ["[0]" syntax]] + ["[0]" error (.only) + ["[0]" try (.only Try)]] + ["[0]" meta]]] + [// + ["[0]" variable] + ["[0]" formula (.only Formula)]]) + +(every .public Equation + [Formula Formula]) + +(the .public (= definition concept) + (-> Formula Formula + Equation) + [definition concept]) + +(the .public in_reverse + (Change Equation) + product.swapped) + +(the .public (as_text [definition concept]) + (text.Injection Equation) + (text (formula.as_text concept) + " = " + (formula.as_text definition))) + +(template.with [,name ,formula] + [(the .public (,name parameter) + (-> Formula + (Change Equation)) + (let [change (,formula parameter)] + (product.then change change)))] + + [[+ formula.+] + [- formula.-] + [x formula.x] + [/ formula./] + [^ formula.^]]) + +(the (function'' parameters value definition) + (-> (List Formula) Formula Formula + Code) + (let [input (list.repeated (list.size parameters) (` formula.Scalar)) + type (` (-> (,* input) + formula.Scalar))] + (` (is (, type) + (.function ((, (formula.as_code value)) + (,* (list#each formula.as_code parameters))) + (, (formula.as_code definition))))))) + +(the (function' parameters value [definition concept]) + (-> (List Formula) Formula Equation + (Try Code)) + (let [input (is (Set variable.Identity) + (|> parameters + (list#each formula.every_variable) + (list.mix set.union (set.empty natural.hash)))) + output (is (Set variable.Identity) + (formula.every_variable value))] + (if (let [there_is_no_circularity + (not (set.sub? input output)) + + all_inputs_are_present_in_definition + (set.= input + (formula.every_variable definition)) + + only_the_concept_is_being_calculated + (set.= output + (formula.every_variable concept))] + (and there_is_no_circularity + all_inputs_are_present_in_definition + only_the_concept_is_being_calculated)) + {try.#Success (function'' parameters value definition)} + {try.#Failure error.not_valid}))) + +(every .public (Function of) + [Formula of + Equation]) + +(the Function' + (type (Function (List Formula)))) + +(the .public function + (syntax.macro (_ [it ?list.any]) + (monad.let meta.monad + [it (meta.eval Function' it) + .let [[concept parameters it] (as (-> Any + Function') + it)]] + (when (function' parameters concept it) + {try.#Success it} + (pure (list it)) + + {try.#Failure error} + (meta.failure error))))) diff --git a/stdlib/source/library/lux/math/algebra/formula.lux b/stdlib/source/library/lux/math/algebra/formula.lux new file mode 100644 index 000000000..0e0978fdf --- /dev/null +++ b/stdlib/source/library/lux/math/algebra/formula.lux @@ -0,0 +1,209 @@ +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +(.using + [library + [lux (.except #Variable) + [math + [number + [/64 + ["[0]" natural] + ["[0]" decimal]]]] + [control + ["[0]" state]] + [data + ["[0]" sum] + ["[0]" product] + ["[0]" text] + [collection + ["[0]" set (.only Set)]]] + [abstract + ["[0]" monad] + ["[0]" equivalence (.only Equivalence)]] + [macro + ["^" pattern] + ["[0]" template]] + [meta + ["[0]" code]]]] + [// + ["[0]" variable (.only Variable)]]) + +... https://en.wikipedia.org/wiki/Scalar_(physics) +(every .public Scalar + Decimal) + +(every .public Formula + (Rec @ + (Variant + {#Constant Scalar} + {#+ @ @} + {#- @ @} + {#x @ @} + {#/ @ @} + {#^ @ @} + {#Variable Variable}))) + +(the .public equivalence + (Equivalence Formula) + (<| equivalence.recursive + (.function (_ equivalence)) + (let [binary (product.equivalence equivalence equivalence)]) + (all sum.equivalence + decimal.equivalence + binary + binary + binary + binary + binary + variable.equivalence + ))) + +(the .public (as_text it) + (text.Injection Formula) + (`` (when it + {#Constant it} + (by decimal.base_10 as it) + + (,, (template.with [,tag ,symbol] + [{,tag parameter it} + (|> (text (as_text it) + " " ,symbol " " + (as_text parameter)) + (text.enclosed ["(" ")"]))] + [[#+ "+"] + [#- "-"] + [#x "x"] + [#/ "/"] + [#^ "^"]])) + + {#Variable it} + (variable.as_text it)))) + +(every .public Environment + Natural) + +(the .public constant + (-> Scalar + Formula) + (|>> {#Constant})) + +(the .public (variable name) + (-> Text + (state.State Environment Formula)) + (monad.let state.monad + [it state.get + _ (state.update ++)] + (pure {#Variable it name}))) + +(template.the (one) + [{#Constant decimal.positive_one}]) + +(the (x' parameter it) + (-> Formula Formula + (Maybe Formula)) + (when [parameter it] + (^.or [(..one) it] + [it (..one)]) + {.#Some it} + + else + {.#None})) + +(the (/' parameter it) + (-> Formula Formula + (Maybe Formula)) + (if (with equivalence + (= parameter it)) + {.#Some (..one)} + (when it + {#x parameter' it'} + (when [(/' parameter parameter') + (/' parameter it')] + (^.or [{.#Some parameter'} _] + [_ {.#Some it'}]) + {.#Some {#x parameter' it'}} + + else + {.#None}) + + else + {.#None}))) + +(the (normal it) + (Change Formula) + (`` (when it + (,, (template.with [,tag ,name] + [{,tag parameter' it'} + (when (,name parameter' it') + {.#Some it} + (normal it) + + else + it)] + + [[#x x'] + [#/ /']])) + + else + it))) + +(template.with [,name ,tag] + [(the .public (,name parameter it) + (-> Formula + (Change Formula)) + (normal {,tag parameter it}))] + + [[+ #+] + [- #-] + [x #x] + [/ #/] + [^ #^]]) + +(the .public new + (for_any (_ it) + (-> (state.State Environment it) + it)) + (|>> (state.value natural.zero) + product.right)) + +(the .public (every_variable it) + (-> Formula + (Set variable.Identity)) + (`` (when it + {#Constant _} + (set.empty natural.hash) + + (,, (template.with [,tag] + [{,tag parameter it} + (set.union (every_variable parameter) + (every_variable it))] + + [[#+] + [#-] + [#x] + [#/] + [#^]])) + + {#Variable it} + (set.of_list natural.hash (list (variable.identity it)))))) + +(the .public (as_code it) + (-> Formula + Code) + (`` (when it + {#Constant it} + (code.decimal it) + + (,, (template.with [,tag ,function] + [{,tag parameter it} + (` (,function (, (as_code parameter)) + (, (as_code it))))] + + [[#+ decimal.+] + [#- decimal.-] + [#x decimal.x] + [#/ decimal./] + [#^ decimal.^]])) + + {#Variable it} + (variable.as_code it)))) diff --git a/stdlib/source/library/lux/math/algebra/variable.lux b/stdlib/source/library/lux/math/algebra/variable.lux new file mode 100644 index 000000000..dfb5a1e87 --- /dev/null +++ b/stdlib/source/library/lux/math/algebra/variable.lux @@ -0,0 +1,52 @@ +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +(.using + [library + [lux (.except Name name) + [math + [number + [/64 + ["[0]" natural]]]] + [data + ["[0]" product] + ["[0]" text]] + [abstract + ["[0]" equivalence (.only Equivalence)]] + [meta + ["[0]" code]]]]) + +(every .public Identity + Natural) + +(every .public Name + Text) + +(every .public Variable + [Identity Name]) + +(the .public identity + (-> Variable + Identity) + product.left) + +(the .public name + (-> Variable + Name) + product.right) + +(the .public equivalence + (Equivalence Variable) + (by equivalence.functor each ..identity natural.equivalence)) + +(the .public (as_text it) + (text.Injection Variable) + (text (name it) + "@" + (by natural.base_10 as (identity it)))) + +(the .public as_code + (-> Variable + Code) + (|>> as_text + code.local)) diff --git a/stdlib/source/library/lux/meta.lux b/stdlib/source/library/lux/meta.lux index 4e76e7c79..e59d5ea7e 100644 --- a/stdlib/source/library/lux/meta.lux +++ b/stdlib/source/library/lux/meta.lux @@ -16,7 +16,7 @@ [/ ["[0]" provenance]]) -(the with_template (.in_module# .prelude .with_template)) +(the with_template (.in_module# .prelude with_template)) ... (.every (Meta it) ... (-> Lux @@ -164,8 +164,7 @@ [target [.#info .#target] Text] [version [.#info .#version] Text] - [configuration [.#info .#configuration] (property.List Text)]] - ) + [configuration [.#info .#configuration] (property.List Text)]]) (the .public provenance (Meta Provenance) diff --git a/stdlib/source/library/lux/physics.lux b/stdlib/source/library/lux/physics.lux index 8e203a509..e834916c3 100644 --- a/stdlib/source/library/lux/physics.lux +++ b/stdlib/source/library/lux/physics.lux @@ -4,12 +4,15 @@ ... https://en.wikipedia.org/wiki/Physics (.using [library - [lux (.except)]]) + [lux (.except) + [math + [algebra + ["[0]" formula]]]]]) ... https://en.wikipedia.org/wiki/Scalar_(physics) (every .public Scalar - Decimal) + formula.Scalar) ... https://en.wikipedia.org/wiki/Elasticity_(physics) (every .public Elasticity - Decimal) + Scalar) diff --git a/stdlib/source/test/lux/math.lux b/stdlib/source/test/lux/math.lux index 238de99b2..413d1d084 100644 --- a/stdlib/source/test/lux/math.lux +++ b/stdlib/source/test/lux/math.lux @@ -36,7 +36,11 @@ ["[1]/[0]" fixed_point]] ["[1][0]" geometry ["[1]/[0]" circle] - ["[1]/[0]" hyperbola]]]) + ["[1]/[0]" hyperbola]] + ["[1][0]" algebra + ["[1]/[0]" variable] + ["[1]/[0]" formula] + ["[1]/[0]" equation]]]) (the complex/0 Complex @@ -150,4 +154,8 @@ /geometry/circle.test /geometry/hyperbola.test + + /algebra/variable.test + /algebra/formula.test + /algebra/equation.test )))) diff --git a/stdlib/source/test/lux/math/algebra/equation.lux b/stdlib/source/test/lux/math/algebra/equation.lux new file mode 100644 index 000000000..9f75998ae --- /dev/null +++ b/stdlib/source/test/lux/math/algebra/equation.lux @@ -0,0 +1,72 @@ +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +(.using + [library + [lux (.except) + [abstract + ["[0]" monad]] + [math + ["[0]" random] + [arithmetic + [infix (.only infix)]] + [number + [/64 + ["[0]" integer] + ["[0]" decimal]]]] + [test + ["_" property (.only Test)]] + [control + ["[0]" state]]]] + [\\library + ["[0]" / (.only) + [// + ["[0]" formula (.only Formula)]]]]) + +(the force_=_mass_x_acceleration + (/.Function [Formula Formula]) + (formula.new (monad.let state.monad + [force (formula.variable "force") + mass (formula.variable "mass") + acceleration (formula.variable "acceleration")] + (pure [force + [mass acceleration] + (infix [force /.= [mass formula.x acceleration]])])))) + +(the force + (/.function (let [[force [mass acceleration] it] force_=_mass_x_acceleration] + [force (list mass acceleration) it]))) + +(the mass + (/.function (let [[force [mass acceleration] it] force_=_mass_x_acceleration + it (|> it + (/./ acceleration) + /.in_reverse)] + [mass (list acceleration force) it]))) + +(the acceleration + (/.function (let [[force [mass acceleration] it] force_=_mass_x_acceleration + it (|> it + (/./ mass) + /.in_reverse)] + [acceleration (list mass force) it]))) + +(the .public test + Test + (<| (_.covering /._) + (monad.let [! random.monad] + [.let [scalar (by ! each + (|>> (integer.% +1,000,000) + integer.decimal) + random.integer)] + expected_mass scalar + expected_acceleration scalar]) + (all _.and + (_.coverage [/.function] + (and (|> (force expected_mass expected_acceleration) + (mass expected_acceleration) + (decimal.= expected_mass)) + (|> (force expected_mass expected_acceleration) + (acceleration expected_mass) + (decimal.= expected_acceleration)))) + ))) diff --git a/stdlib/source/test/lux/math/algebra/formula.lux b/stdlib/source/test/lux/math/algebra/formula.lux new file mode 100644 index 000000000..0bb46408b --- /dev/null +++ b/stdlib/source/test/lux/math/algebra/formula.lux @@ -0,0 +1,24 @@ +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +(.using + [library + [lux (.except) + [abstract + ["[0]" monad]] + [math + ["[0]" random]] + [test + ["_" property (.only Test)]]]] + [\\library + ["[0]" /]]) + +(the .public test + Test + (<| (_.covering /._) + (monad.let [! random.monad] + []) + (all _.and + (_.coverage [/.Formula] + false) + ))) diff --git a/stdlib/source/test/lux/math/algebra/variable.lux b/stdlib/source/test/lux/math/algebra/variable.lux new file mode 100644 index 000000000..0c12e31a5 --- /dev/null +++ b/stdlib/source/test/lux/math/algebra/variable.lux @@ -0,0 +1,24 @@ +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +(.using + [library + [lux (.except) + [abstract + ["[0]" monad]] + [math + ["[0]" random]] + [test + ["_" property (.only Test)]]]] + [\\library + ["[0]" /]]) + +(the .public test + Test + (<| (_.covering /._) + (monad.let [! random.monad] + []) + (all _.and + (_.coverage [/.Variable] + false) + )))