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.
18 # FORMULA: "{[TUPLE] : CLAUSE union
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
46 # SUBROUTINE: StoreConstraint($Kind, $LHS, $RHS, $NumVars)
58 $ConstraintMinIndex[$ConstraintNum] = $VarNum;
59 $MaxConst[$ConstraintNum] = 0;
67 $Constant[$ConstraintNum] = -1;
68 $Kind[$ConstraintNum] = $Ineq;
71 $Constant[$ConstraintNum] = 0;
73 $Kind[$ConstraintNum] = $Eq;
76 $Kind[$ConstraintNum] = $Ineq;
80 @OperandList = split(/\$/, $LHS);
81 foreach $Operand (@OperandList) {
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]//;
94 if($Operand > $MaxConst[$ConstraintNum]) {
95 $MaxConst[$ConstraintNum] = $Operand;
98 $Constant[$ConstraintNum] += $Operand;
104 elsif($Operand eq "-") {
107 $Var[$VarNum] = $Index;
108 $Coeff[$VarNum++] = $Operand;
113 @OperandList = split(/\$/, $RHS);
114 foreach $Operand (@OperandList) {
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]//;
127 if($Operand > $MaxConst[$ConstraintNum]) {
128 $MaxConst[$ConstraintNum] = $Operand;
134 $Constant[$ConstraintNum] += $Operand;
140 elsif($Operand eq "-") {
143 $Var[$VarNum] = $Index;
144 $Coeff[$VarNum++] = -1*$Operand;
148 $ConstraintMaxIndex[$ConstraintNum++] = $VarNum-1;
152 # SUBROUTINE: ParseAndStore()
155 # check for correct command line usage
157 print "USAGE: num_free_vars \n\n";
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";
172 $MaxConstraintNum = 0;
177 while($Line = <STDIN
>) {
179 if($Line !~ /\#/ && $Line ne "") {
183 # ignore whitespace, braces and "union"
184 $Line =~ s/[\s|\}|\{]//g;
187 # avoid Omega comments and blank lines
188 if($Line !~ /\#/ && $Line ne "") {
191 for($q=0; $Skip==0 && $q<$NumLines; $q++) {
192 if($Line eq $LineList[$q]) {
197 $LineList[$NumLines++] = $Line;
200 $ClauseMinIndex[$ClauseNum] = $ConstraintNum;
203 # split TUPLE from the rest of the line
204 ($Tuple, $Rest) = split("]:", $Line);
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.
245 ($Lside, $Rside) = split(/\$/, $Constraint);
248 $Constraint =~ s/</\$/g;
250 elsif ($Rside =~ /</) {
252 $Constraint =~ s/</\$/g;
255 @SubConstraint = split(/\$/, $Constraint);
256 if($#SubConstraint > 3) {
257 print "Too many \"<=\" and \"<\" in a single constraint\n\n";
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) {
268 StoreConstraint
($Less, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
271 StoreConstraint
($LTE, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
276 foreach $LTE_Lexpr (@Part1) {
277 foreach $LTE_Rexpr (@Part2) {
279 StoreConstraint
($Less, $LTE_Lexpr, $LTE_Rexpr, $TotalVars);
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";
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;
345 # SUBROUTINE 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_";
366 print "eq(".$l.", coeffs, ".$Constant[$j].", indices);\n";
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";
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";
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";
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";
397 print " count_accepting_paths(dfa2[".(2*$ClauseNum-2)."], dfa2[".(2*$ClauseNum-2)."]->ns, ".$NumFreeVars.");\n";
398 print " dfaFree(dfa2[".(2*$ClauseNum-2)."]);\n";