-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathlib-gpoly.lisp
667 lines (613 loc) · 44.9 KB
/
lib-gpoly.lisp
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
;; -*- Mode:Lisp; Syntax:ANSI-Common-LISP; Coding:us-ascii-unix; fill-column:158 -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;; @file lib-gpoly.lisp
;; @author Mitch Richling <https://www.mitchr.me>
;; @brief Generate Polynomial Code For General Fields.@EOL
;; @std Common Lisp
;; @copyright
;; @parblock
;; Copyright (c) 1994,1997,1998,2004,2008,2013,2015, Mitchell Jay Richling <https://www.mitchr.me> All rights reserved.
;;
;; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
;;
;; 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
;;
;; 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation
;; and/or other materials provided with the distribution.
;;
;; 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software
;; without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
;; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
;; DAMAGE.
;; @endparblock
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defpackage :MJR_GPOLY
(:USE :COMMON-LISP)
(:DOCUMENTATION "Brief: Generate Polynomial Code For General Fields.;")
(:EXPORT #:mjr_gpoly_help
#:mjr_gpoly_make-simplify
#:mjr_gpoly_make-+
#:mjr_gpoly_make--
#:mjr_gpoly_make-*
#:mjr_gpoly_make-iexpt
#:mjr_gpoly_make-coeff
#:mjr_gpoly_make-scale
#:mjr_gpoly_make-truncate
#:mjr_gpoly_make-rem
#:mjr_gpoly_make-mod
#:mjr_gpoly_make-divides?
#:mjr_gpoly_make-gcd
#:mjr_gpoly_make-degree
#:mjr_gpoly_make-leading-coeff
#:mjr_gpoly_make-constant-coeff
#:mjr_gpoly_make-zerop
#:mjr_gpoly_make-onep
#:mjr_gpoly_make-constantp
#:mjr_gpoly_make-eval
#:mjr_gpoly_make-diff
#:mjr_gpoly_make-subst
#:mjr_gpoly_make-density
#:mjr_gpoly_make-index
;; TODO:
;;#:mjr_gpoly_make-2square-free
))
(in-package :MJR_GPOLY)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mjr_gpoly_help ()
"Back end code to generate code for univariate, dense polynomial libraries. This is not intended for interactive use.
The idea is that a ring structure is defined and codified in another package, and that package is then exploited to generate code for polynomials over that
base ring.
Naming conventions:
* A base ring is defined in a package called 'MJR_FOO' ('foo' is the logical name of the ring)
* The package containing the code for the polynomial ring over 'foo' is called 'MJR_POLYFOO'
MJR_GFP & MJR_POLYGFP are the canonical examples of how to do this."
(documentation 'mjr_gpoly_help 'function))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mjr_gpoly_to-sym-str (&rest rest)
"Convert objects to uppercase strings and concatenate them. If given a single list, apply fucntion to elements."
(if (and rest (listp (car rest)) (null (cdr rest)))
(mapcar (lambda (y) (mjr_gpoly_to-sym-str y)) (car rest))
(format nil "~:@(~{~a~^~}~)" rest)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mjr_gpoly_to-sym (&rest rest)
""
(if (and rest (listp (car rest)) (null (cdr rest)))
(mapcar (lambda (y) (mjr_gpoly_to-sym y)) (car rest))
(intern (apply #'mjr_gpoly_to-sym-str rest))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mjr_gpoly_get-op (ring-name ring-op)
"Return the symbol to use for the operation"
(let ((std-rng (zerop (length ring-name))))
(destructuring-bind (op-name pk-name) (if std-rng
(or (cdr (assoc ring-op
'(("zerop" . ("MJR_CMP_=0" "MJR_CMP"))
("onep" . ("MJR_CMP_=1" "MJR_CMP"))
("divides?" . ("MJR_INTU_DIVIDES?" "MJR_INTU"))
("numberp" . ("NUMBERP" "COMMON-LISP"))
("iexpt" . ("EXPT" "COMMON-LISP"))
("imul" . ("*" "COMMON-LISP")))
:test #'equalp))
(list (mjr_gpoly_to-sym-str ring-op) "COMMON-LISP"))
(list (mjr_gpoly_to-sym-str "mjr_" ring-name "_" (if (equalp ring-op "numberp")
(format nil "~ap" ring-name)
ring-op))
(mjr_gpoly_to-sym-str "mjr_" ring-name)))
(if (find-symbol op-name pk-name)
(intern op-name pk-name)
(if (not (and std-rng (equalp "simplify" op-name)))
(warn "WARNING: Could not find ring (~a) operation (~a) -- function (~a) in package (~a)!" ring-name ring-op op-name pk-name))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-scale (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_SCALE."
(let* ((ring-div-func (mjr_gpoly_get-op ring-name "/"))
(ring-mul-func (mjr_gpoly_get-op ring-name "*"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_scale")))
`(defun ,(intern new-func-name) (,@ring-parameters poly x &optional invert-x)
"Multiply, on the left, the coefficients of POLY by X (or 1/X if INVERT-X is non-NIL)."
(if (not (,ring-numberp-func ,@ring-parameters x))
(error ,(concatenate 'string new-func-name ": The second argument (X) must be a base ring element)")))
(let ((fact (if invert-x
(,ring-div-func ,@ring-parameters x)
x)))
(,poly-simplify-func ,@ring-parameters (map 'vector (lambda (x) (,ring-mul-func ,@ring-parameters x fact)) poly))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-coeff (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_COEFF."
(let ((ring-simplify-func (mjr_gpoly_get-op ring-name "simplify"))
(ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_coeff")))
`(defun ,(intern new-func-name) (,@ring-parameters poly n)
"Return the coefficient on the term of degree n when n is non-negative, or the -n'th (1 based) coefficient if n is negative.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)"
(let ((poly (if (vectorp poly) poly (vector poly)))
(idx (if (minusp n)
(- -1 n)
(let ((plen (length poly)))
(1- (- plen n))))))
(if (array-in-bounds-p poly idx)
,(if ring-simplify-func
`(,ring-simplify-func ,@ring-parameters (aref poly idx))
`(aref poly idx))
,(apply ring-add-func ring-parameters))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-simplify (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_SIMPLIFY."
(let ((ring-zerop-func (mjr_gpoly_get-op ring-name "zerop"))
(ring-simplify-func (mjr_gpoly_get-op ring-name "simplify"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_simplify")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
,(concatenate 'string "Simplify the polynomial by removing leading zero terms. If nothing needs to be done, then POLY is returned (not a copy).
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)
This function is almost FREE if the poly is already simplified, so it can be used to verify a polynomial is simplified without introducing too much
overhead.")
(if (vectorp poly)
(let* ((lt-idx (if (not (,ring-zerop-func ,@ring-parameters (aref poly 0)))
0
(or (position-if (lambda (x) (not (,ring-zerop-func ,@ring-parameters x))) poly)
(1- (length poly)))))
(npoly (if (zerop lt-idx)
poly
(subseq poly lt-idx))))
,(if ring-simplify-func
`(map 'vector (lambda (x) (,ring-simplify-func ,@ring-parameters x)) npoly)
`npoly))
(if (,ring-numberp-func ,@ring-parameters poly)
,(if ring-simplify-func
`(vector (,ring-simplify-func ,@ring-parameters poly))
`(vector poly))
(error ,(concatenate 'string new-func-name ": POLY must be a polynomial or base ring element")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-eval (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_EVAL."
(let ((ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-mul-func (mjr_gpoly_get-op ring-name "*"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_eval")))
`(defun ,(intern new-func-name) (,@ring-parameters poly x)
"Evaluate polynomial.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)"
(if (not (,ring-numberp-func ,@ring-parameters x))
(error ,(concatenate 'string new-func-name ": Polynomials may only be evaluated on base ring elements (i.e. X must be a base ring element)")))
(let* ((poly (,poly-simplify-func ,@ring-parameters poly))
(plen (length poly))
(pval ,(apply ring-add-func ring-parameters)))
(loop for i from 0 upto (1- plen)
do (setq pval (,ring-add-func ,@ring-parameters (,ring-mul-func ,@ring-parameters x pval) (aref poly i)))
finally (return pval))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-+ (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_+."
(let ((ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_+")))
`(defun ,(intern new-func-name) (,@ring-parameters &rest polys)
,(concatenate 'string "Add the given polynomials and base ring elements.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)")
(cond ((null polys) (vector ,(apply ring-add-func ring-parameters))) ;; (,ring-add-func ,@ring-parameters)))
((null (cdr polys)) (if (vectorp (car polys))
(,poly-simplify-func ,@ring-parameters (car polys))
(if (,ring-numberp-func ,@ring-parameters (car polys))
(vector (car polys))
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))
('t (loop for x in polys
for len = (if (vectorp x)
(length x)
(if (,ring-numberp-func ,@ring-parameters x)
1
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements"))))
when (zerop len)
do (error ,(concatenate 'string new-func-name ": Polynomials must not be of zero length!"))
count (vectorp x) into pcnt
collect len into plens
maximize len into nplen
finally (return (if (zerop pcnt)
(vector (reduce (lambda (x y) (,ring-add-func ,@ring-parameters x y)) polys))
(loop with newpoly = (make-array nplen :initial-element (,ring-add-func ,@ring-parameters))
for poly in polys
for plen in plens
do (loop for i downfrom (1- nplen) downto 0
for j downfrom (1- plen) downto 0
do (setf (aref newpoly i)
(,ring-add-func ,@ring-parameters
(aref newpoly i)
(if (vectorp poly) (aref poly j) poly))))
finally (return (,poly-simplify-func ,@ring-parameters newpoly)))))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-- (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_-."
(let ((ring-sub-func (mjr_gpoly_get-op ring-name "-"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(poly-add-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_+"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "MJR_POLY" ring-name "_-")))
`(defun ,(intern new-func-name) (,@ring-parameters &rest polys)
,(concatenate 'string "Subtract the given polynomials.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)")
(cond ((null polys) (error ,(concatenate 'string new-func-name ": At least one argument is required!")))
((null (cdr polys)) (if (vectorp (car polys))
(,poly-simplify-func ,@ring-parameters (map 'vector (lambda (x) (,ring-sub-func ,@ring-parameters x)) (car polys)))
(if (,ring-numberp-func ,@ring-parameters (car polys))
(vector (,ring-sub-func ,@ring-parameters (car polys)))
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))
('t (loop with lhp = (,poly-simplify-func ,@ring-parameters (car polys))
with lhp-len = (length lhp)
with rhp = (apply #',poly-add-func ,@ring-parameters (cdr polys))
with rhp-len = (length rhp)
with ans-len = (max lhp-len rhp-len)
with newpoly = (make-array ans-len :initial-element 0)
for lhp-i downfrom (1- lhp-len)
for rhp-i downfrom (1- rhp-len)
for ans-i downfrom (1- ans-len) downto 0
do (setf (aref newpoly ans-i) (- (if (minusp lhp-i) 0 (aref lhp lhp-i))
(if (minusp rhp-i) 0 (aref rhp rhp-i))))
finally (return (,poly-simplify-func ,@ring-parameters newpoly))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-* (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_*."
(let ((ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-mul-func (mjr_gpoly_get-op ring-name "*"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(poly-mul-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_*"))
(poly-add-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_+"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_*")))
`(defun ,(intern new-func-name) (,@ring-parameters &rest polys)
"Multiply the given polynomials and/or base ring elements.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :).
poly*poly = multiply as polynomials, s*poly & poly*s = multiply s by each element, s*s = multiply base ring elements."
(let ((num-polys (length polys)))
(case num-polys
(0 (vector ,(apply ring-mul-func ring-parameters)))
(1 (,poly-simplify-func ,@ring-parameters (car polys)))
(2 (let ((poly1 (first polys))
(poly2 (second polys)))
(let* ((poly1 (,poly-simplify-func ,@ring-parameters poly1))
(poly2 (,poly-simplify-func ,@ring-parameters poly2))
(plen1 (length poly1))
(plen2 (length poly2)))
(apply #',poly-add-func
,@ring-parameters
(loop for i from 0 upto (1- plen1)
for pcoef1 across poly1
for npl = (make-array (- (+ plen1 plen2) i 1) :initial-element ,(apply ring-add-func ring-parameters))
do (loop for j from 0
for c across poly2
do (setf (aref npl j) (,ring-mul-func ,@ring-parameters c pcoef1)))
collect npl)))))
(otherwise (reduce (lambda (x y) (,poly-mul-func ,@ring-parameters x y)) polys)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-iexpt (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_IEXPT."
(let ((poly-mul-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_*"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_iexpt")))
`(defun ,(intern new-func-name) (,@ring-parameters poly n)
,(concatenate 'string "Compute poly^n
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :).
References:
David Bressoud (1989); Factorization and primality testing; ISBN: 0-387-97040-1; pp33-34")
(cond ((not (integerp n)) (error ,(concatenate 'string new-func-name ": N must be an integer!")))
((minusp n) (error ,(concatenate 'string new-func-name ": N must be non-negative!"))))
(if (zerop n)
(,poly-mul-func ,@ring-parameters)
(let ((pp (,poly-mul-func ,@ring-parameters)))
(loop while (not (zerop n))
finally (return pp)
when (oddp n)
do (setf pp (,poly-mul-func ,@ring-parameters pp poly)
n (- n 1))
do (setf poly (,poly-mul-func ,@ring-parameters poly poly)
n (truncate n 2))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-diff (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_DIFF."
(let* ((ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-imul-func (mjr_gpoly_get-op ring-name "imul"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_diff"))
(new-func-name-sym (intern new-func-name)))
`(defun ,new-func-name-sym (,@ring-parameters poly &optional (order 1))
"Return the ORDER'th derivative of POLY."
(let ((plen (length poly)))
(cond ((< order 0) (error ,(concatenate 'string new-func-name ": ORDER must be non-negative!")))
((= order 0) (copy-seq poly))
((<= plen 1) (make-array 1 :initial-element ,(apply ring-add-func ring-parameters)))
((<= plen order) (make-array 1 :initial-element ,(apply ring-add-func ring-parameters)))
((> order 1) (,new-func-name-sym (,new-func-name-sym poly 1) (1- order)))
('t (,poly-simplify-func ,@ring-parameters
(let ((dpoly (make-array (1- plen) :initial-element ,(apply ring-add-func ring-parameters))))
(loop for i below (1- plen)
do (setf (aref dpoly i) (,ring-imul-func ,@ring-parameters (aref poly i) (- plen i 1)))
finally (return dpoly))))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-leading-coeff (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_LEADING-COEFF."
(let* ((ring-zerop-func (mjr_gpoly_get-op ring-name "zerop"))
(ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-simplify-func (mjr_gpoly_get-op ring-name "simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_leading-coeff")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return the leading term (the non-zero coefficient of the term with highest power).
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :).
Returns 0 if all the coefficients were zero -- note that zero is the additive identity in the base ring."
(let ((lc (if (vectorp poly)
(or (find-if (lambda (x) (not (,ring-zerop-func ,@ring-parameters x))) poly)
,(apply ring-add-func ring-parameters))
(if (,ring-numberp-func ,@ring-parameters poly)
poly
(error ,(concatenate 'string new-func-name ": Arguments must be a polynomial or base ring element"))))))
,(if ring-simplify-func
`(,ring-simplify-func ,@ring-parameters lc)
`lc)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-degree (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_DEGREE."
(let* ((ring-zerop-func (mjr_gpoly_get-op ring-name "zerop"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_degree")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return the degree of POLY.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(if (vectorp poly)
(let ((pos (position-if (lambda (x) (not (,ring-zerop-func ,@ring-parameters x))) poly))
(plen (length poly)))
(if pos
(- plen pos 1)
(if (> plen 0)
0
(error ,(concatenate 'string new-func-name ": Polynomials must be of non-zero length")))))
(if (,ring-numberp-func ,@ring-parameters poly)
0
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-density (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_DENSITY."
(let* ((ring-zerop-func (mjr_gpoly_get-op ring-name "zerop"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_density")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return the density of POLY (i.e. The number of non-zero terms)
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(if (vectorp poly)
(count-if (lambda (x) (not (,ring-zerop-func ,@ring-parameters x))) poly)
(if (,ring-numberp-func ,@ring-parameters poly)
(if (,ring-zerop-func ,@ring-parameters poly)
1
0)
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-index (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_INDEX."
(let* ((ring-zerop-func (mjr_gpoly_get-op ring-name "zerop"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_index")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return the index of POLY (i.e. Sum of the exponents of the non-zero terms)
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(if (vectorp poly)
(loop for i from (1- (length poly)) downto 0
for c across poly
when (not (,ring-zerop-func ,@ring-parameters c))
sum i)
(if (,ring-numberp-func ,@ring-parameters poly)
0
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-constant-coeff (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_CONSTANT-COEFF."
(let* ((ring-simplify-func (mjr_gpoly_get-op ring-name "simplify"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_constant-coeff")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return the coefficient on the term with no x (i.e. zero power term).
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(let ((ct (if (vectorp poly)
(aref poly (1- (length poly)))
(if (,ring-numberp-func ,@ring-parameters poly)
poly
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements"))))))
,(if ring-simplify-func
`(,ring-simplify-func ,@ring-parameters ct)
`ct)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-onep (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_ONEP."
(let* ((ring-onep-func (mjr_gpoly_get-op ring-name "onep"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_onep")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return non-NIL if the polynomial is the unit (i.e. == 1).
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(if (vectorp poly)
(if (= 1 (length poly))
(,ring-onep-func ,@ring-parameters (aref poly 0))
(let ((poly (,poly-simplify-func ,@ring-parameters poly)))
(and (= (length poly) 1) (,ring-onep-func ,@ring-parameters (aref poly 0)))))
(if (,ring-numberp-func ,@ring-parameters poly)
(,ring-onep-func ,@ring-parameters poly)
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-constantp (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_CONSTANTP."
(let* ((ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_constantp")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Return non-NIL if the polynomial is a constant polynomial (i.e. degree 1)
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(if (vectorp poly)
(= 1 (length (,poly-simplify-func ,@ring-parameters poly)))
(if (,ring-numberp-func ,@ring-parameters poly)
't
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-zerop (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_ZEROP."
(let* ((ring-zerop-func (mjr_gpoly_get-op ring-name "zerop"))
(ring-numberp-func (mjr_gpoly_get-op ring-name "numberp"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_zerop")))
`(defun ,(intern new-func-name) (,@ring-parameters poly)
"Returns non-NIL if the polynomial is the zero polynomial.
Things that are not vectors are assumed to be ring elements. This works well when ring elements are not vectors too. :)."
(if (vectorp poly)
(every (lambda (x) (,ring-zerop-func ,@ring-parameters x)) poly)
(if (,ring-numberp-func ,@ring-parameters poly)
(,ring-zerop-func ,@ring-parameters poly)
(error ,(concatenate 'string new-func-name ": Arguments must be Polynomials and/or base ring elements")))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-truncate (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_TRUNCATE."
(let* ((ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-sub-func (mjr_gpoly_get-op ring-name "-"))
(ring-div-func (mjr_gpoly_get-op ring-name "/"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_truncate")))
`(defun ,(intern new-func-name) (,@ring-parameters poly1 poly2)
"Return the quotient and the remainder from POLY1/POLY2.
Based upon a generalization of synthetic division published in 2003 by Lianghuo FAN. The algorithm implemented is a minor generalization of FAN's work that
supports non-monic polynomial divisors. Note that this implementation is not optimized.
Reference: Lianghuo FAN (2003)
A Generalization of Synthetic Division and A General Theorem of Division of Polynomials; Mathematical Medley, June 2003; pp30-37"
(let* ((poly1 (,poly-simplify-func ,@ring-parameters poly1))
(poly2 (,poly-simplify-func ,@ring-parameters poly2))
(len1 (length poly1))
(len2 (length poly2)))
(if (> len2 len1)
(values (vector ,(apply ring-add-func ring-parameters))
poly1)
(if (= 1 (length poly2))
(values (,poly-simplify-func ,@ring-parameters (map 'vector
; MJR TODO NOTE <2011-11-23 13:19:59 CST> mjr_gpoly_make-truncate: Use _scale here
(lambda (x) (,ring-div-func ,@ring-parameters x (aref poly2 0)))
poly1))
(vector ,(apply ring-add-func ring-parameters)))
(let ((tmpvec (make-array len1 :initial-element (aref poly1 0))))
(loop for i from 1 upto (1- len1)
do (setf (aref tmpvec i) (,ring-add-func (aref poly1 i)
(,ring-div-func (loop for j from (max 1 (+ (- len2 len1) i)) upto (1- len2)
sum (* (if (<= 0 (- i j))
(aref tmpvec (- i j))
,(apply ring-add-func ring-parameters))
(,ring-sub-func (aref poly2 j))))
(aref poly2 0)))))
(values (,poly-simplify-func ,@ring-parameters (map 'vector
; MJR TODO NOTE <2011-11-23 13:19:59 CST> mjr_gpoly_make-truncate: Use _scale here
(lambda (x) (,ring-div-func ,@ring-parameters x (aref poly2 0)))
(subseq tmpvec 0 (1+ (- len1 len2)))))
(,poly-simplify-func ,@ring-parameters (subseq tmpvec (1+ (- len1 len2))))))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-mod (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_MOD."
(let* ((poly-truncate-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_truncate"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_mod")))
`(defun ,(intern new-func-name) (,@ring-parameters poly1 poly2)
"Returns the quotient of poly1/poly2"
(multiple-value-bind (quo rem) (,poly-truncate-func ,@ring-parameters poly1 poly2)
(declare (ignore rem))
quo))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-rem (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_REM."
(let* ((poly-truncate-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_truncate"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_rem")))
`(defun ,(intern new-func-name) (,@ring-parameters poly1 poly2)
"Returns the quotient of poly1/poly2"
(multiple-value-bind (quo rem) (,poly-truncate-func ,@ring-parameters poly1 poly2)
(declare (ignore quo))
rem))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-divides? (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_DIVIDES?."
(let* ((ring-divides?-func (mjr_gpoly_get-op ring-name "divides?"))
(poly-truncate-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_truncate"))
(poly-lc-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_leading-coeff"))
(poly-cc-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_constant-coeff"))
(poly-zerop-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_zerop"))
(poly-degree-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_degree"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_divides?")))
`(defun ,(intern new-func-name) (,@ring-parameters poly1 poly2 &key require-integer-quotient)
"Returns the quotient of poly2/poly1 if poly1 divides poly2, and NIL otherwise."
(and (,ring-divides?-func ,@ring-parameters (,poly-lc-func ,@ring-parameters poly1) (,poly-lc-func ,@ring-parameters poly2))
(,ring-divides?-func ,@ring-parameters (,poly-cc-func ,@ring-parameters poly1) (,poly-cc-func ,@ring-parameters poly2))
(<= (,poly-degree-func ,@ring-parameters poly1) (,poly-degree-func ,@ring-parameters poly2))
(multiple-value-bind (quo rem) (,poly-truncate-func ,@ring-parameters poly2 poly1)
(if (,poly-zerop-func ,@ring-parameters rem)
(if (or (not require-integer-quotient) (every #'integerp quo))
quo)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-gcd (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_GCD."
(let* ((ring-add-func (mjr_gpoly_get-op ring-name "+"))
(ring-div-func (mjr_gpoly_get-op ring-name "/"))
(poly-lc-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_leading-coeff"))
(poly-rem-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_rem"))
(poly-zerop-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_zerop"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_gcd")))
`(defun ,(intern new-func-name) (,@ring-parameters poly1 poly2)
"Return monic GCD of poly1 and poly2
References:
Joel S. Cohen (2003); Computer Algebra and Symbolic Computation: Mathematical Methods; ISBN: 1568811594; pp130"
(if (and (,poly-zerop-func ,@ring-parameters poly1) (,poly-zerop-func ,@ring-parameters poly2))
(vector ,(apply ring-add-func ring-parameters))
(let ((poly1w (copy-seq poly1))
(poly2w (copy-seq poly2)))
(loop while (not (,poly-zerop-func ,@ring-parameters poly2w))
do (psetq poly1w poly2w
poly2w (,poly-rem-func ,@ring-parameters poly1w poly2w)))
; MJR TODO NOTE <2011-11-23 13:19:59 CST> mjr_gpoly_make-truncate: Use _scale here
(map 'vector
(lambda (x) (,ring-div-func ,@ring-parameters x (,poly-lc-func ,@ring-parameters poly1w)))
poly1w))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro mjr_gpoly_make-subst (ring-name &rest ring-parameters)
"Construct and defun for MJR_POLY<RING>_SUBST."
(let* ((poly-mul-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_*"))
(poly-add-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_+"))
(poly-simplify-func (mjr_gpoly_to-sym "mjr_poly" ring-name "_simplify"))
(ring-parameters (mjr_gpoly_to-sym ring-parameters))
(new-func-name (mjr_gpoly_to-sym-str "mjr_poly" ring-name "_subst")))
`(defun ,(intern new-func-name) (,@ring-parameters sub-poly poly)
"Substitute SUB-POLY into POLY.
Not very fast, but very flexible."
(let* ((poly (,poly-simplify-func ,@ring-parameters poly))
(sub-poly (,poly-simplify-func ,@ring-parameters sub-poly)))
(apply #',poly-add-func
,@ring-parameters
(loop for pow-val = #(1) then (,poly-mul-func ,@ring-parameters pow-val sub-poly)
for i from (1- (length poly)) downto 0
when (not (zerop (aref poly i)))
collect (,poly-mul-func ,@ring-parameters (aref poly i) pow-val)))))))