File Coverage

blib/lib/PDL/EditDistance.pm
Criterion Covered Total %
statement 65 75 86.6
branch 20 52 38.4
condition 0 6 0.0
subroutine 18 19 94.7
pod 11 11 100.0
total 114 163 69.9


line stmt bran cond sub pod time code
1              
2             #
3             # GENERATED WITH PDL::PP! Don't modify!
4             #
5             package PDL::EditDistance;
6              
7             @EXPORT_OK = qw( edit_costs _edit_costs edit_costs_static edit_distance_full _edit_distance_full PDL::PP _edit_distance_full edit_align_full _edit_align_full PDL::PP _edit_align_full edit_distance_static _edit_distance_static PDL::PP _edit_distance_static edit_align_static _edit_align_static PDL::PP _edit_align_static align_op_insert1 PDL::PP align_op_insert1 align_op_insert2 PDL::PP align_op_insert2 align_op_match PDL::PP align_op_match align_op_substitute PDL::PP align_op_substitute align_op_insert align_op_delete align_ops edit_bestpath _edit_bestpath PDL::PP _edit_bestpath edit_pathtrace _edit_pathtrace PDL::PP _edit_pathtrace edit_lcs _edit_lcs PDL::PP _edit_lcs lcs_backtrace _lcs_backtrace PDL::PP _lcs_backtrace );
8             %EXPORT_TAGS = (Func=>[@EXPORT_OK]);
9              
10 2     2   651380 use PDL::Core;
  2         7  
  2         13  
11 2     2   701 use PDL::Exporter;
  2         3  
  2         14  
12 2     2   53 use DynaLoader;
  2         9  
  2         149  
13              
14              
15              
16             $PDL::EditDistance::VERSION = 0.07;
17             @ISA = ( 'PDL::Exporter','DynaLoader' );
18             push @PDL::Core::PP, __PACKAGE__;
19             bootstrap PDL::EditDistance $VERSION;
20              
21              
22              
23              
24 2     2   11 use strict;
  2         3  
  2         56  
25 2     2   1573 use version;
  2         4779  
  2         12  
