From e9b523e41581d3659b1830926d2bf5cd4a353c2d Mon Sep 17 00:00:00 2001 From: Inari Listenmaa Date: Tue, 21 May 2024 14:13:01 +0800 Subject: [PATCH] WIP: some text on Explainable codebase --- docs/current_system/codebase/explainable.md | 12 ++ .../codebase/generic_mathlang.md | 118 ++++++++++++++++++ docs/current_system/codebase/index.md | 7 +- docs/current_system/codebase/mathlang.md | 70 +++++++++++ 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 docs/current_system/codebase/explainable.md create mode 100644 docs/current_system/codebase/generic_mathlang.md create mode 100644 docs/current_system/codebase/mathlang.md diff --git a/docs/current_system/codebase/explainable.md b/docs/current_system/codebase/explainable.md new file mode 100644 index 0000000..2fb17cf --- /dev/null +++ b/docs/current_system/codebase/explainable.md @@ -0,0 +1,12 @@ +# Explainable + +## Types + +```haskell +type ExplainableIO r st a = RWST (HistoryPath,r) [String] st IO (a,XP) +type Explainable r st a = ExplainableIO r st a +``` + +## Evaluation + +TODO \ No newline at end of file diff --git a/docs/current_system/codebase/generic_mathlang.md b/docs/current_system/codebase/generic_mathlang.md new file mode 100644 index 0000000..a38e284 --- /dev/null +++ b/docs/current_system/codebase/generic_mathlang.md @@ -0,0 +1,118 @@ +# Generic MathLang + +Generic MathLang is meant to be an intermediate step between the [Rule datatype](./rule_ast.md) and [MathLang](./mathlang.md). + +Things that get more structured from Rule. A lot of things in Rule are just free text inside a `MTExpr`, but it gets parsed in Generic MathLang. + +### Arithmetic expressions + +In Rule, a single cell may contain arbitrary expressions. Compare lines 1 and 2: + +``` +SUM,foo,bar,,,,,,, (1) +,,,,,,,,, +foo + bar,,,,,,,,, (2) +``` + +Version (1) is parsed as an arithmetic expression in Rule, but version (2) is just free text. Generic MathLang parses everything it can, even inside the cells. + +### Records + +Text like `foo's,bar's,baz` gets parsed into records: `foo.bar.baz`. + +### Functions + +Rule may define functions as follows (see [example spreadsheet](https://docs.google.com/spreadsheets/d/1cWAb7Ba4HJovQn1PquZzYJjnjKUuhEPhNHzAH4ZfV4I/edit#gid=2100528279) for larger context): + + +``` +GIVEN x IS A Number + y IS A Number +DECIDE x discounted by y IS x * (1 - y) +``` + +And we can apply the function (simplified the arguments): +``` +DECIDE Answer IS firstArg discounted by secondArg +``` + +When parsed into rules, we don't have much structure: + + + +```haskell +HC { hHead = RPConstraint + [ MTT "x", MTT "discounted by", MTT "y" ] RPis + [ MTT "x * (1 - y)" ] + , hBody = Nothing} + +HC { hHead = RPConstraint + [ MTT "Answer" ] RPis + [ MTT "firstArg" + , MTT "discounted by" + , MTT "secondArg" ] + , hBody = Nothing} +``` + +The definition becomes as follows: + +```haskell +( "discounted by", + ( + [ MkVar "x", MkVar "y" ], MkExp + { exp = ENumOp + { numOp = OpMul, nopLeft = MkExp + { exp = EVar + { var = MkVar "x" }, md = [{- omitted some metadata: line number, type etc. -}] + }, nopRight = MkExp + { exp = ENumOp + { numOp = OpMinus, nopLeft = MkExp + { exp = ELit + { lit = EInteger 1 }, md = [{- omitted some metadata -}] + }, nopRight = MkExp + { exp = EVar + { var = MkVar "y" }, md = [{- omitted some metadata -}] + } + }, md = [{- omitted some metadata -}] + } + }, md = [{- omitted some metadata -}] + } + ) + ) +``` + +And the application as follows: + +```haskell +EVarSet + { vsetVar = MkExp + { exp = EVar { var = MkVar "Answer" }, md = [] }, arg = MkExp + { exp = EApp + { func = MkExp + { exp = EApp + { func = MkExp + { exp = EVar + { var = MkVar "discounted by" }, md = [{- omitted some metadata -}] + }, appArg = MkExp + { exp = EVar + { var = MkVar "Step 3" }, md = [{- omitted some metadata -}] + }, md = [] + }, appArg = MkExp + { exp = ERec + { fieldName = MkExp + { exp = EVar + { var = MkVar "risk cap" }, md = [{- omitted some metadata -}] + }, recName = MkExp + { exp = EVar + { var = MkVar "accident" }, md = [{- omitted some metadata -}] + } + }, md = [] + } + }, md = [] + } + } +``` + +## Types + +[](https://github.com/smucclaw/dsl/blob/main/lib/haskell/natural4/src/LS/XPile/MathLang/GenericMathLang/GenericMathLangAST.hs) \ No newline at end of file diff --git a/docs/current_system/codebase/index.md b/docs/current_system/codebase/index.md index 94999cb..e66fa67 100644 --- a/docs/current_system/codebase/index.md +++ b/docs/current_system/codebase/index.md @@ -21,14 +21,17 @@ TODO ## [The 'Explainable' codebase](https://github.com/smucclaw/dsl/tree/main/lib/haskell/explainable) -[TODO] +The Explainable codebase includes the following components. + +- [MathLang](./mathlang.md): a DSL for arithmetic expressions and predicates +- [Explainable](./explainable.md): a monad for evaluating MathLang expressions and providing explanations for the (intermediate and final) results ## Visualizations ### [Ladder Diagram](https://github.com/smucclaw/ladder-diagram) * [The main Ladder Diagram repo](https://github.com/smucclaw/ladder-diagram) - * There are also docs available for this, via + * There are also docs available for this, via ``` npm install jsdoc -g npm run docs diff --git a/docs/current_system/codebase/mathlang.md b/docs/current_system/codebase/mathlang.md new file mode 100644 index 0000000..acfeb84 --- /dev/null +++ b/docs/current_system/codebase/mathlang.md @@ -0,0 +1,70 @@ +# MathLang + +Hornlikes from [Rule](./rule_ast.md) can be transformed into MathLang expressions. AFAIK there's no attempt to transform other rule types (regulative, constitutive, …). + +## Types + +The core of MathLang is the following `Expr` type (reordered here, but all constructors are shown). + +```haskell +type ExprLabel = Maybe String +data Expr a = +-- I think these are the most relevant constructors + Val ExprLabel a -- ^ simple value + | MathBin ExprLabel MathBinOp (Expr a) (Expr a) -- ^ binary arithmetic operation + | MathVar String -- ^ variable reference + | MathSet String (Expr a) -- ^ variable assignment + | MathITE ExprLabel (Pred a) (Expr a) (Expr a) -- ^ if-then-else + | ListFold ExprLabel SomeFold (ExprList a) -- ^ fold a list of expressions into a single expr value + +-- These I find less important / could probably be restructured? + | Parens ExprLabel (Expr a) -- ^ parentheses for grouping (??? why is this needed) + | MathMax ExprLabel (Expr a) (Expr a) -- ^ max of two expressions (ListFold covers this) + | MathMin ExprLabel (Expr a) (Expr a) -- ^ min of two expressions " + | MathApp ExprLabel String [String] (Expr a) -- ^ kind of a hack to allow for function to call another function etc. This constructor is removed in final result and the functions are inlined. + | Undefined ExprLabel -- ^ looks like a quick workaround after realizing there should be a way to recover from failure? + +``` + +There's also similar structure for predicates. + +```haskell +-- | conditional predicates: things that evaluate to a boolean +data Pred a + = PredVal ExprLabel Bool + | PredNot ExprLabel (Pred a) -- ^ boolean not + | PredComp ExprLabel Comp (Expr a) (Expr a) -- ^ Ord comparisions: x < y + | PredBin ExprLabel PredBinOp (Pred a) (Pred a) -- ^ predicate and / or / eq / ne + | PredVar String -- ^ boolean variable retrieval + | PredSet String (Pred a) -- ^ boolean variable assignment + | PredITE ExprLabel (Pred a) (Pred a) (Pred a) -- ^ if then else, booleans + | PredFold ExprLabel AndOr (PredList a) -- ^ and / or a list +``` + +Both expressions and predicates have list versions. PredList is just a type alias, ExprList has constructors for maps, filters etc. There's `MathSection` for partially applying binary functions, for the purpose of mapping over `ExprList`. + +```haskell +type PredList a = [Pred a] + +-- | We can filter, map, and mapIf over lists of expressions. Here, @a@ is pretty much always a @Double@. +data ExprList a + = MathList ExprLabel [Expr a] -- ^ a basic list of `Expr` expressions + | ListMap ExprLabel (MathSection a) (ExprList a) -- ^ apply the function to everything + | ListFilt ExprLabel (Expr a) Comp (ExprList a) -- ^ eliminate the unwanted elements + | ListMapIf ExprLabel (MathSection a) (Expr a) Comp (ExprList a) -- ^ leaving the unwanted elements unchanged + | ListConcat ExprLabel [ExprList a] -- ^ [[a]] -> [a] + | ListITE ExprLabel (Pred a) (ExprList a) (ExprList a) -- ^ if-then-else for expr lists + +data MathSection a + = Id + | MathSection MathBinOp (Expr a) + +data MathBinOp = Plus | Minus | Times | Divide | Modulo +``` + +## Pipeline + +1. Spreadsheet gets parsed into a Rule +2. Rule (only Hornlike) gets transformed into [Generic MathLang](./generic_mathlang.md) +3. Generic MathLang is transformed into MathLang. +