Defining a symbolic inner product

We can get a long way by directly declaring that the symbols in question are NumericQ. For example, θ is normally treated as non-scalar:

CircleDot[a, Times[θ, b]]
(* CircleDot[a, Times[b, θ]] *)

CircleDot[a, Times[Sin[θ], b]]
(* CircleDot[a, Times[b, Sin[θ]]] *)

NumericQ is a protected symbol, but its built-in definition still permits direct assignment (in the same manner as other built-ins like N and Format). Thus, as speculated in the question, we can define θ to be NumericQ to make it act like a scalar:

NumericQ[θ] = True;

CircleDot[a, Times[θ, b]]
(* Times[θ, CircleDot[a, b]] *)

CircleDot[a, Times[Sin[θ], b]]
(* Times[CircleDot[a, b], Sin[θ]] *)

We can take away the numeric status by executing NumericQ[θ] =..

As noted in the question, we must take care when changing the meaning of symbols in this fashion. It is probably not a good idea to change a common symbol like i since it NumericQ status affects many built-in functions. Therefore, I suggest restricting such changes to letter forms that have no other function in your application, (e.g. Greek, double-struck, Gothic, Hebrew, etc).


Try adding this to your existing definitions:

(x_scalar a_)\[CircleDot]b_ := x (a\[CircleDot]b)

This specifies a definition similar to your last one that only applies when the Head of $x$ is scalar, an auxiliary operator we introduce.

Now, suppose that you want $t$ to be a scalar and $vec_i$ to be vectors:

(scalar[t] vec1) \[CircleDot] vec2   (* Out: vec1 \[CircleDot] vec2 scalar[t] *)

The auxiliary function scalar need not have any definition. It is just there as a wrapper to indicate the "type" of $t$.

If you don't want to see the scalar wrapper in your result, you can define a formatting rule for it:

Format[scalar[a_]] := a

The same expression above will then print as follows:

(scalar[t] vec1) \[CircleDot] vec2    (* Out: vec1 \[CircleDot] vec2 t *)

The scalar wrapper is retained, however:

InputForm[%]                          (* Out: vec1 \[CircleDot] vec2 * scalar[t] *)