-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathgetLCM.m
129 lines (111 loc) · 3.37 KB
/
getLCM.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
function [lcm h e] = getLCM(fsys,gsys,noiselevel,notsparse)
% [lcm h e] = getLCM(fsys,gsys,noiselevel,notsparse)
% --------------------------------------------------
% Returns the approximate least common multiple of two given polynomials fsys and gsys. Also
% the factor h such that lcm = g*h is calculated.
%
% lcm = vector, coefficient vector of polynomial which is the least
% common multiple of f and g
%
% h = vector, coefficient vector of polynomial which is the
% factor such that lcm = g*h
%
% e = scalar, mean squared error of least squares solution
% lcm = g * h
%
% fsys = cell, polysys representation of the polynomial f
%
% gsys = cell, polysys representation of the polynomial g
%
% noiselevel = scalar, upper bound on the error on the coefficients
% of fsys and gsys. Default: tolerance for numerical rank Macaulay matrix
%
% notsparse = boolean, if set to 0, then a sparse rank revealing QR
% is used. If set to 1, a dense SVD is used instead.
% Default is 0.
%
% CALLS
% -----
%
% getM.m, getD0.m, getMex.m, updateOrth.m, updateN.m
%
% Kim Batselier, 2011-01-23, edited 2012-01-31: accepts polysys objects now
% warning off all
if nargin == 2
noiselevel = 0;
notsparse = 0;
elseif nargin == 3
notsparse = 0;
end
% check whether both f and g have same number of variables
nf = size(fsys{1,2},2);
ng = size(gsys{1,2},2);
if nf ~= ng
error('Please provide 2 polynomials in the same number of variables');
end
% normalize coefficient vectors
fsys{1,1}=fsys{1,1}/norm(fsys{1,1});
gsys{1,1}=gsys{1,1}/norm(gsys{1,1});
% first get the degrees of the polynomials
df = getD0(fsys);
dg = getD0(gsys);
lcm = [];
h = [];
e = 0;
% need to start iteration over max(deg(f),deg(g))
d = max(df,dg);
% initialization Macaulay matrix and orthogonal basis kernel
if ~notsparse
Mf = getM(fsys,d,1);
[Q , R, P] = qr(Mf'); % very painful if c(d) is comparable to q(d)
Qf=Q(:,size(Mf,1)); % always of full row rank
Nf=Q(:,size(Mf,1)+1:end);
Mg = getM(gsys,d,1);
[Q ,R, P] = qr(Mg'); % very painful if c(d) is comparable to q(d)
Ng = Q(:,size(Mg,1)+1:end);
tol = 20*sum(size(Mf))*eps;
else
Mf=getM(fsys,d)';
[U S V]=svd(Mf);
s=diag(S);
tol=max(size(Mf))*eps(s(1));
r=sum(s > tol );
Qf=U(:,1:r);
Nf=U(:,r+1:end);
Mg = getM(gsys,d);
Ng=null(Mg);
end
while isempty(lcm) && d <= df+dg
if noiselevel % only for nonzero noiselevel we need to overwrite the tolerance
tol=sqrt(2)*( cond(getM(fsys,d)) + cond(getM(gsys,d)) )*noiselevel;
end
[Y, S Z] = svd(full(Ng'*Qf));
if size(S,2)==1
s=S(1);
else
diagS=diag(S);
s=diagS(end);
end
if asin(s)<tol
lcm = sparse(Qf*Z(:,end))';
% decomposition of lcm in M via qr
% Mg is always of full row rank!
% [asin(s) d tol]
M=getM(gsys,d,1);
h = (M'\lcm')';
e = norm(lcm-h*M);
else
d=d+1;
if ~notsparse
[Qf Nf tol] = updateOrth(Qf,Nf,getMex(fsys,d,d-1,1),1);
Ng = updateN(Ng,getMex(gsys,d,d-1,1),1);
else
[Qf Nf tol] = updateOrth(Qf,Nf,getMex(fsys,d,d-1));
Ng = updateN(Ng,getMex(gsys,d,d-1));
end
end
end
if isempty(lcm)
error('Method did not converge, try a smaller tolerance')
end
end