packages feed

deltaq 1.0.0.0 → 1.0.1.0

raw patch · 7 files changed

+238/−52 lines, 7 filesdep ~Chartdep ~probability-polynomialnew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: Chart, probability-polynomial

API changes (from Hackage documentation)

+ DeltaQ.Methods: retryOverlap :: [Duration DQ] -> DQ -> DQ
+ DeltaQ.Methods: retryOverlapN :: Int -> Duration DQ -> DQ -> DQ
+ DeltaQ.PiecewisePolynomial: timeout :: Duration DQ -> DQ -> (DQ, Probability DQ, DQ)
- DeltaQ.Class: class (Ord (Probability o), Enum (Probability o), Num (Probability o), Fractional (Probability o), Outcome o) => DeltaQ o where {
+ DeltaQ.Class: class (Ord Probability o, Enum Probability o, Num Probability o, Fractional Probability o, Outcome o) => DeltaQ o where {
- DeltaQ.Class: class (Ord (Duration o), Num (Duration o)) => Outcome o where {
+ DeltaQ.Class: class (Ord Duration o, Num Duration o) => Outcome o where {
- DeltaQ.PiecewisePolynomial: data () => Moments a
+ DeltaQ.PiecewisePolynomial: data Moments a

Files

CHANGELOG.md view
@@ -1,5 +1,20 @@ # Revision history for `deltaq` +## 1.0.1.0 — 2025-09-26++### Added++* Add combinator `timeout` that returns probabilities conditioned+  on completing within a given duration.+* Add functions `retryOverlap` and `retryOverlapN` for modelin retry policies+  that race time-delayed, independent copies of an outcome against each other.+* Clarify semantics of `deadline`.+* Bump dependencies, allow `containers-0.8`, `QuickCheck-2.16`, `optparse-applicative-0.19`.++### Fixed++* Fix `quantile` to return the correct result when the result is precisely at the boundary between two pieces of the piecewise probability distribution.+ ## 1.0.0.0 — 2024-12-23  * Initial release of the domain-specific language for ∆Q System Development.
deltaq.cabal view
@@ -2,10 +2,10 @@ name:            deltaq  -- Package Versioning Policy: https://pvp.haskell.org--- PVP summary:    +-+------- breaking API changes---                 | | +----- non-breaking API additions---                 | | | +--- code changes with no API change-version:         1.0.0.0+-- PVP summary:  +-+------- breaking API changes+--               | | +----- non-breaking API additions+--               | | | +--- code changes with no API change+version:         1.0.1.0 synopsis:        Framework for ∆Q System Development description:   ∆Q System Development is a paradigm for developing distributed systems@@ -27,23 +27,21 @@ homepage:        https://github.com/DeltaQ-SD/deltaq license:         BSD-3-Clause license-file:    LICENSE-copyright:       Predictable Network Solutions Ltd., 2003-2024+copyright:       Predictable Network Solutions Ltd., 2003-2025 author:          Neil Davies, Heinrich Apfelmus maintainer:      neil.davies@pnsol.ccom- extra-doc-files:   CHANGELOG.md   README.md -tested-with:-  , GHC == 9.10.1+tested-with:     GHC ==8.10.7 || ==9.6.7 || ==9.10.3  common warnings   ghc-options: -Wall  source-repository head   type:     git-  location: git://github.com/DeltaQ-SD/deltaq.git+  location: https://github.com/DeltaQ-SD/deltaq.git   subdir:   lib/deltaq  library@@ -51,11 +49,11 @@   hs-source-dirs:   src   default-language: Haskell2010   build-depends:-    , base >= 4.14.3.0 && < 5-    , deepseq >= 1.4.4.0 && < 1.6-    , Chart >= 1.8 && < 2.0-    , lattices >= 2.2 && < 2.3-    , probability-polynomial >= 1.0 && < 1.1+    , base                    >=4.14.3.0 && <5+    , Chart                   >=1.8      && <2+    , deepseq                 >=1.4.4.0  && <1.6+    , lattices                >=2.2      && <2.3+    , probability-polynomial  >=1.0.1    && <1.1    exposed-modules:     DeltaQ@@ -65,23 +63,19 @@     DeltaQ.Plot  test-suite test-  import:           warnings-  type:             exitcode-stdio-1.0-  hs-source-dirs:   test-  default-language: Haskell2010-+  import:             warnings+  type:               exitcode-stdio-1.0+  hs-source-dirs:     test+  default-language:   Haskell2010   build-tool-depends: hspec-discover:hspec-discover-   build-depends:     , base     , deltaq+    , hspec                   >=2.11.0 && <2.12     , probability-polynomial-    , hspec >= 2.11.0 && < 2.12-    , QuickCheck >= 2.14 && < 2.16--  main-is:-    Spec.hs+    , QuickCheck              >=2.14   && <2.17 +  main-is:            Spec.hs   other-modules:     DeltaQ.ClassSpec     DeltaQ.MethodsSpec@@ -92,21 +86,17 @@   type:             exitcode-stdio-1.0   hs-source-dirs:   benchmark   default-language: Haskell2010-   build-depends:     , base-    , bytestring >= 0.11 && < 0.13-    , deltaq-    , cassava >= 0.5.3.2 && < 0.6-    , criterion >= 1.6 && < 1.7+    , bytestring            >=0.11     && <0.13+    , cassava               >=0.5.3.2  && <0.6+    , criterion             >=1.6      && <1.7     , deepseq-    , hvega >= 0.12 && < 0.13-    , optparse-applicative >= 0.18.1.0 && < 0.19-    , statistics >= 0.16 && < 0.17-    , vector >= 0.12 && < 0.14--  main-is:-    Main.hs+    , deltaq+    , hvega                 >=0.12     && <0.13+    , optparse-applicative  >=0.18.1.0 && <0.20+    , statistics            >=0.16     && <0.17+    , vector                >=0.12     && <0.14 -  other-modules:-    Benchmark.Plot+  main-is:          Main.hs+  other-modules:    Benchmark.Plot
src/DeltaQ/Class.hs view
@@ -176,6 +176,10 @@     -- @choices [(w_1, o_1), (w_2, o_2), …]@ chooses randomly between multiple     -- outcomes. The probability @p_i@ for choosing the outcome @o_i@ is     -- determined by the weights as @p_i = w_i / (w_1 + w_2 + …)@.+    --+    -- Note: The weights @w_i@ have the numeric type @Probability o@,+    -- but for convenience, and unlike probabilities,+    -- they are not restricted to the unit interval \( [0,1] \).     choices :: [(Probability o, o)] -> o     choices [] = never     choices wos =@@ -341,10 +345,16 @@ > deadline (x ./\. y) =  max (deadline x) (deadline y) > > deadline (x .\/. y) =  min (deadline x) (deadline y)->   if failure x = 0, failure y = 0+>   if failure x = 0 and failure y = 0 >+> deadline (x .\/. y) =  deadline x+>   if failure x = 0 and failure y > 0+>+> deadline (x .\/. y) =  max (deadline x) (deadline y)+>   if 1 > failure x > 0 and 1 > failure y > 0+> > deadline (choice p x y) = max (deadline x) (deadline y)->   if p ≠ 0, p ≠ 1, failure x = 0, failure y = 0+>   if p ≠ 0 and p ≠ 1 and failure x < 1 and failure y < 1 > > > deadline (uniform r s)  = Occurs s   if r <= s
src/DeltaQ/Methods.hs view
@@ -17,6 +17,10 @@     , SlackOrHazard (..)     , isSlack     , isHazard+    +    -- * Timeouts+    , retryOverlapN+    , retryOverlap     ) where  import DeltaQ.Class@@ -25,6 +29,10 @@     , Outcome (..)     , eventually     )+import DeltaQ.PiecewisePolynomial+    ( DQ+    , timeout+    )  {-----------------------------------------------------------------------------     Methods@@ -83,3 +91,45 @@     p' = o `successWithin` t      err = error "distanceToReference: inconsistency"++{-----------------------------------------------------------------------------+    Methods+    Timeouts+------------------------------------------------------------------------------}++-- | Retry an outcome @n@ times, take the first instance that succeeds.+--+-- More specifically, @retryOverlapN n dt o@ models the completion times+-- of a race of @n@ independent copies of the outcome @o@ against each other,+-- succeeding when any of the copies first succeeds.+--+-- Copy number @0 <= j < n@ is started after waiting a time @j * dt@.+--+-- If no copy succeeds within total time @n * dt@,+-- the whole outcome fails.+retryOverlapN :: Int -> Duration DQ -> DQ -> DQ+retryOverlapN n dt = retryOverlap (replicate n dt)++-- | Retry an outcome multiple times, take the first instance that succeeds.+--+-- More specifically, @retryOverlap dts o@ models the completion times+-- of a race of @length dts@ independent copies of the outcome @o@+-- against each other, succeeding when any of the copies first succeeds.+--+-- Each copy is started after a timeout+-- in the event that the previous copies have not finished yet;+-- the list @dts@ gives the successive timeouts.+--+-- If no copy succeeds within total time @sum dts@,+-- the whole outcome fails.+retryOverlap :: [Duration DQ] -> DQ -> DQ+retryOverlap dts0 o = go dts0 o+  where+    go [] _ = never+    go (dt:dts) race =+        choice p before (wait dt .>>. retry)+      where+        (before, p, after) = timeout dt race++        -- add another copy of `o` to the race+        retry = go dts (after .\/. o)
src/DeltaQ/PiecewisePolynomial.hs view
@@ -24,6 +24,7 @@     , meetsQTA     , Moments (..)     , moments+    , timeout      -- * Internal     , complexity@@ -186,7 +187,7 @@   where     goJump _ [] = []     goJump prev ((x1, o) : xos)-        | y1 - y0 > 0 = Jump x1 (y0, y1) : nexts+        | y0 < y1   = Jump x1 (y0, y1) : nexts         | otherwise = nexts       where         y1 = Poly.eval o x1@@ -197,7 +198,6 @@         End x1 y1 : goJump o []     goPoly x1 y1 o xos@((x2, _) : _) =         Polynomial (x1, x2) (y1, Poly.eval o x2) o : goJump o xos-        -- TODO: What about the case where y1 == y2, i.e. a constant Polynomial?  {-----------------------------------------------------------------------------     Operations@@ -214,13 +214,14 @@     findInSegments [] _         = Nothing     findInSegments (Jump x1 (y1, y2) : xys) y-        | y1 < y && y <= y2 = Just x1-        | otherwise = findInSegments xys y+        | y1 <= y && y < y2 = Just x1+        | otherwise         = findInSegments xys y     findInSegments (Polynomial (x1, x2) (y1, y2) o : xys) y-        | y1 < y && y <= y2 = Poly.root precision y (x1, x2) o+        | y1 == y           = Just x1+        | y1 <  y && y < y2 = Poly.root precision y (x1, x2) o         | otherwise = findInSegments xys y     findInSegments (End x1 y1 : _) y-        | y1 == y = Just x1+        | y1 == y   = Just x1         | otherwise = Nothing  precision :: Rational@@ -254,9 +255,12 @@     Operations     Moments ------------------------------------------------------------------------------}--- | Compute the success probability of a 'DQ',--- and the first commonly used 'Moments' of the--- probability distribution conditioned on success.+-- | For a given 'DQ', compute+--+-- * the success probability, and+--+-- * the 'Moments' of the conditional probability (distribution)+--   given that the outcome has succeeded. moments :: DQ -> (Rational, Moments Rational) moments (DQ m)     | success == 0 =@@ -266,3 +270,42 @@   where     success = Measure.total m     conditional = Prob.unsafeFromMeasure $ Measure.scale (1/success) m++{-----------------------------------------------------------------------------+    Operations+    Timeout+------------------------------------------------------------------------------}+-- | Given a duration @dt@,+-- decompose a probability distribution of completion times+-- into two conditional probability distributions —+-- one distribution conditional on finishing within @dt@,+-- and the other distribution conditional on finishing after @dt@.+--+-- >   (within, p, after) = timeout dt o+-- >+-- > implies+-- >+-- >   o = choice p within (wait dt .>>. after)+-- >   p = successWithin o dt+-- >+-- >   successWithin within dt = 1+-- >     if p > 0+--+-- We define the corner cases as follows:+--+-- * @successWithin o dt = 0@ implies @before = never@.+--+-- * @successWithin o dt = 1@ implies @after = never@.+--+timeout :: Duration DQ -> DQ -> (DQ, Probability DQ, DQ)+timeout dt (DQ m) = (beforeCond, p, afterCond)+  where+    before = Measure.beforeOrAt dt m+    after = Measure.translate (- dt) $ Measure.after dt m+    p = Measure.total before+    beforeCond+        | p == 0 = never+        | otherwise = DQ $ Measure.scale (1/p) before+    afterCond+        | p == 1 = never+        | otherwise = DQ $ Measure.scale (1/(1-p)) after
test/DeltaQ/MethodsSpec.hs view
@@ -18,10 +18,12 @@     ) import DeltaQ.PiecewisePolynomial     ( DQ+    , timeout     ) import DeltaQ.Methods     ( SlackOrHazard (..)     , meetsRequirement+    , retryOverlap     ) import Test.Hspec     ( Spec@@ -33,6 +35,7 @@     , Positive (..)     , property     , withMaxSuccess+    , (===)     )  {-----------------------------------------------------------------------------@@ -62,3 +65,27 @@                 in  case deltaq `meetsRequirement` (0, 0.9) of                         Hazard (Occurs dt) dp -> dt >= 0 && dp >= 0                         _ -> False++    describe "retryOverlap" $ do+        it "documentation" $ property $+            \(Positive d) (dts' :: [Positive Rational]) ->+                let r = 0+                    s = r + d+                    dts = map (\(Positive dt) -> dt) dts'+                    o = uniform r s :: DQ+                in+                    retryOverlap dts o  ===  retryOverlap' dts o++-- | Implementation of 'retryOverlap' that matches the description+-- in the documentation. +retryOverlap' :: [Duration DQ] -> DQ -> DQ+retryOverlap' dts o =+    cutoff (sum dts)+        $ foldr (.\/.) never+            [ wait dt .>>. o+            | dt <- init (scanl (+) 0 dts)+            ]+  where+    cutoff dt x = choice p before never+      where+        (before, p, _) = timeout dt x
test/DeltaQ/PiecewisePolynomialSpec.hs view
@@ -33,6 +33,7 @@     , fromPositiveMeasure     , meetsQTA     , moments+    , timeout     ) import Numeric.Probability.Moments     ( Moments (..)@@ -279,6 +280,15 @@                 in                     p' <= q'  ==>  quantile' o p' <= quantile' o q' +        it "interval boundary" $ property $+            \(Probability p) (NonNegative t0) (Positive d1) (Positive d2) ->+                let t1 = t0 + d1+                    t2 = t1 + d2+                in+                p > 0 ==>+                    quantile' (choice p (uniform t0 t1) (wait t2)) p+                        === Occurs t1+         it "never" $ property $             \(Probability p) ->                 p > 0 ==>@@ -353,15 +363,30 @@                 deadline' (x ./\. y)                     ===  max (deadline' x) (deadline' y) -        it ".\\/." $ property $+        it ".\\/., zero failure" $ property $             \x y ->                 (failure x == 0 && failure y == 0) ==>                     deadline' (x .\/. y)                         ===  min (deadline' x) (deadline' y) +        it ".\\/., one failure" $ property $+            \(Probability p) x y -> 0 < p && p < 1+                ==> let y' = choice p y never+                    in failure x == 0  ==>+                    deadline' (x .\/. y')+                        ===  deadline' x++        it ".\\/., two failure" $ property $+            \(Probability p) x y -> 0 < p && p < 1+                ==> let x' = choice p x never+                        y' = choice p y never+                    in  (failure x < 1 && failure y < 1)+                    ==> deadline' (x' .\/. y')+                        ===  max (deadline' x') (deadline' y')+         it "choice" $ property $             \(Probability p) x y ->-                (0 < p && p < 1 && failure x == 0 && failure y == 0) ==>+                (0 < p && p < 1 && failure x < 1 && failure y < 1) ==>                     deadline' (choice p x y)                         === max (deadline' x) (deadline' y) @@ -439,6 +464,32 @@             \(NonNegative t) ->                 let ms = Moments{mean = t, variance = 0, skewness = 0, kurtosis = 1}                 in  moments (wait t)  ===  (1, ms)++    describe "timeout" $ do+        it "never" $ property $+            \dt ->+                timeout dt never  ===  (never, 0, never)++        it "probability" $ property $+            \x dt ->+                let (_, p, _) = timeout dt x+                in  p  ===  successWithin x dt++        it "within" $ property $+            \x dt ->+                let (within, p, _) = timeout dt x+                in  p > 0 ==>+                        successWithin within dt  ===  1++        it "wait" $ property $+            \x dt (Positive d) ->+                timeout dt (wait (dt + d) .>>. x)+                    ===  (never, 0, wait d .>>. x)++        it "choice" $ property $+            \x dt ->+                let (within, p, after) = timeout dt x+                in  choice p within (wait dt .>>. after)  ===  x      describe "complexity" $ do         it "grows exponentially with .>>." $ withMaxSuccess 1 $ property $