Skip to content

0.3.0

Latest

Choose a tag to compare

@ad-si ad-si released this 06 Aug 16:42
· 61 commits to main since this release
a36e0de

Between 0.2.0 and 0.3.0 the focus moved from growing the function library
to running real notebooks: Woxi Studio executes complete Wolfram
Demonstrations end to end, the plotters draw what wolframscript draws, and
hundreds of conformance and robustness fixes — many found by differential
fuzzing against wolframscript — closed gaps between the two engines.
Windows became a supported platform with prebuilt binaries. The list only
includes the most prominent changes; the Demonstration-driven fixes are
described in detail in the last section.

Woxi Studio & Wolfram Demonstrations

  • Woxi Studio opens and runs complete Wolfram Demonstration notebooks end
    to end — including definition notebooks and notebooks with embedded
    raster photos — and re-instantiates stored Manipulate widgets when a
    notebook is reopened. Demonstrations such as Kepler's Second Law,
    Parabolic Mirror, Doyle Spirals, Dedekind Cut, Damped Forced Pendulum
    and Merging Schools of Fish serve as end-to-end tests.
  • Manipulate covers the Demonstrations control vocabulary: interactive
    Locators (with LocatorAutoCreate), Trigger, Button,
    ButtonBar, SetterBar, PopupMenu, Checkbox/CheckboxBar,
    Toggler, Opener/OpenerBar, controls nested in TabView,
    PaneSelector or Grid layouts, per-control ControlType lists,
    dynamic control bounds, controls depending on other controls,
    TrackedSymbols, Animate bodies and AnimationRunning.
  • Typeset notebook input is read back as code: inline box syntax, typeset
    Sum/Product boxes, the partial-derivative operator, Part written
    as a bracketed subscript, the radical prefix operators, and the ×
    and ÷ characters.

Plotting & graphics

  • List plots grew Around error bars, IntervalMarkers -> "Bands",
    Callout and Labeled wrappers, PlotMarkers, Epilog, Filling
    (including between datasets), FillingStyle, DataRange,
    InterpolationOrder, Mesh -> Full, PlotLayout, association keys
    as point labels, and TimeSeries input; ComplexListPlot and
    ListLinePlot3D are new.
  • Plot supports Background, Evaluated, EvaluationMonitor and
    Infinity endpoints; automatic ticks match Wolfram's algorithm, tick
    labels switch to scientific notation outside [10^-5, 10^6), frames
    take FrameLabel captions and AxesLabel sits at the end of its
    axis. Contour and density plots fix the marching-squares case table,
    draw their mesh, and keep their shading through Show.
  • Graphics primitives and options: polygons with holes (and their
    measures), Arrowheads, Tube, CapForm, Text offsets,
    Translate and Scale in SVG export, Framed/Highlighted
    rendering, and AspectRatio applied to the plotting area rather than
    the whole image.
  • Graphics3D draws curved surfaces without facet edges, triangulates
    concave polygons, honours EdgeForm[], SphericalRegion and
    ViewAngle, and outlines flat faces the way Wolfram does.
    PolyhedronData gained face lists with Wolfram's vertex order and
    the icosahedral Archimedean solids.
  • Exported SVG embeds the fonts it uses, renders TableForm/MatrixForm
    and the display-form wrappers as grids, and shows machine reals at
    six significant figures.

