packages feed

deltaq 1.1.0.0 → 1.2.0.0

raw patch · 6 files changed

+129/−18 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ DeltaQ.Diagram.Internal: OUniform :: Rational -> Rational -> Op0
+ DeltaQ.Diagram.Internal: textInWidth :: Double -> String -> Diagram SVG
+ DeltaQ.Expr: Uniform :: Rational -> Rational -> Term v

Files

CHANGELOG.md view
@@ -1,5 +1,18 @@ # Revision history for `deltaq` +## 1.2.0.0 — 2025-11-21++### Changed++* Add a constructor `Uniform` to the type `Term`.+* In `DeltaQ.Diagram`:+  * Draw `⊥` instead of using a unicode font glyph.+  * Scale variable names to keep them in the orange circle.+* In `DeltaQ.Plot`: Improve rendering of cumulative distribution functions:+  * Set upper bound of the *y*-axis to 1.+  * Remove gap in the plot at the right end of the *x*-axis.+  * Highlight the success probability when plotting a single distribution.+ ## 1.1.0.0 — 2025-10-14  ### Added
deltaq.cabal view
@@ -5,7 +5,7 @@ -- PVP summary:  +-+------- breaking API changes --               | | +----- non-breaking API additions --               | | | +--- code changes with no API change-version:         1.1.0.0+version:         1.2.0.0 synopsis:        Framework for ∆Q System Development description:   ∆Q System Development is a paradigm for developing distributed systems@@ -82,7 +82,7 @@     , deltaq     , hspec                   >=2.11.0 && <2.12     , probability-polynomial-    , QuickCheck              >=2.14   && <2.17+    , QuickCheck              >=2.14   && <2.18    main-is:            Spec.hs   other-modules:
src/DeltaQ/Diagram/Internal.hs view
@@ -57,6 +57,7 @@     = ONever     | OWait0     | OWait Rational+    | OUniform Rational Rational     deriving (Eq, Ord, Show)  -- | Data attached to a 'Tile'.@@ -81,10 +82,19 @@         , renderToken token         ) +-- | Text constrained to fit into a given width.+--+-- TODO: This is approximate at the moment.+-- Use SVGFonts to fix both the font and the sizing.+textInWidth :: Double -> String -> Diagram SVG+textInWidth _ s+    | length s > 4 = scale (4.5 / fromIntegral (length s)) $ text s+    | otherwise    = text s+ -- | Render a single 'Token' associated with a 'Tile'. renderToken :: Token -> Diagram SVG renderToken (VarT s) =-    scale 0.3 (text s)+    scale 0.3 (textInWidth 1 s)     <> (circle 0.44 & lc orange & lw 4 & fc white)     <> hrule 1 renderToken (Outcome OWait0) =@@ -130,10 +140,19 @@  -- | Render the symbol that represents a known outcome. renderOp0Symbol :: Op0 -> Diagram SVG-renderOp0Symbol ONever    = text "⊥"+renderOp0Symbol ONever    =+    ((fromOffsets [r2 (-0.7,0)] & strokeLine & translate (r2 (0.7/2, -0.35)))+    <> (fromOffsets [r2 (0,0.7)] & strokeLine & translate (r2 (0, -0.35)))+    ) & lw 1.3 renderOp0Symbol OWait0    = mempty renderOp0Symbol (OWait t) =-    text $ "wait " <> printf "%.2f" (fromRational t :: Double)+    textInWidth 1 $+        "wait " <> printf "%.2f" (fromRational t :: Double)+renderOp0Symbol (OUniform tl tr) =+    textInWidth 1 $+        "uniform "+            <> printf "%.2f" (fromRational tl :: Double) <> " "+            <> printf "%.2f" (fromRational tr :: Double)  -- | Render the symbol that represents an operation with multiple arguments renderOpSymbol :: Op -> Diagram SVG@@ -225,6 +244,7 @@ isVarOrKnown Never    = True isVarOrKnown Wait0    = True isVarOrKnown (Wait _) = True+isVarOrKnown (Uniform _ _) = True isVarOrKnown _ = False  -- | Check that a given 'EdgeData' contains no outcome-related data.@@ -272,6 +292,7 @@     emit (y, Term Never    _) = Tile x y $ Outcome ONever     emit (y, Term Wait0    _) = Tile x y $ Outcome OWait0     emit (y, Term (Wait t) _) = Tile x y $ Outcome $ OWait t+    emit (y, Term (Uniform tl tr) _) = Tile x y $ Outcome $ OUniform tl tr     emit (y, _              ) = Tile x y Horizontal  -- | Emit a column with the next vertical items.
src/DeltaQ/Expr.hs view
@@ -57,6 +57,7 @@     ) import DeltaQ.Class     ( Outcome (..)+    , DeltaQ (..)     , ProbabilisticOutcome (..)     ) import DeltaQ.PiecewisePolynomial@@ -108,6 +109,7 @@     go Never    = never     go Wait0    = wait 0     go (Wait t) = wait t+    go (Uniform tl tr) = uniform tl tr     go (Loc  _) = wait 0     go (Seq   xs) = foldr1 (.>>.) $ map go xs     go (Last  xs) = foldr1 (./\.) $ map go xs@@ -147,6 +149,9 @@         -- but with a straight line as graphical representation.     | Wait Rational         -- ^ Succeed after waiting for a fixed amount of time.+    | Uniform Rational Rational+        -- ^ @Uniform l r@ succeeds after an amount of time randomly drawn+        -- from a uniform probability distribution on the interval $[l,r]$.     | Loc String         -- ^ Outcome location with a label.         -- Equivalent to @Wait 0@, but with a labeled box@@ -174,6 +179,7 @@         go Never      = Never         go Wait0      = Wait0         go (Wait t)   = Wait t+        go (Uniform tl tr) = Uniform tl tr         go (Loc  s)   = Loc s         go (Seq   xs) = Seq   $ map go xs         go (Last  xs) = Last  $ map go xs@@ -290,6 +296,7 @@     recurse a@Never = a     recurse a@Wait0 = a     recurse a@(Wait _) = a+    recurse a@(Uniform _ _) = a     recurse a@(Loc  _) = a     recurse (Seq   xs) = Seq $ map every xs     recurse (Last  xs) = Last $ map every xs@@ -308,6 +315,7 @@     recurse x@Never    = f x     recurse x@Wait0    = f x     recurse x@(Wait _) = f x+    recurse x@(Uniform _ _) = f x     recurse x@(Loc  _) = f x     recurse x@(Seq   xs) =         foldl' combine (f x) $ map recurse xs
src/DeltaQ/Plot.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} @@ -28,6 +29,9 @@ import Graphics.Rendering.Chart.Easy     ( (.=)     )+import Text.Printf+    ( printf+    )  import qualified Graphics.Rendering.Chart.Easy as G @@ -47,8 +51,12 @@     => String -- ^ Title     -> o -- ^ Outcome to plot     -> G.Layout Double Double-plotCDF title o =-    plotCDFs title [("", o)]+plotCDF title o = G.execEC $ do+    G.layout_title .= title+    add_x_axis [o]+    add_y_axis_cumulative_probability+    add_line_DeltaQ "" o+    add_failure_probability o  -- | Plot multiple CDFs in a single plot, -- with title.@@ -65,12 +73,8 @@ plotCDFs title namedOutcomes = G.execEC $ do     G.layout_title .= title     add_x_axis (map snd namedOutcomes)-    G.layout_y_axis . G.laxis_title .= "Cumulative Probabilty"-    mapM_ plotOne namedOutcomes-  where-    cv1 = fromRational . toRational-    cv2 = fromRational . toRational-    plotOne (t, o) = G.plot $ G.line t [[(cv1 a, cv2 b) | (a, b) <- toXY o]]+    add_y_axis_cumulative_probability+    mapM_ (uncurry add_line_DeltaQ) namedOutcomes  -- | Plot the cumulative distribution function (CDF) of a 'DeltaQ', -- with title, and annotated with quantiles.@@ -88,15 +92,72 @@ plotCDFWithQuantiles title quantiles o = G.execEC $ do     G.layout_title .= title     add_x_axis [o]-    G.layout_y_axis . G.laxis_title .= "Cumulative Probabilty"-    G.plot $ G.line "" [[(cv1 a, cv2 b) | (a, b) <- toXY o]]+    add_y_axis_cumulative_probability+    add_line_DeltaQ "" o     mapM_ plotQuantile quantiles   where-    cv1 = fromRational . toRational-    cv2 = fromRational . toRational     plotQuantile y = case quantile o y of         Abandoned -> pure ()-        Occurs x -> G.plot $ pure $ focusOnPoint (cv1 x, cv2 y)+        Occurs x -> G.plot $ pure $ focusOnPoint (toTime x, toProb y)++-- | Convenient abbreviation for use in this module.+type PlotDeltaQ o =+    ( DeltaQ o, Enum (Duration o), Fractional (Duration o)+      , Real (Duration o), Real (Probability o)+    )++-- | Add the line graph for a single outcome.+add_line_DeltaQ+    :: PlotDeltaQ o => String -> o -> G.EC (G.Layout Double Double) ()+add_line_DeltaQ name o = G.plot $ do+    let xys = [(toTime a, toProb b) | (a, b) <- toXY o]+        x   = fst (last xys)+        y   = snd (last xys)+    -- plot line data+    l <- G.line name [xys]+    -- add a line to the right end+    pure $+        G.plot_lines_limit_values G.#~+            [ [(G.LValue x, G.LValue y), (G.LMax, G.LValue y)]+            ]+        $ l++-- | Add a dotted horizontal line that indicates the failure probability.+add_failure_probability :: PlotDeltaQ o => o -> G.EC (G.Layout Double Double) ()+add_failure_probability o = do+    G.plot $ pure $ G.execEC $ do+        G.plot_lines_style . G.line_color .= G.opaque G.black+        G.plot_lines_style . G.line_dashes .= [5, 5]+        G.plot_lines_limit_values .=+            [ [(G.LMin, G.LValue y), (G.LValue x, G.LValue y)]+            ]+    let extraLabels = [(y, showProb y)]+    G.layout_y_axis . G.laxis_override .=+        (\ad -> ad G.& (G.axis_labels G.%~ (<> [extraLabels])))+  where+    x = toTime $ eventually 0 id $ deadline o+    y = toProb $ 1 - failure o++-- | Add a @y@-axis to the plot that corresponds to cumulative probability.+add_y_axis_cumulative_probability+    :: G.PlotValue x => G.EC (G.Layout x Double) ()+add_y_axis_cumulative_probability = do+    G.layout_y_axis . G.laxis_title .= "Cumulative Probability"+    G.layout_y_axis . G.laxis_generate .= G.scaledAxis G.def (0,1)++-- | Convert a time to a value on the @x@-axis.+toTime :: Real x => x -> Double+toTime = fromRational . toRational++-- | Convert a probability to a value on the @y@-axis.+toProb :: Real y => y -> Double+toProb = fromRational . toRational++-- | Show a probability in scientific notation with two digits of precision.+showProb :: Double -> String+showProb x+    | x >= 0.01 = printf "%.2f" x+    | otherwise = printf "%.2e\n" x  {-----------------------------------------------------------------------------     Plot
test/DeltaQ/Gen/Term.hs view
@@ -42,6 +42,13 @@     NonNegative a <- arbitrary     pure $ Wait a +-- | Generate a 'uniform'.+genUniform :: Gen (Term v)+genUniform = do+    NonNegative a <- arbitrary+    NonNegative d <- arbitrary+    pure $ Uniform a (a + d)+ -- | Generate a 'var' with a short name. genVar :: Gen v -> Gen (Term v) genVar = fmap Var@@ -53,6 +60,7 @@         [ (20, genVar genName)         , ( 4, genWait)         , ( 2, pure Wait0)+        , ( 4, genUniform)         , ( 4, pure Never)         , ( 1, pure $ Loc "test")         ]