From 3f5d49190f1ea0b5152e0d19462720f88d43b919 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Thu, 1 Apr 2021 19:29:27 +0300 Subject: [PATCH 1/4] feat: basic constraint solving --- purescript/factorio-throughput/.gitignore | 10 + purescript/factorio-throughput/packages.dhall | 27 ++ purescript/factorio-throughput/spago.dhall | 19 ++ purescript/factorio-throughput/src/Lens.purs | 62 +++++ purescript/factorio-throughput/src/Main.purs | 40 +++ .../factorio-throughput/src/Run/Fail.purs | 12 + .../factorio-throughput/src/Run/Reader.purs | 18 ++ .../factorio-throughput/src/Run/Visited.purs | 35 +++ .../factorio-throughput/src/Throughput.purs | 256 ++++++++++++++++++ purescript/factorio-throughput/test/Main.purs | 11 + 10 files changed, 490 insertions(+) create mode 100644 purescript/factorio-throughput/.gitignore create mode 100644 purescript/factorio-throughput/packages.dhall create mode 100644 purescript/factorio-throughput/spago.dhall create mode 100644 purescript/factorio-throughput/src/Lens.purs create mode 100644 purescript/factorio-throughput/src/Main.purs create mode 100644 purescript/factorio-throughput/src/Run/Fail.purs create mode 100644 purescript/factorio-throughput/src/Run/Reader.purs create mode 100644 purescript/factorio-throughput/src/Run/Visited.purs create mode 100644 purescript/factorio-throughput/src/Throughput.purs create mode 100644 purescript/factorio-throughput/test/Main.purs diff --git a/purescript/factorio-throughput/.gitignore b/purescript/factorio-throughput/.gitignore new file mode 100644 index 0000000..30efe19 --- /dev/null +++ b/purescript/factorio-throughput/.gitignore @@ -0,0 +1,10 @@ +/bower_components/ +/node_modules/ +/.pulp-cache/ +/output/ +/generated-docs/ +/.psc-package/ +/.psc* +/.purs* +/.psa* +/.spago diff --git a/purescript/factorio-throughput/packages.dhall b/purescript/factorio-throughput/packages.dhall new file mode 100644 index 0000000..665be90 --- /dev/null +++ b/purescript/factorio-throughput/packages.dhall @@ -0,0 +1,27 @@ +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.14.0-20210324/packages.dhall sha256:b4564d575da6aed1c042ca7936da97c8b7a29473b63f4515f09bb95fae8dddab + +let additions = + { debugged = + { dependencies = + [ "prelude" + , "console" + , "ordered-collections" + , "either" + , "tuples" + , "lists" + , "strings" + , "arrays" + , "bifunctors" + , "record" + , "effect" + , "datetime" + , "enums" + , "unordered-collections" + ] + , repo = "https://github.com/hdgarrood/purescript-debugged" + , version = "master" + } + } + +in upstream // additions diff --git a/purescript/factorio-throughput/spago.dhall b/purescript/factorio-throughput/spago.dhall new file mode 100644 index 0000000..4e675bf --- /dev/null +++ b/purescript/factorio-throughput/spago.dhall @@ -0,0 +1,19 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "my-project" +, dependencies = + [ "console" + , "debug" + , "effect" + , "filterable" + , "profunctor-lenses" + , "psci-support" + , "run" + , "strings" + , "unordered-collections" + ] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/purescript/factorio-throughput/src/Lens.purs b/purescript/factorio-throughput/src/Lens.purs new file mode 100644 index 0000000..7c32d7b --- /dev/null +++ b/purescript/factorio-throughput/src/Lens.purs @@ -0,0 +1,62 @@ +module Functorio.Lens where + +import Prelude + +import Data.HashMap (HashMap) +import Data.HashMap as H +import Data.HashSet (HashSet) +import Data.HashSet as S +import Data.Hashable (class Hashable) +import Data.Lens (AGetter, Fold, Iso', Lens', Setter, iso, lens, over, preview, set, view) +import Data.Maybe (Maybe(..), maybe') +import Data.Maybe.First (First) +import Run (Run) +import Run.Reader (READER, ask) +import Run.State (STATE, get, modify) + +---------- Missing instances +atHashMap :: forall k v. Hashable k => k -> Lens' (HashMap k v) (Maybe v) +atHashMap k = + lens (H.lookup k) \m -> + maybe' (\_ -> H.delete k m) \v -> H.insert k v m + +-- | At implementation for hash sets +atHashSetRaw :: forall v. Hashable v => v -> Lens' (HashSet v) (Maybe Unit) +atHashSetRaw x = lens get (flip update) + where + get xs = + if S.member x xs + then Just unit + else Nothing + update Nothing = S.delete x + update (Just _) = S.insert x + +-- | Boolean implementation for AT on hash sets +atHashSet :: forall v. Hashable v => v -> Lens' (HashSet v) Boolean +atHashSet v = atHashSetRaw v <<< maybeUnitToBoolean + +-- | Helper fro implementing atHashSet' +maybeUnitToBoolean :: Iso' (Maybe Unit) Boolean +maybeUnitToBoolean = iso to from + where + from true = Just unit + from false = Nothing + + to Nothing = false + to _ = true + +--------- Helpers for monadic state +getAt :: forall s t a b r. AGetter s t a b -> Run (STATE s r) a +getAt optic = view optic <$> get + +getPreview :: forall r s t a b. Fold (First a) s t a b -> Run (STATE s r) (Maybe a) +getPreview optic = preview optic <$> get + +setAt :: forall s a b r. Setter s s a b -> b -> Run (STATE s r) Unit +setAt optic value = set optic value # modify + +modifyAt :: forall s a b r. Setter s s a b -> (a -> b) -> Run (STATE s r) Unit +modifyAt optic f = over optic f # modify + +askAt :: forall s t a b r. AGetter s t a b -> Run (READER s r) a +askAt optic = ask <#> view optic \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Main.purs b/purescript/factorio-throughput/src/Main.purs new file mode 100644 index 0000000..ae3eebb --- /dev/null +++ b/purescript/factorio-throughput/src/Main.purs @@ -0,0 +1,40 @@ +module Main where + +import Prelude + +import Data.Compactable (compact) +import Data.Either (Either(..)) +import Data.Foldable (for_) +import Data.HashMap as HashMap +import Data.String (joinWith) +import Data.Tuple (Tuple(..)) +import Data.Tuple.Nested ((/\)) +import Effect (Effect) +import Effect.Class.Console (logShow) +import Effect.Console (log) +import RealFunction (PortSide(..), RealFunction, SolveM, _constraints, collectConstraints, myFactory, runSolveM, tryFindBound) +import Run.Except (runFail) +import Run.Reader.Extra (fromState') + +p :: SolveM (Array RealFunction) +p = do + collectConstraints + a <- fromState' _constraints $ runFail $ tryFindBound (0 /\ Input) + b <- fromState' _constraints $ runFail $ tryFindBound (0 /\ Output) + c <- fromState' _constraints $ runFail $ tryFindBound (1 /\ Input) + d <- fromState' _constraints $ runFail $ tryFindBound (1 /\ Output) + e <- fromState' _constraints $ runFail $ tryFindBound (2 /\ Input) + f <- fromState' _constraints $ runFail $ tryFindBound (2 /\ Output) + g <- fromState' _constraints $ runFail $ tryFindBound (4 /\ Input) + h <- fromState' _constraints $ runFail $ tryFindBound (4 /\ Output) + pure $ compact [a, b, c, d, e, f, g, h] + +main :: Effect Unit +main = do + for_ (HashMap.toArrayBy Tuple myFactory) \(Tuple key value) -> log $ show key <> ": " <> show value + + case runSolveM myFactory p of + Left err -> log err + Right (Tuple s f) -> do + log $ joinWith "\n" $ show <$> s.constraints + logShow $ f <*> pure 0.0 \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Run/Fail.purs b/purescript/factorio-throughput/src/Run/Fail.purs new file mode 100644 index 0000000..d94aeaa --- /dev/null +++ b/purescript/factorio-throughput/src/Run/Fail.purs @@ -0,0 +1,12 @@ +module Run.Fail.Extra where + +import Prelude + +import Data.Compactable (class Compactable, compact) +import Data.Traversable (class Traversable, traverse) +import Run (Run) +import Run.Except (FAIL, runFail) + +-- | `Compact` / `MapMaybe` usnig the `Fail` ability +traverseFail :: forall r t a b. Compactable t => Traversable t => (a -> Run (FAIL r) b) -> t a -> Run r (t b) +traverseFail f = traverse (f >>> runFail) >>> map compact \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Run/Reader.purs b/purescript/factorio-throughput/src/Run/Reader.purs new file mode 100644 index 0000000..b2836c2 --- /dev/null +++ b/purescript/factorio-throughput/src/Run/Reader.purs @@ -0,0 +1,18 @@ +module Run.Reader.Extra where + +import Prelude + +import Data.Lens (AGetter) +import Functorio.Lens (getAt) +import Run (Run) +import Run.Reader (READER, runReader) +import Run.State (STATE, get) +import Type.Row (type (+)) + +-- | Use state from the environemtn to eliminate a reader monad. +fromState :: forall r s a. Run (STATE s + READER s r) a -> Run (STATE s r) a +fromState m = get >>= flip runReader m + +-- | Focus on some state in the environemtn to eliminate a reader monad. +fromState' :: forall s t a b r x. AGetter s t a b -> Run (STATE s + READER a r) x -> Run (STATE s r) x +fromState' optic m = getAt optic >>= flip runReader m \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Run/Visited.purs b/purescript/factorio-throughput/src/Run/Visited.purs new file mode 100644 index 0000000..97322b0 --- /dev/null +++ b/purescript/factorio-throughput/src/Run/Visited.purs @@ -0,0 +1,35 @@ +-- | Allows the programmer to limit a monad to only run once (using a key) +module Visited (VISITED, runVisited, once) where + +import Prelude + +import Data.HashSet (HashSet) +import Data.HashSet as HashSet +import Data.Hashable (class Hashable) +import Run (Run) +import Run.State (State, evalStateAt, getAt, modifyAt) +import Type.Proxy (Proxy(..)) + +-- | Monad keeping track of all the runned monad' keys +type VISITED a r = ( visited :: State (HashSet a) | r ) + +-- | Eliminate the Visited effect +runVisited :: forall d a r. Hashable d => Run (VISITED d r) a -> Run r a +runVisited = evalStateAt _visited mempty + +-- | Mark a key as visited +visit :: forall a r. Hashable a => a -> Run (VISITED a r) Unit +visit e = modifyAt _visited $ HashSet.insert e + +-- | Condition a monad to only run once. +-- | The first argument is a key, +-- | and the second is a default value to use when the monad has already run. +once :: forall d a r. Hashable d => d -> Run (VISITED d r) a -> Run (VISITED d r) a -> Run (VISITED d r) a +once at default m = do + visited <- getAt _visited + if HashSet.member at visited + then default + else visit at *> m + +_visited :: Proxy "visited" +_visited = Proxy \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Throughput.purs b/purescript/factorio-throughput/src/Throughput.purs new file mode 100644 index 0000000..7a4d3d6 --- /dev/null +++ b/purescript/factorio-throughput/src/Throughput.purs @@ -0,0 +1,256 @@ +module RealFunction where + +import Prelude + +import Data.Array (length, mapWithIndex) +import Data.Array as Array +import Data.Either (Either) +import Data.Foldable (for_, minimum) +import Data.FoldableWithIndex (forWithIndex_) +import Data.Generic.Rep (class Generic) +import Data.HashMap (HashMap) +import Data.HashMap as HashMap +import Data.HashMap as Map +import Data.Int (toNumber) +import Data.Lens (Lens') +import Data.Lens.Record (prop) +import Data.List (List(..), (:)) +import Data.List as List +import Data.Maybe (Maybe(..), fromJust, fromMaybe) +import Data.Number (infinity) +import Data.Show.Generic (genericShow) +import Data.Traversable (for) +import Data.Tuple (Tuple(..), uncurry) +import Data.Tuple.Nested (type (/\), (/\)) +import Functorio.Lens (getAt, modifyAt) +import Partial.Unsafe (unsafeCrashWith, unsafePartial) +import Run (Run, extract) +import Run.Except (EXCEPT, fail, runExcept) +import Run.Fail.Extra (traverseFail) +import Run.Reader (READER, ask, runReader) +import Run.State (STATE, runState) +import Type.Proxy (Proxy(..)) +import Type.Row (type (+)) +import Visited (VISITED, once, runVisited) + +type RealFunction = Number -> Number +type BeltConfig = + { speed :: Number + , delay :: Number } + +type ChestConfig = + { maxContent :: Number + , delay :: Number } + +type PortId = Int +type MachineId = Int + +data PortSide = Input | Output + +data Machine + = Belt { input :: PortId, output :: PortId, config :: BeltConfig } + | Chest { inputs :: Array PortId, outputs :: Array PortId, config :: ChestConfig } + | Provider (Array PortId) RealFunction + | Consumer PortId + +type Factory = HashMap MachineId Machine + +---------- Some configs +yellowBelt :: BeltConfig +yellowBelt = { speed: 15.0, delay: 1.0/3.0 } + +redBelt :: BeltConfig +redBelt = { speed: 30.0, delay: 1.0/6.0 } + +blueBelt :: BeltConfig +blueBelt = { speed: 45.0, delay: 1.0/8.0 } + +-- | Example factory +myFactory :: Factory +myFactory = Map.fromArray machines + where + machines = mapWithIndex Tuple + [ Provider [0, 1, 2] $ const 80.0 + , Belt { input: 0, output: 3, config: yellowBelt } + , Belt { input: 1, output: 4, config: redBelt } + , Belt { input: 2, output: 5, config: blueBelt } + , Consumer 3 + , Consumer 4 + , Consumer 5 + ] + +---------- Monad for factory solving +type PortData = + { id :: PortId + , maxInput :: Number -> Number + , maxOutput :: Number -> Number } + +data ConstraintExpression + = PortDependent (Array PortId) (Array PortData -> RealFunction) + | Function RealFunction + | Literal Number + +type BiRelationship = + { p1top2 :: RealFunction + , p2top1 :: RealFunction + , p1 :: PortId /\ PortSide + , p2 :: PortId /\ PortSide } + +type BiRelationshipId = Int + +data ThroughputConstraint + = Limit ConstraintExpression PortSide PortId + | BiRelationship BiRelationshipId BiRelationship + +type Constraints = Array ThroughputConstraint + +type SolveState = + { constraints :: Constraints + , lastId :: Int } + +type SolveM = Run + ( EXCEPT String + + STATE SolveState + + READER Factory + + () ) + +runSolveM :: forall a. Factory -> SolveM a -> Either String (Tuple SolveState a) +runSolveM factory = runReader factory >>> runState initialState >>> runExcept >>> extract + +initialState :: SolveState +initialState = { constraints: [], lastId: 0 } + +focusBiRelationship :: PortId /\ PortSide -> BiRelationship -> Maybe BiRelationship +focusBiRelationship place relationship | relationship.p1 == place = Just relationship + | relationship.p2 == place = Just $ flipBiRelationship relationship + | otherwise = Nothing + +flipBiRelationship :: BiRelationship -> BiRelationship +flipBiRelationship { p1, p2, p1top2, p2top1 } = { p1: p2, p2: p1, p1top2: p2top1, p2top1: p1top2 } + +---------- System solving algorithm +constrain :: ThroughputConstraint -> SolveM Unit +constrain constraint = modifyAt _constraints $ push constraint + where + push = flip Array.snoc + +getId :: SolveM Int +getId = modifyAt _lastId ((+) 1) *> getAt _lastId + +collectConstraints :: SolveM Unit +collectConstraints = do + factory <- ask + for_ (HashMap.toArrayBy (/\) $ factory) $ uncurry collectConstraintsImpl + +getPortData :: forall r. PortId -> Run (READER Constraints r) PortData +getPortData id = ado + maxInput <- tryFindBound $ id /\ Input + maxOutput <- tryFindBound $ id /\ Output + in { id, maxInput, maxOutput } + +evalExpr :: forall r. ConstraintExpression -> Run (READER Constraints r) RealFunction +evalExpr = case _ of + Literal a -> pure (const a) + Function f -> pure f + PortDependent portIds f -> for portIds getPortData <#> f + +tryFindBound :: forall r. PortId /\ PortSide -> Run (READER Constraints r) RealFunction +tryFindBound at = tryFindBoundImpl at <#> \f time -> extract $ runVisited $ f time + +tryFindBoundImpl :: forall r k. + PortId /\ PortSide -> + Run (READER Constraints r) (Number -> Run (VISITED BiRelationshipId k) Number) +tryFindBoundImpl (targetId /\ targetSide) = do + constraints <- ask + pure \time -> constraints + # traverseFail case _ of + Limit expr side id | side == targetSide && id == targetId -> + evalExpr expr <*> pure time + BiRelationship id raw + | Just relationship <- focusBiRelationship (targetId /\ targetSide) raw -> do + f <- once id fail $ tryFindBoundImpl relationship.p2 + f (relationship.p1top2 time) + _ -> fail + # runReader constraints + <#> minimum' + where + minimum' = minimum >>> fromMaybe infinity + +collectConstraintsImpl :: MachineId -> Machine -> SolveM Unit +collectConstraintsImpl at = case _ of + Provider for amount -> do + forWithIndex_ for \index id -> do + let limit ports time + = outputs ports time + # Array.findMap (\(id' /\ f) -> if id == id' then Just (f time) else Nothing) + # unsafePartial fromJust -- TODO: error handling + constrain $ Limit (PortDependent for limit) Input id + where + outputs :: Array PortData -> Number -> Array (PortId /\ RealFunction) + outputs ports time + = outputsImpl (length ports) (List.fromFoldable sorted) amount + # Array.fromFoldable + # Array.zipWith (_.id >>> Tuple) sorted + where + sorted :: Array PortData + sorted = Array.sortWith (_.maxOutput >>> (#) time) ports + + outputsImpl :: Int -> List PortData -> RealFunction -> List RealFunction + outputsImpl 1 (head:Nil) remaining = pure \time -> min (head.maxOutput time) (remaining time) + outputsImpl n (head:tail) remaining = current:(outputsImpl (n - 1) tail $ remaining - current) + where + current time + | head.maxOutput time >= (remaining time) / (toNumber n) = (remaining time) / (toNumber n) + | otherwise = head.maxOutput time + outputsImpl _ _ _ = Nil + + Consumer for -> pure unit + Belt { input, output, config } -> do + biId <- getId + + constrain $ BiRelationship biId + { p1: input /\ Output + , p2: output /\ Input + , p1top2: (+) config.delay + , p2top1: (+) (-config.delay) } + + constrain $ Limit (Literal config.speed) Output input + constrain $ Limit (Literal config.speed) Input output + + _ -> unsafeCrashWith "unimplemented" + +---------- Lenses +_lastId :: Lens' SolveState Int +_lastId = prop (Proxy :: _ "lastId") + +_constraints :: Lens' SolveState (Array ThroughputConstraint) +_constraints = prop (Proxy :: _ "constraints") + +---------- Typeclass instances +derive instance genericMachine :: Generic Machine _ +derive instance genericPortSide :: Generic PortSide _ +derive instance eqPortSide :: Eq PortSide + +instance showMachine :: Show Machine where + show = case _ of + Provider for _ -> "Provider<" <> show for <> ">" + Consumer for -> "Consumer<" <> show for <> ">" + Belt { config, input, output } -> "Belt<" <> show input <> " -> " <> show output <> ", " <> show config <> ">" + Chest { inputs, outputs, config } -> "Chest<" <> show inputs <> " -> " <> show outputs <> ", " <> show config <> ">" + +instance showConstraint :: Show ThroughputConstraint where + show = case _ of + Limit f side id -> show f <> " !> " <> showPort (id /\ side) + BiRelationship _ { p1, p2 } -> showPort p1 <> " <-> " <> showPort p2 + where + showPort (p /\ side) = "?" <> show p <> case side of + Input -> "<-" + Output -> "<-" + +instance showConstraintExpression :: Show ConstraintExpression where + show (Literal i) = show i + show (Function f) = "" + show (PortDependent ids f) = "(" <> show ids <> " -> )" + +instance showPortSide :: Show PortSide where + show = genericShow \ No newline at end of file diff --git a/purescript/factorio-throughput/test/Main.purs b/purescript/factorio-throughput/test/Main.purs new file mode 100644 index 0000000..f91f98c --- /dev/null +++ b/purescript/factorio-throughput/test/Main.purs @@ -0,0 +1,11 @@ +module Test.Main where + +import Prelude + +import Effect (Effect) +import Effect.Class.Console (log) + +main :: Effect Unit +main = do + log "🍝" + log "You should add some tests." From fe0816d037b77524378f7bd244a6801376237898 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Sun, 4 Apr 2021 00:36:18 +0300 Subject: [PATCH 2/4] build: basic esbuild setup --- purescript/factorio-throughput/.gitignore | 1 + purescript/factorio-throughput/build.js | 22 ++ purescript/factorio-throughput/package.json | 13 + purescript/factorio-throughput/pnpm-lock.yaml | 228 ++++++++++++++++++ purescript/factorio-throughput/spago.dhall | 5 + purescript/factorio-throughput/src/index.html | 20 ++ 6 files changed, 289 insertions(+) create mode 100644 purescript/factorio-throughput/build.js create mode 100644 purescript/factorio-throughput/package.json create mode 100644 purescript/factorio-throughput/pnpm-lock.yaml create mode 100644 purescript/factorio-throughput/src/index.html diff --git a/purescript/factorio-throughput/.gitignore b/purescript/factorio-throughput/.gitignore index 30efe19..ba2464c 100644 --- a/purescript/factorio-throughput/.gitignore +++ b/purescript/factorio-throughput/.gitignore @@ -8,3 +8,4 @@ /.purs* /.psa* /.spago +dist diff --git a/purescript/factorio-throughput/build.js b/purescript/factorio-throughput/build.js new file mode 100644 index 0000000..c64fa04 --- /dev/null +++ b/purescript/factorio-throughput/build.js @@ -0,0 +1,22 @@ +const esbuild = require("esbuild"); +const PurescriptPlugin = require("esbuild-plugin-purescript"); +const path = require("path"); + +const isProd = process.env.NODE_ENV === "production"; + +esbuild + .build({ + entryPoints: ["src/index.js"], + bundle: true, + outdir: "dist", + watch: !isProd, + plugins: [ + PurescriptPlugin({ + output: isProd ? path.resolve(__dirname, "dce-output") : undefined, + }), + ], + define: { + global: "window", + }, + }) + .catch((_e) => process.exit(1)); diff --git a/purescript/factorio-throughput/package.json b/purescript/factorio-throughput/package.json new file mode 100644 index 0000000..3f7309f --- /dev/null +++ b/purescript/factorio-throughput/package.json @@ -0,0 +1,13 @@ +{ + "name": "moontorio", + "scripts": { + "build": "node build.js" + }, + "dependencies": { + "calculess": "^1.0.2", + "esbuild": "^0.11.4", + "esbuild-plugin-purescript": "^1.0.0", + "events": "^3.3.0", + "function-plot": "^1.22.7" + } +} diff --git a/purescript/factorio-throughput/pnpm-lock.yaml b/purescript/factorio-throughput/pnpm-lock.yaml new file mode 100644 index 0000000..780fc52 --- /dev/null +++ b/purescript/factorio-throughput/pnpm-lock.yaml @@ -0,0 +1,228 @@ +dependencies: + calculess: 1.0.2 + esbuild: 0.11.4 + esbuild-plugin-purescript: 1.0.0 + events: 3.3.0 + function-plot: 1.22.7 +lockfileVersion: 5.1 +packages: + /@types/assert/1.5.4: + dev: false + resolution: + integrity: sha512-CaFVW21Ulu0J9sUaEWJjwmhkDkeoxa4fniVSERzZC13sU9v8NNM2lMlkfZZv60j47D+qDt0Lyo8skVP3CTXUdA== + /built-in-math-eval/0.3.0: + dependencies: + math-codegen: 0.3.5 + dev: false + resolution: + integrity: sha1-JA3CHLOJQ5WIxhxGDrAHZJfvxBw= + /calculess/1.0.2: + dev: false + resolution: + integrity: sha512-9VCZJhW9fp7JmMgn6aTZ0U8NhcbJRFdD3vPlaYWMKIVIH1z4F/ZgDZKqx28fABjn4HaM4VT1ZoQzsONvI2LrCA== + /clamp/1.0.1: + dev: false + resolution: + integrity: sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ= + /d3-array/2.12.1: + dependencies: + internmap: 1.0.1 + dev: false + resolution: + integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== + /d3-axis/2.1.0: + dev: false + resolution: + integrity: sha512-z/G2TQMyuf0X3qP+Mh+2PimoJD41VOCjViJzT0BHeL/+JQAofkiWZbWxlwFGb1N8EN+Cl/CW+MUKbVzr1689Cw== + /d3-color/2.0.0: + dev: false + resolution: + integrity: sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== + /d3-dispatch/2.0.0: + dev: false + resolution: + integrity: sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA== + /d3-drag/2.0.0: + dependencies: + d3-dispatch: 2.0.0 + d3-selection: 2.0.0 + dev: false + resolution: + integrity: sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w== + /d3-ease/2.0.0: + dev: false + resolution: + integrity: sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ== + /d3-format/2.0.0: + dev: false + resolution: + integrity: sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== + /d3-interpolate/2.0.1: + dependencies: + d3-color: 2.0.0 + dev: false + resolution: + integrity: sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== + /d3-path/2.0.0: + dev: false + resolution: + integrity: sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== + /d3-scale/3.2.4: + dependencies: + d3-array: 2.12.1 + d3-format: 2.0.0 + d3-interpolate: 2.0.1 + d3-time: 2.0.0 + d3-time-format: 3.0.0 + dev: false + resolution: + integrity: sha512-PG6gtpbPCFqKbvdBEswQcJcTzHC8VEd/XzezF5e68KlkT4/ggELw/nR1tv863jY6ufKTvDlzCMZvhe06codbbA== + /d3-selection/2.0.0: + dev: false + resolution: + integrity: sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA== + /d3-shape/2.1.0: + dependencies: + d3-path: 2.0.0 + dev: false + resolution: + integrity: sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA== + /d3-time-format/3.0.0: + dependencies: + d3-time: 2.0.0 + dev: false + resolution: + integrity: sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== + /d3-time/2.0.0: + dev: false + resolution: + integrity: sha512-2mvhstTFcMvwStWd9Tj3e6CEqtOivtD8AUiHT8ido/xmzrI9ijrUUihZ6nHuf/vsScRBonagOdj0Vv+SEL5G3Q== + /d3-timer/2.0.0: + dev: false + resolution: + integrity: sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA== + /d3-transition/2.0.0_d3-selection@2.0.0: + dependencies: + d3-color: 2.0.0 + d3-dispatch: 2.0.0 + d3-ease: 2.0.0 + d3-interpolate: 2.0.1 + d3-selection: 2.0.0 + d3-timer: 2.0.0 + dev: false + peerDependencies: + d3-selection: '2' + resolution: + integrity: sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog== + /d3-zoom/2.0.0: + dependencies: + d3-dispatch: 2.0.0 + d3-drag: 2.0.0 + d3-interpolate: 2.0.1 + d3-selection: 2.0.0 + d3-transition: 2.0.0_d3-selection@2.0.0 + dev: false + resolution: + integrity: sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw== + /double-bits/1.1.1: + dev: false + resolution: + integrity: sha1-WKu6RUlNpND6Nrc60RoobJGEscY= + /esbuild-plugin-purescript/1.0.0: + dev: false + resolution: + integrity: sha512-WdSdRtpm5AoRyDj3vEnmLsMsTY9kl3znRUTQe5ilbtcK/JIJv3Nz6d8lsEA079vmWgjc3JtR7Ii1y1omoz/wLg== + /esbuild/0.11.4: + dev: false + hasBin: true + requiresBuild: true + resolution: + integrity: sha512-qWGlOOTwyTn4f846LoR47Mif4Aek4rY9ChdXN7q7G15HpDYq3pxwnPFWe2os/jOq8naFh2Z+FqWfkq8ZP6kATw== + /events/3.3.0: + dev: false + engines: + node: '>=0.8.x' + resolution: + integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + /extend/3.0.2: + dev: false + resolution: + integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + /function-plot/1.22.7: + dependencies: + built-in-math-eval: 0.3.0 + clamp: 1.0.1 + d3-axis: 2.1.0 + d3-color: 2.0.0 + d3-format: 2.0.0 + d3-interpolate: 2.0.1 + d3-scale: 3.2.4 + d3-selection: 2.0.0 + d3-shape: 2.1.0 + d3-zoom: 2.0.0 + interval-arithmetic-eval: 0.4.7 + dev: false + resolution: + integrity: sha512-rB6FeVqvgNECmt5PhIvFFEOyEjM9AWLIpMkj9Nzbzq9f81Irgn3ZrXAuv5+qnuzM99jPL7ZM4kK3+ImiKXcSHA== + /internmap/1.0.1: + dev: false + resolution: + integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== + /interval-arithmetic-eval/0.4.7: + dependencies: + interval-arithmetic: 1.0.6 + math-codegen: 0.3.5 + dev: false + resolution: + integrity: sha512-ClK+N4efbsgjlZR8h0qd0LQbyzUzJ9IkrjmTnD5MVb4Ytebd0lesoVP4AxLclcsEI+nIieskQ8cepHIWUPaRhQ== + /interval-arithmetic/1.0.6: + dependencies: + '@types/assert': 1.5.4 + is-safe-integer: 2.0.0 + nextafter: 1.0.0 + typedarray: 0.0.6 + dev: false + resolution: + integrity: sha512-eVotDGYPNiEaJ63oa4CeEHgOczZJ3gNHqG5wfVQ2o8sN2CEczQyR82Sjey/Bp36x8e7PtBcBvitcMnw6VUpjgQ== + /is-safe-integer/2.0.0: + dependencies: + max-safe-integer: 1.0.1 + deprecated: This package is no longer relevant as ES2015 support is widespread. + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha512-eDaA39/1+3SNtYTRP28lRYOHMwiB1gfqXQaXcf/+f4mLwKgm8TTDkwJldsdtbgrK1R5CoDbf6AQ0KqP7BKoGtQ== + /math-codegen/0.3.5: + dependencies: + extend: 3.0.2 + mr-parser: 0.2.1 + dev: false + resolution: + integrity: sha1-R5nuRnfe0Ud2bQA8ykt4ee3UDMo= + /max-safe-integer/1.0.1: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-84BgvixWPYwC5tSK85Ei/YO29BA= + /mr-parser/0.2.1: + dev: false + resolution: + integrity: sha1-hhi5ukF+KOn0OaQcaVtVTq/u2Sc= + /nextafter/1.0.0: + dependencies: + double-bits: 1.1.1 + dev: false + resolution: + integrity: sha1-t9d7U1MQ4+CX5gJauwqQNHfsGjo= + /typedarray/0.0.6: + dev: false + resolution: + integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +specifiers: + calculess: ^1.0.2 + esbuild: ^0.11.4 + esbuild-plugin-purescript: ^1.0.0 + events: ^3.3.0 + function-plot: ^1.22.7 diff --git a/purescript/factorio-throughput/spago.dhall b/purescript/factorio-throughput/spago.dhall index 4e675bf..e94d276 100644 --- a/purescript/factorio-throughput/spago.dhall +++ b/purescript/factorio-throughput/spago.dhall @@ -10,7 +10,12 @@ You can edit this file as you like. , "filterable" , "profunctor-lenses" , "psci-support" + , "quickcheck" + , "quickcheck-laws" , "run" + , "spec" + , "spec-discovery" + , "spec-quickcheck" , "strings" , "unordered-collections" ] diff --git a/purescript/factorio-throughput/src/index.html b/purescript/factorio-throughput/src/index.html new file mode 100644 index 0000000..44dacf4 --- /dev/null +++ b/purescript/factorio-throughput/src/index.html @@ -0,0 +1,20 @@ + + + + + + + Moontorio + + + + + + + + \ No newline at end of file From 0bb81bfc46f54838613fd9e4b02839aa35ca6d79 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Sun, 4 Apr 2021 00:37:14 +0300 Subject: [PATCH 3/4] feat: basic rendering --- purescript/factorio-throughput/src/Main.purs | 39 ++++---- .../factorio-throughput/src/Render.purs | 18 ++++ .../factorio-throughput/src/Run/Id.purs | 33 +++++++ .../factorio-throughput/src/Throughput.purs | 90 ++++++++++++++----- purescript/factorio-throughput/src/index.js | 38 ++++++++ 5 files changed, 172 insertions(+), 46 deletions(-) create mode 100644 purescript/factorio-throughput/src/Render.purs create mode 100644 purescript/factorio-throughput/src/Run/Id.purs create mode 100644 purescript/factorio-throughput/src/index.js diff --git a/purescript/factorio-throughput/src/Main.purs b/purescript/factorio-throughput/src/Main.purs index ae3eebb..0f2e3fd 100644 --- a/purescript/factorio-throughput/src/Main.purs +++ b/purescript/factorio-throughput/src/Main.purs @@ -2,39 +2,34 @@ module Main where import Prelude -import Data.Compactable (compact) import Data.Either (Either(..)) -import Data.Foldable (for_) -import Data.HashMap as HashMap -import Data.String (joinWith) import Data.Tuple (Tuple(..)) import Data.Tuple.Nested ((/\)) import Effect (Effect) -import Effect.Class.Console (logShow) import Effect.Console (log) -import RealFunction (PortSide(..), RealFunction, SolveM, _constraints, collectConstraints, myFactory, runSolveM, tryFindBound) -import Run.Except (runFail) -import Run.Reader.Extra (fromState') +import Moontorio.Render (RenderFn, renderFactory) +import RealFunction (PortSide(..), RealFunction, SolveM, collectConstraints, myFactory, runSolveM, tryFindBoundSolveM) p :: SolveM (Array RealFunction) p = do collectConstraints - a <- fromState' _constraints $ runFail $ tryFindBound (0 /\ Input) - b <- fromState' _constraints $ runFail $ tryFindBound (0 /\ Output) - c <- fromState' _constraints $ runFail $ tryFindBound (1 /\ Input) - d <- fromState' _constraints $ runFail $ tryFindBound (1 /\ Output) - e <- fromState' _constraints $ runFail $ tryFindBound (2 /\ Input) - f <- fromState' _constraints $ runFail $ tryFindBound (2 /\ Output) - g <- fromState' _constraints $ runFail $ tryFindBound (4 /\ Input) - h <- fromState' _constraints $ runFail $ tryFindBound (4 /\ Output) - pure $ compact [a, b, c, d, e, f, g, h] + a <- tryFindBoundSolveM (0 /\ Input) + b <- tryFindBoundSolveM (0 /\ Output) + c <- tryFindBoundSolveM (1 /\ Input) + d <- tryFindBoundSolveM (1 /\ Output) + e <- tryFindBoundSolveM (2 /\ Input) + f <- tryFindBoundSolveM (2 /\ Output) + g <- tryFindBoundSolveM (4 /\ Input) + h <- tryFindBoundSolveM (4 /\ Output) + pure [a, b, c, d, e, f, g, h] -main :: Effect Unit -main = do - for_ (HashMap.toArrayBy Tuple myFactory) \(Tuple key value) -> log $ show key <> ": " <> show value +main :: RenderFn -> Effect Unit +main render = do + -- for_ (HashMap.toArrayBy Tuple myFactory) \(Tuple key value) -> log $ show key <> ": " <> show value case runSolveM myFactory p of Left err -> log err Right (Tuple s f) -> do - log $ joinWith "\n" $ show <$> s.constraints - logShow $ f <*> pure 0.0 \ No newline at end of file + renderFactory render myFactory s.constraints + -- log $ joinWith "\n" $ show <$> s.constraints + -- logShow $ f <*> pure 0.0 \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Render.purs b/purescript/factorio-throughput/src/Render.purs new file mode 100644 index 0000000..ab7391b --- /dev/null +++ b/purescript/factorio-throughput/src/Render.purs @@ -0,0 +1,18 @@ +module Moontorio.Render where + +import Prelude + +import Data.Foldable (for_) +import Data.Tuple.Nested ((/\)) +import Effect (Effect) +import RealFunction (Constraints, Factory, PortSide(..), RealFunction, factoryPorts, tryFindBoundPure, tryFindValuePure) + +type RenderFn = String -> Array RealFunction -> Effect Unit + +renderFactory :: RenderFn -> Factory -> Constraints -> Effect Unit +renderFactory render factory constraints = for_ (factoryPorts factory) \portId -> do + let inputMax = tryFindBoundPure (portId /\ Input) constraints + let outputMax = tryFindBoundPure (portId /\ Output) constraints + let actual = tryFindValuePure portId constraints + + render ("Port " <> show portId) [inputMax, outputMax, actual] \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Run/Id.purs b/purescript/factorio-throughput/src/Run/Id.purs new file mode 100644 index 0000000..962de55 --- /dev/null +++ b/purescript/factorio-throughput/src/Run/Id.purs @@ -0,0 +1,33 @@ +module Run.Supply where + +import Prelude + +import Data.Tuple (Tuple(..)) +import Run (Run, Step(..), lift, on, runAccumPure) +import Type.Proxy (Proxy(..)) + +-- | Monad providing an infinite supply of values of a particular type. +-- | Example use cases: generating unique ids. +data SupplyF s a = Supply (s -> a) + +type SUPPLY s r = ( supply :: SupplyF s | r ) + +generate :: forall r s. Run (SUPPLY s r) s +generate = lift _supply (Supply identity) + +-- | Elimininate the supply monad using a function generating the next value +runSupply :: forall r s a. (s -> s) -> s -> Run (SUPPLY s r) a -> Run r a +runSupply next + = runAccumPure + (next >>> \current -> on _supply (Loop <<< handleSupply current) Done) + (\s a -> a) + where + handleSupply :: forall i. s -> SupplyF s i -> Tuple s i + handleSupply current (Supply continue) = Tuple current (continue current) + +---------- Typeclass instances +derive instance functorSupply :: Functor (SupplyF s) + +--------- SProxies +_supply :: Proxy "supply" +_supply = Proxy \ No newline at end of file diff --git a/purescript/factorio-throughput/src/Throughput.purs b/purescript/factorio-throughput/src/Throughput.purs index 7a4d3d6..1f03ea7 100644 --- a/purescript/factorio-throughput/src/Throughput.purs +++ b/purescript/factorio-throughput/src/Throughput.purs @@ -5,12 +5,13 @@ import Prelude import Data.Array (length, mapWithIndex) import Data.Array as Array import Data.Either (Either) -import Data.Foldable (for_, minimum) +import Data.Foldable (foldMap, for_, minimum) import Data.FoldableWithIndex (forWithIndex_) import Data.Generic.Rep (class Generic) import Data.HashMap (HashMap) import Data.HashMap as HashMap import Data.HashMap as Map +import Data.HashSet as HashSet import Data.Int (toNumber) import Data.Lens (Lens') import Data.Lens.Record (prop) @@ -20,15 +21,18 @@ import Data.Maybe (Maybe(..), fromJust, fromMaybe) import Data.Number (infinity) import Data.Show.Generic (genericShow) import Data.Traversable (for) -import Data.Tuple (Tuple(..), uncurry) +import Data.Tuple (Tuple(..), fst, uncurry) import Data.Tuple.Nested (type (/\), (/\)) -import Functorio.Lens (getAt, modifyAt) +import Functorio.Lens (modifyAt) +import Math (sin) import Partial.Unsafe (unsafeCrashWith, unsafePartial) import Run (Run, extract) import Run.Except (EXCEPT, fail, runExcept) import Run.Fail.Extra (traverseFail) import Run.Reader (READER, ask, runReader) +import Run.Reader.Extra (fromState') import Run.State (STATE, runState) +import Run.Supply (SUPPLY, generate, runSupply) import Type.Proxy (Proxy(..)) import Type.Row (type (+)) import Visited (VISITED, once, runVisited) @@ -57,28 +61,34 @@ type Factory = HashMap MachineId Machine ---------- Some configs yellowBelt :: BeltConfig -yellowBelt = { speed: 15.0, delay: 1.0/3.0 } +yellowBelt = { speed: 15.0, delay: 4.0/3.0 } redBelt :: BeltConfig -redBelt = { speed: 30.0, delay: 1.0/6.0 } +redBelt = { speed: 30.0, delay: 4.0/6.0 } blueBelt :: BeltConfig -blueBelt = { speed: 45.0, delay: 1.0/8.0 } +blueBelt = { speed: 45.0, delay: 4.0/8.0 } -- | Example factory myFactory :: Factory myFactory = Map.fromArray machines where machines = mapWithIndex Tuple - [ Provider [0, 1, 2] $ const 80.0 + [ Provider [0, 1] $ startsAtZero $ \t -> 40.0 + 10.0 * sin t , Belt { input: 0, output: 3, config: yellowBelt } , Belt { input: 1, output: 4, config: redBelt } - , Belt { input: 2, output: 5, config: blueBelt } + -- , Belt { input: 2, output: 5, config: blueBelt } , Consumer 3 , Consumer 4 - , Consumer 5 ] +---------- Helpers for real functions +type Endomorphism a = a -> a + +startsAtZero :: Endomorphism RealFunction +startsAtZero f x | x >= 0.0 = f x + | otherwise = 0.0 + ---------- Monad for factory solving type PortData = { id :: PortId @@ -105,38 +115,44 @@ data ThroughputConstraint type Constraints = Array ThroughputConstraint type SolveState = - { constraints :: Constraints - , lastId :: Int } + { constraints :: Constraints } type SolveM = Run ( EXCEPT String + STATE SolveState + READER Factory + + SUPPLY Int + () ) runSolveM :: forall a. Factory -> SolveM a -> Either String (Tuple SolveState a) -runSolveM factory = runReader factory >>> runState initialState >>> runExcept >>> extract - -initialState :: SolveState -initialState = { constraints: [], lastId: 0 } +runSolveM factory = runReader factory >>> runState mempty >>> runExcept >>> runSupply ((+) 1) 0 >>> extract focusBiRelationship :: PortId /\ PortSide -> BiRelationship -> Maybe BiRelationship focusBiRelationship place relationship | relationship.p1 == place = Just relationship | relationship.p2 == place = Just $ flipBiRelationship relationship | otherwise = Nothing +focusBiRelationshipWithoutSide :: PortId -> BiRelationship -> Maybe BiRelationship +focusBiRelationshipWithoutSide id relationship | fst relationship.p1 == id = Just relationship + | fst relationship.p2 == id = Just $ flipBiRelationship relationship + | otherwise = Nothing + flipBiRelationship :: BiRelationship -> BiRelationship flipBiRelationship { p1, p2, p1top2, p2top1 } = { p1: p2, p2: p1, p1top2: p2top1, p2top1: p1top2 } +factoryPorts :: Factory -> HashSet.HashSet PortId +factoryPorts = foldMap case _ of + Belt { input, output } -> HashSet.fromArray [input, output] + Provider outputs _ -> HashSet.fromArray outputs + Chest { inputs, outputs } -> HashSet.fromArray (inputs <> outputs) + Consumer input -> HashSet.singleton input + ---------- System solving algorithm constrain :: ThroughputConstraint -> SolveM Unit constrain constraint = modifyAt _constraints $ push constraint where push = flip Array.snoc -getId :: SolveM Int -getId = modifyAt _lastId ((+) 1) *> getAt _lastId - collectConstraints :: SolveM Unit collectConstraints = do factory <- ask @@ -157,6 +173,12 @@ evalExpr = case _ of tryFindBound :: forall r. PortId /\ PortSide -> Run (READER Constraints r) RealFunction tryFindBound at = tryFindBoundImpl at <#> \f time -> extract $ runVisited $ f time +tryFindBoundSolveM :: PortId /\ PortSide -> SolveM RealFunction +tryFindBoundSolveM at = fromState' _constraints $ tryFindBound at + +tryFindBoundPure :: PortId /\ PortSide -> Constraints -> RealFunction +tryFindBoundPure at constraints = extract $ runReader constraints $ tryFindBound at + tryFindBoundImpl :: forall r k. PortId /\ PortSide -> Run (READER Constraints r) (Number -> Run (VISITED BiRelationshipId k) Number) @@ -174,7 +196,29 @@ tryFindBoundImpl (targetId /\ targetSide) = do # runReader constraints <#> minimum' where - minimum' = minimum >>> fromMaybe infinity + minimum' = minimum >>> fromMaybe 0.0 + +tryFindValue :: forall r. PortId -> Run (READER Constraints r) RealFunction +tryFindValue at = tryFindValueImpl at <#> \f time -> extract $ runVisited $ f time + +tryFindValueImpl :: forall r k. PortId -> Run (READER Constraints r) (Number -> Run (VISITED BiRelationshipId k) Number) +tryFindValueImpl targetId = do + constraints <- ask + pure \time -> constraints + # traverseFail case _ of + Limit expr _ id | id == targetId -> evalExpr expr <*> pure time + BiRelationship id raw + | Just relationship <- focusBiRelationshipWithoutSide targetId raw -> do + f <- once id fail $ tryFindValueImpl $ fst relationship.p2 + f (relationship.p1top2 time) + _ -> fail + # runReader constraints + <#> minimum' + where + minimum' = minimum >>> fromMaybe 0.0 + +tryFindValuePure :: PortId -> Constraints -> RealFunction +tryFindValuePure at constraints = extract $ runReader constraints $ tryFindValue at collectConstraintsImpl :: MachineId -> Machine -> SolveM Unit collectConstraintsImpl at = case _ of @@ -204,9 +248,10 @@ collectConstraintsImpl at = case _ of | otherwise = head.maxOutput time outputsImpl _ _ _ = Nil - Consumer for -> pure unit + Consumer for -> do + constrain $ Limit (Literal infinity) Output for Belt { input, output, config } -> do - biId <- getId + biId <- generate constrain $ BiRelationship biId { p1: input /\ Output @@ -220,9 +265,6 @@ collectConstraintsImpl at = case _ of _ -> unsafeCrashWith "unimplemented" ---------- Lenses -_lastId :: Lens' SolveState Int -_lastId = prop (Proxy :: _ "lastId") - _constraints :: Lens' SolveState (Array ThroughputConstraint) _constraints = prop (Proxy :: _ "constraints") diff --git a/purescript/factorio-throughput/src/index.js b/purescript/factorio-throughput/src/index.js new file mode 100644 index 0000000..5e19d4b --- /dev/null +++ b/purescript/factorio-throughput/src/index.js @@ -0,0 +1,38 @@ +import { main } from "Main.purs"; +import functionPlot from "function-plot"; + +let lastId = 0; +const root = document.body; + +const width = 400; +const height = 250; + +const render = (name) => (functions) => () => { + const currentId = ++lastId; + + console.log("Renering!!!"); + + const node = document.createElement("div"); + node.id = currentId; + node.title = name; + node.className = "graph"; + + root.appendChild(node); + + const functionData = functions.map((fn) => ({ + fn: (scope) => fn(scope.x), + graphType: "polyline", + })); + + functionPlot({ + target: node, + width, + height, + yAxis: { domain: [-5, 35] }, + xAxis: { domain: [-1, 5] }, + grid: true, + data: functionData, + }); +}; + +main(render)(); From 3f6091369ab8d32fafc1d504eed2af0f435525c0 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Sun, 4 Jun 2023 15:29:29 +0200 Subject: [PATCH 4/4] Commiting some old changes --- purescript/factorio-throughput/.gitignore | 5 + .../factorio-throughput/idea/example.pdf | Bin 0 -> 59080 bytes .../factorio-throughput/idea/example.tex | 94 ++++++++++++++++++ purescript/factorio-throughput/idea/hmm.pdf | Bin 0 -> 72050 bytes purescript/factorio-throughput/idea/hmm.tex | 77 ++++++++++++++ .../factorio-throughput/src/Throughput.purs | 60 ++++++----- .../factorio-throughput/src/Utils/Ord.purs | 33 ++++++ 7 files changed, 244 insertions(+), 25 deletions(-) create mode 100644 purescript/factorio-throughput/idea/example.pdf create mode 100644 purescript/factorio-throughput/idea/example.tex create mode 100644 purescript/factorio-throughput/idea/hmm.pdf create mode 100644 purescript/factorio-throughput/idea/hmm.tex create mode 100644 purescript/factorio-throughput/src/Utils/Ord.purs diff --git a/purescript/factorio-throughput/.gitignore b/purescript/factorio-throughput/.gitignore index ba2464c..1349821 100644 --- a/purescript/factorio-throughput/.gitignore +++ b/purescript/factorio-throughput/.gitignore @@ -9,3 +9,8 @@ /.psa* /.spago dist +*.aux +*.fls +*.fdb_* +*.synctex* +*.log diff --git a/purescript/factorio-throughput/idea/example.pdf b/purescript/factorio-throughput/idea/example.pdf new file mode 100644 index 0000000000000000000000000000000000000000..17cd036dc6723b93f6b7673fc9480d5e79ce60fb GIT binary patch literal 59080 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%0AlP{Hm(-ale4h-KB=H|$p1+HQ~eh-$8J4WGJM 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�O69LQR(&nZEkEFOP$f`O z1;+py+s}3-jWkX>NSs%u%NrNk3{;s~7ThXgTF@WU*Hx;v60`f`)I%hn{6LzuqmS^6 z$3>;eb2V2PqC@JzNoGa(lWn1I&{%pw0so5?<@h(lq4(L!8ih>(U}@z=VaQIw&1r&TqrZ5zi<&fs*d^a-O z5?r!e5;D93vRu-VQe6Dp?9%+wvOE%^6#qBL`zrskRvdi)mCoS*5hCYoLUFe9um e;{RQ-K#-Xm$jj|rl|1}>99$?gG%{+kDE|Sf`TNKK literal 0 HcmV?d00001 diff --git a/purescript/factorio-throughput/idea/example.tex b/purescript/factorio-throughput/idea/example.tex new file mode 100644 index 0000000..bc199bd --- /dev/null +++ b/purescript/factorio-throughput/idea/example.tex @@ -0,0 +1,94 @@ +\documentclass[a4paper, 12pt]{article} + +\newcommand{\bold}{\textbf} + +\usepackage[english]{babel} +\usepackage{amsmath} +\usepackage{tikz} +\usepackage{indentfirst} + +\begin{document} + +\newcommand{\q2}{\quad\quad} + +\title{\Large{\bold{Moontorio}}} +\author{Matei Adriel} +\date {} + +\maketitle + +\section{Example 1} + +Solve the following factory: + +\vspace*{20pt} +\begin{figure}[h] +\centering +\begin{tikzpicture}[shorten >=1pt, auto, node distance={30mm}, + main/.style = {draw, rectangle}] + +\node[main] (3) {$consumer_1$}; +\node[main] (1) [above left of=3] {$provider_1$}; +\node[main] (2) [below left of=3] {$provider_2$}; +\node[main] (4) [right of=2] {$consumer_2$}; + +\draw[->] (1) edge node{$p_1$} (3); +\draw[->] (2) edge node{$p_2$} (3); +\draw[->] (2) edge node{$p_3$} (4); + +\end{tikzpicture} +\caption{Factory} +\label{fig:Factory} +\end{figure} + +Generating the constraints: +\begin{figure}[h] +\centering + +\begin{equation} + p_1(t) < provider_1(t) +\end{equation} + +\begin{equation} + p_3(t) < consumer_2(t) +\end{equation} + +\begin{equation} +\begin{split} + \begin{cases} + \begin{cases} + p_2(t) &< \displaystyle\frac{consumer_1(t)}{2}\\ + p_1(t) &< consumer_1(t) - p_2(t) + \end{cases} + \ ,&\;\mbox{if } p_1(t) \geq p_2(t)\\\\ + \begin{cases} + p_1(t) &< \displaystyle\frac{consumer_1(t)}{2}\\ + p_2(t) &< consumer_1(t) - p_1(t) + \end{cases} + \ ,&\;\mbox{if } p_1(t) < p_2(t) + \end{cases} +\end{split} +\end{equation} + +\begin{equation} +\begin{split} + \begin{cases} + \begin{cases} + p_3(t) &< \displaystyle\frac{provider_2(t)}{2}\\ + p_2(t) &< provider_2(t) - p_3(t) + \end{cases} + \ ,&\;\mbox{if } p_2(t) \geq p_3(t)\\\\ + \begin{cases} + p_2(t) &< \displaystyle\frac{provider_2(t)}{2}\\ + p_3(t) &< provider_2(t) - p_3(t) + \end{cases} + \ ,&\;\mbox{if } p_2(t) < p_3(t) + \end{cases} +\end{split} +\end{equation} + +\caption{Constraints} +\label{fig:Constraints} +\end{figure} + +\end{document} diff --git a/purescript/factorio-throughput/idea/hmm.pdf b/purescript/factorio-throughput/idea/hmm.pdf new file mode 100644 index 0000000000000000000000000000000000000000..69f6bf8c0d2e083b553d6d3459c15bb35069fb73 GIT binary patch literal 72050 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 literal 0 HcmV?d00001 diff --git a/purescript/factorio-throughput/idea/hmm.tex b/purescript/factorio-throughput/idea/hmm.tex new file mode 100644 index 0000000..2eeb8d2 --- /dev/null +++ b/purescript/factorio-throughput/idea/hmm.tex @@ -0,0 +1,77 @@ +\documentclass[a4paper, 12pt]{article} + +\newcommand{\bold}{\textbf} + +\usepackage[english]{babel} +\usepackage{amsmath} +\usepackage{tikz} +\usepackage{indentfirst} + +\begin{document} + +\newcommand{\q2}{\quad\quad} + +\title{\Large{\bold{Moontorio}}} +\author{Matei Adriel} +\date {} + +\maketitle + +\section{Describing a factory} + +A factory is made out of machines. A machine is either a provider, a belt or a consumer. Machines are connected by ports. + +\begin{figure}[h] + +\begin{equation} +\begin{split} +Machines\ A,\ B,\ C\ &::=\; belt\ p_i\ p_o \\ + &\quad|\quad provider\ p_1,\ p_2,\ ...\ p_n \\ + &\quad|\quad consumer\ p_1,\ p_2,\ ...\ p_n +\end{split} +\end{equation} +\caption{Machines} +\label{Machines} +\end{figure} + +We can represent the factory as a directed graph, with the machines being the nodes and the ports being the edges: + +\vspace*{20pt} +\begin{figure}[h] +\centering +\begin{tikzpicture}[shorten >=1pt, auto, node distance={50mm}, + main/.style = {draw, rectangle}] + +\node[main] (1) {$provider_1$}; +\node[main] (2) [right of=1] {$belt_1$}; +\node[main] (3) [right of=2] {$consumer_1$}; + +\draw[->] (1) edge node{$p_1$} (2); +\draw[->] (2) edge node{$p_2$} (3); + +\end{tikzpicture} +\caption{Example of a simple factory} +\label{SimpleFactory} +\end{figure} + +\section{Constraints} +The first step of the factory solving process is the constraint generation. +We currently use 3 different types of constraints (Figure \ref{Constraints}). +Let's take them one step at a time. The first two constrains ( + $p_k(t) <_{\Leftarrow} f(t)$ and $p_k(t) <_{\Rightarrow} f(t)$ +) are pretty similar, both limiting the flow through a port. + +\begin{figure}[ht] + +\begin{equation} +\begin{split} +Constraints\quad C_k\ &::=\; p_k(t) <_{\Leftarrow} f(t) \\ + &\quad|\quad p_k(t) <_{\Rightarrow} f(t) \\ + &\quad|\quad p_1(t) = p_2(f(t)) +\end{split} +\end{equation} +\caption{Constraints} +\label{Constraints} +\end{figure} + +\end{document} diff --git a/purescript/factorio-throughput/src/Throughput.purs b/purescript/factorio-throughput/src/Throughput.purs index 1f03ea7..a9fe5ad 100644 --- a/purescript/factorio-throughput/src/Throughput.purs +++ b/purescript/factorio-throughput/src/Throughput.purs @@ -6,7 +6,7 @@ import Data.Array (length, mapWithIndex) import Data.Array as Array import Data.Either (Either) import Data.Foldable (foldMap, for_, minimum) -import Data.FoldableWithIndex (forWithIndex_) +import Data.FoldableWithIndex (foldlWithIndex, forWithIndex_) import Data.Generic.Rep (class Generic) import Data.HashMap (HashMap) import Data.HashMap as HashMap @@ -16,12 +16,11 @@ import Data.Int (toNumber) import Data.Lens (Lens') import Data.Lens.Record (prop) import Data.List (List(..), (:)) -import Data.List as List import Data.Maybe (Maybe(..), fromJust, fromMaybe) import Data.Number (infinity) import Data.Show.Generic (genericShow) import Data.Traversable (for) -import Data.Tuple (Tuple(..), fst, uncurry) +import Data.Tuple (Tuple(..), fst, snd, uncurry) import Data.Tuple.Nested (type (/\), (/\)) import Functorio.Lens (modifyAt) import Math (sin) @@ -70,8 +69,8 @@ blueBelt :: BeltConfig blueBelt = { speed: 45.0, delay: 4.0/8.0 } -- | Example factory -myFactory :: Factory -myFactory = Map.fromArray machines +myFactory1 :: Factory +myFactory1 = Map.fromArray machines where machines = mapWithIndex Tuple [ Provider [0, 1] $ startsAtZero $ \t -> 40.0 + 10.0 * sin t @@ -82,6 +81,19 @@ myFactory = Map.fromArray machines , Consumer 4 ] +myFactory :: Factory +myFactory = Map.fromArray machines + where + machines = mapWithIndex Tuple + [ Provider [0, 1, 2] $ startsAtZero $ \t -> 80.0 + , Belt { input: 0, output: 3, config: yellowBelt } + , Belt { input: 1, output: 4, config: redBelt } + , Belt { input: 2, output: 5, config: blueBelt } + , Consumer 3 + , Consumer 4 + , Consumer 5 + ] + ---------- Helpers for real functions type Endomorphism a = a -> a @@ -190,7 +202,7 @@ tryFindBoundImpl (targetId /\ targetSide) = do evalExpr expr <*> pure time BiRelationship id raw | Just relationship <- focusBiRelationship (targetId /\ targetSide) raw -> do - f <- once id fail $ tryFindBoundImpl relationship.p2 + f <- once id fail $ tryFindValueImpl $ fst relationship.p2 f (relationship.p1top2 time) _ -> fail # runReader constraints @@ -225,29 +237,27 @@ collectConstraintsImpl at = case _ of Provider for amount -> do forWithIndex_ for \index id -> do let limit ports time - = outputs ports time - # Array.findMap (\(id' /\ f) -> if id == id' then Just (f time) else Nothing) - # unsafePartial fromJust -- TODO: error handling + = ports + # map (\port -> port.id /\ port.maxOutput time) + # outputs (amount time) + # Array.findMap (\(id' /\ f) -> if id == id' then Just f else Nothing) + # unsafePartial fromJust constrain $ Limit (PortDependent for limit) Input id where - outputs :: Array PortData -> Number -> Array (PortId /\ RealFunction) - outputs ports time - = outputsImpl (length ports) (List.fromFoldable sorted) amount + outputs :: Number -> Array (PortId /\ Number) -> Array (PortId /\ Number) + outputs total ports + = ports + # Array.sortWith snd + # foldlWithIndex (\index (past /\ remaining) (id /\ value) -> do + let current + | lengthLeft <- remaining / toNumber (count - index), value >= lengthLeft = lengthLeft + | otherwise = value + ((id /\ current):past) /\ (remaining - current)) + (Nil /\ total) + # fst # Array.fromFoldable - # Array.zipWith (_.id >>> Tuple) sorted where - sorted :: Array PortData - sorted = Array.sortWith (_.maxOutput >>> (#) time) ports - - outputsImpl :: Int -> List PortData -> RealFunction -> List RealFunction - outputsImpl 1 (head:Nil) remaining = pure \time -> min (head.maxOutput time) (remaining time) - outputsImpl n (head:tail) remaining = current:(outputsImpl (n - 1) tail $ remaining - current) - where - current time - | head.maxOutput time >= (remaining time) / (toNumber n) = (remaining time) / (toNumber n) - | otherwise = head.maxOutput time - outputsImpl _ _ _ = Nil - + count = length ports Consumer for -> do constrain $ Limit (Literal infinity) Output for Belt { input, output, config } -> do diff --git a/purescript/factorio-throughput/src/Utils/Ord.purs b/purescript/factorio-throughput/src/Utils/Ord.purs new file mode 100644 index 0000000..02bdc90 --- /dev/null +++ b/purescript/factorio-throughput/src/Utils/Ord.purs @@ -0,0 +1,33 @@ +module Moontorio.Ord.Extra (Side, left, right, OrderedArray, binarySearch) where + +import Prelude + +import Data.Array (length, unsafeIndex) +import Data.Maybe (Maybe(..)) +import Partial.Unsafe (unsafePartial) + +type OrderedArray = Array +newtype Side = Side Boolean + +left :: Side +left = Side false + +right :: Side +right = Side true + +binarySearch :: forall a. (Int -> a -> Side) -> OrderedArray a -> Maybe Int +binarySearch f arr = unsafePartial $ findImpl 0 (length arr) + where + findImpl :: Partial => _ + findImpl start length | length == 0 = Nothing + | length == 1 = Just start + | otherwise = do + let middle = start + length / 2 + let element = unsafeIndex arr middle + if f middle element == left then + findImpl start (middle - start) + else + findImpl middle (length + start - middle) + +---------- Typeclass instances +derive instance eqSide :: Eq Side \ No newline at end of file