
obj1:= a*b+a*c+d;
@factorise!(%){b,c};
tst1:= (b+c)*a+d-@(obj1);
@collect_terms!(%);
@assert(tst1);

obj2:= 2*a+b*a;
@factorise!(%){b};
tst2:= (2+b)*a-@(obj2);
@collect_terms!(%);
@assert(tst2);

obj3:= 3*a*b + 5*c*b;
@factorise!(%){a,c};
tst3:= (3 a + 5 c) b - @(obj3);
@collect_terms!(%);
@assert(tst3);

# Test 4-6: factor_out
#
@reset.
obj4:= a b + a c e + a d - a:
@factor_out!(%){a};
tst4:= a ( b + c e + d - 1 ) - @(obj4);
@collect_terms!(%);
@assert(tst4);

#@reset.
#obj4b:= c - a;
#@factor_out!(%){a};
# FIXME: leads to \prod{a}{-1}.

@reset.
obj5:= 3 a b + 2 a c e + 5 a c + 7 e f - 2 c e + c d - a d + a - c:
@factor_out!(%){a,c};
@factor_out!(%){a,c};
tst5:=  a * c * (2 * e + 5) + c * ( - 2 * e + d - 1) + a * (3 * b - d + 1) + 7 * e * f - @(obj5);
@collect_terms!(%);
@assert(tst5);

# Non-commuting objects

# Basic behaviour
@reset.
{A, B, C, D, E}::NonCommuting.
obj := A B + A C + D A + E A:
@factor_out!(%)(A);
tst := A*(B + C) + (D + E)*A - @(obj);
@collect_terms!(%);
@assert(tst);

@reset.
{A, B, C, D}::AntiCommuting.
obj := A B + A C + D A:
@factor_out!(%)(A);
tst := A*(B + C - D) - @(obj);
@collect_terms!(%);
@assert(tst);


# Ordering of pulled out factors
@reset.
{A, B}::AntiCommuting.
obj := A B c X + c B A Y:
@factor_out!(%)(A, B, c);
tst := A B c * (X - Y) - @(obj);
@collect_terms!(%);
@assert(tst);

@reset.
{A, B}::AntiCommuting.
{A, X, Y}::NonCommuting.
{B, X, Y}::NonCommuting.
obj := A B c X + c B A Y + X A B c + Y c B A:
@factor_out!(%)(c, A, B);
tst := c A B * (X - Y) + c * (X - Y) * A B - @(obj);
@collect_terms!(%);
@assert(tst);

# Ordering past a non commuting term
@reset.
{A, B, C, D, E}::AntiCommuting.
{A, X}::NonCommuting.
{B, X}::NonCommuting.
obj := X A B Y + X B A Z:
@factor_out!(%)(A, B, X);
tst := X A B (Y - Z) - @(obj);
@collect_terms!(%);
@assert(tst);

obj := A B X A B Y + B A X B A Z:
@factor_out!(%)(A, B, X);
tst := A B X A B (Y + Z) - @(obj);
@collect_terms!(%);
@assert(tst);

obj := A B C D Y + D A B C Z:
@factor_out!(%)(A, B, C, D);
tst := A B C D (Y - Z) - @(obj);
@collect_terms!(%);
@assert(tst);



# Test 10: Indices
#
@reset.
obj:= A_{a} B_{b} + A_{a} C_{b} + A_{b} D_{a};
@factor_out!(%)(A_{a});
tst: A_{a} (B_{b} + C_{b}) + A_{b} D_{a} - @(obj);
@collect_terms!(%);
@assert(%);



@reset.
{a,b,m,n,p,q}::Indices.
obj6:= A_{m n} C_{m n} D_{p q} + A_{p m} C_{m n} D_{n q} + A_{m n} C_{m n} E_{p q} Q;
@factor_out!(%){ A_{a b}, C_{m n} };

# NOTE: see the email to James Allen on Thu, 14 Oct 2010 20:58:52 +0100. 
# Should be solved by modifying @rename_dummies. The text below is obsolete but
# kept until the bug is fixed.
#
# This is very subtle. Consider
#
#   A_{m n} C_{n p} D_{m p} + A_{q r} C_{r s} E_{q t} F_{t s}
#
# This can clearly factor_out A & C. Standard comparison of the two prefactors
# would give a match, since  A_{m n} C_{n p} and A_{q r} C_{r s}  are equivalent.
# But we would need to relabel indices along the way.
#
# However, @collect_terms does not do this type of collecting either: it requires
# you to rename dummies first. If we do that, our problem goes away here too.

{m,n,p,q,r,s,t}::Indices.
A_{m n} C_{n p} D_{m p} + A_{q r} C_{r s} E_{q t} F_{t s};
@rename_dummies!(%);

# So the conclusion is that we would prefer to stick to a simpler matching, in which
# we only allow for dummy index names to differ. But what do we then do with

{m,n,p,q,r,s,t}::Indices.
A_{m n} D_{m p} Q_{n p} + A_{q r} E_{q t} F_{t s} Q_{r s} ;
@rename_dummies!(%);

# -> A_{m n} * D_{m p} * Q_{n p} + A_{m n} * E_{m p} * F_{p q} * Q_{n q};

# This does not lead to equal A*Q factors. So it seems that we are forced
# to do a comparison in which we flag
#
#    A_{m n} Q_{m n}  and  A_{m n} Q_{n q} as un-equal 
#
#    A_{m n} Q_{n q}  and  A_{m n} Q_{n p} as equal
#
#
