implement new setReworks mechanism that calls Random only for no of jobs to be reworked (was all jobs)
3 files changed, 83 insertions(+), 26 deletions(-)

M src/Main.elm
M src/Rework.elm
R src/Step.elm => 
M src/Main.elm +1 -1
@@ 17,9 17,9 @@ import Html
 import Lib exposing (..)
 import Maybe.Extra exposing (..)
 import Numbers exposing (Quartile(..), quartile)
+import Rework exposing (..)
 import Round exposing (..)
 import Stats exposing (..)
-import Step exposing (..)
 import Task
 import Time
 import Types exposing (..)

          
M src/Rework.elm +82 -0
@@ 3,6 3,7 @@ module Rework exposing (..)
 import Field exposing (..)
 import Random
 import Random.Extra
+import Random.List
 import Types exposing (..)
 
 

          
@@ 27,3 28,84 @@ setRework p j =
 setReworksSingleMode : ProbPerRound -> List Job -> Random.Generator (List Job)
 setReworksSingleMode p =
     Random.Extra.traverse (setRework p)
+
+
+
+-- new setRework mechanism to improve perf with increasing no. of jobs on w0
+-- aim: constant computing amount for increasing no. of jobs on w0
+-- relevance: rework mechanism consumes ≈ half of computing time, which is the biggest chunk
+-- example situation: 100 jobs on w0, rework probability is 1%
+-- approach: pick 1 job by random and set it to require rework
+-- sub-problem: what if we end up with decimal no. of jobs,
+-- i.e. 100 jobs at 0.5% rework probability => 0.5 jobs
+-- or 2 jobs at 1 % rework probability => 0.02 jobs
+-- approach: 0.5 and 0.02 jobs are probabilities 0.5 and 0.02 for
+-- an additional job to be picked and set to require rework
+-- reworkProb * jobsAtW0
+-- (nonDecimal, decimal) = …
+-- jobsToRequireRework = nonDecimal + additional decimal
+-- newW0 = setRework jobsToRequireRework w0
+--additional : Float -> Random.Generator Bool
+--additional prob = _
+-- | p is percentage, i.e. 0.1 is 0.1%
+
+
+bool : Float -> Random.Generator Bool
+bool p =
+    Random.map (\n -> n < round (p * 1000 / 100)) <| Random.int 1 1000
+
+
+detNoOfJobsRequiringRework : ProbPerRound -> Int -> Random.Generator Int
+detNoOfJobsRequiringRework p w0Count =
+    let
+        reworkJobs =
+            p * toFloat w0Count
+
+        nonDecimal =
+            round reworkJobs
+
+        decimal =
+            reworkJobs - toFloat nonDecimal
+
+        additional =
+            Random.map
+                (\x ->
+                    if x then
+                        1
+
+                    else
+                        0
+                )
+            <|
+                bool decimal
+    in
+    Random.map (\x -> nonDecimal + x) additional
+
+
+setReworks : ProbPerRound -> ( Field, Field ) -> Random.Generator ( Field, Field )
+setReworks p ( kf, nkf ) =
+    Random.map2 Tuple.pair (setReworksFieldWrapper p kf) (setReworksFieldWrapper p nkf)
+
+
+setReworksFieldWrapper : ProbPerRound -> Field -> Random.Generator Field
+setReworksFieldWrapper p field =
+    detNoOfJobsRequiringRework p (List.length field.w0) |> Random.andThen (setReworksField field)
+
+
+setReworksField : Field -> Int -> Random.Generator Field
+setReworksField field n =
+    Random.map (\x -> { field | w0 = x }) <| setReworkNew n field.w0
+
+
+setReworkNew : Int -> List Job -> Random.Generator (List Job)
+setReworkNew n =
+    let
+        toRework =
+            List.map (\x -> updateRework x NeedsRework)
+    in
+    Random.map (\( a, b ) -> toRework a ++ b) << Random.List.choices n
+
+
+setReworksCmd : Model -> Cmd Msg
+setReworksCmd model =
+    Random.generate SetReworksDone <| setReworks model.reworkProbPerRound ( model.kit, model.nkit )

          
R src/Step.elm =>  +0 -25
@@ 1,25 0,0 @@ 
-module Step exposing (..)
-
-import Random
-import Random.Extra
-import Rework exposing (..)
-import Types exposing (..)
-
-
-
--- step mode
-
-
-setReworksField : ProbPerRound -> Field -> Random.Generator Field
-setReworksField p f =
-    Random.Extra.traverse (setRework p) f.w0 |> Random.andThen (\x -> Random.constant { f | w0 = x })
-
-
-setReworks : ProbPerRound -> ( Field, Field ) -> Random.Generator ( Field, Field )
-setReworks p ( kf, nkf ) =
-    Random.map2 Tuple.pair (setReworksField p kf) (setReworksField p nkf)
-
-
-setReworksCmd : Model -> Cmd Msg
-setReworksCmd model =
-    Random.generate SetReworksDone <| setReworks model.reworkProbPerRound ( model.kit, model.nkit )