tag:github.com,2008:https://github.com/SymbolicML/DynamicExpressions.jl/releasesRelease notes from DynamicExpressions.jl2025-07-26T18:58:47Ztag:github.com,2008:Repository/552482193/v2.3.02025-07-26T18:58:48Zv2.3.0<h2>DynamicExpressions v2.3.0</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v2.2.1...v2.3.0">Diff since v2.2.1</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>Parse expressions without interpolation (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3265846847" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/137" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/137/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/137">#137</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v2.2.12025-06-27T11:07:10Zv2.2.1<h2>DynamicExpressions v2.2.1</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v2.2.0...v2.2.1">Diff since v2.2.0</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>fix: precompilation warning (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3182111764" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/136" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/136/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/136">#136</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v2.2.02025-06-26T11:27:28Zv2.2.0<h2>DynamicExpressions v2.2.0</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v2.1.0...v2.2.0">Diff since v2.1.0</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>feat: option to skip fused kernels (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3091589615" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/128" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/128/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/128">#128</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v2.1.02025-06-24T22:12:56Zv2.1.0<h2>DynamicExpressions v2.1.0</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v2.0.1...v2.1.0">Diff since v2.0.1</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>fix: <code>default_node_type</code> should not prescribe degree (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3173046202" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/133" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/133/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/133">#133</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
<li>test: fix issue where test eval fails due to incomplete eval (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3173051070" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/134" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/134/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/134">#134</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v2.0.12025-06-20T11:37:29Zv2.0.1<h2>DynamicExpressions v2.0.1</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v2.0.0...v2.0.1">Diff since v2.0.0</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>Permit n-argument operators (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3054125537" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/127" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/127/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/127">#127</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
<li>fix: recursive type inference issue (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3162906845" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/132" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/132/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/132">#132</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v2.0.02025-06-15T02:51:53Zv2.0.0<p>DynamicExpressions.jl v2.0 introduces support for n-arity operators (nodes with arbitrary numbers of children), which required some breaking changes to implement. This guide will help you migrate your code from v1.x to v2.0.</p>
<h2>Summary</h2>
<ul>
<li>Types
<ul>
<li><code>Node{T}</code> is now <code>Node{T,D}</code> where <code>D</code> is the maximum degree</li>
<li><code>AbstractExpressionNode{T}</code> is now <code>AbstractExpressionNode{T,D}</code></li>
<li><code>AbstractNode</code> is now <code>AbstractNode{D}</code></li>
<li>Before, <code>Node{T}</code> had fields <code>l::Node{T}</code> and <code>r::Node{T}</code>. Now, the type is <code>Node{T,D}</code>, and it has the field <code>children::NTuple{D,Nullable{Node{T,D}}}</code>.</li>
</ul>
</li>
<li>Accessors
<ul>
<li>You can now access children by index with <code>get_child(tree, i)</code>
<ul>
<li><code>tree.l</code> can now be written as <code>get_child(tree, 1)</code></li>
<li><code>tree.r</code> can now be written as <code>get_child(tree, 2)</code></li>
<li><em>note: you can access multiple children with <code>get_children(tree, Val(degree))</code></em></li>
</ul>
</li>
<li>You can now set children by index with <code>set_child!(tree, child, i)</code>
<ul>
<li><code>tree.l = child</code> should now be written as <code>set_child!(tree, child, 1)</code></li>
<li><code>tree.r = child</code> should now be written as <code>set_child!(tree, child, 2)</code></li>
<li><em>note: you can set multiple children with <code>set_children!(tree, children)</code></em></li>
</ul>
</li>
</ul>
</li>
<li>Constructors
<ul>
<li><code>Node{T}(; op=1, l=x)</code> should now be written as <code>Node{T}(; op=1, children=(x,))</code></li>
<li><code>Node{T}(; op=1, l=x, r=y)</code> should now be written as <code>Node{T}(; op=1, children=(x, y))</code></li>
<li>You may now use <code>Node{T,D}(; op=1, children=(x,))</code> to specify degree other than the default of 2.</li>
</ul>
</li>
<li>OperatorEnum
<ul>
<li><code>OperatorEnum</code> (and <code>GenericOperatorEnum</code>) now uses a single <code>ops</code> field: this is a tuple of tuples, indexed by arity.
<ul>
<li><code>operators.unaops</code> is now written as <code>operators.ops[1]</code>, and <code>operators.binops</code> is now written as <code>operators.ops[2]</code>.</li>
</ul>
</li>
<li><code>OperatorEnum(binary_operators=(+, -, *), unary_operators=(sin, cos))</code> can now be written as <code>OperatorEnum(2 => (+, -, *), 1 => (sin, cos))</code>
<ul>
<li>This API permits higher-arity operators: <code>OperatorEnum(1 => (sin, cos), 2 => (+, -, *), 3 => (fma, max))</code>.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Breaking Changes</h2>
<p>The main breaking change is that <code>Node{T}</code> is now <code>Node{T,D}</code> where <code>D</code> is the <strong>maximum degree</strong> of any possible node in the tree. <code>node.degree</code> is <em>still</em> the same as before, and is such that <code>node.degree <= D</code>.</p>
<p>Similarly, <code>AbstractExpressionNode{T}</code> is now <code>AbstractExpressionNode{T,D}</code>, and <code>AbstractNode</code> is now <code>AbstractNode{D}</code>.</p>
<p>Before, <code>Node{T}</code> had fields <code>l::Node{T}</code> and <code>r::Node{T}</code>. Now, it has a single combined field <code>children::NTuple{D,Nullable{Node{T,D}}}</code>. This is a tuple of wrapped node objects, which should be accessed with <code>get_child(tree, i)</code> and set with <code>set_child!(tree, child, i)</code>. However, the old getters and setters will still function for binary trees (<code>.l</code> and <code>.r</code>).</p>
<p>You may now use <code>Node{T,D}(; op=1, children=(x,))</code> to specify degree other than the default of 2. However, the default <code>Node{T}(; op=1, children=(x,))</code> is still available and will result in type <code>Node{T,2}</code>.</p>
<h3>Necessary Changes to Your Code</h3>
<p>The main breaking change that requires some modifications is patterns that explicitly match <code>tree.degree</code> in conditional logic. The <code>tree.degree == 0</code> branch can be left alone, but higher arity nodes should be generalized.</p>
<p>For code like this:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# This pattern ONLY works for binary trees (degree ≤ 2)
if tree.degree == 0
# leaf node
elseif tree.degree == 1
# unary operator
else # tree.degree == 2 # <-- This violates the assumption in 2.0
# binary operator
end"><pre><span class="pl-c"><span class="pl-c">#</span> This pattern ONLY works for binary trees (degree ≤ 2)</span>
<span class="pl-k">if</span> tree<span class="pl-k">.</span>degree <span class="pl-k">==</span> <span class="pl-c1">0</span>
<span class="pl-c"><span class="pl-c">#</span> leaf node</span>
<span class="pl-k">elseif</span> tree<span class="pl-k">.</span>degree <span class="pl-k">==</span> <span class="pl-c1">1</span>
<span class="pl-c"><span class="pl-c">#</span> unary operator</span>
<span class="pl-k">else</span> <span class="pl-c"><span class="pl-c">#</span> tree.degree == 2 # <-- This violates the assumption in 2.0</span>
<span class="pl-c"><span class="pl-c">#</span> binary operator</span>
<span class="pl-k">end</span></pre></div>
<p>You have two options for upgrading</p>
<ol>
<li>
<p>Constrain your type signatures: Use <code>::AbstractExpressionNode{T,2}</code> to only accept binary trees, and refuse higher-arity nodes</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="function my_function(tree::AbstractExpressionNode{T,2}) where T
if tree.degree == 0
# leaf
elseif tree.degree == 1
# unary
else # tree.degree == 2, guaranteed
# binary
end
end"><pre><span class="pl-k">function</span> <span class="pl-en">my_function</span>(tree<span class="pl-k">::</span><span class="pl-c1">AbstractExpressionNode{T,2}</span>) <span class="pl-k">where</span> T
<span class="pl-k">if</span> tree<span class="pl-k">.</span>degree <span class="pl-k">==</span> <span class="pl-c1">0</span>
<span class="pl-c"><span class="pl-c">#</span> leaf</span>
<span class="pl-k">elseif</span> tree<span class="pl-k">.</span>degree <span class="pl-k">==</span> <span class="pl-c1">1</span>
<span class="pl-c"><span class="pl-c">#</span> unary </span>
<span class="pl-k">else</span> <span class="pl-c"><span class="pl-c">#</span> tree.degree == 2, guaranteed</span>
<span class="pl-c"><span class="pl-c">#</span> binary</span>
<span class="pl-k">end</span>
<span class="pl-k">end</span></pre></div>
</li>
<li>
<p>Rewrite your code to be more generic. (<em>Note that for recursive algorithms, you can often do things with a <code>tree_mapreduce</code>, which already handles the general case.</em>)</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# 2: Handle arbitrary arity
function my_function(tree::AbstractExpressionNode{T}) where T
if tree.degree == 0
# leaf
else # higher arity
deg = tree.degree
for i in 1:deg
child = get_child(tree, i)
# process child...
end
end
end"><pre><span class="pl-c"><span class="pl-c">#</span> 2: Handle arbitrary arity</span>
<span class="pl-k">function</span> <span class="pl-en">my_function</span>(tree<span class="pl-k">::</span><span class="pl-c1">AbstractExpressionNode{T}</span>) <span class="pl-k">where</span> T
<span class="pl-k">if</span> tree<span class="pl-k">.</span>degree <span class="pl-k">==</span> <span class="pl-c1">0</span>
<span class="pl-c"><span class="pl-c">#</span> leaf</span>
<span class="pl-k">else</span> <span class="pl-c"><span class="pl-c">#</span> higher arity</span>
deg <span class="pl-k">=</span> tree<span class="pl-k">.</span>degree
<span class="pl-k">for</span> i <span class="pl-k">in</span> <span class="pl-c1">1</span><span class="pl-k">:</span>deg
child <span class="pl-k">=</span> <span class="pl-c1">get_child</span>(tree, i)
<span class="pl-c"><span class="pl-c">#</span> process child...</span>
<span class="pl-k">end</span>
<span class="pl-k">end</span>
<span class="pl-k">end</span></pre></div>
<p>However, normally what is done internally for max efficiency for the general approach is to use patterns like:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="@generated function my_function(tree::AbstractExpressionNode{T,D}) where {T,D}
quote
deg = tree.degree
deg == 0 && process_leaf(tree)
Base.Cartesian.@nif(
$deg,
i -> i == deg,
i -> let children = get_children(tree, Val(i))
# Now, `children` is a type-stable tuple of children
end,
)
end
end"><pre><span class="pl-c1">@generated</span> <span class="pl-k">function</span> <span class="pl-en">my_function</span>(tree<span class="pl-k">::</span><span class="pl-c1">AbstractExpressionNode{T,D}</span>) <span class="pl-k">where</span> {T,D}
<span class="pl-k">quote</span>
deg <span class="pl-k">=</span> tree<span class="pl-k">.</span>degree
deg <span class="pl-k">==</span> <span class="pl-c1">0</span> <span class="pl-k">&&</span> <span class="pl-c1">process_leaf</span>(tree)
Base<span class="pl-k">.</span>Cartesian<span class="pl-k">.</span><span class="pl-c1">@nif</span>(
<span class="pl-k">$</span>deg,
i <span class="pl-k">-></span> i <span class="pl-k">==</span> deg,
i <span class="pl-k">-></span> <span class="pl-k">let</span> children <span class="pl-k">=</span> <span class="pl-c1">get_children</span>(tree, <span class="pl-c1">Val</span>(i))
<span class="pl-c"><span class="pl-c">#</span> Now, `children` is a type-stable tuple of children</span>
<span class="pl-k">end</span>,
)
<span class="pl-k">end</span>
<span class="pl-k">end</span></pre></div>
<p>Note that the <code>@generated</code> is needed to pass <code>D</code> to the Cartesian macro.</p>
</li>
</ol>
<h2>Property Access (Non-Breaking)</h2>
<p>Note: <code>.l</code> and <code>.r</code> property access still work and will continue to be supported on types with <code>D == 2</code>. However, the generic accessors are more flexible, so upgrading to them is recommended.</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# old_child = tree.l
old_child = get_child(tree, 1)
# tree.r = new_child
set_child!(tree, new_child, 2)"><pre><span class="pl-c"><span class="pl-c">#</span> old_child = tree.l</span>
old_child <span class="pl-k">=</span> <span class="pl-c1">get_child</span>(tree, <span class="pl-c1">1</span>)
<span class="pl-c"><span class="pl-c">#</span> tree.r = new_child</span>
<span class="pl-c1">set_child!</span>(tree, new_child, <span class="pl-c1">2</span>)</pre></div>
<p>This lets you write code that prescribes arbitrary arity.</p>
<h2>Node Construction (Non-Breaking)</h2>
<p>For binary trees, you can still use the syntax:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="x = Node{Float64}(; feature=1)
tree = Node{Float64}(; op=1, children=(x,))"><pre>x <span class="pl-k">=</span> <span class="pl-c1">Node</span><span class="pl-c1">{Float64}</span>(; feature<span class="pl-k">=</span><span class="pl-c1">1</span>)
tree <span class="pl-k">=</span> <span class="pl-c1">Node</span><span class="pl-c1">{Float64}</span>(; op<span class="pl-k">=</span><span class="pl-c1">1</span>, children<span class="pl-k">=</span>(x,))</pre></div>
<p>For higher-arity trees, you may pass <code>D</code> to specify the maximum degree in the tree:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="x = Node{Float64,3}(; feature=1)
y = Node{Float64,3}(; feature=2)
z = Node{Float64,3}(; feature=3)
tree = Node{Float64,3}(; op=1, children=(x, y, z))"><pre>x <span class="pl-k">=</span> <span class="pl-c1">Node</span><span class="pl-c1">{Float64,3}</span>(; feature<span class="pl-k">=</span><span class="pl-c1">1</span>)
y <span class="pl-k">=</span> <span class="pl-c1">Node</span><span class="pl-c1">{Float64,3}</span>(; feature<span class="pl-k">=</span><span class="pl-c1">2</span>)
z <span class="pl-k">=</span> <span class="pl-c1">Node</span><span class="pl-c1">{Float64,3}</span>(; feature<span class="pl-k">=</span><span class="pl-c1">3</span>)
tree <span class="pl-k">=</span> <span class="pl-c1">Node</span><span class="pl-c1">{Float64,3}</span>(; op<span class="pl-k">=</span><span class="pl-c1">1</span>, children<span class="pl-k">=</span>(x, y, z))</pre></div>
<h2>OperatorEnum redesign (Non-Breaking)</h2>
<p><code>OperatorEnum</code> (and <code>GenericOperatorEnum</code>) now uses a single <code>ops</code> field: this is a tuple of tuples, indexed by arity. <code>operators.unaops</code> is now written as <code>operators.ops[1]</code>, and <code>operators.binops</code> is now written as <code>operators.ops[2]</code>.</p>
<p>However, the properties are aliased, so the old syntax will still work.</p>
<p>Along with this, there is a new API for constructing <code>OperatorEnum</code>s:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# operators = OperatorEnum(binary_operators=(+, -, *), unary_operators=(sin, cos)) # old
operators = OperatorEnum(2 => (+, -, *), 1 => (sin, cos))"><pre><span class="pl-c"><span class="pl-c">#</span> operators = OperatorEnum(binary_operators=(+, -, *), unary_operators=(sin, cos)) # old</span>
operators <span class="pl-k">=</span> <span class="pl-c1">OperatorEnum</span>(<span class="pl-c1">2</span> <span class="pl-k">=></span> (<span class="pl-k">+</span>, <span class="pl-k">-</span>, <span class="pl-k">*</span>), <span class="pl-c1">1</span> <span class="pl-k">=></span> (sin, cos))</pre></div>
<p>This API permits higher-arity operators:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="operators = OperatorEnum(1 => (sin, cos), 2 => (+, -, *), 3 => (fma, max))"><pre>operators <span class="pl-k">=</span> <span class="pl-c1">OperatorEnum</span>(<span class="pl-c1">1</span> <span class="pl-k">=></span> (sin, cos), <span class="pl-c1">2</span> <span class="pl-k">=></span> (<span class="pl-k">+</span>, <span class="pl-k">-</span>, <span class="pl-k">*</span>), <span class="pl-c1">3</span> <span class="pl-k">=></span> (fma, max))</pre></div>
<p>(Note that the order you pass the pairs is not important.)</p>
<p><strong>Full Changelog</strong>: <a class="commit-link" href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v1.10.3...v2.0.0"><tt>v1.10.3...v2.0.0</tt></a></p>MilesCranmertag:github.com,2008:Repository/552482193/v1.10.32025-06-14T21:11:48Zv1.10.3<h2>DynamicExpressions v1.10.3</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v1.10.2...v1.10.3">Diff since v1.10.2</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>fix: mutation error for Zygote (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3146666563" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/130" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/130/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/130">#130</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
<li>fix: move non_differentiable to special module for JET masking (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3146692419" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/131" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/131/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/131">#131</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v1.10.22025-05-23T21:39:52Zv1.10.2<h2>DynamicExpressions v1.10.2</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v1.10.1...v1.10.2">Diff since v1.10.1</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>CompatHelper: bump compat for Zygote in [weakdeps] to 0.7, (keep existing compat) (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2769067944" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/119" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/119/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/119">#119</a>) (@github-actions[bot])</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v1.10.12025-04-29T10:56:01Zv1.10.1<h2>DynamicExpressions v1.10.1</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v1.10.0...v1.10.1">Diff since v1.10.0</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>fix: avoid returning view for generic operators (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3027788036" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/126" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/126/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/126">#126</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/552482193/v1.10.02025-02-28T20:38:03Zv1.10.0<h2>DynamicExpressions v1.10.0</h2>
<p><a href="https://github.com/SymbolicML/DynamicExpressions.jl/compare/v1.9.4...v1.10.0">Diff since v1.9.4</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>Fix minute typo (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2783799233" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/120" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/120/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/120">#120</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sunxd3/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/sunxd3">@sunxd3</a>)</li>
<li>feat: allow separate operator names for pretty printing (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2887914438" data-permission-text="Title is private" data-url="https://github.com/SymbolicML/DynamicExpressions.jl/issues/122" data-hovercard-type="pull_request" data-hovercard-url="/SymbolicML/DynamicExpressions.jl/pull/122/hovercard" href="https://github.com/SymbolicML/DynamicExpressions.jl/pull/122">#122</a>) (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/MilesCranmer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/MilesCranmer">@MilesCranmer</a>)</li>
</ul>github-actions[bot]