# Struggling with defining a good factorization rule in SymbolicUtils.jl

**URL:** https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522
**Category:** General Usage
**Tags:** symbolic-utils
**Created:** [March 12, 2024, 2:54pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522 "2024-03-12T14:54:19Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![Alseidon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alseidon/32/207775_2.png) [@Alseidon](https://discourse.julialang.org/u/Alseidon)
#### Post date: [March 12, 2024, 2:54pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/1 "2024-03-12T14:54:19Z")

</div>

I started playing with `Symbolics.jl` but started needing more rewriting rules than what’s currently proposed. Taking a quick look at [the rewrite docs](https://symbolicutils.juliasymbolics.org/rewrite/), I don’t understand why some of the examples below don’t work.

```julia
using SymbolicUtils

@syms a::Real b::Real c::Real
factor = @acrule (~x*~y + ~x*~z) => ~x * (~y + ~z)

factor(a*b + a*c) # a*(b+c)
factor(sin(a)*b + sin(a)*c) # nothing
factor(2b+2c) # 2(b+c)
factor(2a*b + 2a*c) # nothing
factor(a^2 + a*c) # nothing

```

Any clue as to what’s happening here and how to fix it? (I am sure there are much better ways to write a factorization rule, including an arbitrary number of sum terms which I couldn’t figure out with segment variables).

---

<div class="post-metadata">

### Author: ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)
#### Post date: [March 12, 2024, 9:57pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/2 "2024-03-12T21:57:28Z")

</div>

Try defining two rules.

```julia
factor1 = @rule (~x * ~y + ~x * ~z) => ~x * (~y + ~z)
factor2 = @rule (~x * ~z + ~y * ~z) => (~x + ~y) * ~z
factor1(a*b + a*c) # a*(b + c)
factor2(a*b + a*c) # nothing
factor1(sin(a)*b + sin(a)*c) # nothing
factor2(sin(a)*b + sin(a)*c) # (b + c)*sin(a)

```

I think the root problem is that SymbolicsUtils.jl is not aware of the inherent commutativity of the multiplication operator `*`. The `@acrule` macro only imposes associativity-commutativity for the top-level operator, which is the `+` operator for the rule with LHS `(~x * ~y + ~x * ~z)`. This seems to be a serious limitation though not strictly speaking a bug. It’ll be great if Symbolics devs can offer some insights here. Should I file a GitHub issue?

The example `factor(2a*b + 2a*c)` will not work because `2*a*b` cannot be matched by `~x*~y`, a well documented behavior (or perhaps limitation) of SymbolicsUtils.

---

<div class="post-metadata">

### Author: ![Alseidon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alseidon/32/207775_2.png) [@Alseidon](https://discourse.julialang.org/u/Alseidon)
#### Post date: [March 13, 2024, 8:32am UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/3 "2024-03-13T08:32:45Z")

</div>

> [@greatpet](#):
>
> I think the root problem is that [SymbolicsUtils.jl](https://juliahub.com/ui/Packages/General/SymbolicsUtils) is not aware of the inherent commutativity of the multiplication operator `*`.

Thank you for your answer! My guess woud be then that SymbolicUtils rearranges `sin(a)*b` into `b*sin(a)`, thus why only right factorization works.

It would probably be a good idea to file an issue, I can do it if you lack the time.

> [@greatpet](#):
>
> The example `factor(2a*b + 2a*c)` will not work because `2*a*b` cannot be matched by `~x*~y`, a well documented behavior (or perhaps limitation) of SymbolicsUtils.

Speaking of this, the rules seem to work on the top-level expression but never on sub-expressions: for instance (taking your `factor1` and `factor2`),

```julia
factor = Rewriters.RestartedChain([factor1, factor2])
factor(2*(a*b + a*c)) # 2*(a*b + a*c)

```

Is this also part of SymbolicUtils’ limitations? Is there a way to circumvent this?

---

<div class="post-metadata">

### Author: ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)
#### Post date: [March 13, 2024, 2:51pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/4 "2024-03-13T14:51:43Z")

</div>

To match sub-expressions, use `Prewalk` or `Postwalk`:

```julia
using SymbolicUtils
factor1 = @rule (~x * ~y + ~x * ~z) => ~x * (~y + ~z)
factor2 = @rule (~x * ~z + ~y * ~z) => (~x + ~y) * ~z
factor = Rewriters.Prewalk(Rewriters.Chain([factor1, factor2]))
factor(2*(a*b + a*c)) # 2a*(b + c)

```

Indeed I’m a bit too busy to file an issue, though I wouldn’t expect a quick resolution anyway, since implementing the requested feature seems to be a difficult job.

---

<div class="post-metadata">

### Author: ![Alseidon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alseidon/32/207775_2.png) [@Alseidon](https://discourse.julialang.org/u/Alseidon)
#### Post date: [March 13, 2024, 3:25pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/5 "2024-03-13T15:25:00Z")

</div>

Thank you for the answer! `Prewalk` is indeed what I was looking for.

I created the [issue](https://github.com/JuliaSymbolics/SymbolicUtils.jl/issues/586) for the AC problem – if you see ways to improve it don’t hesitate, I am not used to writing issues yet!

---

<div class="post-metadata">

### Author: ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)
#### Post date: [March 13, 2024, 10:50pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/6 "2024-03-13T22:50:21Z")

</div>

Your description of the issue looks clear enough!

---

<div class="post-metadata">

### Author: ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)
#### Post date: [August 29, 2024, 2:36pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/7 "2024-08-29T14:36:00Z")

</div>

I have a [pending pull request](https://github.com/JuliaSymbolics/SymbolicUtils.jl/pull/642) which would solve this problem. With the new code, you can pass an extra `fullac` option to the `@rule` macro to enable fully nested associative-commutative pattern matching.

```julia
# warning: example for in-development code
julia> using SymbolicUtils

julia> @syms a b c

julia> factor = @rule (~x*~y + ~x*~z) => ~x * (~y + ~z) fullac;

julia> factor(sin(a)*b + sin(a)*c)
(b + c)*sin(a)

julia> factor(a*b + a*c)
a*(b + c)

```

To factor `2a*b + 2a*c`, you’ll need to match a factor which consists of more than one term, using segment patterns (in combination with my new code):

```julia
julia> factor2 = @rule ( ~~x*~y +~~ x*~z) => *(~~x..., ~y+~z) fullac;

julia> factor2(2a*b + 2a*c)
2a*(b + c)

```

Here `~~x` has matched with the arguments `[2, a]` of the `*` operator, and the list is splat on the RHS to recover the product `2a`.

---

<div class="post-metadata">

### Author: ![sumiya11](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sumiya11/32/207147_2.png) [@sumiya11](https://discourse.julialang.org/u/sumiya11)
#### Post date: [August 29, 2024, 9:27pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/8 "2024-08-29T21:27:31Z")

</div>

For Symbolics.jl, it is possible to use the new `factor_use_nemo` (uses Nemo.jl):

```julia
julia> using Symbolics, Nemo

julia> @variables a b c;

julia> f = expand((a - 1)*(a^2 + b^2)*(a - c));

julia> Symbolics.factor_use_nemo(f)[2]
3-element Vector{Num}:
 -(1//1) + a
   a^2 + b^2
       a - c

```

We might want to export a version of it.

---

<div class="post-metadata">

### Author: ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)
#### Post date: [August 29, 2024, 11:07pm UTC](https://discourse.julialang.org/t/struggling-with-defining-a-good-factorization-rule-in-symbolicutils-jl/111522/9 "2024-08-29T23:07:03Z")

</div>

That’s very nice. I’d love to see an additional feature: it should be possible to use the Nemo backend to factorize more general expressions, e.g. `log(a)^2 - log(b)^2 == (log(a) + log(b)) * (log(a) - log(b))`, if you map the two logarithms (or any other functions) into polynomial variables.

I was just using the factorization example to demonstrate associative-commutative pattern matching. Of course a serious library like Nemo is the way to go to do factorizations properly.
