File Coverage

blib/lib/Math/MVPoly/Polynomial.pm
Criterion Covered Total %
statement 265 362 73.2
branch 49 58 84.4
condition 3 3 100.0
subroutine 25 27 92.5
pod 23 24 95.8
total 365 474 77.0


line stmt bran cond sub pod time code
1             package Math::MVPoly::Polynomial;
2            
3             # Copyright (c) 1998 by Brian Guarraci. All rights reserved.
4             # This program is free software; you can redistribute it and/or modify it
5             # under the same terms as Perl itself.
6            
7 1     1   6 use strict;
  1         3  
  1         30  
8 1     1   655 use Math::MVPoly::Monomial;
  1         4  
  1         30  
9 1     1   9 use Math::MVPoly::Integer;
  1         2  
  1         3371  
10            
11             $Math::MVPoly::VERSION = '0.2b';
12            
13             sub
14             new
15             {
16 69     69 1 79 my $self;
17             my $m;
18            
19 69         93 $self = {};
20            
21 69         155 $self->{MONOMIALS} = [];
22 69         113 $self->{MONORDER} = 'grlex';
23 69         97 $self->{VARORDER} = [];
24 69         93 $self->{VERBOSE} = 0;
25            
26 69         81 bless($self); # but see below
27 69         114 return $self;
28             }
29            
30             sub
31             copy
32             {
33 26     26 1 35 my $self = shift;
34 26         29 my $p = shift;
35 26         27 my $monomials;
36             my $varOrder;
37 0         0 my $copy_monomials;
38 0         0 my $copy_varOrder;
39 0         0 my $copy_order;
40 0         0 my $m;
41 0         0 my $f;
42            
43 26         49 $copy_order = $p->monOrder();
44 26         54 $self->monOrder($copy_order);
45            
46 26         47 $monomials = $p->monomials();
47 26         44 $copy_monomials = [@$monomials];
48 26         45 $self->monomials($copy_monomials);
49            
50 26         51 $varOrder = $p->varOrder();
51 26         47 $copy_varOrder = [@$varOrder];
52 26         52 $self->varOrder($copy_varOrder);
53            
54 26         42 return $self;
55             }
56            
57             sub
58             monOrder
59             {
60 302     302 1 525 my $self = shift;
61 302 100       542 if (@_)
62             {
63 64         124 $self->{MONORDER} = shift;
64             }
65 302         766 return($self->{MONORDER});
66             }
67            
68             sub
69             verbose
70             {
71 83     83 0 97 my $self = shift;
72 83 100       153 if (@_)
73             {
74 17         28 $self->{VERBOSE} = shift;
75             }
76 83         232 return($self->{VERBOSE});
77             }
78            
79             sub
80             varOrder
81             {
82 108     108 1 128 my $self = shift;
83 108 100       213 if (@_)
84             {
85 54         82 $self->{VARORDER} = shift;
86             }
87 108         216 return($self->{VARORDER});
88             }
89            
90             sub
91             monomials
92             {
93 733     733 1 857 my $self = shift;
94 733 100       1304 if (@_)
95             {
96 336         504 $self->{MONOMIALS} = shift;
97             }
98 733         1565 return($self->{MONOMIALS});
99             }
100            
101             sub
102             insertMonomial
103             {
104 84     84 1 106 my $self = shift;
105 84         90 my $m = shift;
106 84         73 my $monomials;
107            
108 84         131 $monomials = $self->monomials();
109            
110 84         134 push(@$monomials, $m);
111            
112 84         156 $self->simplify();
113 84         183 $self->applyOrder();
114             }
115            
116             sub
117             simplify
118             {
119 84     84 1 88 my $self = shift;
120 84         80 my $monomials;
121             my %hash;
122 0         0 my $m;
123 0         0 my $hm;
124 0         0 my $f;
125 0         0 my $sig;
126            
127 84         121 $monomials = $self->monomials();
128            
129 84         128 foreach $m (@$monomials)
130             {
131 154         429 $sig = $m->getSignature();
132            
133 154 100       299 if (exists($hash{$sig}))
134             {
135 10         16 $hm = $hash{$sig};
136 10         32 $hm = $hm->add($m);
137 10         20 $hash{$sig} = $hm;
138            
139 10 50       26 if ($hm->coefficient() == 0)
140             {
141 10         24 delete $hash{$sig};
142 10         26 next;
143             }
144             else
145             {
146             }
147             }
148             else
149             {
150 144         272 $hash{$sig} = $m;
151             }
152            
153 144         328 $m->reduceCoefficient();
154             }
155            
156 84         180 $monomials = [values %hash];
157            
158 84         206 $self->monomials($monomials);
159             }
160            
161             sub
162             fromString
163             {
164 9     9 1 11 my $self = shift;
165 9         13 my $eq = shift;
166 9         36 my $m;
167             my $pat;
168 0         0 my @parts;
169 0         0 my $f;
170 0         0 my $varOrder;
171            
172 9         13 $_ = $eq;
173            
174 9         16 s/\s//g; # remove all white space
175 9         23 s/\+/\ \+/g; # move a space in front of all +'s
176 9         22 s/\-/\ \-/g; # move a space in front of all -'s
177            
178 9         26 @parts = grep {/\S/} split();
  23         136  
179            
180 9         20 $varOrder = $self->varOrder();
181            
182 9         16 foreach $f (@parts)
183             {
184 23         72 $m = Math::MVPoly::Monomial->new();
185 23         97 $m->varOrder([@$varOrder]);
186 23         56 $m->fromString($f);
187 23         52 $self->insertMonomial($m);
188             }
189             }
190            
191             sub
192             toString
193             {
194 17     17 1 22 my $self = shift;
195 17         20 my $s;
196             my $m;
197 0         0 my $sig;
198 0         0 my $monomials;
199            
200 17         32 $monomials = $self->monomials();
201            
202 17         23 $s = "";
203            
204            
205 17 50       41 if ($#$monomials < 0)
206             {
207 0         0 $s .= "0";
208             }
209             else
210             {
211 17         29 foreach $m (@$monomials)
212             {
213 49         101 $m->verbose($self->verbose());
214 49         124 $s .= $m->toString();
215             }
216            
217 17 50       39 if (! $self->verbose())
218             {
219 17 100       72 if ($s =~ /^\+/)
220             {
221 15         34 $s = substr($s,1);
222             }
223             }
224             }
225            
226 17         58 return $s;
227             }
228            
229             sub
230             applyOrder
231             {
232 113     113 1 122 my $self = shift;
233 113         141 my $monomials;
234             my @list;
235 0         0 my $f;
236 0         0 my $m;
237            
238 113         189 $monomials = $self->monomials();
239            
240 113         203 $self->monomials($monomials);
241            
242 113 100       202 if ($self->monOrder() eq 'lex')
    100          
    50          
    0          
243             {
244 19         60 $monomials = [sort SortByLexOrder @$monomials];
245             }
246             elsif ($self->monOrder() eq 'grlex')
247             {
248 89         273 $monomials = [sort SortByGrLex @$monomials];
249             }
250             elsif ($self->monOrder() eq 'grevlex')
251             {
252 5         16 $monomials = [sort SortByGrevLex @$monomials];
253             }
254             elsif ($self->monOrder() eq 'tdeg')
255             {
256 0         0 $monomials = [sort SortByTotalDegree @$monomials];
257             }
258            
259 113         257 $self->monomials($monomials);
260             }
261            
262             sub
263             SortByLexOrder
264             {
265 48     48 1 49 my $left;
266             my $right;
267 0         0 my $varOrder;
268 0         0 my $a_vars;
269 0         0 my $b_vars;
270 0         0 my $f;
271            
272             # proceed down the variable order to perform lex order
273 48         122 $varOrder = $a->varOrder();
274            
275 48         116 $a_vars = $a->variables();
276 48         104 $b_vars = $b->variables();
277            
278 48         53 $left = 0;
279 48         56 $right = 0;
280            
281 48         59 foreach $f (@$varOrder)
282             {
283 64 100       153 if ($a_vars->{$f} != $b_vars->{$f})
284             {
285 48 100       95 if ($a_vars->{$f} > $b_vars->{$f})
286             {
287 25         28 $right = 1;
288             }
289             else
290             {
291 23         28 $left = 1;
292             }
293 48         55 last;
294             }
295             }
296            
297 48         95 $left <=> $right;
298             }
299            
300             sub
301             SortByGrevLex
302             {
303 17     17 1 16 my $left;
304             my $right;
305 0         0 my $varOrder;
306 0         0 my $a_vars;
307 0         0 my $b_vars;
308 0         0 my $f;
309            
310 17         39 $left = $b->getTotalDegree();
311 17         39 $right = $a->getTotalDegree();
312            
313 17 100       40 if ($b->getTotalDegree() == $a->getTotalDegree())
314             {
315             # proceed down the variable order to perform lex order
316 4         14 $varOrder = $a->varOrder();
317            
318 4         14 $a_vars = $a->variables();
319 4         11 $b_vars = $b->variables();
320            
321 4         5 $left = 0;
322 4         6 $right = 0;
323            
324 4         8 foreach $f (@$varOrder)
325             {
326 6 100       17 if ($a_vars->{$f} != $b_vars->{$f})
327             {
328 4 100       11 if ($a_vars->{$f} < $b_vars->{$f})
329             {
330 2         4 $right = 1;
331             }
332             else
333             {
334 2         3 $left = 1;
335             }
336 4         7 last;
337             }
338             }
339             }
340            
341 17         32 $left <=> $right;
342             }
343            
344             sub
345             SortByGrLex
346             {
347 73     73 1 76 my $left;
348             my $right;
349 0         0 my $varOrder;
350 0         0 my $a_vars;
351 0         0 my $b_vars;
352 0         0 my $f;
353            
354 73         175 $left = $b->getTotalDegree();
355 73         163 $right = $a->getTotalDegree();
356            
357 73 100       209 if ($b->getTotalDegree() == $a->getTotalDegree())
358             {
359             # proceed down the variable order to perform lex order
360 17         42 $varOrder = $a->varOrder();
361            
362 17         39 $a_vars = $a->variables();
363 17         40 $b_vars = $b->variables();
364            
365 17         19 $left = 0;
366 17         16 $right = 0;
367            
368 17         26 foreach $f (@$varOrder)
369             {
370 21 100       49 if ($a_vars->{$f} != $b_vars->{$f})
371             {
372 17 100       37 if ($a_vars->{$f} > $b_vars->{$f})
373             {
374 11         14 $right = 1;
375             }
376             else
377             {
378 6         8 $left = 1;
379             }
380 17         25 last;
381             }
382             }
383             }
384            
385 73         253 $left <=> $right;
386             }
387            
388             sub
389             SortByTotalDegree
390             {
391 0     0 1 0 $b->getTotalDegree() <=> $a->getTotalDegree();
392             }
393            
394             sub
395             getLT
396             {
397 26     26 1 35 my $self = shift;
398 26         27 my $m;
399             my $monomials;
400            
401 26         45 $monomials = $self->monomials();
402 26         78 $m = Math::MVPoly::Monomial->new();
403 26         71 $m->copy($$monomials[0]);
404            
405 26         47 return($m);
406             }
407            
408             sub
409             isNotZero
410             {
411 12     12 1 17 my $self = shift;
412 12         15 my $g = shift;
413 12         10 my $flag;
414             my $monomials;
415            
416 12         24 $monomials = $self->monomials();
417            
418 12         15 $flag = 0;
419            
420 12 100       49 if ($#$monomials >= 0)
421             {
422 8         11 $flag = 1;
423             }
424            
425 12         35 return($flag);
426             }
427            
428             sub
429             mult
430             {
431 8     8 1 14 my $self = shift;
432 8         8 my $q = shift;
433 8         10 my $myMonomials;
434             my $monomials;
435 0         0 my $f;
436 0         0 my $p;
437 0         0 my $z;
438 0         0 my $m;
439            
440 8         20 $p = Math::MVPoly::Polynomial->new();
441            
442 8         17 $myMonomials = $self->monomials();
443            
444 8 100       23 if (ref($q) eq "Math::MVPoly::Monomial")
445             {
446 7         12 $f = $q;
447 7         14 $q = Math::MVPoly::Polynomial->new();
448 7         12 $q->insertMonomial($f);
449             }
450            
451 8         26 $monomials = $q->monomials();
452            
453 8         15 foreach $f (@$myMonomials)
454             {
455 16         26 foreach $m (@$monomials)
456             {
457 17         46 $z = $f->mult($m);
458 17         35 $p->insertMonomial($z);
459             }
460             }
461            
462 8         30 return $p;
463             }
464            
465             sub
466             add
467             {
468 10     10 1 17 my $self = shift;
469 10         72 my $q = shift;
470 10         13 my $p;
471             my $monomials;
472 0         0 my $f;
473 0         0 my $m;
474            
475 10         23 $p = Math::MVPoly::Polynomial->new();
476 10         23 $p->copy($self);
477            
478 10 100       28 if (ref($q) eq "Math::MVPoly::Monomial")
479             {
480 9         11 $f = $q;
481 9         18 $q = Math::MVPoly::Polynomial->new();
482 9         20 $q->insertMonomial($f);
483             }
484            
485 10         22 $monomials = $q->monomials();
486            
487 10         18 foreach $f (@$monomials)
488             {
489 11         30 $m = Math::MVPoly::Monomial->new();
490 11         30 $m->copy($f);
491 11         23 $p->insertMonomial($f);
492             }
493            
494 10         54 return $p;
495             }
496            
497             sub
498             subtract
499             {
500 9     9 1 13 my $self = shift;
501 9         9 my $q = shift;
502 9         12 my $p;
503             my $monomials;
504 0         0 my $f;
505 0         0 my $neg;
506 0         0 my $m;
507            
508 9         21 $p = Math::MVPoly::Polynomial->new();
509 9         19 $p->copy($self);
510            
511 9 100       26 if (ref($q) eq "Math::MVPoly::Monomial")
512             {
513 4         7 $f = $q;
514 4         11 $q = Math::MVPoly::Polynomial->new();
515 4         9 $q->insertMonomial($f);
516             }
517            
518 9         17 $monomials = $q->monomials();
519            
520 9         32 $neg = Math::MVPoly::Monomial->new();
521 9         26 $neg->fromString("-1");
522            
523 9         20 foreach $f (@$monomials)
524             {
525 13         64 $m = $f->mult($neg);
526 13         37 $p->insertMonomial($m);
527             }
528            
529 9         51 return($p);
530             }
531            
532             sub
533             divide
534             {
535 3     3 1 4 my $self = shift;
536 3         5 my $ft = shift;
537 3         5 my $divisionOccured;
538             my $lt_p;
539 0         0 my $lt_fi;
540 0         0 my $at;
541 0         0 my $m;
542 0         0 my $z;
543 0         0 my $q;
544 0         0 my $r;
545 0         0 my $p;
546 0         0 my $s;
547 0         0 my $i;
548            
549 3 50       10 if (ref($ft) ne "ARRAY")
550             {
551 3         6 $ft = [$ft];
552             }
553            
554 3         5 $s = $#$ft;
555 3         5 $at = [];
556            
557             # initialize the output variables
558 3         6 foreach $i (0..$s)
559             {
560 3         10 push(@$at, Math::MVPoly::Polynomial->new());
561             }
562 3         8 $r = Math::MVPoly::Polynomial->new();
563            
564 3         8 $p = Math::MVPoly::Polynomial->new();
565 3         8 $p->copy($self); # f is $self
566            
567 3         8 while($p->isNotZero())
568             {
569 7         11 $i = 0;
570 7         9 $divisionOccured = 0;
571            
572 7   100     40 while($i <= $s && !$divisionOccured)
573             {
574 7         23 $lt_fi = $$ft[$i]->getLT();
575 7         24 $lt_p = $p->getLT();
576 7 100       25 if ($lt_fi->canDivide($lt_p))
577             {
578 3         12 $m = $lt_p->divide($lt_fi);
579 3         11 $$at[$i] = $$at[$i]->add($m);
580 3         11 $z = $$ft[$i]->mult($m);
581 3         9 $p = $p->subtract($z);
582 3         22 $divisionOccured = 1;
583             }
584             else
585             {
586 4         12 $i++;
587             }
588             }
589 7 100       19 if (! $divisionOccured)
590             {
591 4         8 $z = $p->getLT();
592 4         15 $r = $r->add($z);
593 4         14 $p = $p->subtract($z);
594             }
595             }
596            
597 3         28 return [@$at,$r];
598             }
599            
600             sub
601             gcd
602             {
603 1     1 1 2 my $self = shift;
604 1         2 my $g = shift;
605 1         1 my $h;
606             my $e;
607 0         0 my $s;
608 0         0 my $i;
609 0         0 my $r;
610            
611 1         4 $h = Math::MVPoly::Polynomial->new();
612 1         3 $h->copy($self);
613            
614 1         3 $s = Math::MVPoly::Polynomial->new();
615 1         3 $s->copy($g);
616            
617 1         4 while($s->isNotZero())
618             {
619 1         4 $e = $h->divide($s);
620 1         3 $r = $$e[1];
621 1         4 $h->copy($s);
622 1         3 $s->copy($r);
623             }
624            
625 1         7 return ($h)
626             }
627            
628             sub
629             reduce
630             {
631 0     0 1 0 my $self = shift;
632 0         0 my $monomials;
633             my $m;
634 0         0 my $numerGCD;
635 0         0 my $denomGCD;
636 0         0 my $i;
637 0         0 my $j;
638 0         0 my $r;
639 0         0 my $z;
640 0         0 my $np;
641 0         0 my $np2;
642 0         0 my $n;
643            
644             # reduction goals:
645             #
646             # try to get as many 1's as coefficients as possible
647             # make the coefficient of the first monomial (if more than one) > 0
648             #
649             # ASIDE: there is a lot of work being done here...but this is no trivial task
650             # to reduce a polynomial into a simpler form
651             #
652            
653 0         0 $monomials = $self->monomials();
654            
655             # determine the gcd for the numerators and denominators
656 0         0 $m = $$monomials[0];
657 0         0 ($i,$j) = $m->coeff_to_ND();
658 0         0 $numerGCD = $i;
659 0         0 $denomGCD = $j;
660            
661 0         0 foreach $m (@$monomials[1..$#$monomials])
662             {
663 0         0 ($i,$j) = $m->coeff_to_ND();
664 0         0 $numerGCD = Integer::gcd($numerGCD, $i);
665 0         0 $denomGCD = Integer::gcd($denomGCD, $j);
666             }
667            
668 0         0 $z = Math::MVPoly::Monomial->new();
669 0         0 $z->coeff_from_ND(1,$numerGCD);
670 0         0 $np = Math::MVPoly::Polynomial->new();
671            
672             # divide through by the numerator gcd
673 0         0 foreach $m (@$monomials)
674             {
675 0         0 $n = $m->mult($z);
676 0         0 $np = $np->add($n);
677             }
678            
679 0         0 $z = Math::MVPoly::Monomial->new();
680 0         0 $z->coefficient($denomGCD);
681            
682 0         0 $np2 = Math::MVPoly::Polynomial->new();
683            
684 0         0 $monomials = $np->monomials();
685            
686             # multiply through by the denominator gcd
687 0         0 foreach $m (@$monomials)
688             {
689 0         0 $n = $m->mult($z);
690 0         0 $np2 = $np2->add($n);
691             }
692            
693             # see if the first coefficient is > 0
694 0         0 $m = $np2->getLT();
695            
696 0 0       0 if ($m->coefficient() < 0)
697             {
698 0         0 $z = Math::MVPoly::Monomial->new();
699 0         0 $z->fromString("-1");
700 0         0 $np2 = $np2->mult($z);
701             }
702            
703 0         0 $self->copy($np2);
704             }
705            
706             sub
707             spoly
708             {
709 2     2 1 4 my $self = shift;
710 2         4 my $g = shift;
711 2         3 my $lcm;
712             my $q;
713 0         0 my $p1;
714 0         0 my $p2;
715 0         0 my $spoly;
716 0         0 my $lt_g;
717 0         0 my $lt_f;
718 0         0 my $f;
719            
720             #
721             # S(f,g) = (x^l/LT(f))*f - (x^l/LT(g))*g
722             #
723             # where x is a monomial with coefficients l, the LCM of LT(g) and LT(f) where
724             #
725             # l(i) = max(a(i), B(i)), a = LT(f), B = LT(g), and i is the ith exponent
726             #
727            
728 2         4 $f = $self;
729            
730 2         5 $lt_f = $f->getLT();
731 2         4 $lt_g = $g->getLT();
732            
733 2         6 $lcm = $lt_f->getLCM($lt_g);
734            
735 2         9 $q = $lcm->divide($lt_f);
736 2         12 $p1 = $f->mult($q);
737            
738 2         5 $q = $lcm->divide($lt_g);
739 2         8 $p2 = $g->mult($q);
740            
741 2         8 $spoly = $p1->subtract($p2);
742            
743 2         38 return $spoly;
744             }
745            
746             1;
747            
748             __END__