I'm trying to Maxima-fy my Mathematica box options formula
(https://github.com/barrycarter/bcapps/blob/master/box-option-value.m)
but Maxima crashes on a fairly simple integration:
load(distrib);
pdflp(x, p0, v, p1, p2, t1, t2) := pdf_normal(x,log(p0),sqrt(t1)*v);
cdfmaxlp(x, p0, v, p1, p2, t1, t2) := 1-erf(x/(v*sqrt(t2-t1)/sqrt(2)));
upandin(p0, v, p1, p2, t1, t2) :=
integrate(
float(
pdflp(x, p0, v, p1, p2, t1, t2)*
cdfmaxlp(log(p1)-x, p0, v, p1, p2, t1, t2)
),
x, minf, log(p1));
Evaluating upandin w/ certain values crashes:
upandin(1, .15, 1.01, 1.02, 1/365.2425, 2/365.2425);
rat: replaced -.00995033085316809 by -603/60601 = -.00995033085262619
rat: replaced 2.718281828459045 by 23225/8544 = 2.718281835205993
rat: replaced 8116.5 by 16233/2 = 8116.5
rat: replaced 2.718281828459045 by 23225/8544 = 2.718281835205993
rat: replaced -8116.5 by -16233/2 = -8116.5
rat: replaced 1.0 by 1/1 = 1.0
rat: replaced 1.792882852833688 by 4484/2501 = 1.792882846861255
rat: replaced 180.1832400641081 by 126849/704 = 180.1832386363636
rat: replaced 2.718281828459045 by 23225/8544 = 2.718281835205993
rat: replaced -8116.5 by -16233/2 = -8116.5
rat: replaced -1.0 by -1/1 = -1.0
rat: replaced 1.792882852833688 by 4484/2501 = 1.792882846861255
rat: replaced 180.1832400641081 by 126849/704 = 180.1832386363636
rat: replaced 2.718281828459045 by 23225/8544 = 2.718281835205993
rat: replaced -8116.5 by -16233/2 = -8116.5
rat: replaced 1.0 by 1/1 = 1.0
rat: replaced -1.0 by -1/1 = -1.0
Maxima encountered a Lisp error:
The value 16090668801 is not of type FIXNUM.
Without the float() in upandin, Maxima just leaves the integral in
original form.
Can someone help? I thought converting Mathematica to Maxima would be
easy, but now I'm not as sure.
The Mathematica version works fine:
pdflp[x_, p0_, v_, p1_, p2_, t1_, t2_] :=
PDF[NormalDistribution[Log[p0],Sqrt[t1]*v]][x]
cdfmaxlp[x_, p0_, v_, p1_, p2_, t1_, t2_] := 1-Erf[x/(v*Sqrt[t2-t1]/Sqrt[2])];
(* NIntegrate below "equivalent" to Maximas float(); no closed form *)
upandin[p0_, v_, p1_, p2_, t1_, t2_] :=
NIntegrate[pdflp[x, p0, v, p1, p2, t1, t2]*
cdfmaxlp[Log[p1]-x, p0, v, p1, p2, t1, t2],
{x, -Infinity, Log[p1]}]
upandin[1, .15, 1.01, 1.02, 1/365.2425, 2/365.2425]
0.0998337
EDIT: Is there any open source Mathematica-like program that WILL
numerically approximate this function? I'd really like to release open
source code to an open source platform.
(I probably have no business answering this, but...)
Just a guess, but it seems that integrate wants to make the input exact again, and maybe is doing some difficult bignum computations involving rational arithmetic. It rationalize your approximate e (Euler number) so that means it could behave differently from integrate(0 with exact input.
Might want to check
http://eagle.cs.kent.edu/MAXIMA/maxima_21.html
or
http://www.delorie.com/gnu/docs/maxima/maxima_62.html
for dedicated numerical code e.g from Quadpack.
(Still wondering why I'm even trying to answer this. There must be Maxima expertise somewhere on Stack Overflow.)
Daniel Lichtblau
Wolfram Research
Use quad_qagi to numerically approximate an integral over an infinite interval. ?? quad_ shows info about Quadpack functions.
load (distrib);
pdflp (x, p0, v, p1, p2, t1, t2) := pdf_normal (x, log(p0), sqrt(t1)*v);
cdfmaxlp (x, p0, v, p1, p2, t1, t2) := 1 - erf(x/(v * sqrt(t2 - t1)/sqrt(2)));
upandin (p0, v, p1, p2, t1, t2) := block ([integrand],
integrand : pdflp (x, p0, v, p1, p2, t1, t2) * cdfmaxlp (log(p1) - x, p0, v, p1, p2, t1, t2),
quad_qagi (integrand, x, minf, log(p1)));
upandin (1, .15, 1.01, 1.02, 1/365.2425, 2/365.2425);
=> [.09983372557898755, 2.839204848435967E-10, 225, 0]
Sorry for the late reply. Leaving this here in case someone finds it by searching.
I know Maxima tries very hard to avoid floats, and I think that's what it's trying to do here, but I'm not enough of a Maxima guru to explain how to prevent it. Pretty much anything numerical can handle this, although you might have to break the interval or transform the integrand manually. Note that you say it's fairly simple, but it's awfully steep: for these parameters, the integrand is ~6*10^(-34) at 0.1 and ~3*10^(-206) at -0.1. That's enough of a range to give lots of naive integration algorithms fits.
Anyway, you can do it easily enough in Sage using tools from scipy and gsl behind the scenes:
import scipy.stats
def pdflp(x,p0,v,t1):
return scipy.stats.norm(log(p0), sqrt(t1)*v).pdf(x)
def cdfmaxlp(x,v,t1,t2):
return (1-erf(x/(v*sqrt(t2-t1)/sqrt(2.))))
def upandin(p0, v, p1, p2, t1, t2):
integrand = lambda x: (pdflp(x,p0,v,t1) * cdfmaxlp(log(p1)-x,v,t1,t2))
return numerical_integral(integrand, -Infinity, log(p1))
sage: upandin(1, .15, 1.01, 1.02, 1/365.2425, 2/365.2425)
(0.099833725578983457, 7.5174412058308382e-07)
or use mpmath's quad if you need arbitrary precision. [I had a guess at the "correct" value here, but since we don't have that much precision to start with, it's kind of silly.]
Maxima's 'integrate' function does symbolic, not numeric, integration. When it returns a noun form from an integral, that means it can't perform the (symbolic) integration. Changing the parameters of the expression from exact to floating (using 'float') won't change that.
I think what you're looking for is a numeric integration routine -- Maxima offers a variety of those, from the very basic romberg to a variety of Quadpack methods (try ?? quad for documentation).
-s
PS As for "this crappy 'open source' stuff" -- what brought that on? You might want to look at the history of Macsyma/Maxima in the Wikipedia article for some perspective.
Related
As shown in the image below, I'm creating a program that will make a 2D animation of a truck that is made up of two articulated parts.
The truck pulls the trailer.
The trailer moves according to the docking axis on the truck.
Then, when the truck turns, the trailer should gradually align itself with the new angle of the truck, as it does in real life.
I would like to know if there is any formula or algorithm that does this calculation in an easy way.
I've already seen inverse kinematics equations, but I think for just 2 parts it would not be so complex.
Can anybody help me?
Let A be the midpoint under the front axle, B be the midpoint under the middle axle, and C be the midpoint under the rear axle. For simplicity assume that the hitch is at point B. These are all functions of time t, for example A(t) = (a_x(t), a_y(t).
The trick is this. B is moving directly towards A with the component of A's velocity in that direction. Or in symbols, dB/dt = (dA/dt).(A-B)/||A-B|| And similarly, dC/dt = (dB/dt).(B-C)/||B-C|| where . is the dot product.
This turns into a non-linear first-order system in 6 variables. This can be solved with normal techniques, such as https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods.
UPDATE: Added code
Here is a Python implementation. You can replace it with https://rosettacode.org/wiki/Runge-Kutta_method for your favorite language and your favorite linear algebra library. Or even hand-roll that.
For my example I started with A at (1, 1), B at (2, 1) and C at (2, 2). Then pulled A to the origin in steps of size 0.01. That can be altered to anything that you want.
#! /usr/bin/env python
import numpy
# Runga Kutta method.
def RK4(f):
return lambda t, y, dt: (
lambda dy1: (
lambda dy2: (
lambda dy3: (
lambda dy4: (dy1 + 2*dy2 + 2*dy3 + dy4)/6
)( dt * f( t + dt , y + dy3 ) )
)( dt * f( t + dt/2, y + dy2/2 ) )
)( dt * f( t + dt/2, y + dy1/2 ) )
)( dt * f( t , y ) )
# da is a function giving velocity of a at a time t.
# The other three are the positions of the three points.
def calculate_dy (da, A0, B0, C0):
l_ab = float(numpy.linalg.norm(A0 - B0))
l_bc = float(numpy.linalg.norm(B0 - C0))
# t is time, y = [A, B, C]
def update (t, y):
(A, B, C) = y
dA = da(t)
ab_unit = (A - B) / float(numpy.linalg.norm(A-B))
# The first term is the force. The second is a correction to
# cause roundoff errors in length to be selfcorrecting.
dB = (dA.dot(ab_unit) + float(numpy.linalg.norm(A-B))/l_ab - l_ab) * ab_unit
bc_unit = (B - C) / float(numpy.linalg.norm(B-C))
# The first term is the force. The second is a correction to
# cause roundoff errors in length to be selfcorrecting.
dC = (dB.dot(bc_unit) + float(numpy.linalg.norm(B-C))/l_bc - l_bc) * bc_unit
return numpy.array([dA, dB, dC])
return RK4(update)
A0 = numpy.array([1.0, 1.0])
B0 = numpy.array([2.0, 1.0])
C0 = numpy.array([2.0, 2.0])
dy = calculate_dy(lambda t: numpy.array([-1.0, -1.0]), A0, B0, C0)
t, y, dt = 0., numpy.array([A0, B0, C0]), .02
while t <= 1.01:
print( (t, y) )
t, y = t + dt, y + dy( t, y, dt )
By the answers I saw, I realized that the solution is not really simple and will have to be solved by an Inverse Kinematics algorithm.
This site is an example and it is a just a start, although it still does not solve everything, since the point C is fixed and in the case of the truck it should move.
Based on this Analytic Two-Bone IK in 2D article, I made a fully functional model in Geogebra, where the nucleus consists of two simple mathematical equations.
This is My First Logic Programming Language course so this is a really Dumb Question But I cannot for the life of me figure out how does this power predicate work I've tried making a search tree to trace it But I still cannot understand how is it working
mult(_ , 0 ,0).
mult(X , Y, Z):-
Y > 0,
Y1 is Y - 1,
mult(X,Y1,Z1),
Z is Z1 + X.
exp2(_ ,0 , 1).
exp2(X,Y,Z):-
Y > 0,
Y1 is Y - 1,
exp2(X , Y1 , Z1),
mult(X,Z1,Z).
I so far get that I'm going to call the exp2 predicate till I reach the point where the Y is going to be Zero then I'm going to start multiplying from there, but At the last call when it's at exp2(2 , 1 , Z) what is the Z value and how does the predicate work from there?
Thank you very much =)
EDIT: I'm really sorry for the Late reply I had some problems and couldn't access my PC
I'll walk through mult/3 in more detail here, but I'll leave exp2/3 to you as an exercise. It's similar..
As I mentioned in my comment, you want to read a Prolog predicate as a rule.
mult(_ , 0 ,0).
This rule says 0 is the result of multiplying anything (_) by 0. The variable _ is an anonymous variable, meaning it is not only a variable, but you don't care what its value is.
mult(X, Y, Z) :-
This says, Z is the result of multiplying X by Y if....
Y > 0,
Establish that Y is greater than 0.
Y1 is Y - 1,
And that Y1 has the value of Y minus 1.
mult(X, Y1, Z1),
And that Z1 is the result of multiplying X by Y1.
Z is Z1 + X.
And Z is the value of Z1 plus X.
Or reading the mult(X, Y, Z) rule altogether:
Z is the result of multiplying X by Y if Y is greater than 0, and Y1 is Y-1, and Z1 is the result of multiplying X by Y1, and Z is the result of adding Z1 to X.
Now digging a little deeper, you can see this is a recursive definition, as in the multiplication of two numbers is being defined by another multiplication. But what is being multiplied is important. Mathematically, it's using the fact that x * y is equal to x * (y - 1) + x. So it keeps reducing the second multiplicand by 1 and calling itself on the slightly reduced problem. When does this recursive reduction finally end? Well, as shown above, the second rule says Y must be greater than 0. If Y is 0, then the first rule, mult(_, 0, 0) applies and the recursion finally comes back with a 0.
If you are not sure how recursion works or are unfamiliar with it, I highly recommend Googling it to understand it. That is, indeed, a concept that applies to many computer languages. But you need to be careful about learning Prolog via comparison with other languages. Prolog is fundamentally different in it's behavior from procedural/imperative languages like Java, Python, C, C++, etc. It's best to get used to interpreting Prolog rules and facts as I have described above.
Say you want to compute 2^3 as assign result to R.
For that you will call exp2(2, 3, R).
It will recursively call exp2(2, 2, R1) and then exp2(2, 1, R2) and finally exp(2, 0, R3).
At this point exp(_, 0, 1) will match and R3 will be assigned to 1.
Then when call stack unfolds 1 will be multiplied by 2 three times.
In Java this logic would be encoded as follows. Execution would go pretty much the same route.
public static int Exp2(int X, int Y) {
if (Y == 0) { // exp2(_, 0, 1).
return 1;
}
if (Y > 0) { // Y > 0
int Y1 = Y - 1; // Y1 is Y - 1
int Z1 = Exp2(X, Y1); // exp2(X, Y1, Z1);
return X * Z1; // mult(X, Z1, Z).
}
return -1; // this should never happen.
}
I have a function that uses 4 parameters, called tile . It is designed to work the following way :
tile(?E, ?S, ?W, ?N, ?ID)
I would like a getter function that given an ID, it returns the first 4 parameters: E, S, W and N.
I have tried something like:
coordonates(tile(E,S,W,N,L), (E,S,W,N)).
But it does not return the actual values, only true.
If I type tile(E, S, W, N, #1) in the terminal I get the desired result but I do not know what exactly is returned (a list maybe?).
Let's suppose our facts describing tile looks as follows:
tile(p1,p2,p3,p4,id1).
tile(q1,q2,q3,q4,id2).
tile(r1,r2,r3,r4,id3).
In this we have a finite number of facts. That can be checked by the most general query for tile:
?- tile(E,S,W,N,I).
E = p1,
S = p2,
W = p3,
N = p4,
I = id1 ; % <---- user input ; to continue
E = q1,
S = q2,
W = q3,
N = q4,
I = id2 ; % <---- user input ; to continue
E = r1,
S = r2,
W = r3,
N = r4,
I = id3. % <---- toplevel outputs . -- we're done
So in theory, we could define coordonates as follows:
coordonates(id1, t(p1, p2, p3, p4)).
coordonates(id2, t(q1, q2, q3, q4)).
coordonates(id3, t(r1, r2, r3, r4)).
which could be queried for id2 as follows:
?- coordonates(id2,X).
X = t(q1, q2, q3, q4).
I used the functor t to group the solution, to make clear that it is not the predicate tile we defined earlier. There's also a lot of repetition in this definition which is already a hint, that we can do better. What we are looking for is a rule which tells us how, given we have a answer for tile, we can describe coordonates. In logical terms, this is written as an implication of the form: goal1 ∧ ... ∧ goalN → head. which means "Suppose I know that goal1 to goalN is true, then I also know that head is true." In Prolog, this is written backwards:
head :-
goal1,
% ...
goalN.
Let's go back to our task: we know something about a tile and we want to describe how the projection looks like. This means, our code looks as follows:
coordonates( ... ) :-
% ...
tile(E,S,W,N,I).
The body tile(E,S,W,N,I) is the most general form we can write (see our query above) and can be read as "suppose I have any tile at coordinates E S W N with id I". Now we only need to fill in, how coordonates should look like. We know it has two arguments, because it relates the id with the four other elements. Lets give them names, say Id and Coords:
coordonates(Id, Coords) :-
% ...
tile(E,S,W,N,I).
Now we only need to find out how to relate E,S,E,N and I with Id and Coords. One is easy: Id is just I. The other one is also not too hard, we just need to group the coordinates into one term. We can pick an arbitrary one, but already above decided to take t, so we will stick with it:
coordonates(Id, Coords) :-
Id = I,
Coords = t(E,S,W,N),
tile(E,S,W,N,I).
This already works as we expect:
?- coordonates(X,Y).
X = id1,
Y = t(p1, p2, p3, p4) ;
X = id2,
Y = t(q1, q2, q3, q4) ;
X = id3,
Y = t(r1, r2, r3, r4).
Now we can make one observation: if two terms are equal, we can use one instead of the other. So instead of writing Id = I, we can just reuse Id. The same goes for Coords and t(E,S,W,N):
coordonates(I, t(E,S,W,N)) :-
tile(E,S,W,N,I).
It couldn't be much shorter :-)
You have to declare 'E, S, W and N' so that prolog can unify those parameters with the input when you make the query. Something like (In the most basic case):
tile(['cordE1','cordS1','cordW1','cordN1'],1).
tile(['cordE2','cordS2','cordW2','cordN2'],2).
tile(['cordE3','cordS3','cordW3','cordN3'],3).
Query:
?- tile(C,2).
C = [cordE2, cordS2, cordW2, cordN2].
?- tile(C,1).
C = [cordE1, cordS1, cordW1, cordN1].
?- tile(C,3).
C = [cordE3, cordS3, cordW3, cordN3].
I have a problem with root finding and am having difficulty in getting it to work in this instance.
Some complicated function I need.
f[x_, lambda_, alpha_, beta_, mu_] =
Module[{gamma},
gamma = Sqrt[alpha^2 - beta^2];
(gamma^(2*lambda)/((2*alpha)^(lambda - 1/2)*Sqrt[Pi]*Gamma[lambda]))*
Abs[x - mu]^(lambda - 1/2)*
BesselK[lambda - 1/2, alpha Abs[x - mu]] E^(beta (x - mu))
];
A function I want to find the root of is defined as the integral of this function so I use quadrature:
F[x_, lambda_, alpha_, beta_, mu_] :=
NIntegrate[f[t, lambda, alpha, beta, mu], {t, 0, x}];
Now the problem, mathematica has difficulty solving the roots of this equation,
Q[u_, lambda_, alpha_, beta_, mu_] :=
x /. FindRoot[F[x, lambda, alpha, beta, mu] == u, {x, 1}]
Does anybody know why? The integral is defined at all points in R. f here is a density function and F its CDF.
Thanks for reading.
Try using := instead of = in the definition of f and see if that helps.
Incidentally when you use this SetDelayed syntax, you don't need semicolons to suppress output, because it doesn't immediately create output.
Here is some sample output, courtesy of belisarius and WReach:
I'm trying to figure out how to use Mathematica to solve systems of equations where some of the variables and coefficients are vectors. A simple example would be something like
where I know A, V, and the magnitude of P, and I have to solve for t and the direction of P. (Basically, given two rays A and B, where I know everything about A but only the origin and magnitude of B, figure out what the direction of B must be such that it intersects A.)
Now, I know how to solve this sort of thing by hand, but that's slow and error-prone, so I was hoping I could use Mathematica to speed things along and error-check me. However, I can't see how to get Mathematica to symbolically solve equations involving vectors like this.
I've looked in the VectorAnalysis package, without finding anything there that seems relevant; meanwhile the Linear Algebra package only seems to have a solver for linear systems (which this isn't, since I don't know t or P, just |P|).
I tried doing the simpleminded thing: expanding the vectors into their components (pretend they're 3D) and solving them as if I were trying to equate two parametric functions,
Solve[
{ Function[t, {Bx + Vx*t, By + Vy*t, Bz + Vz*t}][t] ==
Function[t, {Px*t, Py*t, Pz*t}][t],
Px^2 + Py^2 + Pz^2 == Q^2 } ,
{ t, Px, Py, Pz }
]
but the "solution" that spits out is a huge mess of coefficients and congestion. It also forces me to expand out each of the dimensions I feed it.
What I want is a nice symbolic solution in terms of dot products, cross products, and norms:
But I can't see how to tell Solve that some of the coefficients are vectors instead of scalars.
Is this possible? Can Mathematica give me symbolic solutions on vectors? Or should I just stick with No.2 Pencil technology?
(Just to be clear, I'm not interested in the solution to the particular equation at top -- I'm asking if I can use Mathematica to solve computational geometry problems like that generally without my having to express everything as an explicit matrix of {Ax, Ay, Az}, etc.)
With Mathematica 7.0.1.0
Clear[A, V, P];
A = {1, 2, 3};
V = {4, 5, 6};
P = {P1, P2, P3};
Solve[A + V t == P, P]
outputs:
{{P1 -> 1 + 4 t, P2 -> 2 + 5 t, P3 -> 3 (1 + 2 t)}}
Typing out P = {P1, P2, P3} can be annoying if the array or matrix is large.
Clear[A, V, PP, P];
A = {1, 2, 3};
V = {4, 5, 6};
PP = Array[P, 3];
Solve[A + V t == PP, PP]
outputs:
{{P[1] -> 1 + 4 t, P[2] -> 2 + 5 t, P[3] -> 3 (1 + 2 t)}}
Matrix vector inner product:
Clear[A, xx, bb];
A = {{1, 5}, {6, 7}};
xx = Array[x, 2];
bb = Array[b, 2];
Solve[A.xx == bb, xx]
outputs:
{{x[1] -> 1/23 (-7 b[1] + 5 b[2]), x[2] -> 1/23 (6 b[1] - b[2])}}
Matrix multiplication:
Clear[A, BB, d];
A = {{1, 5}, {6, 7}};
BB = Array[B, {2, 2}];
d = {{6, 7}, {8, 9}};
Solve[A.BB == d]
outputs:
{{B[1, 1] -> -(2/23), B[2, 1] -> 28/23, B[1, 2] -> -(4/23), B[2, 2] -> 33/23}}
The dot product has an infix notation built in just use a period for the dot.
I do not think the cross product does however. This is how you use the Notation package to make one. "X" will become our infix form of Cross. I suggest coping the example from the Notation, Symbolize and InfixNotation tutorial. Also use the Notation Palette which helps abstract away some of the Box syntax.
Clear[X]
Needs["Notation`"]
Notation[x_ X y_\[DoubleLongLeftRightArrow]Cross[x_, y_]]
Notation[NotationTemplateTag[
RowBox[{x_, , X, , y_, }]] \[DoubleLongLeftRightArrow]
NotationTemplateTag[RowBox[{ ,
RowBox[{Cross, [,
RowBox[{x_, ,, y_}], ]}]}]]]
{a, b, c} X {x, y, z}
outputs:
{-c y + b z, c x - a z, -b x + a y}
The above looks horrible but when using the Notation Palette it looks like:
Clear[X]
Needs["Notation`"]
Notation[x_ X y_\[DoubleLongLeftRightArrow]Cross[x_, y_]]
{a, b, c} X {x, y, z}
I have run into some quirks using the notation package in the past versions of mathematica so be careful.
I don't have a general solution for you by any means (MathForum may be the better way to go), but there are some tips that I can offer you. The first is to do the expansion of your vectors into components in a more systematic way. For instance, I would solve the equation you wrote as follows.
rawSol = With[{coords = {x, y, z}},
Solve[
Flatten[
{A[#] + V[#] t == P[#] t & /# coords,
Total[P[#]^2 & /# coords] == P^2}],
Flatten[{t, P /# coords}]]];
Then you can work with the rawSol variable more easily. Next, because you are referring the vector components in a uniform way (always matching the Mathematica pattern v_[x|y|z]), you can define rules that will aid in simplifying them. I played around a bit before coming up with the following rules:
vectorRules =
{forms___ + vec_[x]^2 + vec_[y]^2 + vec_[z]^2 :> forms + vec^2,
forms___ + c_. v1_[x]*v2_[x] + c_. v1_[y]*v2_[y] + c_. v1_[z]*v2_[z] :>
forms + c v1\[CenterDot]v2};
These rules will simplify the relationships for vector norms and dot products (cross-products are left as a likely painful exercise for the reader). EDIT: rcollyer pointed out that you can make c optional in the rule for dot products, so you only need two rules for norms and dot products.
With these rules, I was immediately able to simplify the solution for t into a form very close to yours:
In[3] := t /. rawSol //. vectorRules // Simplify // InputForm
Out[3] = {(A \[CenterDot] V - Sqrt[A^2*(P^2 - V^2) +
(A \[CenterDot] V)^2])/(P^2 - V^2),
(A \[CenterDot] V + Sqrt[A^2*(P^2 - V^2) +
(A \[CenterDot] V)^2])/(P^2 - V^2)}
Like I said, it's not a complete way of solving these kinds of problems by any means, but if you're careful about casting the problem into terms that are easy to work with from a pattern-matching and rule-replacement standpoint, you can go pretty far.
I've taken a somewhat different approach to this issue. I've made some definitions that return this output:
Patterns that are known to be vector quantities may be specified using vec[_], patterns that have an OverVector[] or OverHat[] wrapper (symbols with a vector or hat over them) are assumed to be vectors by default.
The definitions are experimental and should be treated as such, but they seem to work well. I expect to add to this over time.
Here are the definitions. The need to be pasted into a Mathematica Notebook cell and converted to StandardForm to see them properly.
Unprotect[vExpand,vExpand$,Cross,Plus,Times,CenterDot];
(* vec[pat] determines if pat is a vector quantity.
vec[pat] can be used to define patterns that should be treated as vectors.
Default: Patterns are assumed to be scalar unless otherwise defined *)
vec[_]:=False;
(* Symbols with a vector hat, or vector operations on vectors are assumed to be vectors *)
vec[OverVector[_]]:=True;
vec[OverHat[_]]:=True;
vec[u_?vec+v_?vec]:=True;
vec[u_?vec-v_?vec]:=True;
vec[u_?vec\[Cross]v_?vec]:=True;
vec[u_?VectorQ]:=True;
(* Placeholder for matrix types *)
mat[a_]:=False;
(* Anything not defined as a vector or matrix is a scalar *)
scal[x_]:=!(vec[x]\[Or]mat[x]);
scal[x_?scal+y_?scal]:=True;scal[x_?scal y_?scal]:=True;
(* Scalars times vectors are vectors *)
vec[a_?scal u_?vec]:=True;
mat[a_?scal m_?mat]:=True;
vExpand$[u_?vec\[Cross](v_?vec+w_?vec)]:=vExpand$[u\[Cross]v]+vExpand$[u\[Cross]w];
vExpand$[(u_?vec+v_?vec)\[Cross]w_?vec]:=vExpand$[u\[Cross]w]+vExpand$[v\[Cross]w];
vExpand$[u_?vec\[CenterDot](v_?vec+w_?vec)]:=vExpand$[u\[CenterDot]v]+vExpand$[u\[CenterDot]w];
vExpand$[(u_?vec+v_?vec)\[CenterDot]w_?vec]:=vExpand$[u\[CenterDot]w]+vExpand$[v\[CenterDot]w];
vExpand$[s_?scal (u_?vec\[Cross]v_?vec)]:=Expand[s] vExpand$[u\[Cross]v];
vExpand$[s_?scal (u_?vec\[CenterDot]v_?vec)]:=Expand[s] vExpand$[u\[CenterDot]v];
vExpand$[Plus[x__]]:=vExpand$/#Plus[x];
vExpand$[s_?scal,Plus[x__]]:=Expand[s](vExpand$/#Plus[x]);
vExpand$[Times[x__]]:=vExpand$/#Times[x];
vExpand[e_]:=e//.e:>Expand[vExpand$[e]]
(* Some simplification rules *)
(u_?vec\[Cross]u_?vec):=\!\(\*OverscriptBox["0", "\[RightVector]"]\);
(u_?vec+\!\(\*OverscriptBox["0", "\[RightVector]"]\)):=u;
0v_?vec:=\!\(\*OverscriptBox["0", "\[RightVector]"]\);
\!\(\*OverscriptBox["0", "\[RightVector]"]\)\[CenterDot]v_?vec:=0;
v_?vec\[CenterDot]\!\(\*OverscriptBox["0", "\[RightVector]"]\):=0;
(a_?scal u_?vec)\[Cross]v_?vec :=a u\[Cross]v;u_?vec\[Cross](a_?scal v_?vec ):=a u\[Cross]v;
(a_?scal u_?vec)\[CenterDot]v_?vec :=a u\[CenterDot]v;
u_?vec\[CenterDot](a_?scal v_?vec) :=a u\[CenterDot]v;
(* Stealing behavior from Dot *)
Attributes[CenterDot]=Attributes[Dot];
Protect[vExpand,vExpand$,Cross,Plus,Times,CenterDot];