Calculus, algebra & equation solving

  • Integrate learned the antiderivatives of the error, Fresnel, inverse
    hyperbolic and exponential-integral families, Sin/Cos[x^2] to
    Fresnel integrals, Exp[a x^2] to Erfi, 1/Log[x] to
    LogIntegral, trigonometric integrals over a linear term to
    Si/Ci, u = x^n substitution, Euler's log-trig definite
    integrals and Abs of a linear argument. NIntegrate handles
    endpoint singularities, multi-segment ranges and iterated
    multi-dimensional integrals (NSum/NProduct likewise).
  • Differentiation covers Piecewise, HeavisideTheta (to DiracDelta,
    with its scaling law), KroneckerDelta, Floor/Ceiling, argument
    derivatives of the Bessel and Hankel functions, PolyLog,
    ExpIntegralE, the Airy primes and the incomplete elliptic
    integrals, plus the fractional CaputoD.
  • Series expands Gamma at its pole, Zeta at 1 (Laurent) and
    algebraic expressions at Infinity; limits are decided from the
    leading exponent at infinity, and MaxLimit/MinLimit handle
    bounded trigonometric oscillations.
  • Solving: x^n == c in radicals, polynomials with machine-real
    coefficients, systems over a modulus, Modulus and MaxRoots
    options, NSolve domain argument, NSolveValues, SolveValues
    result shaping, and Reduce over higher-degree polynomial
    inequalities. DSolve handles non-constant forcing and orders its
    fundamental pairs; NDSolve solves systems and constrained ODEs;
    RSolve solves the logistic map at r = 4 and golden-ratio
    recurrences in the Fibonacci/Lucas basis.
  • Optimization: LinearProgramming (exact simplex solver with variable
    bounds), constrained FindMinimum/FindMaximum/NArgMin/NArgMax,
    the domain argument, NonlinearModelFit, constrained and weighted
    Fit, and the minimum-norm fit for rank-deficient designs.
  • Structural algebra: RootReduce and RootApproximant, Root objects
    treated as the numbers they are, polynomial reduction modulo
    polynomials, hyperbolic support in TrigReduce/TrigFactor, and
    many canonical-ordering fixes so sums, products and radicals print
    exactly as wolframscript prints them.

Special functions, statistics & number theory

  • Symbolic reductions for the hypergeometric families (0F1, 1F1,
    HypergeometricU, HypergeometricPFQ Bessel forms), PolyLog,
    LerchPhi, the incomplete Beta and Gamma functions,
    GegenbauerC[n, 1/2, x], parity of Gudermannian, Haversine,
    Sinc, Erf and the Fresnel functions, hyperbolic
    imaginary-period shifts, and exact values of the Carlson elliptic
    integrals. Factorial Taylor sums fold to Sin/Cos/Sinh/Cosh,
    Sum[1/n^s] gives Zeta[s], and sums of HarmonicNumber give
    hyperharmonic closed forms.
  • Numeric evaluation of the Coulomb wavefunctions at nonzero eta,
    CarlsonRF at complex arguments, two-argument Erf, PolyLog with
    real order, and inverse trigonometric functions at complex floats.
  • Astronomy: SunPosition, MoonPosition, MoonPhase, eclipses and
    related functions compute from platform-independent ephemerides, as
    an observer on the ground sees them.
  • Distributions: SkewNormalDistribution; CDF/Quantile/Median for
    the discrete families (NegativeBinomial, Pascal, BetaBinomial,
    Zipf, Benford, …); skewness, kurtosis, raw moments,
    characteristic functions and MGFs for many more; moments of
    TruncatedDistribution and CensoredDistribution; RandomVariate
    sampling for BinomialDistribution and hand-written distributions;
    and parameter-range validation instead of silent nonsense.

Lists, arrays & structured data

  • SparseArray behaves like the array it stores: arithmetic stays
    sparse, Part reaches into higher ranks, the structural list
    operations densify transparently, and the array predicates and grid
    queries see through it.
  • Dataset answers queries through the Query engine instead of a few
    fixed shapes, and the statistics functions see through it.
    TimeSeries can be transformed, combined, resampled, windowed and
    rescaled; MovingMap supports padded and time-windowed forms.
  • List operations rounded out: Periodic/Reflected/Cyclic padding
    (with nested padding arrays), two-dimensional ListConvolve and
    ListCorrelate with generalized operations, MapAt with All and
    Span, ordering functions in SortBy/KeySort, nested GroupBy
    classifiers, rule-based StringSplit/SequenceSplit, and the
    structured matrices (CauchyMatrix, BlockDiagonalMatrix,
    CompanionMatrix) plus Symmetrize/SymmetrizedArray and
    TensorExpand.

