1 /* file "linear_ineq.cc" */
3 /* Copyright (c) 1994 Stanford University
7 This software is provided under the terms described in
8 the "suif_copyright.h" include file. */
10 #include <suif_copyright.h>
12 #define _MODULE_ "libsuifmath.a"
13 #pragma implementation "linear_ineq.h"
22 no_integer_result_hook_f NIR_hook
= NULL
;
23 integer_solver_hook_f IS_hook
= NULL
;
27 /* ##################################################
28 ##### constraint #####
29 ################################################## */
33 /********************************************************************************
36 * when the raw represent R>=0 -> R>-1 compliment is R<=-1 -> -1-R>=0 *
37 ********************************************************************************/
38 void constraint::complement()
46 /********************************************************************************
48 ********************************************************************************/
49 /* if (!norm_bounds), this /= row_gcd();
51 g = row_gcd(all but 0)
52 this /= g; (take floor of this[0]/g);
55 boolean
constraint::normalize(boolean norm_bounds
)
58 for(int i
=(norm_bounds
)?1:0; i
<n(); i
++)
63 g
= gcd(g
, ABS((*this)[i
]));
68 for(int i
=1; i
<n(); i
++)
70 int new0
= (int) floor(((double)R
[0])/(double)g
);
71 boolean chg
= ((g
*new0
) != R
[0]);
83 /********************************************************************************
84 * highest non-zero value *
85 ********************************************************************************/
86 int constraint::rank() const
89 const int * curr
= &(R
[n()-1]);
92 if(*curr
-- != 0) return i
;
97 for(int cc = 0; cc<n(); cc++)
98 if(c(cc) != 0) rnk=cc;
102 /********************************************************************************
104 * return val s.t. For all c R[c]!=0 val +=sort_order[c] *
105 ********************************************************************************/
106 int constraint::highest_order(const constraint
& sort_order
) const
108 assert(sort_order
.n() == this->n());
111 for(int cc
= 0; cc
<n(); cc
++)
112 if(c(cc
) != 0) hi
= hi
+ sort_order
.c(cc
);
117 /********************************************************************************
118 * Only one non-zero variable (1st location is a const, thus can have any val. *
119 ********************************************************************************/
120 boolean
constraint::unique() const
122 boolean found
= FALSE
;
123 for(int cc
= 1; cc
<n(); cc
++)
126 return FALSE
; // more than one
128 found
= TRUE
; // found first
131 return TRUE
; // last one was the only var
133 return FALSE
; // Only constant
137 /********************************************************************************
139 ********************************************************************************/
140 int constraint::row_gcd() const
143 for(int i
= 0; i
<n(); i
++)
148 g
= gcd(g
, ABS(c(i
)));
153 int constraint::row_lcm() const
156 for(int i
= 0; i
<n(); i
++)
161 l
= lcm(l
, ABS(c(i
)));
169 then result[i]=1 if lower<=this[i]<=upper
170 else result[i]=1 if lower<=leftofthis[i]<=upper
171 where leftofthis[i] = sum(0,i,this[i]==type)-1
174 constraint
constraint::make_filter(int type
, int lower
, int upper
) const
176 constraint
reply(n());
178 if(type
== 0) { // array vars;
179 for(int i
= 0; i
<n(); i
++)
180 reply
[i
] = ((c(i
) >= lower
)&&(c(i
) <= upper
))?1:0;
183 for(int i
= 0; i
<n(); i
++) {
184 if(type
==c(i
)) count
++;
185 reply
[i
] = ((count
>= lower
)&&(count
<= upper
))?1:0;
193 returns AND(0<=i<n(),kernal[i] && same_sign(this[i],sgn))
196 int constraint::filter(const constraint
& kernal
, int sgn
) const
198 for(int i
= 0; i
<n(); i
++)
199 if(kernal
.c(i
) == 1) // mark in kernal
200 if(c(i
) != 0) // entry in constraint
201 if(c(i
)*sgn
>= 0) // sign +/- check sign of entry
202 return 1; // if sign=0 any sign is ok
208 /* ##################################################
210 ################################################## */
213 integer_row
*lin_ineq::alloc_rows(int num_rows
)
216 return new constraint
[num_rows
];
220 /********************************************************************************
221 * Column Operations *
222 ********************************************************************************/
223 int lin_ineq::col_lcm(int col
) const
225 assert((col
>=0)&&(col
<nn
));
227 for(int i
= 0; i
<mm
; i
++)
228 if(r(i
).c(col
) != 0) {
230 l
= ABS(r(i
).c(col
));
232 l
= lcm(l
, ABS(r(i
).c(col
)));
238 int lin_ineq::col_gcd(int col
) const
240 assert((col
>=0)&&(col
<nn
));
242 for(int i
= 0; i
<mm
; i
++)
243 if(r(i
).c(col
) != 0) {
245 g
= ABS(r(i
).c(col
));
247 g
= gcd(g
, ABS(r(i
).c(col
)));
254 /********************************************************************************
256 ********************************************************************************/
257 lin_ineq
lin_ineq::operator&&(const lin_ineq
& mat
) const
259 if(m() == 0) return mat
;
260 if(mat
.m() == 0) return *this;
262 assert(n() == mat
.n());
264 lin_ineq
result(this, m()+mat
.m());
265 for(int i
=0; i
<mat
.m(); i
++)
266 result
[i
+m()] = mat
.r(i
);
271 lin_ineq
&lin_ineq::operator&=(const lin_ineq
& mat
)
273 if(mat
.m() == 0) return *this;
274 if(m() == 0) { init(mat
); return *this; };
276 assert(n() == mat
.n());
279 do_add_rows(mat
.m());
281 for(int i
=0; i
<mat
.m(); i
++)
282 (*this)[i
+oldm
] = mat
.r(i
);
287 // for debugging operator~();
288 // static int soln_count = 0;
290 int lin_ineq::operator~() const
292 assert_msg(NIR_hook
, ("No integer solver given, "
293 "(link in the dependence library)"));
294 // fprintf(stderr,"[%d]lin_ineq::~ applied to\n",++soln_count);
296 boolean ans
= (*NIR_hook
)(*this, NULL
);
297 // fprintf(stderr,"result == %d\n",(int)ans);
301 boolean
lin_ineq::operator>=(const lin_ineq
& mat
) const
303 assert(n() == mat
.n());
307 lin_ineq
testln(&mat
, mat
.m()+1);
309 for(int i
=0; i
<m(); i
++) {
310 testln
[mat
.m()] = -r(i
);
311 if((~testln
)==0) return 0;
314 lin_ineq tmp
= mat
||(*this);
316 fprintf(stderr
,"Error in dependence test!!!\n THIS = \n");
318 fprintf(stderr
,"MAT = \n");
320 fprintf(stderr
,"tmp = \n");
328 lin_ineq
lin_ineq::operator%(const constraint
& row
) const
330 return lin_ineq(integer_matrix::operator%(row
));
333 /********************************************************************************
335 ********************************************************************************/
336 void lin_ineq::print(FILE *fp
, int flag
) const
339 for (int i
=0; i
<m(); i
++) {
340 if(flag
== 1) fprintf(fp
,"%2d: ", i
);
341 for (int j
=0; j
<n(); j
++) {
342 fprintf(fp
, " %6d", r(i
).c(j
));
349 int lin_ineq::max_rank() const
352 for(int i
=0; i
<m(); i
++) rank
= MAX(rank
, r(i
).rank());
358 /********************************************************************************
361 ********************************************************************************/
362 void lin_ineq::del_zeros()
364 int *lst
= new int[m()];
369 if((r(i
).rank() != 0) || (r(i
).c(0) < 0)) {
377 for (src
=0, dst
=0; src
< m(); src
++) {
380 (*this)[dst
] ^= (*this)[src
];
389 /********************************************************************************
392 ********************************************************************************/
393 void lin_ineq::del_unused_var()
397 integer_row
lst(tmpM
.n());
402 for(i
=0; i
<tmpM
.m(); i
++)
403 for(j
=0; j
<tmpM
.n(); j
++) if(tmpM
[i
][j
]) lst
[j
] = 1;
409 /********************************************************************************
412 ********************************************************************************/
414 void lin_ineq::normalize(boolean norm_bounds
)
416 for(int i
=0; i
< this->m(); i
++)
417 (*this)[i
].normalize(norm_bounds
);
421 /********************************************************************************
424 ********************************************************************************/
425 // rem identical rows;
426 // as compared to itself and (0,a-1);
427 void lin_ineq::del_repetition(int a
, int b
, integer_row
*deleted
)
430 if ((m() > 0) && (a
<= b
)) {
433 int *rank
= new int[m()];
435 for(i
=0; i
< m(); i
++) {
436 rank
[i
] = (*this)[i
].rank();
439 integer_row
*del_rows
= deleted
? deleted
: new integer_row(m());
441 assert(deleted
->n() == m());
442 for(i
=a
; i
<= b
; i
++)
443 for(int j
=0; j
< i
; j
++) {
444 if(rank
[i
] == rank
[j
])
445 if((*this)[i
] == (*this)[j
]) {
446 (*del_rows
)[j
] = 1; // two equals
452 do_del_rows(*del_rows
);
453 if (!deleted
) delete del_rows
;
457 // rem identical rows in (incl)range;
458 void lin_ineq::del_repetition()
462 del_repetition(0, m()-1);
465 // rem otherwise identical row with bigger constant;
466 // in (incl) range given;
467 void lin_ineq::del_loose(int r1
, int r2
, integer_row
*deleted
)
471 integer_row
*del_rows
= deleted
? deleted
: new integer_row(m());
473 assert (deleted
->n() == m());
475 int *this_rank
= new int[m()];
477 assert ((0<=r1
) && (r1
<=r2
) && (r2
<m()));
479 for(int j
= 0; j
<m(); j
++)
480 this_rank
[j
] = (*this)[j
].rank();
482 for (int i
=r1
; i
<= r2
; i
++)
483 if (((*del_rows
)[i
]==0) && ((*this)[i
].rank() != 0)) {
484 constraint A
= (*this)[i
];
486 int A_rank
= A
.rank();
488 for (int j
=0; j
< i
; j
++) {
489 if (A_rank
== this_rank
[j
]) {
490 constraint B
= (*this)[j
];
491 int c2
= (*this)[j
][0];
505 do_del_rows(*del_rows
);
506 if (!deleted
) delete del_rows
;
509 // rem otherwise identical row with bigger constant;
510 void lin_ineq::del_loose()
512 if (m() <= 1) return;
516 void lin_ineq::row_swap(int i
, int j
)
518 assert((i
>=0)&&(i
<m()));
519 assert((j
>=0)&&(j
<m()));
527 /********************************************************************************
530 * If sort order is given sort in the increasing order of f(M[i]) *
531 * f(M[i]) = val s.t. For all c M[i][c]!=0 val=MAX(s_order[c]) *
532 * else Sort S in the order of increasing constraint rank *
533 ********************************************************************************/
538 void rh_swap(rh
& o
) {
540 tmp
= rnk
; rnk
= o
.rnk
; o
.rnk
= tmp
;
541 tmp
= high
; high
= o
.high
; o
.high
= tmp
;
545 // if s_order, sort according to
546 // row.highest_order(s_order)+row.rank();
547 // (recall row.highest_order(s_order) = Sum{i s.t. row[i]!=0} s_order[i]);
548 // dir > 0 => sort into row[i] <= row[i+1];
549 void lin_ineq::sort(const constraint
* s_order
, int dir
)
551 if(this->m() <= 1) return;
553 if(s_order
) assert(s_order
->n() == this->n());
555 rh
* RH
= new rh
[this->m()];
558 for(i
=0; i
<this->m(); i
++) {
559 RH
[i
].rnk
= (*this)[i
].rank();
560 RH
[i
].high
= (s_order
)?(*this)[i
].highest_order(*s_order
):0;
563 // s_order->print(stderr);
564 // for(int f=0; f<this->m(); f++)
565 // fprintf(stderr,"(%d %d+%d) ", f, (*this)[f].highest_order(*s_order),
566 // (*this)[f].rank());
567 // fprintf(stderr,"\n");
569 for(i
=0; i
<this->m()-1; i
++) {
571 for(int j
=i
+1; j
<this->m(); j
++)
574 if(RH
[swap
].high
+RH
[swap
].rnk
> RH
[j
].high
+RH
[j
].rnk
)
577 if(RH
[swap
].high
+RH
[swap
].rnk
< RH
[j
].high
+RH
[j
].rnk
)
582 if(RH
[swap
].rnk
> RH
[j
].rnk
) swap
= j
;
584 if(RH
[swap
].rnk
< RH
[j
].rnk
) swap
= j
;
588 RH
[i
].rh_swap(RH
[swap
]);
589 this->row_swap(i
, swap
);
596 /********************************************************************************
598 ********************************************************************************/
601 deletes rows for which filter(kernal,sgn) is not true;
603 void lin_ineq::do_filter_thru(const constraint
& kernal
, int sign
)
606 integer_row
del_rows(m());
608 for(int i
=0; i
<m(); i
++)
609 if(!(*this)[i
].filter(kernal
, sign
))
611 do_del_rows(del_rows
);
615 lin_ineq
lin_ineq::filter_thru(const constraint
& kernal
, int sign
) const
617 lin_ineq
result(this);
618 result
.do_filter_thru(kernal
,sign
);
623 deletes rows for which filter(kernal,sgn) is true;
625 void lin_ineq::do_filter_away(const constraint
& kernal
, int sign
)
628 integer_row
del_rows(m());
630 for(int i
=0; i
<m(); i
++)
631 if((*this)[i
].filter(kernal
, sign
))
633 do_del_rows(del_rows
);
637 lin_ineq
lin_ineq::filter_away(const constraint
& kernal
, int sign
) const
639 lin_ineq
result(this);
640 result
.do_filter_away(kernal
,sign
);
645 Takes a row with a non-0 for every variable whose bounds matter.
646 Modifies the row to take the transitive closure over this leq,
647 adding every variable related to those vars.
649 void lin_ineq::do_bounds(integer_row
&bounds0
) const
651 assert(bounds0
.n() == n());
653 boolean changed
= TRUE
;
658 for (i
=1; i
<n(); i
++) {
660 for (int j
=0; j
<m(); j
++) {
661 const integer_row
&thisrow
= r(j
);
663 for (int i2
=1; i2
<n(); i2
++) {
664 if ((i2
!= i
) && thisrow
.c(i2
)) {
678 /* ##################################################
679 ##### lin_ineq_negate_iter #####
680 ################################################## */
681 void lin_ineq_negate_iter::init(const lin_ineq
& l
)
689 done_mark
= 0x01 << L
.m();
693 lin_ineq
* lin_ineq_negate_iter::step()
699 for(int i
=0; i
<L
.m(); i
++) {
700 if(chang
& 0x01) L
[i
] = -L
[i
];
710 /* ##################################################
711 ##### lin_ineq_difference_iter #####
712 ################################################## */
714 void lin_ineq_difference_iter::init(const lin_ineq
& A
, const lin_ineq
& B
)
728 // remove constraints of D that are also bounds of A
729 integer_matrix
m1A(1,A
.n());
730 lin_ineq A1
= Compose(2, 1,
733 for(int i
=0; i
<D
.m(); i
++) {
734 A1
[A1
.m()-1] = -D
[i
];
742 lin_ineq
* lin_ineq_difference_iter::step()
746 return new lin_ineq(D
);
748 lin_ineq
* ret
= new lin_ineq(curr
, D
.n());
750 ret
= new lin_ineq(D
.resize(0, curr
, 0, D
.n()));
751 (*ret
)[curr
] = -(*ret
)[curr
];
757 /* ##################################################
758 ##### lin_ineq_op #####
759 ################################################## */
762 /********************************************************************************
764 ********************************************************************************/
765 lin_ineq_op::lin_ineq_op(int sz
, const int * k
)
769 kind
[0] = NM_CONSTANT
;
771 for(int i
=1; i
<kind
.n(); i
++)
775 lin_ineq_op::lin_ineq_op(int a
, int b
)
779 kind
[0] = NM_CONSTANT
;
781 for(i
=1; i
<a
; i
++) kind
[i
] = NM_SYMBOLS
;
782 for(i
=a
; i
<a
+b
; i
++) kind
[i
] = NM_LOCATIONS
;
786 /********************************************************************************
788 ********************************************************************************/
790 lin_ineq
lin_ineq_op::get(const lin_ineq
& LEQ
, int nloc
, int sgn
) const
792 /* flt[i] = 1 if there are nloc+1 NM_LOCATIONS left of column i in kind */
793 constraint flt
= kind
.make_filter(NM_LOCATIONS
, nloc
);
795 /* removes rows not containing right signed value in column of flt */
796 lin_ineq result
= LEQ
.filter_thru(flt
, sgn
);
801 lin_ineq
lin_ineq_op::rem(const lin_ineq
& LEQ
, int nloc
, int sgn
) const
803 constraint flt
= kind
.make_filter(NM_LOCATIONS
, nloc
);
805 lin_ineq result
= LEQ
.filter_away(flt
, sgn
);
811 // keeps only rows with a + value in a column i;
812 // with at least nloc+1 NM_LOCATIONS to the left of it in kind;
813 lin_ineq
lin_ineq_op::get_lesser(const lin_ineq
& LEQ
, int nloc
) const
815 constraint flt
= kind
.make_filter(NM_LOCATIONS
, nloc
, LEQ
.n());
817 lin_ineq result
= LEQ
.filter_away(flt
, 0);
822 // opposite of get_lesser();
823 lin_ineq
lin_ineq_op::get_greater(const lin_ineq
& LEQ
, int nloc
) const
825 constraint flt
= kind
.make_filter(NM_LOCATIONS
, nloc
, LEQ
.n());
827 lin_ineq result
= LEQ
.filter_thru(flt
, 0);
833 lin_ineq
lin_ineq_op::get_exclusive(const lin_ineq
& LEQ
, int nloc
, int sgn
)
836 // get rows with a value of right sign in nloc+1 NM_LOCATIONS;
837 lin_ineq result
= get(LEQ
, nloc
, sgn
);
839 constraint flt
= kind
.make_filter(NM_LOCATIONS
) - kind
.make_filter(NM_LOCATIONS
, nloc
);
841 // get rid of such rows with any non-0 value in another NM_LOCATIONS col;
842 result
= result
.filter_away(flt
, 0);
849 /********************************************************************************
850 * overlap or contigous ranges in given dim *
852 * - get both ineq's with given array dim present and no other array dims *
853 * - If no subset of ineq`s exist like that, cannot get an indipendent *
854 * variable which might overlap or fuse toghter -> good bye *
855 * - If there is an overlap of the ind. dimention all the time can merge *
856 * - Now check if the two dimentions can be fused toghter. i.e. no gap in the *
857 * middle of the two ranges. *
858 ********************************************************************************/
859 lin_ineq
lin_ineq_op::overlap_or_contig(const lin_ineq
& a
, const lin_ineq
& b
,
867 // get rows from a/b with non-0 only in column of nloc+1 NM_LOCATIONS;
868 // but in no other NM_LOCATIONS columns;
869 curr_a
= get_exclusive(a
, nloc
, 0);
870 curr_b
= get_exclusive(b
, nloc
, 0);
872 if((curr_a
.is_empty())||(curr_b
.is_empty())) return result
;
874 // Now check if a is after b
876 // get rows from a with + values in nloc+1 columns;
877 curr_a
= get_exclusive_lower(a
, nloc
);
878 // get rows from b with - values in nloc+1 columns;
879 curr_b
= get_exclusive_upper(b
, nloc
);
881 int gap1
= check_gap(curr_a
, curr_b
);
882 if(gap1
< 0) return result
;
885 curr_a
= get_exclusive_upper(a
, nloc
);
886 curr_b
= get_exclusive_lower(b
, nloc
);
888 int gap2
= check_gap(curr_a
, curr_b
);
889 if(gap2
< 0) return result
;
892 result
= rem_lower(a
, nloc
) || rem_upper(b
, nloc
); // remove lower_a and upper_b
894 result
= rem_upper(a
, nloc
) || rem_lower(b
, nloc
); // remove upper_a and lower_b
900 /********************************************************************************
903 * input: for a single array dim. a set with upper bounds and the *
904 * other set with lower bounds *
905 * Order does not matter (if a is LB then b is UB vice vesa) *
908 * ------------|---|------- *
910 * From LB i <= a a - i >= 0 *
911 * From UB i >= b -b + i >= 0 *
913 * The gap between rangers cannot be grater than 1 a >= b - 1 *
917 * For each constraint L in Lower bound set of ineqs *
918 * For each constraint U in Upper bound set of ineqs *
920 * if k only is a constant (rank(k) == 0) *
921 * if const(k) >= -1 *
922 * dist = min(dist, cosnt(k)) *
923 * delete U from set of upper bounds *
924 * if gap is no grater than 1 U shoud be empty. *
925 * Now do the same to L *
926 ********************************************************************************/
927 int lin_ineq_op::check_gap(const lin_ineq
& a
, const lin_ineq
& b
) const
934 for(int i
= 0; i
< a
.num_constraint(); i
++)
935 for(int j
= 0; j
< b
.num_constraint(); j
++) {
939 dist
= MIN(dist
+2, k
.c(0));
948 if((!liq_a
.is_empty())||(!liq_a
.is_empty())) return -1;