source: git/Singular/spSpolyLoop.pl @ d2b2a7

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