Strings, dates, import & export

  • XML imports to symbolic XML (namespaces included) and writes back out
    the way wolframscript does; CSV fixes cell quoting, empty fields and
    header inference; JSON export fails cleanly on unrepresentable
    values; URLBuild, URLQueryEncode/URLQueryDecode, TextCases
    for words and sentences, CharacterName and CharacterNormalize
    are new.
  • Dates: MaxDate/MinDate, ISO and week-based date elements, exact
    rational DateDifference sub-day units, month rollover in
    AbsoluteTime, and DateObject granularity truncation.
  • Output forms: TeXForm sets matrices as LaTeX arrays and matches
    wolframscript, CForm/FortranForm fix their operators and
    numbers, and the NumberForm display family shares one
    option-aware renderer (NumberSigns, ExponentFunction,
    NumberPadding, decimal-point alignment, BaseForm inner values).
  • Patterns: Verbatim heads, Longest/Shortest/
    OrderlessPatternSequence, Overlaps -> All reporting every match
    at every start, string-pattern back-references, and implicitly named
    blanks in StringSplit.

Images & audio

  • Image processing: ImagePad, ImageCrop, ImageFilter,
    MeanFilter, ImageDifference, ImageMeasurements,
    MorphologicalComponents, ComponentMeasurements,
    DeleteSmallComponents and MaxDetect/MinDetect on matrices;
    Blur is the GaussianFilter it claims to be, Sharpen sharpens
    by Wolfram's amount, and EdgeDetect runs on the gradient Woxi
    already had.
  • Audio: the accessors, AudioNormalize/AudioReverse/AudioPad, and
    ListPlay with playback in the Playground and Woxi Studio.

Robustness & conformance

  • Several rounds of differential fuzzing against wolframscript fixed
    dozens of silent divergences in arithmetic, ordering, Simplify,
    Together and friends.
  • Edge cases that used to abort the evaluator or panic now return the
    message Wolfram reports: FactorInteger near 2^64, degenerate
    random specifications, empty-list arguments, invalid permutation
    lists, out-of-range arguments and bad string positions across many
    heads.
  • Evaluation-semantics fixes: the builtin attribute table, Switch
    pattern evaluation, Return no longer escaping Table/Map/
    Select, Sequence through postfix application, Unevaluated
    wrappers, chained ReplaceAll, Condition precedence, postfix ++
    binding, and a parser call-limit fix for deeply nested brackets.
  • Enclose and the Confirm family, Success and the Failure
    object family, and $MessageList (preserved around Quiet) are
    implemented.

Platform, performance & tooling

  • Windows is a supported platform: the unit tests pass and run in CI,
    and the nightly builds produce Windows binaries of both woxi and
    Woxi Studio.
  • Prebuilt binaries for Linux, macOS and Windows are attached to every
    GitHub release, with a checksum file.
  • The browser (WASM) build supports Export, including PNG/JPEG plot
    export via host rasterization.
  • CI checks formatting and clippy (the codebase is clippy-clean outside
    three allowed lints), debug builds use opt-level = 1, and the
    crate metadata was fixed for crates.io publishing.

