File: PolyNorm.eo

package info (click to toggle)
cvc5 1.3.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 87,260 kB
  • sloc: cpp: 383,850; java: 12,207; python: 12,090; sh: 5,679; ansic: 4,729; lisp: 763; perl: 208; makefile: 38
file content (237 lines) | stat: -rw-r--r-- 11,851 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
(include "../theories/Ints.eo")
(include "../theories/Reals.eo")
(include "../theories/BitVectors.eo")
(include "../programs/Utils.eo")

; define: $typeunion
; args:
; - T Type: A type.
; - U Type: A type.
; return: >
;   The "type union" of T and U. This method is used for the type rules
;   for operators that allow mixed arithmetic. It also permits that the union
;   of two equal types is itself.
(define $typeunion ((T Type) (U Type))
  (eo::ite (eo::eq T U) T ($arith_typeunion T U)))

; Definitions of monomials and polynomials.
; A monomial is a list of terms that are ordered by `$compare_var` and a rational coefficient.
; A polynomial is a list of monomials whose monomials are ordered by `$compare_var`.
(declare-const @@Monomial Type)
(define @Monomial () @@Monomial)
(declare-parameterized-const @@mon ((T Type :implicit)) (-> T Real @Monomial))
(define @mon () @@mon)

(declare-const @@Polynomial Type)
(define @Polynomial () @@Polynomial)
(declare-const @@poly.zero @Polynomial)
(define @poly.zero () @@Polynomial)
(declare-const @@poly (-> @Monomial @Polynomial @Polynomial) :right-assoc-nil @poly.zero)
(define @poly () @@poly)

; program: $poly_neg
; args:
; - p @Polynomial: The polynomial to negate.
; return: the negation of the given polynomial.
(program $poly_neg ((T Type) (c Real) (a T) (p @Polynomial :list))
  :signature (@Polynomial) @Polynomial
  (
    (($poly_neg @poly.zero)           @poly.zero)
    (($poly_neg (@poly (@mon a c) p)) (eo::cons @poly (@mon a (eo::neg c)) ($poly_neg p)))
  )
)
; program: $poly_mod_coeffs
; args:
; - p @Polynomial: The polynomial to modify.
; - w Int: The modulus to consider
; return: the given polynomial where all coefficient are taken mod w.
(program $poly_mod_coeffs ((T Type) (c Real) (a T) (p @Polynomial :list) (w Int))
  :signature (@Polynomial Int) @Polynomial
  (
    (($poly_mod_coeffs @poly.zero w)           @poly.zero)
    (($poly_mod_coeffs (@poly (@mon a c) p) w) (eo::define ((newc (eo::zmod (eo::to_z c) w)))
                                               (eo::ite (eo::eq newc 0)
                                                 ; if it becomes zero, it cancels
                                                 ($poly_mod_coeffs p w)
                                                 (eo::cons @poly (@mon a (eo::to_q newc)) ($poly_mod_coeffs p w)))))
  )
)

; program: $poly_add
; args:
; - p1 @Polynomial: The first polynomial to add.
; - p2 @Polynomial: The second polynomial to add.
; return: the addition of the given polynomials.
(program $poly_add ((T Type) (U Type) (c1 Real) (a1 T) (c2 Real) (a2 U) (p @Polynomial) (p1 @Polynomial :list) (p2 @Polynomial :list))
  :signature (@Polynomial @Polynomial) @Polynomial
  (
    (($poly_add (@poly (@mon a1 c1) p1) (@poly (@mon a2 c2) p2)) (eo::ite (eo::eq a1 a2)
                                                                  (eo::define ((ca (eo::add c1 c2)) (pa ($poly_add p1 p2)))
                                                                  ; check if cancels
                                                                  (eo::ite (eo::eq ca 0/1) pa (eo::cons @poly (@mon a1 ca) pa)))
                                                                (eo::ite ($compare_var a1 a2)
                                                                  (eo::cons @poly (@mon a1 c1) ($poly_add p1 (@poly (@mon a2 c2) p2)))
                                                                  (eo::cons @poly (@mon a2 c2) ($poly_add (@poly (@mon a1 c1) p1) p2)))))
    (($poly_add @poly.zero p)                                    p)
    (($poly_add p @poly.zero)                                    p)
  )
)

