/* Pull out only specific factors, usually numeric or constant. Note that gcd(sqrt(2),sqrt(6))=3D1, so don't expect to find common factors inside radicals. -- perhaps fix this some day */ pullout_specific(expr,%%part):=3D /* %%part is fluid */ if not(atom(expr)) and inpart(expr,0)=3D"+"=20 then block([comm:gcd_part(args(expr)), listarith:true], /* For division by comm */ comm*apply("+",args(expr)/comm)) else expr$ pullout(expr):=3Dpullout_specific(expr,identity)$ scan_pullout(expr):=3Dscanmap('pullout,expr,bottomup)$ pullout_num(expr):=3Dpullout_specific(expr,numfactor)$ scan_pullout_num(expr):=3Dscanmap('pullout_num,expr,bottomup)$ pullout_const(expr):=3Dpullout_specific(expr,constfactor)$ scan_pullout_const(expr):=3Dscanmap('pullout_const,expr,bottomup)$ /* Pulls out common factors in a sum. Uses content. Not recommended, because content is a CRE function and thus expands everything. Also, results depend on variable ordering. */ pullout_using_content(expr):=3D if not(atom(expr)) and inpart(expr,0)=3D"+"=20 then product(content(expr)[i],i,1,2) else expr$ scan_pullout_using_content(expr):=3Dscanmap('pullout_using_content,expr,b= ottomup)$ /* Utilities */ /* Do not use elsewhere -- depends on fluid variable %%part */ gcd_part(list):=3D block([res:(%%part)(first(list))], while (list:rest(list)) # [] and res # 1 do res: gcd(res,(%%part)(first(list))), /* Bound by = pullout_specific */ res)$ /* The identity function */ identity(x):=3Dx$ /* The constant factor of an expression, e.g. constfactor(2*%pi*r) =3D> 2*%pi */ constfactor(ex):=3D if numberp(ex) or constantp(ex) then ex elseif not(atom(ex)) and inpart(ex,0)=3D"*" then apply("*",map(constfactor,args(ex))) else 1$