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 +13/−0
- deltaq.cabal +2/−2
- src/DeltaQ/Diagram/Internal.hs +24/−3
- src/DeltaQ/Expr.hs +8/−0
- src/DeltaQ/Plot.hs +74/−13
- test/DeltaQ/Gen/Term.hs +8/−0
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") ]