source: git/Singular/spSpolyLoop.pl @ 82ac59

spielwiese
Last change on this file since 82ac59 was 82ac59, checked in by Olaf Bachmann <obachman@…>, 26 years ago
* small bug fix git-svn-id: file:///usr/local/Singular/svn/trunk@1301 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100755
File size: 15.9 KB
Line 
1#!/usr/local/bin/perl
2###########################################################################
3# $Id: spSpolyLoop.pl,v 1.4 1998-03-31 12:18:51 obachman Exp $
4
5###########################################################################
6##
7## FILE: spSpolyLoops.pl
8## PURPOSE: Generates spSpolyLoop's and spGetSpolyLoop as specified by
9## variable @input. Writes result to stdout, warning/errors to stderr.
10## AUTHOR: obachman (3/98)
11##
12
13
14
15
16###########################################################################
17##
18## Supporting procedures
19##
20
21sub Warning
22{
23  print STDERR $_[0], "\n";
24}
25
26
27# Each occureence of CALL_<fn>(...) in $string is replaced by
28# `eval fn(..., $argv)'. Modified string is returned.
29sub Expand
30{
31  local($string, $argv) = @_;
32  local(@lines, @call, $call, $prefix, $postfix, $whitespaces, $result);
33  local($i, $j);
34
35  @lines = split(/\n/, $_[0]);
36  for ($i = 0; $i <= $#lines; $i++)
37  {
38    if ($lines[$i] =~ /CALL_/)
39    {
40      ($whitespaces, $prefix, $call, $postfix) = &ParseLine($lines[$i]);
41      #insert $argv as last argument to call
42      if ($call =~ /\(\s*\)$/)
43      {
44        $call =~ s/\(\s*\)$/\(\$argv\)/;
45      }
46      else
47      {
48        $call =~ s/\)$/\,\$argv\)/;
49      }
50      $call = "& ".$call.";";
51      $call = eval $call;
52      @call = split(/\n/,"$whitespaces$prefix$call$postfix");
53      for ($j=1; $j <= $#call; $j++)
54      {
55        $call[$j] = $whitespaces.$call[$j];
56      }
57      $lines[$i] = join("\n", @call);
58    }
59  }
60  $result = join("\n", @lines);
61  if ($call) 
62  {
63    return (&Expand($result));
64  }
65  else
66  {
67    return $result;
68  }
69}
70
71# takes a line containing CALL_ apart into and returns
72# ($whitespace, $prefix, $call, $postfix)
73sub ParseLine
74{
75  local($line) = @_;
76  local($i, $c_start, $c_length, $bcount);
77  local($whitespace, $prefix, $call, $postfix);
78 
79  while(substr($line, $i, 1) =~ /\s/ && $i <= length($line))
80  {
81    $whitespace = $whitespace.substr($line, $i, 1);
82    $i++;
83  }
84 
85  while(substr($line, $i) !~ /^CALL_/  && $i <= length($line))
86  {
87    $prefix = $prefix.substr($line, $i, 1);
88    $i++;
89  }
90 
91  $i = $i+5;
92  $c_start = $i;
93  while(substr($line, $i, 1) ne "(" && $i <= length($line))
94  {
95    $i++;
96  }
97  if (substr($line, $i, 1) eq "(")
98  {
99    $bcount = 1;
100    $i++;
101    while ($bcount > 0 && $i <= length($line))
102    {
103      if (substr($line, $i, 1) eq ")")
104      {
105        $bcount--;
106      }
107      elsif (substr($line, $i, 1) eq "(")
108      {
109        $bcount++;
110      }
111      elsif (substr($line, $i, 1) eq "\"")
112      {
113        $i++;
114        while ((substr($line, $i, 1) ne "\"" || 
115                substr($line, $i-1, 1) eq "\\") && 
116               $i <= length($line))
117        {
118          $i++;
119        }
120      }
121      $i++;
122    }
123  }
124  $call = substr($line, $c_start, $i - $c_start);
125  $postfix = substr($line, $i);
126  return ($whitespace, $prefix, $call, $postfix);
127}
128
129
130###########################################################################
131##
132## Specification of the properties which determine an spSpolyLoop
133##
134## Properties need to have following syntax: propVAL, where prop is
135## short "prefix" name of properties, and needs to be in lower caps, and
136## VAL is possible value and needs to be in all upper caps.
137##
138## Furthermore, observe the following conventions
139## @Protperty = ("propGEN", "propVAL1", ...)
140## $EnumType{prop} = Property
141## GetProperty($string) should always return a valid value.
142
143## need to hard-wire properties here, because they are needed in the interface to surrounding C++-code:
144
145@Properties = ("ch", "ot", "hom", "nw");
146@Characteristics = ("chGEN", "chMODP");
147$EnumType{"ch"} = "Characteristics";
148sub GetCharacteristic
149{
150  foreach $element (split('_', $_[0]))
151  {
152    return ($element) if ($element =~ /^ch/ && 
153                          grep(/$element/, @Characteristics));
154  }
155  return $Characteristics[0];
156}
157 
158@OrderingTypes = ("otGEN", "otEXP", "otCOMPEXP", "otEXPCOMP");
159$EnumType{"ot"} = "OrderingTypes";
160sub GetOrderingType
161{
162  foreach $element (split('_', $_[0]))
163  {
164    return ($element) if ($element =~ /^ot/ && 
165                         grep(/$element/, @OrderingTypes));
166  }
167  return $OrderingTypes[0];
168}
169
170@Homogs = ("homGEN", "homYES"); 
171$EnumType{"hom"} = "Homogs";
172sub GetHomog
173{
174  foreach $element (split('_', $_[0]))
175  {
176    return ($element) if ($element =~ /^hom/ &&
177                          grep(/$element/, @Homogs));
178  }
179  return $Homogs[0];
180}
181
182@NumWords = ("nwGEN", "nwONE", "nwTWO", "nwEVEN", "nwODD");
183$EnumType{"nw"} = "NumWords";
184sub GetNumWords
185{
186  foreach $element (split('_', $_[0]))
187  {
188    return ($element) if ($element =~ /^nw/ &&
189                          grep(/$element/, @NumWords));
190  }
191  return $NumWords[0];
192}
193
194# given a list of "short" prefix properties, generate enumeration type
195# specification for each property
196sub Generate_EnumTypes
197{
198  local(@evalues, $source);
199 
200  foreach $key (@_)
201  {
202    $etype = $EnumType{$key};
203    if ($etype =~ /\w+/)
204    {
205      @evalues = eval '@'.$etype;
206      if ($#evalues >= 0)
207      {
208        $source = $source."typedef enum $etype {". $evalues[0] . " = 0";
209        shift @evalues;
210        foreach $evalue (@evalues)
211        {
212          $source = $source.", $evalue";
213        }
214        $source = $source."} $etype;\n";
215      }
216      else
217      {
218        & Warning("No enum values for type: $etype");
219      }
220    }
221    else
222    {
223      & Warning("Unknown enumeration type index: $key");
224    }
225  }
226  return $source;
227}
228
229###########################################################################
230##
231## Template of the spSpolyLoop
232## Is modified by Expand
233##
234
235$spSpolyLoopBodyTemplate = <<_EOT_
236(poly a1, poly a2, poly monom, poly spNoether)
237{
238  poly a = monom,                         // collects the result
239       b = pNew(),                        // stores a1*monom
240       c;                                 // used for temporary storage
241  number tm   = pGetCoeff(monom),         // coefficient of monom
242         tneg = CALL_NCOPYNEG(tm),        // - (coefficient of monom)
243         tb;                              // used for tm*coeff(a1)
244  Order_t order;                          // used for homog case
245
246  if (a2==NULL) goto Finish;              // we are done if a2 is 0
247
248  CALL_INITORDER(order, a2);              // inits order for homog case
249 
250
251  CALL_PCOPYADDFAST(b, a1, monom, order);  // now a2 != NULL -- set up b
252
253  // MAIN LOOP:
254  Top:     // compare b = monom*a1 and a2 w.r.t. monomial ordering
255    register long d;
256    CALL_COMPARE(b, a2, d);
257
258  Equal:   // b equals a2
259//    assume(pComp0(b, a2) == 0);
260    if (pComp0(b, a2) != 0)
261    {
262       WarnS("Wrong comp in SpolyLoop\n");
263       pComp0(b,a2);
264    }
265
266    tb = CALL_NMULT("pGetCoeff(a1)",tm);
267    if (!CALL_NEQUAL("pGetCoeff(a2)",tb))
268    {
269      pSetCoeff0(a2,CALL_NSUB("pGetCoeff(a2)",tb)); // adjust coeff of a2
270      a = pNext(a) = a2; // append a2 to result and advance a2
271      pIter(a2);
272    }
273    else
274    { // coeffs are equal, so their difference is 0:
275      c = a2;  // do not append anything to result: Delete a2 and advance
276      pIter(a2);
277      CALL_NDELETE("&pGetCoeff(c)");
278      pFree1(c);
279    }
280    CALL_NDELETE("&tb");
281    pIter(a1);
282    if (a2 == NULL || a1 == NULL) goto Finish; // are we done ?
283    CALL_PCOPYADDFAST(b, a1, monom, order); // No! So, get new b = a1*monom
284    goto Top;
285
286  NotEqual:     // b != a2
287    if (d < 0)  // b < a2:
288    {
289      assume(pComp0(b, a2) == -1);
290    if (pComp0(b, a2) != -1)
291    {
292       WarnS("Wrong comp in SpolyLoop\n");
293       pComp0(b,a2);
294    }
295      a = pNext(a) = a2;// append a2 to result and advance a2
296      pIter(a2);
297      if (a2==NULL) goto Finish;;
298      goto Top;
299    }
300    else // now d >= 0, i.e., b > a2
301    {
302      assume(pComp0(b, a2) == 1);
303    if (pComp0(b, a2) != 1)
304    {
305       WarnS("Wrong comp in SpolyLoop\n");
306       pComp0(b,a2);
307    }
308      pSetCoeff0(b,CALL_NMULT("pGetCoeff(a1)",tneg));
309      a = pNext(a) = b;       // append b to result and advance a1
310      pIter(a1);
311      b = pNew();
312      if (a1 == NULL) goto Finish; // are we done?
313      CALL_PCOPYADDFAST(b, a1, monom, order); // No! So, update b = a1*monom
314      goto Top;
315    }
316 
317 Finish: // a1 or a2 is NULL: Clean-up time
318   assume(a1 == NULL || a2 == NULL);
319   if (a1 == NULL) // append rest of a2 to result
320     pNext(a) = a2;
321   else  // append (- a1*monom) to result
322     CALL_MULTCOPYX(a1, monom, a, tneg, spNoether);
323   CALL_NDELETE("&tneg");
324   pFree1(b);
325}
326
327_EOT_
328  ;
329
330###########################################################################
331##
332## "Macros" needed in expansion of spSpolyLoop
333##
334sub NCOPYNEG
335{
336  local($number, $argv) = @_;
337 
338  return "npNegM($number)" if (& GetCharacteristic($argv) eq "chMODP");
339  return "nNeg(nCopy($number))";
340}
341
342sub NDELETE
343{
344  local($number, $argv) = @_;
345 
346  return "" if (& GetCharacteristic($argv) eq "chMODP");
347  return "nDelete($number)";
348}
349
350sub NMULT
351{
352  local($m1, $m2, $argv) = @_;
353 
354  return "npMultM($m1, $m2)" if (& GetCharacteristic($argv) eq "chMODP");
355  return "nMult($m1, $m2)";
356}
357
358sub NSUB
359{
360  local($m1, $m2, $argv) = @_;
361 
362  return "npSubM($m1, $m2)" if (& GetCharacteristic($argv) eq "chMODP");
363  return "nSub($m1, $m2)";
364}
365
366sub NEQUAL
367{
368  local($m1, $m2, $argv) = @_;
369 
370  return "npEqualM($m1, $m2)" if (& GetCharacteristic($argv) eq "chMODP");
371  return "nEqual($m1, $m2)";
372} 
373
374sub MULTCOPYX
375{
376  local($p, $monom, $n, $exp, $spNoether, $argv) = @_;
377 
378  return "spMultCopyX($p, $monom, $n, $exp, $spNoether)" 
379    if (& GetCharacteristic($argv) eq "chMODP");
380  return "spGMultCopyX($p, $monom, $n, $exp, $spNoether)";
381}
382
383sub INITORDER
384{
385  local($order, $p, $argv) = @_;
386 
387  return "$order = $p->Order" if (&GetHomog($argv) eq "homYES");
388  return "";
389}
390
391 
392sub PCOPYADDFAST
393{
394  local($p1, $p2, $p3, $order, $argv) = @_;
395 
396  return "pCopyAddFastHomog($p1, $p2, $p3, $order)" 
397    if (&GetHomog($argv) eq "homYES");
398  return "pCopyAddFast0($p1, $p2, $p3)";
399}
400
401###########################################################################
402##
403## COMPARE "macro": Besides generating th source code which
404## accomplishes monomial comparisons, it also generates the (global)
405## string $rargv charcaterising the generated spSpolyLoop
406##
407sub COMPARE
408{
409  local($p1, $p2, $d, $argv) = @_;
410  local($ot, $hom, $nw, $res);
411 
412  $rargv = &GetCharacteristic($argv);
413  $ot = &GetOrderingType($argv);
414  $rargv =  $rargv."_".$ot;
415  if ($ot eq "otCOMPEXP" ||
416      $ot eq "otEXPCOMP" ||
417      $ot eq "otEXP")
418  {
419    if ($ot eq "otCOMPEXP")
420    {
421      $res = "$d = pGetComp($p2) - pGetComp($p1);\n";
422      $res = $res."NonZeroTestA($d, pComponentOrder, goto NotEqual);\n";
423      $ot = "otEXP";
424    }
425    $hom = &GetHomog($argv);
426    $rargv =  $rargv."_".$hom;
427    if ($hom ne "homYES")
428    {
429      $res = $res."$d = pGetOrder($p1) - pGetOrder($p2);\n";
430      $res = $res."NonZeroTestA($d, pOrdSgn, goto NotEqual);\n";
431    }
432    $nw = &GetNumWords($argv);
433    $rargv =  $rargv."_".$nw;
434    $res = join("_", $res, pMonComp, $ot, $nw);
435    if ($nw eq "nwONE" || $nw eq "nwTWO")
436    {
437      $res = $res."($p1, $p2, $d, NonZeroA($d, pLexSgn, goto NotEqual ), goto Equal);" 
438    }
439    else
440    {
441      $res = $res."($p1, $p2, pVariables1W, $d, NonZeroA($d, pLexSgn, goto NotEqual ), goto Equal);";
442    }
443    return $res;
444  }
445  else
446  {
447    # general ordering type
448    return ("if (($d = pComp0($p1, $p2))) goto NotEqual; else goto Equal;");
449  }
450}
451
452
453###########################################################################
454##
455## Generates an spSpolyLoop from a given "$argv" input string,
456## i.e. property string
457##
458## Returns spSpolyLoop and sets global associative array
459## $loops{$rargv} to generated loop.
460##
461
462sub Generate_SpolyLoop
463{
464  local($argv)= @_;
465  local($loopbody);
466
467  $loopbody = &Expand($spSpolyLoopBodyTemplate, $argv);
468
469  & Warning("Can not realize $argv: Changed to $rargv") if ($argv ne $rargv);
470
471  if (grep(/$rargv/, keys(%loops)))
472  {
473    & Warning("Duplicate entry $rargv: Ignoring $argv");
474    return;
475  }
476  else
477  {
478    $loops{$rargv} = "static void spSpolyLoop_$rargv\n$loopbody\n";
479    return ($loops{$rargv});
480  }
481}
482
483#gnerates SpolyLoops from array of $argv strings
484sub Generate_SpolyLoops
485{
486  local(%loops);
487 
488  foreach $argv (@_)
489  {
490    & Generate_SpolyLoop($argv);
491  }
492  return (%loops);
493}
494
495###########################################################################
496##
497## Generates array of $argv strings from a given input string by
498## "orthoganization", i.e. komma-separated entries in input string are
499## replaced by two argv strings containing the respective entrie.
500##
501
502sub FlattenInputString
503{
504  local($str) = @_;
505 
506  if ($str =~ /_/)
507  {
508    local(@parts, $head, @subresults, @result);
509    @parts = split(/_/, $str);
510    $head = shift(@parts);
511    @subresults = &FlattenInputString(join("_", @parts));
512    foreach $part (split(/,/, $head))
513    {
514      foreach $subresult (@subresults)
515      {
516        @result = (@result, $part."_".$subresult);
517      }
518    }
519    return (@result);
520  }
521  return (split(/,/, $str));
522}
523
524# generate array of $argv strings from array of input strings
525sub FlattenInput
526{
527  local(@result);
528  foreach $entry (@_)
529  {
530    $entry =~ s/\s//;
531    @result = (@result, & FlattenInputString($entry));
532  }
533  return @result;
534}
535
536
537###########################################################################
538##
539## GetSpolyLoop routines
540## They all work on valid $argv strings, only.
541##
542
543## Given a $prefix and an array of $argv's, return all the "next"
544## values, i.e. strings deliminted by $prefix and next '_'.
545sub GetNextKeys
546{
547  local($prefix, @values, $value);
548 
549  $prefix = shift(@_);
550  $prefix = $prefix."_" unless ($prefix eq "");
551  foreach $element (@_)
552  {
553    if ($prefix eq "")
554    {
555      ($value = $element) =~ s/^([a-zA-Z]*)(\w*)/\1/;
556      @values = ($value, @values) unless grep(/^$value$/, @values);
557    }
558    elsif ($element =~ /^$prefix/)
559    {
560      ($value = $element) =~ s/^($prefix)([a-zA-Z]*)(\w*)/\2/;
561      @values = ($value, @values) unless grep(/^$value$/, @values);
562    }
563  }
564  return @values;
565}
566
567# recursively generates "GetSpolyLoop" by working through all $argv's
568# which math $prefix
569# Sets $checks{$prefix}, if $prefix eq $argv
570sub GenerateBody_GetSpolyLoop
571{
572  local($prefix, $nextprefix, $source, $newsource, $prop, $curr_prop, $gen_key);
573 
574  $prefix = shift(@_);
575 
576  #check for exact match -- then we are done
577  if (grep(/^$prefix$/, @_))
578  {
579    $checks{$prefix} = "return spSpolyLoop_$prefix;\n";
580    return ($checks{$prefix});
581  }
582 
583  foreach $key (& GetNextKeys($prefix, @_))
584  {
585    if ($key =~ /\w+/)
586    {
587      # get prop,
588      ($prop = $key) =~ s/([a-z]*)([A-Z]*)/\1/;
589      #check prop against exiting ones
590      if ($curr_prop)
591      {
592        if ($prop ne $curr_prop)
593        {
594          & Warning("Different propes at same level: $prop : $curr_prop");
595          next;
596        }
597      }
598      else
599      {
600        $curr_prop = $prop;
601      }
602      # delay handling of "GEN" field
603      if ($key =~ /GEN/)
604      {
605        $gen_key = $key;
606        next;
607      }
608      # let's work recursively
609      if ($prefix eq "")
610      {
611        $nextprefix = $key;
612      }
613      else
614      {
615        $nextprefix = $prefix."_".$key;
616      }
617      $newsource=&GenerateBody_GetSpolyLoop($nextprefix,grep(/$nextprefix/,@_));
618      if ($newsource)
619      {
620        $source = $source."if ($prop == $key)\n{\n".$newsource."}\n";
621      }
622    }
623  }
624 
625  # take care of general key, if it exists
626  if ($gen_key)
627  {
628    $gen_key  = $prefix."_".$gen_key unless ($prefix eq "");
629    $source = $source . &GenerateBody_GetSpolyLoop($gen_key,grep(/$gen_key/,@_));
630  }
631  return ($source);
632}
633
634
635sub Generate_GetSpolyLoop
636{
637  local($header);
638 
639  $header = "static spSpolyLoopProc spGetSpolyLoop(";
640 
641  foreach $key (@Properties)
642  {
643    $etype = $EnumType{$key};
644    if ($etype =~ /\w+/)
645    {
646      $header = $header."$etype $key,";
647    }
648  }
649  chop($header);
650 
651  return ($header. 
652          ")\n{\n" . 
653          &GenerateBody_GetSpolyLoop("", @_). 
654          "return NULL;\n}\n");
655}
656
657
658###########################################################################
659##
660## Input Specification
661##
662
663@input = ("chMODP".
664          "_otEXP,otCOMPEXP,otEXPCOMP".
665          "_homGEN,homYES".
666          "_nwONE,nwTWO,nwEVEN,nwODD");
667
668
669#flatten out input
670@finput = &FlattenInput(@input);
671
672#generate loops
673%loops = & Generate_SpolyLoops(@finput);
674
675# Generate GetSpolyLoop based on generated loops
676$getspolyloop = & Generate_GetSpolyLoop(sort(keys(%loops)));
677
678# Output results
679print & Generate_EnumTypes(@Properties);
680
681foreach $key (sort(keys(%checks)))
682{
683  print $loops{$key};
684}
685
686print $getspolyloop;
687
688
689
690
691 
692
693
694
695
696
697
698
699
Note: See TracBrowser for help on using the repository browser.