Why does definite integration in SymbolicNumericIntegration.jl produce different outputs in these cases?

Why does the SymbolicNumericIntegration.integrate function not seem to respect the detailed=false argument when using .( execution? Also, when then operating on a matrix, it seems to return the indefinite integral rather than the definite integral.

import Symbolics
using SymbolicNumericIntegration: integrate

Symbolics.@variables x
f = [ x^0, x^1, x^2 ]
F = f * transpose( f )

Resulting in a matrix F containing expressions on which I want to perform definite integration:

3×3 Matrix{Symbolics.Num}:
   1    x  x^2
   x  x^2  x^3
 x^2  x^3  x^4

Definite integration of a single term of F, requesting only the solved output

  • detailed (default: true): (solved, unsolved, err) output format. If detailed=false, only the final integral is returned.

Works as expected

julia> integrate( F[1,2], (x, 0, 1); detailed=false )
1//2

However, if I use the . execution on the same term, the detailed=false appears ignored, and the solved output is the indefinite integral rather than the definite integral e.g., the (x, 0, 1) input also appears ignored. Also, I’m not sure why it now thinks there’s an error of x in this?

julia> integrate.( F[1,2], (x, 0, 1); detailed=false )
((1//2)*(x^2), 0, x)

And what I really want to do is perform definite integration on each term of F at the same time, hence the exploration into . execution. As you can see below it appears to return the solved output in indefinite form - but only in the first row… the other rows appear incorrect - maybe outputting the unsolved and error fields?

> integrate.( F, (x, 0, 1); detailed=false )
3×3 Matrix{Any}:
   x     (1//2)*(x^2)     (1//3)*(x^3)
   0    0                0
 x^2  x^3              x^4

What I expected was that I would get a matrix of definite integrals:

3×3 Matrix{Any}:
   1  1//2  1//3
1//2  1//3  1//4
1//3  1//4  1//5

Any ideas what’s going on?

( EDIT: wrote the first draft of this on an airplane with spotty wi-fi, and didn’t realize I hit “submit”)

Ah… because it’s broadcasting against the second positional argument (x, 0, 1):

julia> integrate.( f, (x, 0, 1); detailed=false )
3-element Vector{Symbolics.Num}:
   x
   0
 x^2

julia> integrate( f[1], x; detailed=false )
x

julia> integrate( f[2], 0; detailed=false )
0

julia> integrate( f[3], 1; detailed=false )
x^2

Which is also why, if f isn’t a 3-element Vector, say is a 4-element Vector it errors:

julia> f = [ x^0, x^1, x^2, x^3 ]
4-element Vector{Symbolics.Num}:
   1
   x
 x^2
 x^3

julia> integrate.( f, (x, 0, 1); detailed=false )
ERROR: DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 4 and 3
Stacktrace:
 [1] _bcs1
   @ .\broadcast.jl:555 [inlined]
 [2] _bcs
   @ .\broadcast.jl:549 [inlined]
 [3] broadcast_shape
   @ .\broadcast.jl:543 [inlined]
 [4] combine_axes
   @ .\broadcast.jl:524 [inlined]
 [5] instantiate
   @ .\broadcast.jl:306 [inlined]
 [6] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, Base.Broadcast.var"#43#44"{@Kwargs{…}, typeof(integrate)}, Tuple{Vector{…}, Tuple{…}}})
   @ Base.Broadcast .\broadcast.jl:903
 [7] top-level scope
   @ REPL[85]:1
Some type information was truncated. Use `show(err)` to see complete types.

The solution is to create an array of tuples, one for each element of f or F:

julia> domain = fill( ( x, 0, 1 ), size( f ) )
3-element Vector{Tuple{Symbolics.Num, Int64, Int64}}:
 (x, 0, 1)
 (x, 0, 1)
 (x, 0, 1)

julia> fI = integrate.( f, domain; detailed=false )
3-element Vector{Real}:
  1
 1//2
 1//3

and

julia> domain = fill( ( x, 0, 1 ), size( F ) )
3×3 Matrix{Tuple{Symbolics.Num, Int64, Int64}}:
 (x, 0, 1)  (x, 0, 1)  (x, 0, 1)
 (x, 0, 1)  (x, 0, 1)  (x, 0, 1)
 (x, 0, 1)  (x, 0, 1)  (x, 0, 1)

julia> FI = integrate.( F, domain; detailed=false )
3×3 Matrix{Real}:
  1    1//2  1//3
 1//2  1//3  1//4
 1//3  1//4  1//5

A bit quirky, but I guess it makes sense.