summaryrefslogtreecommitdiffstats
path: root/SD-VBS/common/toolbox/toolbox_basic/matching/pub
diff options
context:
space:
mode:
Diffstat (limited to 'SD-VBS/common/toolbox/toolbox_basic/matching/pub')
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/Contents.m26
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allcosts.m17
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allperm.m17
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/condass.m54
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/demo.m38
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/hungarian.m464
-rwxr-xr-xSD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/test.m87
7 files changed, 703 insertions, 0 deletions
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/Contents.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/Contents.m
new file mode 100755
index 0000000..3ddb232
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/Contents.m
@@ -0,0 +1,26 @@
1%Functions related to the assignment problem.
2%Version 1.0, 25-May-1999.
3%
4%Copyright (c) 1995-1999 Niclas Borlin, Dept. of Computing Science,
5% Umea University, SE-901 87 UMEA, Sweden.
6% Niclas.Borlin@cs.umu.se.
7% www.cs.umu.se/~niclas.
8%
9%All standard disclaimers apply.
10%
11%You are free to use this code as you wish. If you use it for a
12%publication or in a commercial package, please include an
13%acknowledgement and/or at least send me an email. (Looks good in my CV :-).
14%
15%Main functions:
16% hungarian - calculate a solution of the square assignment
17% problem. See HELP for a reference.
18% condass - calculate a condition number of the solution to the
19% assignment problem. See HELP for a reference.
20% allcosts - calculate the costs of all possible assignments.
21% allperms - calculate all possible permutations/assignments of a
22% given problem size.
23%
24%Test/demo functions.
25% demo - short demonstration of the main functions.
26% test - test/verification of the main functions.
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allcosts.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allcosts.m
new file mode 100755
index 0000000..ffdb8b9
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allcosts.m
@@ -0,0 +1,17 @@
1function [c,p]=allcosts(C)
2%ALLCOSTS Calculate all costs for an assignment problem.
3%
4%[c,p]=allcosts(C)
5%c returns the costs, p the corresponding permutations.
6
7% v1.0 95-07-18. Niclas Borlin, niclas@cs.umu.se.
8
9p=allperm(size(C,1));
10
11c=zeros(size(p,1),1);
12
13I=eye(size(C,1));
14
15for i=1:size(p,1)
16 c(i)=sum(C(logical(sparse(p(i,:),1:size(C,1),1))));
17end
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allperm.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allperm.m
new file mode 100755
index 0000000..b8d419e
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/allperm.m
@@ -0,0 +1,17 @@
1function p=allperm(n)
2%ALLPERM All permutation matrix.
3%
4%p=allperm(n)
5%Returns a matrix with all permutations of 1:n stored row-wise.
6
7% v1.0 95-07-18. Niclas Borlin, niclas@cs.umu.se.
8
9if (n<=1)
10 p=1;
11else
12 q=allperm(n-1);
13 p=[];
14 for i=1:n
15 p=[p;i*ones(size(q,1),1) q+(q>=i)];
16 end
17end
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/condass.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/condass.m
new file mode 100755
index 0000000..82552e7
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/condass.m
@@ -0,0 +1,54 @@
1function [k,C1,T1,C2,T2]=condass(A)
2%CONDASS Calculate condition number of the assigment problem.
3%
4%[k,C1,T1,C2,T2]=condass(A)
5%A - A square cost matrix.
6%k - The condition number of the assigment problem.
7%C1 - The best assigment.
8%T1 - The lowest cost.
9%C2 - The second best assignment.
10%T2 - The second lowest cost.
11%
12%The condition number is calculated as the relative difference between
13%the best and second best solutions, as described in Nystrom, Soderkvist,
14%and Wedin, "A Note on some Identification Problems Arising in Roentgen
15%Stereo Photogrammetric Analysis", J of Biomechanics, 27(10):1291-1294,
16%1994.
17
18% v1.0 96-09-14. Niclas Borlin, niclas@cs.umu.se.
19
20% A substantial effort was put into this code. If you use it for a
21% publication or otherwise, please include an acknowledgement and notify
22% me by email. /Niclas
23
24% Create a large number used to block selected assignments.
25big=sum(sum(A))+1;
26
27% Get best assigment.
28[C1,T1]=hungarian(A);
29
30% Initialize second best solution.
31T2=inf;
32C2=zeros(size(C1));
33
34% Create a work matrix.
35B=A;
36for i=1:length(C1)
37 % Block assigment in column i.
38 B(C1(i),i)=big;
39 % Get best assigment with this one blocked.
40 [C,T]=hungarian(B);
41 if (T<T2)
42 % Remember it if it's the best so far.
43 T2=T;
44 C2=C;
45 end
46 % Remove blocking in column i.
47 B(C1(i),i)=A(C1(i),i);
48end
49
50% Calculate difference...
51mu=T2-T1;
52
53% ...and condition number.
54k=T1/mu;
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/demo.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/demo.m
new file mode 100755
index 0000000..2d34e37
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/demo.m
@@ -0,0 +1,38 @@
1A=magic(10);
2B=A(4:7,4:7);
3disp('Cost matrix:')
4disp(B)
5disp('Calculating best assignment...');
6[c,t]=hungarian(B);
7disp('Best assignment (as row indices):')
8disp(c)
9disp('Best assignment (as logical matrix):')
10disp(logical(full(sparse(c,1:4,1))))
11disp('Lowest cost:')
12disp(t)
13
14disp(sprintf('\nCalculating condition number for solution...'));
15[k,c1,t1,c2,t2]=condass(B);
16disp('Lowest cost (should be same as above): ')
17disp(t1)
18disp('corresponding assignment (should be same as above):')
19disp(c1)
20disp('Second lowest cost: ')
21disp(t2)
22disp('corresponding assignment:')
23disp(c2)
24disp('Condition number for solution:')
25disp(k)
26
27disp(sprintf('\nCalculating all possible costs...'));
28[c,p]=allcosts(B);
29% Sort by cost.
30[y,i]=sort(c);
31disp('The three lowest costs:')
32disp(c(i(1:3)))
33disp('Corresponding assignments:')
34disp(p(i(1:3),:))
35disp('The three highest costs:')
36disp(c(i(end+[-2:0])))
37disp('Corresponding assignments:')
38disp(p(i(end+[-2:0]),:))
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/hungarian.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/hungarian.m
new file mode 100755
index 0000000..0b493f0
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/hungarian.m
@@ -0,0 +1,464 @@
1function [C,T]=hungarian(A)
2%HUNGARIAN Solve the Assignment problem using the Hungarian method.
3%
4%[C,T]=hungarian(A)
5%A - a square cost matrix.
6%C - the optimal assignment.
7%T - the cost of the optimal assignment.
8
9% Adapted from the FORTRAN IV code in Carpaneto and Toth, "Algorithm 548:
10% Solution of the assignment problem [H]", ACM Transactions on
11% Mathematical Software, 6(1):104-111, 1980.
12
13% v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
14% Department of Computing Science, Umeå University,
15% Sweden.
16% All standard disclaimers apply.
17
18% A substantial effort was put into this code. If you use it for a
19% publication or otherwise, please include an acknowledgement or at least
20% notify me by email. /Niclas
21
22[m,n]=size(A);
23
24if (m~=n)
25 error('HUNGARIAN: Cost matrix must be square!');
26end
27
28% Save original cost matrix.
29orig=A;
30
31% Reduce matrix.
32A=hminired(A);
33
34% Do an initial assignment.
35[A,C,U]=hminiass(A);
36
37% Repeat while we have unassigned rows.
38while (U(n+1))
39 % Start with no path, no unchecked zeros, and no unexplored rows.
40 LR=zeros(1,n);
41 LC=zeros(1,n);
42 CH=zeros(1,n);
43 RH=[zeros(1,n) -1];
44
45 % No labelled columns.
46 SLC=[];
47
48 % Start path in first unassigned row.
49 r=U(n+1);
50 % Mark row with end-of-path label.
51 LR(r)=-1;
52 % Insert row first in labelled row set.
53 SLR=r;
54
55 % Repeat until we manage to find an assignable zero.
56 while (1)
57 % If there are free zeros in row r
58 if (A(r,n+1)~=0)
59 % ...get column of first free zero.
60 l=-A(r,n+1);
61
62 % If there are more free zeros in row r and row r in not
63 % yet marked as unexplored..
64 if (A(r,l)~=0 & RH(r)==0)
65 % Insert row r first in unexplored list.
66 RH(r)=RH(n+1);
67 RH(n+1)=r;
68
69 % Mark in which column the next unexplored zero in this row
70 % is.
71 CH(r)=-A(r,l);
72 end
73 else
74 % If all rows are explored..
75 if (RH(n+1)<=0)
76 % Reduce matrix.
77 [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR);
78 end
79
80 % Re-start with first unexplored row.
81 r=RH(n+1);
82 % Get column of next free zero in row r.
83 l=CH(r);
84 % Advance "column of next free zero".
85 CH(r)=-A(r,l);
86 % If this zero is last in the list..
87 if (A(r,l)==0)
88 % ...remove row r from unexplored list.
89 RH(n+1)=RH(r);
90 RH(r)=0;
91 end
92 end
93
94 % While the column l is labelled, i.e. in path.
95 while (LC(l)~=0)
96 % If row r is explored..
97 if (RH(r)==0)
98 % If all rows are explored..
99 if (RH(n+1)<=0)
100 % Reduce cost matrix.
101 [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR);
102 end
103
104 % Re-start with first unexplored row.
105 r=RH(n+1);
106 end
107
108 % Get column of next free zero in row r.
109 l=CH(r);
110
111 % Advance "column of next free zero".
112 CH(r)=-A(r,l);
113
114 % If this zero is last in list..
115 if(A(r,l)==0)
116 % ...remove row r from unexplored list.
117 RH(n+1)=RH(r);
118 RH(r)=0;
119 end
120 end
121
122 % If the column found is unassigned..
123 if (C(l)==0)
124 % Flip all zeros along the path in LR,LC.
125 [A,C,U]=hmflip(A,C,LC,LR,U,l,r);
126 % ...and exit to continue with next unassigned row.
127 break;
128 else
129 % ...else add zero to path.
130
131 % Label column l with row r.
132 LC(l)=r;
133
134 % Add l to the set of labelled columns.
135 SLC=[SLC l];
136
137 % Continue with the row assigned to column l.
138 r=C(l);
139
140 % Label row r with column l.
141 LR(r)=l;
142
143 % Add r to the set of labelled rows.
144 SLR=[SLR r];
145 end
146 end
147end
148
149% Calculate the total cost.
150T=sum(orig(logical(sparse(C,1:size(orig,2),1))));
151
152
153function A=hminired(A)
154%HMINIRED Initial reduction of cost matrix for the Hungarian method.
155%
156%B=assredin(A)
157%A - the unreduced cost matris.
158%B - the reduced cost matrix with linked zeros in each row.
159
160% v1.0 96-06-13. Niclas Borlin, niclas@cs.umu.se.
161
162[m,n]=size(A);
163
164% Subtract column-minimum values from each column.
165colMin=min(A);
166A=A-colMin(ones(n,1),:);
167
168% Subtract row-minimum values from each row.
169rowMin=min(A')';
170A=A-rowMin(:,ones(1,n));
171
172% Get positions of all zeros.
173[i,j]=find(A==0);
174
175% Extend A to give room for row zero list header column.
176A(1,n+1)=0;
177for k=1:n
178 % Get all column in this row.
179 cols=j(k==i)';
180 % Insert pointers in matrix.
181 A(k,[n+1 cols])=[-cols 0];
182end
183
184
185function [A,C,U]=hminiass(A)
186%HMINIASS Initial assignment of the Hungarian method.
187%
188%[B,C,U]=hminiass(A)
189%A - the reduced cost matrix.
190%B - the reduced cost matrix, with assigned zeros removed from lists.
191%C - a vector. C(J)=I means row I is assigned to column J,
192% i.e. there is an assigned zero in position I,J.
193%U - a vector with a linked list of unassigned rows.
194
195% v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
196
197[n,np1]=size(A);
198
199% Initalize return vectors.
200C=zeros(1,n);
201U=zeros(1,n+1);
202
203% Initialize last/next zero "pointers".
204LZ=zeros(1,n);
205NZ=zeros(1,n);
206
207for i=1:n
208 % Set j to first unassigned zero in row i.
209 lj=n+1;
210 j=-A(i,lj);
211
212 % Repeat until we have no more zeros (j==0) or we find a zero
213 % in an unassigned column (c(j)==0).
214
215 while (C(j)~=0)
216 % Advance lj and j in zero list.
217 lj=j;
218 j=-A(i,lj);
219
220 % Stop if we hit end of list.
221 if (j==0)
222 break;
223 end
224 end
225
226 if (j~=0)
227 % We found a zero in an unassigned column.
228
229 % Assign row i to column j.
230 C(j)=i;
231
232 % Remove A(i,j) from unassigned zero list.
233 A(i,lj)=A(i,j);
234
235 % Update next/last unassigned zero pointers.
236 NZ(i)=-A(i,j);
237 LZ(i)=lj;
238
239 % Indicate A(i,j) is an assigned zero.
240 A(i,j)=0;
241 else
242 % We found no zero in an unassigned column.
243
244 % Check all zeros in this row.
245
246 lj=n+1;
247 j=-A(i,lj);
248
249 % Check all zeros in this row for a suitable zero in another row.
250 while (j~=0)
251 % Check the in the row assigned to this column.
252 r=C(j);
253
254 % Pick up last/next pointers.
255 lm=LZ(r);
256 m=NZ(r);
257
258 % Check all unchecked zeros in free list of this row.
259 while (m~=0)
260 % Stop if we find an unassigned column.
261 if (C(m)==0)
262 break;
263 end
264
265 % Advance one step in list.
266 lm=m;
267 m=-A(r,lm);
268 end
269
270 if (m==0)
271 % We failed on row r. Continue with next zero on row i.
272 lj=j;
273 j=-A(i,lj);
274 else
275 % We found a zero in an unassigned column.
276
277 % Replace zero at (r,m) in unassigned list with zero at (r,j)
278 A(r,lm)=-j;
279 A(r,j)=A(r,m);
280
281 % Update last/next pointers in row r.
282 NZ(r)=-A(r,m);
283 LZ(r)=j;
284
285 % Mark A(r,m) as an assigned zero in the matrix . . .
286 A(r,m)=0;
287
288 % ...and in the assignment vector.
289 C(m)=r;
290
291 % Remove A(i,j) from unassigned list.
292 A(i,lj)=A(i,j);
293
294 % Update last/next pointers in row r.
295 NZ(i)=-A(i,j);
296 LZ(i)=lj;
297
298 % Mark A(r,m) as an assigned zero in the matrix . . .
299 A(i,j)=0;
300
301 % ...and in the assignment vector.
302 C(j)=i;
303
304 % Stop search.
305 break;
306 end
307 end
308 end
309end
310
311% Create vector with list of unassigned rows.
312
313% Mark all rows have assignment.
314r=zeros(1,n);
315rows=C(C~=0);
316r(rows)=rows;
317empty=find(r==0);
318
319% Create vector with linked list of unassigned rows.
320U=zeros(1,n+1);
321U([n+1 empty])=[empty 0];
322
323
324function [A,C,U]=hmflip(A,C,LC,LR,U,l,r)
325%HMFLIP Flip assignment state of all zeros along a path.
326%
327%[A,C,U]=hmflip(A,C,LC,LR,U,l,r)
328%Input:
329%A - the cost matrix.
330%C - the assignment vector.
331%LC - the column label vector.
332%LR - the row label vector.
333%U - the
334%r,l - position of last zero in path.
335%Output:
336%A - updated cost matrix.
337%C - updated assignment vector.
338%U - updated unassigned row list vector.
339
340% v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
341
342n=size(A,1);
343
344while (1)
345 % Move assignment in column l to row r.
346 C(l)=r;
347
348 % Find zero to be removed from zero list..
349
350 % Find zero before this.
351 m=find(A(r,:)==-l);
352
353 % Link past this zero.
354 A(r,m)=A(r,l);
355
356 A(r,l)=0;
357
358 % If this was the first zero of the path..
359 if (LR(r)<0)
360 ...remove row from unassigned row list and return.
361 U(n+1)=U(r);
362 U(r)=0;
363 return;
364 else
365
366 % Move back in this row along the path and get column of next zero.
367 l=LR(r);
368
369 % Insert zero at (r,l) first in zero list.
370 A(r,l)=A(r,n+1);
371 A(r,n+1)=-l;
372
373 % Continue back along the column to get row of next zero in path.
374 r=LC(l);
375 end
376end
377
378
379function [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR)
380%HMREDUCE Reduce parts of cost matrix in the Hungerian method.
381%
382%[A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR)
383%Input:
384%A - Cost matrix.
385%CH - vector of column of 'next zeros' in each row.
386%RH - vector with list of unexplored rows.
387%LC - column labels.
388%RC - row labels.
389%SLC - set of column labels.
390%SLR - set of row labels.
391%
392%Output:
393%A - Reduced cost matrix.
394%CH - Updated vector of 'next zeros' in each row.
395%RH - Updated vector of unexplored rows.
396
397% v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se.
398
399n=size(A,1);
400
401% Find which rows are covered, i.e. unlabelled.
402coveredRows=LR==0;
403
404% Find which columns are covered, i.e. labelled.
405coveredCols=LC~=0;
406
407r=find(~coveredRows);
408c=find(~coveredCols);
409
410% Get minimum of uncovered elements.
411m=min(min(A(r,c)));
412
413% Subtract minimum from all uncovered elements.
414A(r,c)=A(r,c)-m;
415
416% Check all uncovered columns..
417for j=c
418 % ...and uncovered rows in path order..
419 for i=SLR
420 % If this is a (new) zero..
421 if (A(i,j)==0)
422 % If the row is not in unexplored list..
423 if (RH(i)==0)
424 % ...insert it first in unexplored list.
425 RH(i)=RH(n+1);
426 RH(n+1)=i;
427 % Mark this zero as "next free" in this row.
428 CH(i)=j;
429 end
430 % Find last unassigned zero on row I.
431 row=A(i,:);
432 colsInList=-row(row<0);
433 if (length(colsInList)==0)
434 % No zeros in the list.
435 l=n+1;
436 else
437 l=colsInList(row(colsInList)==0);
438 end
439 % Append this zero to end of list.
440 A(i,l)=-j;
441 end
442 end
443end
444
445% Add minimum to all doubly covered elements.
446r=find(coveredRows);
447c=find(coveredCols);
448
449% Take care of the zeros we will remove.
450[i,j]=find(A(r,c)<=0);
451
452i=r(i);
453j=c(j);
454
455for k=1:length(i)
456 % Find zero before this in this row.
457 lj=find(A(i(k),:)==-j(k));
458 % Link past it.
459 A(i(k),lj)=A(i(k),j(k));
460 % Mark it as assigned.
461 A(i(k),j(k))=0;
462end
463
464A(r,c)=A(r,c)+m;
diff --git a/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/test.m b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/test.m
new file mode 100755
index 0000000..4c238f2
--- /dev/null
+++ b/SD-VBS/common/toolbox/toolbox_basic/matching/pub/contrib/v5/optim/assignprob/test.m
@@ -0,0 +1,87 @@
1disp('Testing hungarian...');
2A=magic(10);
3B=A(4:7,4:7);
4[c,t]=hungarian(B);
5if (any(c~=[2 1 3 4]))
6 disp('Wrong coupling!');
7elseif (t~=77)
8 disp('Wrong solution!');
9else
10 disp('Hungarian appears OK.');
11end
12
13disp('Testing condass...');
14[k,c1,t1,c2,t2]=condass(B);
15if (any(c1~=[2 1 3 4]))
16 disp('Wrong best coupling!');
17elseif (t1~=77)
18 disp('Wrong lowest cost!');
19elseif (any(c2~=[1 2 3 4]))
20 disp('Wrong second best coupling!');
21elseif (t2~=102)
22 disp('Wrong second lowest cost!');
23elseif (k~=t1/(t2-t1))
24 disp('Wrong condition number!');
25else
26 disp('condass appears OK.');
27end
28
29disp('Testing allcosts...');
30[c,p]=allcosts(B);
31cTrue=[ 102
32 127
33 202
34 227
35 222
36 222
37 77
38 102
39 182
40 202
41 202
42 197
43 177
44 202
45 182
46 202
47 302
48 297
49 202
50 202
51 207
52 202
53 307
54 302
55];
56pTrue=[ 1 2 3 4
57 1 2 4 3
58 1 3 2 4
59 1 3 4 2
60 1 4 2 3
61 1 4 3 2
62 2 1 3 4
63 2 1 4 3
64 2 3 1 4
65 2 3 4 1
66 2 4 1 3
67 2 4 3 1
68 3 1 2 4
69 3 1 4 2
70 3 2 1 4
71 3 2 4 1
72 3 4 1 2
73 3 4 2 1
74 4 1 2 3
75 4 1 3 2
76 4 2 1 3
77 4 2 3 1
78 4 3 1 2
79 4 3 2 1
80 ];
81if (any(c~=cTrue))
82 disp('Wrong costs!');
83elseif (any(p~=pTrue))
84 disp('Wrong permutations!');
85else
86 disp('allcosts appears OK.');
87end