add tests/ehrhart.README explaining origin of some of the ehrhart inputs
[barvinok.git] / parker / generate_code.pl
blob7615b5456548f720d79beec135e4831b0388c3ab
1 #!/usr/local/bin/perl
3 # Erin Parker (parker@cs.unc.edu), March 2004
5 # generate_code.pl -- Takes as input a Presburger formula and gives as output source code
6 # for building a DFA representation of the formula and subsequently
7 # counting the number of accepting paths in the DFA to reveal the
8 # number of solutions to the original formula. (For details on
9 # this method see Parker & Chatterjee, Compiler Construction 2004.)
11 # The input formula is assumed to be written in the style of the Omega Library. The
12 # output source code makes calls to Constantinos Bartzis' DFA-construction code and the
13 # MONA tool's DFA Library. This code is certainly not guaranteed to be bug-free. It really
14 # is designed to process the sort of representations I typically see when using the Omega
15 # Library for the expression and manipulation of Presburger formulas of interest to me.
16 # ---Erin
18 # FORMULA: "{[TUPLE] : CLAUSE union
19 # CLAUSE union
20 # ... union
21 # CLAUSE}"
22 # CLAUSE: "CONSTRAINT && CONSTRAINT && ... && CONSTRAINT"
23 # CONSTRAINT: "coeff*var +/- ... (+/- const) eq/ineq coeff*var +/- ... (+/- constant)"
25 # NumFreeVars -- number of free variables, given on command line
26 # FreeVar -- array of free variable names, "In_1 In_2 . . . In_{NumFreeVars}"
27 # ClauseMinIndex, ClauseMaxIndex -- CLAUSE i owns CONSTRAINTs
28 # ClauseMinIndex to ClauseMaxIndex
29 # NumStrideVars -- for CLAUSE i, NumStrideVars gives number of stride variables
30 # ConstraintMinIndex, ConstraintMaxIndex -- CONSTRAINT i owns variables
31 # (from array Var) ConstraintMinIndex to ConstrainMaxIndex with
32 # coefficients (from array Coeff)
33 # Constant -- CONSTRAINT i owns constant i
34 # Kind -- CONSTRAINT i is of type $Eq or $Ineq
35 # MaxConst -- MaxConst i is the largest coeff or constant in CONSTRAINT i
38 $False = 0;
39 $True = 1;
41 $Eq = 0;
42 $Ineq = $LTE = 1;
43 $Less = 2;
46 # SUBROUTINE: StoreConstraint($Kind, $LHS, $RHS, $NumVars)
47 sub StoreConstraint {
49 my($Kind);
50 $Kind = $_[0];
51 my ($LHS);
52 $LHS = $_[1];
53 my ($RHS);
54 $RHS = $_[2];
55 my ($NumVars);
56 $NumVars = $_[3];
58 $ConstraintMinIndex[$ConstraintNum] = $VarNum;
59 $MaxConst[$ConstraintNum] = 0;
61 $LHS =~ s/\+/\$\+/g;
62 $LHS =~ s/\-/\$\-/g;
63 $RHS =~ s/\+/\$\+/g;
64 $RHS =~ s/\-/\$\-/g;
66 if($Kind == $LTE) {
67 $Constant[$ConstraintNum] = -1;
68 $Kind[$ConstraintNum] = $Ineq;
70 else {
71 $Constant[$ConstraintNum] = 0;
72 if($Kind == $Eq) {
73 $Kind[$ConstraintNum] = $Eq;
75 else {
76 $Kind[$ConstraintNum] = $Ineq;
80 @OperandList = split(/\$/, $LHS);
81 foreach $Operand (@OperandList) {
82 if($Operand ne "") {
83 $Operand =~ s/\+//;
84 $Found = $False;
85 for($x=0; $x<$NumVars; $x++) {
86 if($Operand =~ /$FreeVar[$x]/ && $Operand !~ /$FreeVar[$x]\S/ &&
87 ($Operand !~ /\D$FreeVar[$x]/ || $Operand =~ /-$FreeVar[$x]/)) {
88 $Operand =~ s/$FreeVar[$x]//;
89 $Found = $True;
90 $Index = $x;
91 $x = $NumVars;
94 if($Operand > $MaxConst[$ConstraintNum]) {
95 $MaxConst[$ConstraintNum] = $Operand;
97 if(!$Found) {
98 $Constant[$ConstraintNum] += $Operand;
100 else {
101 if($Operand eq "") {
102 $Operand = 1;
104 elsif($Operand eq "-") {
105 $Operand = -1;
107 $Var[$VarNum] = $Index;
108 $Coeff[$VarNum++] = $Operand;
113 @OperandList = split(/\$/, $RHS);
114 foreach $Operand (@OperandList) {
115 if($Operand ne "") {
116 $Operand =~ s/\+//;
117 $Found = $False;
118 for($x=0; $x<$NumVars; $x++) {
119 if($Operand =~ $FreeVar[$x] && $Operand !~ /$FreeVar[$x]\S/ &&
120 ($Operand !~ /\D$FreeVar[$x]/ || $Operand =~ /-$FreeVar[$x]/)) {
121 $Operand =~ s/$FreeVar[$x]//;
122 $Found = $True;
123 $Index = $x;
124 $x = $NumVars;
127 if($Operand > $MaxConst[$ConstraintNum]) {
128 $MaxConst[$ConstraintNum] = $Operand;
130 if(!$Found) {
131 if($Operand != 0) {
132 $Operand *= -1;
134 $Constant[$ConstraintNum] += $Operand;
136 else {
137 if($Operand eq "") {
138 $Operand = 1;
140 elsif($Operand eq "-") {
141 $Operand = -1;
143 $Var[$VarNum] = $Index;
144 $Coeff[$VarNum++] = -1*$Operand;
148 $ConstraintMaxIndex[$ConstraintNum++] = $VarNum-1;
152 # SUBROUTINE: ParseAndStore()
153 sub ParseAndStore {
155 # check for correct command line usage
156 if(@ARGV < 1) {
157 print "USAGE: num_free_vars \n\n";
158 exit;
161 # create free variable names
162 $NumFreeVars = $ARGV[0];
163 for($z=0; $z<$NumFreeVars; $z++) {
164 $FreeVar[$z] = "In_".($z+1);
167 print "/* This code is automatically generated to build a DFA\n";
168 print " representing integer solutions to the following formula.\n\n";
170 $ClauseNum = 0;
171 $ConstraintNum = 0;
172 $MaxConstraintNum = 0;
173 $VarNum = 0;
175 $NumLines = 0;
177 while($Line = <STDIN>) {
179 if($Line !~ /\#/ && $Line ne "") {
180 print " ".$Line;
183 # ignore whitespace, braces and "union"
184 $Line =~ s/[\s|\}|\{]//g;
185 $Line =~ s/union//g;
187 # avoid Omega comments and blank lines
188 if($Line !~ /\#/ && $Line ne "") {
190 $Skip = 0;
191 for($q=0; $Skip==0 && $q<$NumLines; $q++) {
192 if($Line eq $LineList[$q]) {
193 $Skip = 1;
196 if($Skip==0) {
197 $LineList[$NumLines++] = $Line;
200 $ClauseMinIndex[$ClauseNum] = $ConstraintNum;
203 # split TUPLE from the rest of the line
204 ($Tuple, $Rest) = split("]:", $Line);
205 $Tuple =~ s/\[//g;
206 @TupleVar = split(",", $Tuple);
208 # create any necessary constraints from list of tuple variables
209 for($i=0; $i<=$#TupleVar; $i++) {
211 if($TupleVar[$i] ne $FreeVar[$i]) {
212 StoreConstraint($eq, $FreeVar[$i], $TupleVar[$i], $NumFreeVars);
216 # split the rest of the line into CONSTRAINTs
217 @ConstraintList = split("&&", $Rest);
219 # handle "Exists(..." in input formula
220 $NumStrideVars[$ClauseNum] = 0;
221 if($ConstraintList[0] =~ /Exists/) {
222 $ConstraintList[0] =~ s/Exists\(//g;
223 ($ExistsPart, $ConstraintList[0]) = split(":", $ConstraintList[0]);
224 @StrideVar = split(",", $ExistsPart);
226 for($e=0; $e<=$#StrideVar; $e++, $NumStrideVars[$ClauseNum]++) {
227 $FreeVar[$NumFreeVars+$e] = $StrideVar[$e];
230 $ConstraintList[-1] =~ s/\)//g;
233 $TotalVars = $NumFreeVars + $NumStrideVars[$ClauseNum];
235 # process each CONSTRAINT
236 foreach $Constraint (@ConstraintList) {
238 # handle '<=' in CONSTRAINT
239 if($Constraint =~ /<=/) {
240 $Constraint =~ s/<=/\$/g;
241 # Note: This does not handle every possible combination of
242 # '<=' and '<' in constraint.
243 $Lspecial = $False;
244 $Rspecial = $False;
245 ($Lside, $Rside) = split(/\$/, $Constraint);
246 if ($Lside =~ /</) {
247 $Lspecial = $True;
248 $Constraint =~ s/</\$/g;
250 elsif ($Rside =~ /</) {
251 $Rspecial = $True;
252 $Constraint =~ s/</\$/g;
255 @SubConstraint = split(/\$/, $Constraint);
256 if($#SubConstraint > 3) {
257 print "Too many \"<=\" and \"<\" in a single constraint\n\n";
258 exit;
260 @Part0 = split(/,/, $SubConstraint[0]);
261 @Part1 = split(/,/, $SubConstraint[1]);
262 @Part2 = split(/,/, $SubConstraint[2]);
263 @Part3 = split(/,/, $SubConstraint[3]);
265 foreach $LTE_Lexpr (@Part0) {
266 foreach $LTE_Rexpr (@Part1) {
267 if ($Lspecial) {
268 StoreConstraint($Less, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
270 else {
271 StoreConstraint($LTE, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
276 foreach $LTE_Lexpr (@Part1) {
277 foreach $LTE_Rexpr (@Part2) {
278 if ($Rspecial) {
279 StoreConstraint($Less, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
281 else {
282 StoreConstraint($LTE, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
287 foreach $LTE_Lexpr (@Part2) {
288 foreach $LTE_Rexpr (@Part3) {
289 StoreConstraint($LTE, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
294 # handle '=' in CONSTRAINT
295 elsif($Constraint =~ /=/) {
296 @SubConstraint = split(/=/, $Constraint);
298 @Part0 = split(/,/, $SubConstraint[0]);
299 @Part1 = split(/,/, $SubConstraint[1]);
301 foreach $EQ_Lexpr (@Part0) {
302 foreach $EQ_Rexpr (@Part1) {
303 StoreConstraint($Eq, $EQ_Lexpr, $EQ_Rexpr, $TotalVars);
308 # handle '<' in Constraint
309 elsif($Constraint =~ /</) {
310 @SubConstraint = split(/</, $Constraint);
312 @Part0 = split(/,/, $SubConstraint[0]);
313 @Part1 = split(/,/, $SubConstraint[1]);
314 @Part2 = split(/,/, $SubConstraint[2]);
316 if($#SubConstraint > 2) {
317 print "Too many \"<\" in a single constraint\n\n";
318 exit;
321 foreach $LESS_Lexpr (@Part0) {
322 foreach $LESS_Rexpr (@Part1) {
323 StoreConstraint($Less, $LESS_Lexpr, $LESS_Rexpr, $TotalVars);
327 foreach $LESS_Lexpr (@subLESSs_1) {
328 foreach $LESS_Rexpr (@subLESSs_2) {
329 StoreConstraint($Less, $LESS_Lexpr, $LESS_Rexpr, $TotalVars);
334 if(2*($ConstraintNum - $ClauseMinIndex[$ClauseNum] - 1) - 1 > $MaxConstraintNum) {
335 $MaxConstraintNum = 2*($ConstraintNum - $ClauseMinIndex[$ClauseNum] - 1) - 1;
337 $ClauseMaxIndex[$ClauseNum++] = $ConstraintNum-1;
341 print "*/\n\n";
345 # SUBROUTINE GenerateCode()
346 sub GenerateCode {
348 print "#include \"count_solutions.h\"\n\n";
350 print "int main(void) {\n\n";
351 print " int coeffs[".($NumFreeVars+3)."];\n";
352 print " int indices[".($NumFreeVars+3)."];\n";
353 print " DFA* dfa1[".($MaxConstraintNum+4)."];\n";
354 print " DFA* dfa2[".(2*$ClauseNum-1)."];\n\n";
356 for($i=0, $n=0; $i<$ClauseNum; $i++, $n++) {
357 for($j=$ClauseMinIndex[$i], $m=0; $j<=$ClauseMaxIndex[$i]; $j++, $m++) {
358 for($k=$ConstraintMinIndex[$j], $l=0; $k<=$ConstraintMaxIndex[$j]; $k++, $l++) {
359 print " coeffs[".$l."] = ".$Coeff[$k].";\n";
360 print " indices[".$l."] = ".$Var[$k].";\n";
362 print " dfa1[".$m."] = build_DFA_";
363 if($Kind[$j]) {
364 print "in";
366 print "eq(".$l.", coeffs, ".$Constant[$j].", indices);\n";
367 if($m>0) {
368 print " dfa1[".(++$m)."] = dfaMinimize(dfaProduct(dfa1[".($m-2)."], dfa1[".($m-1)."], dfaAND));\n";
369 print " dfaFree(dfa1[".($m-2)."]);\n dfaFree(dfa1[".($m-1)."]);\n";
371 print "\n";
374 for ($f=0; $f<$NumStrideVars[$i]; $f++) {
375 if ($f == $NumStrideVars[$i]-1) {
376 print " dfa2[".($n)."] = dfaMinimize(dfaProject(dfa1[".($m-1)."], ".($NumFreeVars+$f)."));\n";
377 print " dfaFree(dfa1[".($m-1)."]);\n";
379 else {
380 print " dfa1[".($m++)."] = dfaMinimize(dfaProject(dfa1[".($m-2)."], ".($NumFreeVars+$f)."));\n";
381 print " dfaFree(dfa1[".($m-2)."]);\n";
385 if ($NumStrideVars[$i] == 0) {
386 print " dfa2[".($n)."] = dfaCopy(dfa1[".($m-1)."]);\n";
387 print " dfaFree(dfa1[".($m-1)."]);\n";
390 if($n>0) {
391 print " dfa2[".(++$n)."] = dfaMinimize(dfaProduct(dfa2[".($n-2)."], dfa2[".($n-1)."], dfaOR));\n";
392 print " dfaFree(dfa2[".($n-2)."]);\n dfaFree(dfa2[".($n-1)."]);\n";
394 print "\n\n";
397 print " count_accepting_paths(dfa2[".(2*$ClauseNum-2)."], dfa2[".(2*$ClauseNum-2)."]->ns, ".$NumFreeVars.");\n";
398 print " dfaFree(dfa2[".(2*$ClauseNum-2)."]);\n";
399 print "}\n\n";
403 # MAIN ROUNTINE
405 ParseAndStore();
406 GenerateCode();