; program: $mvar_mul_mvar
; args:
; - a X: The first monomial variable to multiply.
; - c Y: The second monomial variable to multiply.
; return: the multiplication of the given monomial variables.
(program $mvar_mul_mvar ((T Type) (U Type) (V Type) (W Type) (X Type) (Y Type) (Z Type)
                         (a1 T) (a2 U :list) (c1 V) (c2 W :list)
                         (m Int)  (ba1 (BitVec m)) (ba2 (BitVec m) :list) (bc1 (BitVec m)) (bc2 (BitVec m) :list))
  :signature (X Y) ($typeunion X Y)
  (
    (($mvar_mul_mvar (* a1 a2) (* c1 c2))  (eo::ite ($compare_var a1 c1)
                                             (eo::cons * a1 ($mvar_mul_mvar a2 (* c1 c2)))
                                             (eo::cons * c1 ($mvar_mul_mvar (* a1 a2) c2))))
    (($mvar_mul_mvar (* a1 a2) 1)          (* a1 a2))
    (($mvar_mul_mvar 1 (* c1 c2))          (* c1 c2))
    (($mvar_mul_mvar (bvmul ba1 ba2) (bvmul bc1 bc2))  (eo::ite ($compare_var ba1 bc1)
                                                         (eo::cons bvmul ba1 ($mvar_mul_mvar ba2 (bvmul bc1 bc2)))
                                                         (eo::cons bvmul bc1 ($mvar_mul_mvar (bvmul ba1 ba2) bc2))))
    (($mvar_mul_mvar (bvmul ba1 ba2) bc1)              (eo::requires (eo::to_z bc1) 1 (bvmul ba1 ba2)))
    (($mvar_mul_mvar ba1 (bvmul bc1 bc2))              (eo::requires (eo::to_z ba1) 1 (bvmul bc1 bc2)))
    (($mvar_mul_mvar ba1 bc1)                          (eo::requires (eo::to_z ba1) 1
                                                       (eo::requires (eo::to_z bc1) 1 ba1)))
  )
)

; program: $mon_mul_mon
; args:
; - a @Monomial: The first monomial to multiply.
; - b @Monomial: The second monomial to multiply.
; return: the multiplication of the given monomials.
(program $mon_mul_mon ((T Type) (U Type) (a1 T) (a2 U) (c1 Real) (c2 Real))
  :signature (@Monomial @Monomial) @Monomial
  (
    (($mon_mul_mon (@mon a1 c1) (@mon a2 c2))  (@mon ($mvar_mul_mvar a1 a2) (eo::mul c1 c2)))
  )
)

; program: $poly_mul_mon
; args:
; - a @Monomial: The monomial to multiply.
; - p @Polynomial: The polynomial to multiply.
; return: the multiplication of the polynomial by a monomial.
(program $poly_mul_mon ((m1 @Monomial) (m2 @Monomial) (p2 @Polynomial :list))
  :signature (@Monomial @Polynomial) @Polynomial
  (
    (($poly_mul_mon m1 (@poly m2 p2)) ($poly_add (@poly ($mon_mul_mon m1 m2)) ($poly_mul_mon m1 p2)))   ; NOTE: this amounts to an insertion sort
    (($poly_mul_mon m1 @poly.zero)    @poly.zero)
  )
)

; program: $poly_mul
; args:
; - p1 @Polynomial: The first polynomial to multiply.
; - p2 @Polynomial: The second polynomial to multiply.
; return: the multiplication of the given polynomials.
(program $poly_mul ((m @Monomial) (p1 @Polynomial :list) (p @Polynomial))
  :signature (@Polynomial @Polynomial) @Polynomial
  (
    (($poly_mul (@poly m p1) p) ($poly_add ($poly_mul_mon m p) ($poly_mul p1 p)))
    (($poly_mul @poly.zero p)   @poly.zero)
    (($poly_mul p @poly.zero)   @poly.zero)
  )
)

; program: $get_arith_poly_norm_div
; args:
; - a1 T: The numerator to process of type Int or Real.
; - a1p @Polynomial: The normalization of a1.
; - a2 T: The denominator to process of type Int or Real.
; return: >
;   The polynomial corresponding to the (normalized) form of (/ a1 a2).
(define $get_arith_poly_norm_div ((U Type :implicit) (V Type :implicit) (a1 U) (a1p @Polynomial) (a2 V))
  (eo::define ((a2q (eo::to_q a2)))
  (eo::ite (eo::ite (eo::is_q a2q) (eo::not (eo::eq a2q 0/1)) false)
    ; if division by non-zero constant, we normalize
    ($poly_mul_mon (@mon 1 (eo::qdiv 1/1 a2q)) a1p)
    ; otherwise it is treated as a variable
    (@poly (@mon (* (/ a1 a2)) 1/1)))))