26              
27             ## $PDL_ATLEAST_2_014 : avoid in-place reshape() in _edit_pdl() for PDL >= 2.014
28             ## + prior to PDL-2.014, PDL::reshape() returned a new PDL, but modifies
29             ## the calling object in-place for v2.014
30             our $PDL_ATLEAST_2_014 = version->parse($PDL::VERSION) >= version->parse("2.014");
31              
32             =pod
33              
34             =head1 NAME
35              
36             PDL::EditDistance - Wagner-Fischer edit distance and alignment for PDLs.
37              
38             =head1 SYNOPSIS
39              
40             use PDL;
41             use PDL::EditDistance;
42              
43             ##-- input PDLs
44             $a = pdl([map { ord($_) } qw(G U M B O)]);
45             $b = pdl([map { ord($_) } qw(G A M B O L)]);
46              
47             $a1 = pdl([0, map { ord($_) } qw(G U M B O)]);
48             $b1 = pdl([0, map { ord($_) } qw(G A M B O L)]);
49              
50             ##-------------------------------------------------------------
51             ## Levenshtein distance
52             $dist = edit_distance_static($a,$b, 0,1,1,1);
53             ($dist,$align) = edit_align_static($a,$b, 0,1,1,1);
54              
55             ##-------------------------------------------------------------
56             ## Wagner-Fischer distance
57             @costs = ($costMatch=0,$costInsert=1,$costDelete=1,$costSubstitute=2);
58             $dist = edit_distance_static($a,$b, @costs);
59             ($dist,$align) = edit_align_static($a,$b, @costs);
60              
61             ##-------------------------------------------------------------
62             ## General edit distance
63             $costsMatch = random($a->nelem+1, $b->nelem+1);
64             $costsIns = random($a->nelem+1, $b->nelem+1);
65             $costsDel = random($a->nelem+1, $b->nelem+1);
66             $costsSubst = random($a->nelem+1, $b->nelem+1);
67             @costs = ($costsMatch,$costsIns,$costDel,$costsSubst);
68             $dist = edit_distance_full($a,$b,@costs);
69             ($dist,$align) = edit_align_full($a,$b,@costs);
70              
71             ##-------------------------------------------------------------
72             ## Alignment
73             $op_match = align_op_match(); ##-- constant
74             $op_del = align_op_insert1(); ##-- constant
75             $op_ins = align_op_insert2(); ##-- constant
76             $op_subst = align_op_substitute(); ##-- constant
77              
78             ($apath,$bpath,$pathlen) = edit_bestpath($align);
79             ($ai,$bi,$ops,$pathlen) = edit_pathtrace($align);
80              
81             ##-------------------------------------------------------------
82             ## Longest Common Subsequence
83             $lcs = edit_lcs($a,$b);
84             ($ai,$bi,$lcslen) = lcs_backtrace($a,$b,$lcs);
85              
86             =cut
87              
88              
89              
90              
91              
92              
93              
94             =head1 FUNCTIONS
95              
96              
97              
98             =cut
99              
100              
101              
102              
103              
104              
105             =pod
106              
107             =head2 _edit_pdl
108              
109             =for sig
110              
111             Signature: (a(N); [o]apdl(N+1))
112              
113             Convenience method.
114             Returns a pdl $apdl() suitable for representing $a(),
115             which can be specified as a UTF-8 or byte-string, as an arrays of numbers, or as a PDL.
116             $apdl(0) is always set to zero.
117              
118             =cut
119              
120             sub _edit_pdl {
121 20 100   20   168835 if (UNIVERSAL::isa($_[0],'PDL')) {
    100          
122 17 50       80 return ($PDL_ATLEAST_2_014 ? $_[0]->pdl : $_[0])->flat->reshape($_[0]->nelem+1)->rotate(1);
123             }
124             #return pdl(byte,[0, map { ord($_) } split(//,$_[0])]) if (!ref($_[0]) && !utf8::is_utf8($_[0])); ##-- byte-string (old)
125             elsif (!ref($_[0])) {
126 2 100       13 return pdl(long,[0, unpack('C0C*',$_[0])]) if (utf8::is_utf8($_[0])); ##-- utf8-string
127 1         5 return pdl(byte,[0, unpack('U0C*',$_[0])]); ##-- byte-string
128             }
129 1         3 return pdl([0,@{$_[0]}]);
  1         4  
130             }
131              
132              
133              
134              
135              
136             =pod
137              
138             =head2 edit_costs
139              
140             =for sig
141              
142             Signature: (PDL::Type type; int N; int M;
143             [o]costsMatch(N+1,M+1); [o]costsIns(N+1,M+1); [o]costsDel(N+1,M+1); [o]costsSubst(N+1,M+1))
144              
145             Convenience method.
146             Ensures existence and proper dimensionality of cost matrices for inputs
147             of length N and M.
148              
149             =cut
150              
151             sub edit_costs {
152 3     3 1 12 return _edit_costs($_[0],$_[1]+1,$_[2]+1,@_[3..$#_]);
153             }
154              
155              
156              
157              
158              
159             =pod
160              
161             =head2 _edit_costs
162              
163             =for sig
164              
165             Signature: (PDL::Type type; int N1; int M1;
166             [o]costsMatch(N1,M1); [o]costsIns(N1,M1); [o]costsDel(N1,M1); [o]costsSubst(N1,M1))
167              
168             Low-level method.
169             Ensures existence and proper dimensionality of cost matrices for inputs
170             of length N1-1 and M1-1.
171              
172             =cut
173              
174             sub _edit_costs {
175             #my ($type,$n1,$m1,$costsMatch,$costsIns,$costsDel,$costsSubst) = @_;
176 3     3   12 return (_edit_matrix(@_[0..2],$_[3]),
177             _edit_matrix(@_[0..2],$_[4]),
178             _edit_matrix(@_[0..2],$_[5]),
179             _edit_matrix(@_[0..2],$_[6]));
180             }
181              
182             ##-- $matrix = _edit_matrix($type,$dim0,$dim1,$mat)
183             sub _edit_matrix {
184 12 50   12   557 return zeroes(@_[0..2]) if (!defined($_[3]));
185 0 0 0     0 $_[3]->reshape(@_[1,2]) if ($_[3]->ndims != 2 || $_[3]->dim(0) != $_[1] || $_[3]->dim(1) != $_[2]);
      0        
186 0 0       0 return $_[3]->type == $_[0] ? $_[3] : $_[3]->convert($_[0]);
187             }
188              
189              
190              
191              
192             =pod
193              
194             =head2 edit_costs_static
195              
196             =for sig
197              
198             Signature: (PDL::Type type; int N; int M;
199             staticCostMatch(); staticCostIns(); staticCostSubst();
200             [o]costsMatch(N+1,M+1); [o]costsIns(N+1,M+1); [o]costsDel(N+1,M+1); [o]costsSubst(N+1,M+1))
201              
202             Convenience method.
203              
204             =cut
205              
206             sub edit_costs_static {
207             #my ($type,$n,$m, $cMatch,$cIns,$cDel,$cSubst, $costsMatch,$costsIns,$costsDel,$costsSubst) = @_;
208 3     3 1 1570 my @costs = edit_costs(@_[0..2],@_[7..$#_]);
209 3         161 $costs[$_] .= $_[$_+3] foreach (0..3);
210 3         199 return @costs;
211             }
212              
213              
214              
215              
216             =pod
217              
218             =head2 edit_distance_full
219              
220             =for sig
221              
222             Signature: (a(N); b(M);
223             costsMatch(N+1,M+1); costsIns(N+1,M+1); costsDel(N+1,M+1); costsSubst(N+1,M+1);
224             [o]dist(N+1,M+1); [o]align(N+1,M+1))
225              
226             Convenience method.
227             Compute the edit distance matrix for inputs $a() and $b(), and
228             cost matrices $costsMatch(), $costsIns(), $costsDel(), and $costsSubst().
229             $a() and $b() may be specified as PDLs, arrays of numbers, or as strings.
230              
231             =cut
232              
233             sub edit_distance_full {
234 1     1 1 89 return _edit_distance_full(_edit_pdl($_[0]), _edit_pdl($_[1]), @_[2..$#_]);
235             }
236              
237              
238              
239              
240              
241             =head2 _edit_distance_full
242              
243             =for sig
244              
245             Signature: (a1(N1); b1(M1); costsMatch(N1,M1); costsIns(N1,M1); costsDel(N1,M1); costsSubst(N1,M1); [o]dist(N1,M1))
246              
247              
248             Low-level method.
249             Compute the edit distance matrix for input PDLs $a1() and $b1() and
250             cost matrices $costsMatch(), $costsIns(), $costsDel(), and $costsSubst().
251              
252             The first elements of $a1() and $b1() are ignored.
253              
254              
255             =for bad
256              
257             _edit_distance_full does not process bad values.
258             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
259              
260              
261             =cut
262              
263              
264              
265              
266              
267              
268             *_edit_distance_full = \&PDL::_edit_distance_full;
269              
270              
271              
272              
273             =pod
274              
275             =head2 edit_align_full
276              
277             =for sig
278              
279             Signature: (a(N); b(M);
280             costsMatch(N+1,M+1); costsIns(N+1,M+1); costsDel(N+1,N+1); costsSubst(N+1,M+1);
281             [o]dist(N+1,M+1); [o]align(N+1,M+1))
282              
283             Convenience method.
284             Compute the edit distance and alignment matrices for inputs $a() and $b(), and
285             cost matrices $costsMatch(), $costsIns(), $costsDel(), and $costsSubst().
286             $a() and $b() may be specified as PDLs, arrays of numbers, or as strings.
287              
288             =cut
289              
290             sub edit_align_full {
291 1     1 1 76 return _edit_align_full(_edit_pdl($_[0]), _edit_pdl($_[1]), @_[2..$#_]);
292             }
293              
294              
295              
296              
297              
298             =head2 _edit_align_full
299              
300             =for sig
301              
302             Signature: (a1(N1); b1(M1); costsMatch(N1,M1); costsIns(N1,M1); costsDel(N1,M1); costsSubst(N1,M1); [o]dist(N1,M1); byte [o]align(N1,M1))
303              
304              
305             Low-level method.
306             Compute the edit distance and alignment matrix for input PDLs $a1() and $b1() and
307             cost matrices $costsMatch(), $costsIns(), $costsDel(), and $costsSubst().
308              
309             The first elements of $a1() and $b1() are ignored.
310              
311              
312             =for bad
313              
314             _edit_align_full does not process bad values.
315             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
316              
317              
318             =cut
319              
320              
321              
322              
323              
324              
325             *_edit_align_full = \&PDL::_edit_align_full;
326              
327              
328              
329              
330             =pod
331              
332             =head2 edit_distance_static
333              
334             =for sig
335              
336             Signature: (a(N); b(M);
337             staticCostMatch(); staticCostIns(); staticCostDel(); staticCostSubst();
338             [o]dist(N+1,M+1))
339              
340             Convenience method.
341             Compute the edit distance matrix for inputs $a() and $b() given
342             a static cost schema @costs = ($staticCostMatch(), $staticCostIns(), $staticCostDel(), and $staticCostSubst()).
343             $a() and $b() may be specified as PDLs, arrays of numbers, or as strings.
344             Functionally equivalent to edit_distance_full($matches,@costs,$dist),
345             but slightly faster.
346              
347             =cut
348              
349             sub edit_distance_static {
350 1     1 1 938 return _edit_distance_static(_edit_pdl($_[0]), _edit_pdl($_[1]), @_[2..$#_]);
351             }
352              
353              
354              
355              
356              
357             =head2 _edit_distance_static
358              
359             =for sig
360              
361             Signature: (a1(N1); b1(M1); costMatch(); costIns(); costDel(); costSubst(); [o]dist(N1,M1))
362              
363              
364             Low-level method.
365             Compute the edit distance matrix for input PDLs $a1() and $b1() given a
366             static cost schema @costs = ($costMatch(), $costIns(), $costDel(), $costSubst()).
367             Functionally identitical to _edit_distance_matrix_full($matches,@costs,$dist),
368             but slightly faster.
369              
370             The first elements of $a1() and $b1() are ignored.
371              
372              
373             =for bad
374              
375             _edit_distance_static does not process bad values.
376             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
377              
378              
379             =cut
380              
381              
382              
383              
384              
385              
386             *_edit_distance_static = \&PDL::_edit_distance_static;
387              
388              
389              
390              
391             =pod
392              
393             =head2 edit_align_static
394              
395             =for sig
396              
397             Signature: (a(N); b(M);
398             staticCostMatch(); staticCostIns(); staticCostDel(); staticCostSubst();
399             [o]dist(N+1,M+1); [o]align(N+1,M+1))
400              
401             Convenience method.
402             Compute the edit distance and alignment matrices for inputs $a() and $b() given
403             a static cost schema @costs = ($staticCostMatch(), $staticCostIns(), $staticCostDel(), and $staticCostSubst()).
404             $a() and $b() may be specified as PDLs, arrays of numbers, or as strings.
405             Functionally equivalent to edit_align_full($matches,@costs,$dist),
406             but slightly faster.
407              
408             =cut
409              
410             sub edit_align_static {
411 3     3 1 2100 return _edit_align_static(_edit_pdl($_[0]), _edit_pdl($_[1]), @_[2..$#_]);
412             }
413              
414              
415              
416              
417              
418             =head2 _edit_align_static
419              
420             =for sig
421              
422             Signature: (a1(N1); b1(M1); costMatch(); costIns(); costDel(); costSubst(); [o]dist(N1,M1); byte [o]align(N1,M1))
423              
424              
425             Low-level method.
426             Compute the edit distance and alignment matrices for input PDLs $a1() and $b1() given a
427             static cost schema @costs = ($costMatch(), $costIns(), $costDel(), $costSubst()).
428             Functionally identitical to _edit_distance_matrix_full($matches,@costs,$dist),
429             but slightly faster.
430              
431             The first elements of $a1() and $b1() are ignored.
432              
433              
434             =for bad
435              
436             _edit_align_static does not process bad values.
437             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
438              
439              
440             =cut
441              
442              
443              
444              
445              
446              
447             *_edit_align_static = \&PDL::_edit_align_static;
448              
449              
450              
451              
452              
453             =head2 align_op_insert1
454              
455             =for sig
456              
457             Signature: ([o]a())
458              
459             =for ref
460              
461             Alignment matrix value constant for insertion operations on $a() string.
462              
463             =for bad
464              
465             align_op_insert1 does not process bad values.
466             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
467              
468              
469             =cut
470              
471              
472              
473              
474              
475              
476             *align_op_insert1 = \&PDL::align_op_insert1;
477              
478              
479              
480              
481              
482             =head2 align_op_insert2
483              
484             =for sig
485              
486             Signature: ([o]a())
487              
488             =for ref
489              
490             Alignment matrix value constant for insertion operations on $a() string.
491              
492             =for bad
493              
494             align_op_insert2 does not process bad values.
495             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
496              
497              
498             =cut
499              
500              
501              
502              
503              
504              
505             *align_op_insert2 = \&PDL::align_op_insert2;
506              
507              
508              
509              
510              
511             =head2 align_op_match
512              
513             =for sig
514              
515             Signature: ([o]a())
516              
517             =for ref
518              
519             Alignment matrix value constant for matches.
520              
521             =for bad
522              
523             align_op_match does not process bad values.
524             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
525              
526              
527             =cut
528              
529              
530              
531              
532              
533              
534             *align_op_match = \&PDL::align_op_match;
535              
536              
537              
538              
539              
540             =head2 align_op_substitute
541              
542             =for sig
543              
544             Signature: ([o]a())
545              
546             =for ref
547              
548             Alignment matrix value constant for substitution operations.
549              
550             =for bad
551              
552             align_op_substitute does not process bad values.
553             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
554              
555              
556             =cut
557              
558              
559              
560              
561              
562              
563             *align_op_substitute = \&PDL::align_op_substitute;
564              
565              
566              
567              
568             =pod
569              
570             =head2 align_op_delete
571              
572             Alias for align_op_insert1()
573              
574             =head2 align_op_insert
575              
576             Alias for align_op_insert2()
577              
578             =cut
579              
580             *align_op_delete = \&align_op_insert1;
581             *align_op_insert = \&align_op_insert2;
582              
583              
584              
585             =pod
586              
587             =head2 align_ops
588              
589             =for sig
590              
591             Signature: ([o]ops(4))
592              
593             Alignment matrix value constants 4-element pdl (match,insert1,insert2,substitute).a
594              
595             =cut
596              
597 0     0 1 0 sub align_ops { return PDL->sequence(PDL::byte(),4); }
598              
599              
600              
601              
602             =pod
603              
604             =head2 edit_bestpath
605              
606             =for sig
607              
608             Signature: (align(N+1,M+1); [o]apath(N+M+2); [o]bpath(N+M+2); [o]pathlen())
609              
610             Convenience method.
611             Compute best path through alignment matrix $align().
612             Stores paths for original input strings $a() and $b() in $apath() and $bpath()
613             respectively.
614             Negative values in $apath() and $bpath() indicate insertion/deletion operations.
615             On completion, $pathlen() holds the actual length of the paths.
616              
617             =cut
618              
619             sub edit_bestpath {
620 1     1 1 138 my ($align,$apath,$bpath,$len) = @_;
621 1 50       8 $len=pdl(long,$align->dim(0)+$align->dim(1)) if (!defined($len));
622 1 50       52 if (!defined($apath)) { $apath=zeroes(long,$len); }
  1         6  
623 0 0       0 else { $apath->reshape($len) if ($apath->nelem < $len); }
624 1 50       85 if (!defined($bpath)) { $bpath = zeroes(long,$len); }
  1         4  
625 0 0       0 else { $bpath->reshape($len) if ($bpath->nelem < $len); }
626 1         120 _edit_bestpath($align, $apath, $bpath, $len, $align->dim(0)-1, $align->dim(1)-1);
627 1         5 return ($apath,$bpath,$len);
628             }
629              
630              
631              
632              
633              
634             =head2 _edit_bestpath
635              
636             =for sig
637              
638             Signature: (align(N1,M1); int [o]apath(L); int [o]bpath(L); int [o]len(); int ifinal; int jfinal)
639              
640              
641             Low-level method.
642             Compute best path through alignment matrix $align() from final index ($ifinal,$jfinal).
643             Stores paths for (original) input strings $a() and $b() in $apath() and $bpath()
644             respectively.
645             Negative values in $apath() and $bpath() indicate insertion/deletion operations.
646             On completion, $pathlen() holds the actual length of the paths.
647              
648              
649             =for bad
650              
651             _edit_bestpath does not process bad values.
652             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
653              
654              
655             =cut
656              
657              
658              
659              
660              
661              
662             *_edit_bestpath = \&PDL::_edit_bestpath;
663              
664              
665              
666              
667             =pod
668              
669             =head2 edit_pathtrace
670              
671             =for sig
672              
673             Signature: ( align(N+1,M+1); [o]ai(L); [o]bi(L); [o]ops(L); [o]$pathlen() )
674              
675             Convenience method.
676             Compute alignment path backtrace through alignment matrix $align() from final index ($ifinal,$jfinal).
677             Stores raw paths for (original) input strings $a() and $b() in $ai() and $bi()
678             respectively.
679             Unlike edit_bestpath(), null-moves for $ai() and $bi() are not stored here as negative values.
680             Returned pdls ($ai,$bi,$ops) are trimmed to the appropriate path length.
681              
682             =cut
683              
684             sub edit_pathtrace {
685 1     1 1 145 my ($align,$ai,$bi,$ops,$len) = @_;
686 1 50       7 $len=pdl(long,$align->dim(0)+$align->dim(1)) if (!defined($len));
687 1 50       48 if (!defined($ai)) { $ai=zeroes(long,$len); }
  1         4  
688 0 0       0 else { $ai->reshape($len) if ($ai->nelem < $len); }
689 1 50       73 if (!defined($bi)) { $bi = zeroes(long,$len); }
  1         4  
690 0 0       0 else { $bi->reshape($len) if ($bi->nelem < $len); }
691 1 50       69 if (!defined($ops)) { $ops = zeroes(long,$len); }
  1         4  
692 0 0       0 else { $ops->reshape($len) if ($ops->nelem < $len); }
693 1         119 _edit_pathtrace($align, $ai,$bi,$ops,$len, $align->dim(0)-1,$align->dim(1)-1);
694 1         6 my $lens = ($len->sclr-1);
695 1         12 return ((map { $_->slice("0:$lens") } ($ai,$bi,$ops)), $len);
  3         37  
696             }
697              
698              
699              
700              
701              
702             =head2 _edit_pathtrace
703              
704             =for sig
705              
706             Signature: (align(N1,M1); int [o]ai(L); int [o]bi(L); int [o]ops(L); int [o]len(); int ifinal; int jfinal)
707              
708              
709             Low-level method.
710             Compute alignment path backtrace through alignment matrix $align() from final index ($ifinal,$jfinal).
711             Stores raw paths for (original) input strings $a() and $b() in $ai() and $bi()
712             respectively.
713             Unlike edit_bestpath(), null-moves for $ai() and $bi() are not stored here as negative values.
714             Returned pdls ($ai,$bi,$ops) are trimmed to the appropriate path length.
715              
716              
717             =for bad
718              
719             _edit_pathtrace does not process bad values.
720             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
721              
722              
723             =cut
724              
725              
726              
727              
728              
729              
730             *_edit_pathtrace = \&PDL::_edit_pathtrace;
731              
732              
733              
734              
735             =pod
736              
737             =head2 edit_lcs
738              
739             =for sig
740              
741             Signature: (a(N); b(M); int [o]lcs(N+1,M+1);)
742              
743             Convenience method.
744             Compute the longest common subsequence (LCS) matrix for input PDLs $a1() and $b1().
745             The output matrix $lcs() contains at cell ($i+1,$j+1) the length of the LCS
746             between $a1(0..$i) and $b1(0..$j); thus $lcs($N,$M) contains the
747             length of the LCS between $a() and $b().
748              
749             =cut
750              
751             sub edit_lcs {
752 1     1 1 436 return _edit_lcs(_edit_pdl($_[0]), _edit_pdl($_[1]), @_[2..$#_]);
753             }
754              
755              
756              
757              
758              
759             =head2 _edit_lcs
760              
761             =for sig
762              
763             Signature: (a1(N1); b1(M1); int [o]lcs(N1,M1))
764              
765              
766             Low-level method.
767             Compute the longest common subsequence (LCS) matrix for input PDLs $a1() and $b1().
768             The initial (zeroth) elements of $a1() and $b1() are ignored.
769             The output matrix $lcs() contains at cell ($i,$j) the length of the LCS
770             between $a1(1..$i) and $b1(1..$j); thus $lcs($N1-1,$M1-1) contains the
771             length of the LCS between $a1() and $b1().
772              
773              
774             =for bad
775              
776             _edit_lcs does not process bad values.
777             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
778              
779              
780             =cut
781              
782              
783              
784              
785              
786              
787             *_edit_lcs = \&PDL::_edit_lcs;
788              
789              
790              
791              
792             =pod
793              
794             =head2 lcs_backtrace
795              
796             =for sig
797              
798             Signature: (a(N); b(M); int lcs(N+1,M+1); int ifinal(); int jfinal(); int [o]ai(L); int [o]bi(L); int [o]len())
799              
800             Convenience method.
801             Compute longest-common-subsequence backtrace through LCS matrix $lcs()
802             for original input strings ($a(),$b()) from final index ($ifinal,$jfinal).
803             Stores raw paths for (original) input strings $a() and $b() in $ai() and $bi()
804             respectively.
805              
806             =cut
807              
808             sub lcs_backtrace {
809 1     1 1 158 my ($a,$b,$lcs,$ifinal,$jfinal,$ai,$bi,$len) = @_;
810 1 50       8 $len=pdl(long, pdl(long,$lcs->dims)->min) if (!defined($len));
811 1 50       151 if (!defined($ai)) { $ai=zeroes(long,$len); }
  1         4  
812 0 0       0 else { $ai->reshape($len) if ($ai->nelem < $len); }
813 1 50       74 if (!defined($bi)) { $bi = zeroes(long,$len); }
  1         4  
814 0 0       0 else { $bi->reshape($len) if ($bi->nelem < $len); }
815 1 50       72 if (!defined($ifinal)) { $ifinal = $lcs->dim(0)-1; }
  1         5  
816 1 50       4 if (!defined($jfinal)) { $jfinal = $lcs->dim(1)-1; }
  1         4  
817 1         3 _lcs_backtrace(_edit_pdl($a),_edit_pdl($b), $lcs,$ifinal,$jfinal, $ai,$bi,$len);
818 1         160 my $lens = ($len->sclr-1);
819 1         13 return ($ai->slice("0:$lens"),$bi->slice("0:$lens"), $len);
820             }
821              
822              
823              
824              
825              
826             =head2 _lcs_backtrace
827              
828             =for sig
829              
830             Signature: (a1(N1); b1(M1); int lcs(N1,M1); int ifinal(); int jfinal(); [o]ai(L); [o]bi(L); int [o]len())
831              
832              
833             Low-level method.
834             Compute longest-common-subsequence backtrace through LCS matrix $lcs()
835             for initial-padded strings ($a1(),$b1()) from final index ($ifinal,$jfinal).
836             Stores raw paths for (original) input strings $a() and $b() in $ai() and $bi()
837             respectively.
838              
839              
840             =for bad
841              
842             _lcs_backtrace does not process bad values.
843             It will set the bad-value flag of all output piddles if the flag is set for any of the input piddles.
844              
845              
846             =cut
847              
848              
849              
850              
851              
852              
853             *_lcs_backtrace = \&PDL::_lcs_backtrace;
854              
855              
856              
857              
858             ##---------------------------------------------------------------------
859             =pod
860              
861             =head1 ACKNOWLEDGEMENTS
862              
863             Perl by Larry Wall.
864              
865             PDL by Karl Glazebrook, Tuomas J. Lukka, Christian Soeller, and others.
866              
867             =cut
868              
869             ##----------------------------------------------------------------------
870             =pod
871              
872             =head1 KNOWN BUGS
873              
874             Probably many.
875              
876             =cut
877              
878              
879             ##---------------------------------------------------------------------
880             =pod
881              
882             =head1 AUTHOR
883              
884             Bryan Jurish Emoocow@cpan.orgE
885              
886             =head2 Copyright Policy
887              
888             Copyright (C) 2006-2015, Bryan Jurish. All rights reserved.
889              
890             This package is free software, and entirely without warranty.
891             You may redistribute it and/or modify it under the same terms
892             as Perl itself, either Perl 5.20.2, or at your option any later
893             version of Perl 5.
894              
895             =head1 SEE ALSO
896              
897             perl(1), PDL(3perl).
898              
899             =cut
900              
901              
902              
903             ;
904              
905              
906              
907             # Exit with OK status
908              
909             1;
910              
911