Demonstration-driven fixes in detail

  • Fixes driven by a Wolfram Demonstration that draws a rational cyclic
    polygon inside its circumcircle:
    • Sphere and Ball draw in a two-dimensional Graphics: in the plane
      a sphere is the circle bounding it and a ball the filled disk. Both
      used to be dropped, and since Circumsphere returns a Sphere
      whatever the dimension, a picture built around a circumcircle came
      out with no circle at all. A list of centres draws one per point,
      and Ball[2] is the unit disk at the origin.
    • A Style around a label paints its Background behind the text —
      Style[Text[…], 12, Background -> White] is what keeps a distance
      label readable over the line it sits on. Only a Background written
      on the Text itself was drawn before.
    • A square factor too large to reach by trial division comes out of a
      radical: Sqrt[100003^2 * 115] is 100003 Sqrt[115]. Sqrt and the
      c Sqrt[r] merge used to look for square factors to different
      depths, so each rewrote what the other produced and halving such a
      coefficient — the Mean of two points carrying a radical — never
      returned.
  • Fixes driven by the plane-geometry Wolfram Demonstrations that stack a
    numeric readout over a drawing:
    • A Pane[…] grid cell shows what it holds. Pane only reserves an
      area for its content, so a body laid out as
      Grid[{{Pane[…]}, {Graphics[…]}}] used to print the whole
      Pane[…] call as source text in place of the readout — and
      stretch the grid to the width of that source. Item[…] and
      Text[…] cells are peeled the same way, through the one helper
      every display pass already shares.
    • Dividers -> All rules every position of a grid, the outer edges
      included, so the grid is drawn as a closed box. Only the
      boundaries between cells were ruled before, which is what
      Dividers -> Center means; the two now differ, and either can be
      set per direction as Dividers -> {colspec, rowspec}.
    • Spacings -> {{i -> s, …}, …} sets the gap at individual column
      positions — position i is the gap to the left of column i, and
      position ncols + 1 the margin after the last column. A
      list-valued horizontal spec used to be dropped, so a readout that
      groups its columns with wide and tight gaps came out evenly and
      far too widely spaced. A plain {s1, s2, …} names the positions
      in order, and positions left out keep the default gap.
  • Manipulate improvements (driven by the "Recursive Exercises" Wolfram
    Demonstrations, which nest circles inside circles):
    • The leading assignments a body makes before anything else are
      evaluated with the control variables at their initial values, the
      way Wolfram evaluates the body before laying the controls out.
      A body opening with u = {…, ss[-1., 1., n, dc]}, where ss
      recurses down to a literal-1 base case, used to recurse on a
      symbolic depth that never reached the base case, so extraction
      never returned and no widget appeared at all.
    • A choice list built from another control's variable
      (Range[1, If[flat, 3, 6], 1]) is re-resolved against the live
      bindings, so a level setter offering six levels flat narrows to
      three in 3D. A selected value the narrowed list no longer offers
      falls back to the last one it does, and the body is rendered again
      for it. Previously the list was fixed at build time.
    • ControlType -> Slider over a choice list renders a slider that
      steps through the choices, matching Wolfram; a twenty-entry
      colour-scheme list used to become a dropdown.
  • Fixes driven by a Wolfram Demonstration that runs a cellular automaton
    over a dendrite and compares it with the linear case:
    • A layout that holds pictures — Grid[{{plot1, plot2}, …}], a
      Column of them, a Pane around either — is composed into the one
      picture a notebook shows. The visual hosts (Playground, Woxi Studio)
      only ever reported the last graphic drawn while the layout was
      evaluated, so a Manipulate body that arranges several plots in a
      grid displayed a single one of them and dropped the rest.
    • A Grid's columns line up when its rows hold different things: the
      caption under a picture is centred on that picture instead of
      being packed against the left edge of the grid.
    • LayeredGraphPlot and TreePlot draw the layered embedding they
      name, rather than the circular one every graph got. Vertices are
      placed by distance from a root, and the second argument (Left,
      Right, Top, Bottom) says which edge the roots go on.
    • DirectedEdges -> False draws a graph's edges as plain lines
      instead of arrows, and ImageSize sizes a graph plot — a
      Demonstration asking for a wide, short strip used to get the
      360-point default square.
    • ArrayPlot draws its FrameLabel, on any of the four edges, with
      the left and right labels rotated onto theirs.
  • Fixes driven by the "Selectivity in a Semibatch Reactor" Wolfram
    Demonstration:
    • Text inside a Graphics3D scene is drawn — a labelled 3D
      schematic used to arrive with no lettering at all. It honours the
      Style size and colour, typesets Subscript/Superscript, and
      respects the alignment offset of Text[expr, pos, offset].
    • Scaled[{sx, sy}] places a Text or Inset by fraction of the
      plot range, in Graphics and in a plot's Epilog alike. The
      fractions used to be unreadable, dropping every such label onto
      the origin.
    • Inset[Graphics3D[…], pos] embeds a three-dimensional picture in a
      flat one at its own size, instead of printing -Graphics3D-.
    • Framed[…] around a label draws its box — a border, and a panel
      when a Background is given — rather than printing its own
      source over the picture. FrameStyle -> None keeps the panel and
      drops the border.
    • Subscript/Superscript in a Text label typeset as scripts
      instead of falling through to the two-line OutputForm box.
    • Graphics accepts Prolog and Epilog, drawn under and over its
      content and taking no part in the plot range.
    • A Manipulate control panel written as a Grid drops its
      SpanFromLeft / SpanFromAbove cell markers; they used to
      survive as display elements and appear as literal text under the
      widget, one row per marker.
    • A control label computed with Row[Flatten[{…, Riffle[…], …}]] is
      evaluated before it is typeset, so the button shows the caption
      rather than the source of the computation.
  • Fixes driven by the "Illustrative Performance Characteristics of Modern
    Motorcycles" Wolfram Demonstration:
    • Piecewise holds its pieces, so the value of a piece whose condition
      is False is never evaluated. This is what makes the construct a
      guard: Piecewise[{{f[w], 0 <= w <= wmax}}, 0] no longer calls f
      out of range, and the messages that call emitted are gone.
    • FindRoot falls back to a difference quotient when the symbolic
      derivative does not reduce to a number at the current iterate —
      differentiating a non-smooth function leaves Derivative[1, 0][Max][…]
      standing. It used to give up with FindRoot::nlnum and return
      unevaluated. Messages emitted by the discarded attempt (D::ivar
      and friends) no longer reach the user.
    • A ControlType -> … given to the Manipulate itself types every
      control that does not pick one, and a list value assigns one type per
      control in spec order. The Demonstrations idiom — controls laid out in
      a Grid[…], typed once for the whole panel — now renders the dropdowns
      the author asked for instead of over-wide SetterBars.
  • Fixes driven by a Wolfram Demonstration that draws a complex function as
    a colored vector field:
    • ColorData[name, "ColorFunction"] gives the gradient's color
      function, the same object ColorData[name] gives on its own. It
      used to be reported as unimplemented, so every primitive colored
      through it fell back to black. ColorData[name, "Range"] reads
      the parameter interval alongside it.
    • Graphics[…, ImagePadding -> …] honours the padding (it was only
      read by the plot functions), so the drawing area sits where the
      notebook puts it instead of at the automatic frame margins.
    • A named Arrowheads size is a fraction of the plot width and
      nothing else. It used to be capped at 45% of the arrow carrying
      it, which shrank the heads of a dense vector field — where each
      arrow is barely longer than its head — to unreadable specks.
  • Fixes driven by the "Mass with a Spring and a Rubber Band" Wolfram
    Demonstration:
    • Substituting an NDSolve solution into a derivative
      (y'[t] /. sol) evaluates numerically instead of echoing a
      Derivative[…] expression, so a phase portrait of a numeric
      solution can be plotted.
    • A plot nested in a Row inside a Column keeps its own coordinate
      space and is drawn (it used to render blank).
    • Frame -> True labels its frame ticks even with Axes -> False.
    • AspectRatio together with ImagePadding sizes the image so the
      plot area spans the full width, instead of shrinking it into a
      canvas sized by the default ratio.
    • Labels written as a function of the plot variable typeset the way
      Wolfram draws them — AxesLabel -> {t, y[t]} reads y(t) and a
      derivative reads y′(t), where both used to be dropped — and a
      Manipulate control labelled Style["y", Italic]' shows y′.
  • Symbol names may contain $ anywhere (a$b, signal$1), matching Wolfram.
  • PlotRange bounds given in reversed order (e.g. {3, -3}) normalize to
    the same plot as the sorted form, matching Wolfram.
  • Manipulate improvements (driven by the "Oscilloscope with Two Signal
    Inputs" Wolfram Demonstration):
    • Style[…], bare-string, and Delimiter arguments are treated as
      static annotation rows between controls (no more spurious
      Manipulate::vsform messages) and render as headings/separators
      in Woxi Studio and the Playground.
    • Compound control variables such as Subscript[signal, 1] work: they
      are bound through synthesized symbols and keep a typeset label
      (signal₁).
    • Control specs may carry trailing options (ControlType -> PopupMenu,
      ImageSize -> Tiny, …); ControlType -> PopupMenu always renders
      a dropdown.
    • A Manipulate whose body is an Animate[…] renders as one combined
      widget, AnimationRunning -> False builds the widget paused, and
      an Infinity animation bound gets a finite looping window.
  • Woxi Studio re-instantiates stored Manipulate widgets when opening a
    notebook (instead of showing the saved DynamicModuleBox[…] text dump).
  • Manipulate improvements (driven by the "Center of Mass of a Polygon"
    Wolfram Demonstration):
    • Locator controls are interactive: a single point binds as a 2D
      slider, a point list becomes a per-point X/Y control (with
      add/remove when LocatorAutoCreate -> True, and a multi-handle
      drag pad in the Playground), instead of freezing the variable at
      its initial value.
    • Discrete choices whose rule label is a graphic ("+" -> myIcon[2])
      render the icon in the SetterBar instead of dumping the label's
      InputForm.
    • A bare control-type shorthand in the range position
      ({{p, init}, Locator}) is no longer misread as a Dynamic[…]
      range.
  • InputForm keeps required parentheses around loose operands of @@, /@,
    @@@, and . (Plus @@ (x*y)/2, a . (b - c)); previously the
    printed form re-parsed to a different expression, silently corrupting
    re-evaluated Manipulate bodies.
  • PlotLabel works on plain Graphics[…] (rendered as a centered title),
    and labels may be arbitrary expressions such as
    Row[{"center of mass: ", CM}] on all plot types.
  • An operator that binds tighter than Times now reaches into an adjacent
    implicit product: 2 Times @@ {3, 4} is 2 (Times @@ {3, 4}) and
    a b . c is a (b . c), matching Wolfram. Previously the whole product
    became one operand, so lcm^n Times @@ Table[…] applied the wrong head.
  • Manipulate improvements (driven by the "Descartes's Rule of Signs"
    Wolfram Demonstration):
    • Setter, Toggler, CheckboxBar, Opener and OpenerBar are
      recognised as control types. A Setter spec used to be read as a
      slider bound, and since one unparsable spec aborts the whole
      extraction, the entire Manipulate fell back to a text echo.
    • {v, domain, ControlType -> None} starts v at the first choice of
      its domain rather than binding the choice list itself.
    • TrackedSymbols :> {…} limits which controls re-run the body; the
      others move without re-rendering, as in Wolfram.
  • Display of Text[content] in the visual hosts (Woxi Studio, the
    Playground) shows the content, so a Text@Pane[Column[{…}]] body
    renders the whole column instead of only the picture inside it.
  • TraditionalForm inside a layout is typeset in conventional notation
    rather than being stripped to StandardForm markup: Equal reads =
    (, , likewise), a Row of strings and Style[…]s is set as
    the text it displays, and a term with a negative coefficient carries
    its sign on the operator (a - 130 x³, not a + -130 x³).