; program: $get_arith_poly_norm
; args:
; - a T: The arithmetic term to process of type Int or Real.
; return: the polynomial corresponding to the (normalized) form of a.
(program $get_arith_poly_norm ((T Type) (U Type) (V Type) (a T) (a1 U) (a2 V :list))
  :signature (T) @Polynomial
  (
    (($get_arith_poly_norm (- a1))          ($poly_neg ($get_arith_poly_norm a1)))
    (($get_arith_poly_norm (+ a1 a2))       ($poly_add ($get_arith_poly_norm a1) ($get_arith_poly_norm a2)))
    (($get_arith_poly_norm (- a1 a2))       ($poly_add ($get_arith_poly_norm a1) ($poly_neg ($get_arith_poly_norm a2))))
    (($get_arith_poly_norm (* a1 a2))       ($poly_mul ($get_arith_poly_norm a1) ($get_arith_poly_norm a2)))
    (($get_arith_poly_norm (/ a1 a2))       ($get_arith_poly_norm_div a1 ($get_arith_poly_norm a1) a2))
    (($get_arith_poly_norm (/_total a1 a2)) ($get_arith_poly_norm_div a1 ($get_arith_poly_norm a1) a2))
    (($get_arith_poly_norm (to_real a1))    ($get_arith_poly_norm a1))
    (($get_arith_poly_norm a)               (eo::define ((aq (eo::to_q a)))
                                            ; check if a is a constant (Int or Real)
                                            (eo::ite (eo::is_q aq)
                                              ; if it is zero, it cancels, otherwise it is 1 with itself as coefficient
                                              (eo::ite (eo::is_eq aq 0/1)
                                                @poly.zero
                                                (@poly (@mon 1 aq)))
                                            (@poly (@mon (* a) 1/1)))))    ; introduces list
  )
)

; program: $get_bv_poly_norm_rec
; args:
; - b (BitVec m): The bitvector term to process.
; return: the polynomial corresponding to the (normalized) form of b, prior to taking mod of its coefficients.
(program $get_bv_poly_norm_rec ((m Int) (b (BitVec m)) (b1 (BitVec m)) (b2 (BitVec m) :list))
  :signature ((BitVec m)) @Polynomial
  (
    (($get_bv_poly_norm_rec (bvneg b1))    ($poly_neg ($get_bv_poly_norm_rec b1)))
    (($get_bv_poly_norm_rec (bvadd b1 b2)) ($poly_add ($get_bv_poly_norm_rec b1) ($get_bv_poly_norm_rec b2)))
    (($get_bv_poly_norm_rec (bvsub b1 b2)) ($poly_add ($get_bv_poly_norm_rec b1) ($poly_neg ($get_bv_poly_norm_rec b2))))
    (($get_bv_poly_norm_rec (bvmul b1 b2)) ($poly_mul ($get_bv_poly_norm_rec b1) ($get_bv_poly_norm_rec b2)))
    (($get_bv_poly_norm_rec b)             (eo::define ((bt (eo::typeof b)))
                                           (eo::define ((one (eo::to_bin ($bv_bitwidth bt) 1)))
                                           (eo::ite (eo::is_bin b)
                                             (eo::define ((bz (eo::to_z b)))
                                             ; if it is zero, it cancels, otherwise it is 1 with itself as coefficient
                                             (eo::ite (eo::is_eq bz 0)
                                               @poly.zero
                                               (@poly (@mon one (eo::to_q bz)))))
                                           (@poly (@mon (bvmul b) 1/1))))))    ; introduces list
  )
)

; program: $get_bv_poly_norm
; args:
; - w Int: two raised to the bitwidth of the second argument.
; - b (BitVec m): The bitvector term to process.
; return: the polynomial corresponding to the (normalized) form of b.
(define $get_bv_poly_norm ((m Int :implicit) (w Int) (b (BitVec m)))
  ($poly_mod_coeffs ($get_bv_poly_norm_rec b) w))

; program: $arith_poly_to_term_rec
; args:
; - p @Polynomial: The polynomial to convert to a term.
; return: The term corresponding to the polynomial p.
; note: This method always returns a term of type Real and is not in n-ary
;       form, as 0/1 instead of 0 is used as the last element.
; note: This is a helper for $arith_poly_to_term below.
(program $arith_poly_to_term_rec ((T Type) (p @Polynomial :list) (a T) (c Real))
  :signature (@Polynomial) Real
  (
    (($arith_poly_to_term_rec @poly.zero) 0/1)
    (($arith_poly_to_term_rec (@poly (@mon a c) p)) (+ (* c a) ($arith_poly_to_term_rec p)))
  )
)

; define: $arith_poly_to_term
; args:
; - t T: The term to normalize. This is expected to be a term whose type is Int or Real.
; return: >
;   a term corresponding to the polynomial obtained by converting t to a polynomial.
;   This can be used for normalizing terms according to arithmetic.
(define $arith_poly_to_term ((T Type :implicit) (t T))
  ($arith_poly_to_term_rec ($get_arith_poly_norm t)))