# Automatic conversion of ^ to repeated \* without applying promotion rule

**URL:** https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261
**Category:** Numerics
**Created:** [July 11, 2019, 6:26pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261 "2019-07-11T18:26:54Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![brianguenter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brianguenter/32/29519_2.png) [@brianguenter](https://discourse.julialang.org/u/brianguenter)
#### Post date: [July 11, 2019, 6:26pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/1 "2019-07-11T18:26:54Z")

</div>

I’m writing a symbolic differentiation library for Julia (see [https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/main-65.pdf](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/main-65.pdf) if you are interested) and ran into a problem with promote rules and ^. In an expression like a^7, where a is one of my symbolic numbers, I expected the promotion rule to be applied to the exponent to turn it into a symbolic constant returning a symbolic expression a^7. Instead it seems that before the promote rule is called a^7 is transformed into ((a \* (a \* a)) \* ((a \* a) \* (a \* a))). This is a harder expression to differentiate efficiently. My code doesn’t control when the promote rule to convert from numbers to symbolic numbers gets called.

Is there any way around this behavior?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [July 11, 2019, 6:34pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/2 "2019-07-11T18:34:43Z")

</div>

> In an expression like `a^7`, where a is one of my symbolic numbers, I expected the promotion rule to be applied to the exponent to turn it into a symbolic constant returning a symbolic expression `a^7`. Instead it seems that before the promote rule is called `a^7` is transformed into `((a * (a * a)) * ((a * a) * (a * a)))`.

I’m not sure what this has to do with promotion rules? Not every arithmetic operation promotes its operands to a common type.

If `a` is a `Number`, then `a^7` [by default calls](https://github.com/JuliaLang/julia/blob/3efdda65d4046a4825353dddc090a6235764fa8f/base/intfuncs.jl#L222) `power_by_squaring(a, 7)` — promotion rules are never invoked. To override it, define a method `Base.:^(a::MySymbolicNumber, p::Integer)` that does what you want.

If you want, you can also have it do something different (e.g. more optimized) for [literal integer powers](https://github.com/JuliaLang/julia/blob/3efdda65d4046a4825353dddc090a6235764fa8f/base/intfuncs.jl#L224-L231) than for variable integer exponents.

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [July 11, 2019, 9:39pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/3 "2019-07-11T21:39:36Z")

</div>

I think you are hit by the quirk that `a^7` and `begin x=7; a^7 end` are very different things in julia (look at `Meta.@lower`).

Once you successfully handled the `begin x=7; a^x` case, you can just `Base.literal_pow(typeof(^), var::YourType, ::Val{N}) where N = var^N`.

---

<div class="post-metadata">

### Author: ![brianguenter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brianguenter/32/29519_2.png) [@brianguenter](https://discourse.julialang.org/u/brianguenter)
#### Post date: [July 11, 2019, 9:59pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/4 "2019-07-11T21:59:45Z")

</div>

Thank you for point this out. Did you mean

`a^7` and `begin x=7; a^x`

``

`instead of`

``

`a^7` and `begin x=7; a^7`

``

`Is this covered in the Julia documentation somewhere? I would have thought they were the same.`

``

`-brian`

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [July 11, 2019, 11:13pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/5 "2019-07-11T23:13:51Z")

</div>

> [@foobar\_lv2](#):
>
> I think you are hit by the quirk that `a^7` and `begin x=7; a^x; end` are very different things in julia

I don’t see how that would affect him here. `a^7` lowers to `Base.literal_pow(^, a, Val{7}())`, but that calls `^(a, 7)` by default. So overriding `Base.:^` as I suggested should be sufficient.

It sounds like the problem was that he was expecting `a^7` to call `^(promote(a,7)...)`, i.e. to promote the operands to a common type, when in fact for integer exponents it calls `Base.power_by_squaring` without promotion.

> [@brianguenter](#):
>
> Is this covered in the Julia documentation somewhere?

It’s in [the documentation for `^`](https://docs.julialang.org/en/latest/base/math/#Base.:%5E-Tuple%7BNumber,Number%7D), in addition to the source that I linked, but there is an [open issue](https://github.com/JuliaLang/julia/issues/28685) for more docs. However, as I said above, it doesn’t seem like it should affect you here.

---

<div class="post-metadata">

### Author: ![brianguenter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brianguenter/32/29519_2.png) [@brianguenter](https://discourse.julialang.org/u/brianguenter)
#### Post date: [July 11, 2019, 11:32pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/6 "2019-07-11T23:32:09Z")

</div>

I have solved the problem (so far anyway) by overriding various versions of Base.:^ as suggested by stevengj. Thanks for explaining this.

It seems logically consistent though that a promotion rule would be applied to a^7, even if it does nothing for normal Number types. It would make it simpler to introduce your own types that interact well with the existing Julia Number  
types and operators. It was surprising when it didn’t because promotion worked seamlessly for the other binary operators, +,/,\*,- . I naively expected it would work for ^ as well. Perhaps adding this promotion rule would cause other weird bugs and that’s  
why it wasn’t done.

Thanks everybody for your help.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [July 13, 2019, 12:16pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/7 "2019-07-13T12:16:51Z")

</div>

> [@brianguenter](#):
>
> It seems logically consistent though that a promotion rule would be applied to a^7, even if it does nothing for normal Number types.

Not at all.

In an exponentiation operations like `a^7`, not only is it not _necessary_ to promote `a` and `7` to a common type, often it is not even _sensible_ to do so. For example, consider the case where `a` is a matrix, or a dimensionful quantity, or even a string (since `*` is string concatenation in Julia).

Second, even in cases where you _could_ promote operands to a common type, realize that the promotion should really be seen as a **fallback** — _if_ there is no more-specialized method for `a OP b`, it tries promoting `a` and `b` to a common type and then calling `OP`. But in lots of cases there will be more specialized methods. For example, if you were computing `(3+4im) + 7`, you _could_ promote to a common type as `(3+4im) + (7+0im)`, but there is actually a specialized method for `complex + real` that only adds the real parts, saving an addition.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [July 13, 2019, 12:41pm UTC](https://discourse.julialang.org/t/automatic-conversion-of-to-repeated-without-applying-promotion-rule/26261/8 "2019-07-13T12:41:36Z")

</div>

This is great advice, would you consider making a small PR to [the manual](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Promotion-1)?
