Cyclotomic polynomial: Difference between revisions

m (J: minor "speedup" (not adequately benchmarked))
(→‎{{header|jq}}: task2(10))
 
(32 intermediate revisions by 6 users not shown)
Line 14:
=={{header|C++}}==
{{trans|Java}}
<langsyntaxhighlight lang="cpp">#include <algorithm>
#include <iostream>
#include <initializer_list>
Line 532:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>Task 1: cyclotomic polynomials for n <= 30:
Line 581:
{{trans|Java}}
{{works with|C sharp|8}}
<langsyntaxhighlight lang="csharp">using System;
using System.Collections;
using System.Collections.Generic;
Line 816:
};
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 865:
=={{header|D}}==
{{trans|Kotlin}}
<langsyntaxhighlight lang="d">import std.algorithm;
import std.exception;
import std.format;
Line 1,303:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>Task 1: cyclotomic polynomials for n <= 30:
Line 1,351:
=={{header|Fermat}}==
This isn't terribly efficient if you have to calculate many cyclotomics- store them in an array rather than using recursion instead if you need to do that- but it showcases Fermat's strength at polynomial expressions.
<langsyntaxhighlight lang="fermat">
&(J=x); {adjoin x as the variable in the polynomials}
 
Line 1,381:
od;
!!(m,' : ',i);
od;</langsyntaxhighlight>
 
=={{header|Go}}==
{{trans|Java}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,824:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,877:
Uses synthetic polynomial division and simple memoization.
 
<langsyntaxhighlight lang="haskell">import Data.List
import Data.Numbers.Primes (primeFactors)
 
Line 1,915:
-- general case
(p, m):ps -> let cm = cyclotomics !! (n `div` (p ^ m))
in lift (lift cm p `shortDiv` cm) (p^(m-1))</langsyntaxhighlight>
 
Simple examples
Line 1,930:
The task solution
 
<langsyntaxhighlight lang="haskell">showPoly [] = "0"
showPoly p = foldl1 (\r -> (r ++) . term) $
dropWhile null $
Line 1,965:
 
skipBy n [] = []
skipBy n lst = let (x:_, b) = splitAt n lst in x:skipBy n b</langsyntaxhighlight>
 
Result
Line 2,015:
=={{header|J}}==
 
For values up to 70, we can find cyclotomic polynomials by finding a polynomial with roots of unity relatively prime to the order of the polynomial:
Implementation of routine to find nth cyclotomic polynomial:
 
<syntaxhighlight lang="j">cyclo=: {{<.-:1+(++) p. 1;^0j2p1* y%~1+I.1=y+.1+i.y}}</syntaxhighlight>
<lang J>{{ if.0>nc<'cache' do.cache=:y end.}} a:;_1 1
 
This approach suggests that cyclotomic polynomial zero should be <tt>f<sub>0</sub>(x)= 1</tt>
 
Routine to find the nth cyclotomic polynomial:
 
<syntaxhighlight lang="j">{{ if.0>nc<'cache' do.cache=:y end.}} (,1);_1 1
 
cyclotomic=: {{
Line 2,053 ⟶ 2,059:
'x y'=. x,:y
while. j=. j-1 do.
if. 0={.yx do. j=. j-<:i=. 0 i.~ 0=yx
q=. q,ji#0
x=. ji |.!.0 x
else.
q=. q, r=. x %&{. y
Line 2,061 ⟶ 2,067:
end.
end.q
}}</langsyntaxhighlight>
 
If you take all the divisors of a number. (For example, for 12, the divisors are: 1, 2, 3, 4, 6 and 12) and find the product of their cyclotomic polynomials (for example, for 12, x-1, x+1, x<sup>2</sup>+x+1, x<sup>2</sup>+1, x<sup>2</sup>-x+1, and x<sup>4</sup>-x<sup>2</sup>+1) you get x<sup>n</sup>-1 (for 12, that would of course be x<sup>12</sup>-1).
 
Notes:
 
* the coefficients of cyclotomic polynomials after 1 form a palindrome (that's the <tt>q#1</tt> phrase in the implementation).
* the cyclotomic polynomial for a prime number has as many terms as that number, and the coefficients are all 1 (with no intervening zeros -- the highest power is one less than that prime).
* powers of primes add zero coefficients to the polynomial (that's the <tt>,(y%*/q) {."0</tt> ... phrase in the implementation). This means that we can mostly ignore powers of prime numbers -- they're just going to correspond to zeros we add to the base polynomial.
* an even base cyclotomic polynomial is the same as the corresponding odd base cyclotomic polynomial except with x replaced by negative x. (that's the <tt>(* 1 _1 $~ #)</tt> phrase in the implementation.
* To deal with the general case, we use polynomial division, x<sup>n</sup>-1 divided by the polynomial product the cyclotomic polynomials of the proper divisors of number we're looking for.
* <tt>+//.@(*/)</tt> is polynomial product in J.
 
Task examples:
 
<langsyntaxhighlight Jlang="j">taskfmt=: {{
c=. ":each j=.cyclotomic y
raw=. rplc&'_-' ;:inv}.,'+';"0|.(*|j)#c('(',[,],')'"_)each '*x^',&":L:0 <"0 i.#c
Line 2,124 ⟶ 2,141:
8 6545
9 6545
10 10465</langsyntaxhighlight>
 
=== Another approach ===
 
As noted in the [http://jsoftware.com/pipermail/programming/2022-March/060209.html J programming forum], we can improve the big-O character of this algorithm by using the [[Fast Fourier transform#J|fast fourier transform]] for polynomial multiplication and division.
 
<syntaxhighlight lang="j">NB. install'math/fftw'
require'math/fftw'
 
cyclotomic000=: {{ assert.0<y
if. y = 1 do. _1 1 return. end.
'q p'=. __ q: y
if. 1=#q do.
,(y%*/q) {."0 q#1
elseif.2={.q do.
,(y%*/q) {."0 (* 1 _1 $~ #) cyclotomic */}.q
elseif. 1 e. 1 < p do.
,(y%*/q) {."0 cyclotomic */q
else.
lgl=. {:$ ctlist=. cyclotomic "0 }:*/@>,{1,each q NB. ctlist is 2-d table of polynomial divisors
lgd=. # dividend=. _1,(-y){.1 NB. (x^n) - 1, and its size
lg=. >.&.(2&^.) lgl >. lgd NB. required lengths of all polynomials for fft transforms
NB. really, "divisor" is the fft of the divisor!
divisor=. */ fftw"1 lg{."1 ctlist NB. FFT article doesn't deal with lists of multiplicands
unpad roundreal ifftw"1 divisor %~ fftw lg{.dividend NB. similar to article's multiplication
end.
}}
 
roundreal =: [: <. 0.5 + 9&o.</syntaxhighlight>
 
This variation for polynomial division is only valid when there's no remainder to be concerned with (which is the case, here). The article mentioned in the comments is an essay on using [[j:Essays/FFT|fft for polynomial multiplication]]
 
This approach gave slightly over a 16x speedup for <tt>taskorder 10</tt>, from a 2 element cache, with an approximately 50% increased memory footprint. (Remember, of course, that benchmarks and benchmark ratios have dependencies on computer architecture and language implementation, and the host environment.)
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.Collections;
Line 2,654 ⟶ 2,703:
 
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,700 ⟶ 2,749:
CP[6545] has coefficient with magnitude = 9
CP[10465] has coefficient with magnitude = 10
</pre>
 
===Alternative Version===
An alternative example using the algorithm from "Matters Computational" by Jorg Arndt, pages 704 - 705.
It completes the task in less than 2 seconds.
<syntaxhighlight lang="java">
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
public class CyclotomicPolynomials {
 
public static void main(String[] args) {
System.out.println("Task 1: Cyclotomic polynomials for n <= 30:");
for ( int cpIndex = 1; cpIndex <= 30; cpIndex++ ) {
System.out.println("CP[" + cpIndex + "] = " + toString(cyclotomicPolynomial(cpIndex)));
}
System.out.println();
System.out.println("Task 2: Smallest cyclotomic polynomial with n or -n as a coefficient:");
System.out.println("CP[1] has a coefficient with magnitude 1");
int cpIndex = 2;
for ( int coefficient = 2; coefficient <= 10; coefficient++ ) {
while ( BigInteger.valueOf(cpIndex).isProbablePrime(PRIME_CERTAINTY)
|| ! hasHeight(cyclotomicPolynomial(cpIndex), coefficient) ) {
cpIndex += 1;
}
System.out.println("CP[" + cpIndex + "] has a coefficient with magnitude " + coefficient);
}
}
// Return the Cyclotomic Polynomial of order 'cpIndex' as an array of coefficients,
// where, for example, the polynomial 3x^2 - 1 is represented by the array [3, 0, -1].
private static int[] cyclotomicPolynomial(int cpIndex) {
int[] polynomial = new int[] { 1, -1 };
if ( cpIndex == 1 ) {
return polynomial;
}
if ( BigInteger.valueOf(cpIndex).isProbablePrime(PRIME_CERTAINTY) ) {
int[] result = new int[cpIndex];
Arrays.fill(result, 1);
return result;
}
List<Integer> primes = distinctPrimeFactors(cpIndex);
int product = 1;
for ( int prime : primes ) {
int[] numerator = substituteExponent(polynomial, prime);
polynomial = exactDivision(numerator, polynomial);
product *= prime;
}
polynomial = substituteExponent(polynomial, cpIndex / product);
return polynomial;
}
// Return the Cyclotomic Polynomial obtained from 'polynomial' by replacing x with x^'exponent'.
private static int[] substituteExponent(int[] polynomial, int exponent) {
int[] result = new int[exponent * ( polynomial.length - 1 ) + 1];
for ( int i = polynomial.length - 1; i >= 0; i-- ) {
result[i * exponent] = polynomial[i];
}
return result;
}
// Return the Cyclotomic Polynomial equal to 'dividend' / 'divisor'. The division is always exact.
private static int[] exactDivision(int[] dividend, int[] divisor) {
int[] result = Arrays.copyOf(dividend, dividend.length);
for ( int i = 0; i < dividend.length - divisor.length + 1; i++ ) {
if ( result[i] != 0 ) {
for ( int j = 1; j < divisor.length; j ++ ) {
result[i + j] += -divisor[j] * result[i];
}
}
}
result = Arrays.copyOf(result, result.length - divisor.length + 1);
return result;
}
 
// Return whether 'polynomial' has a coefficient of equal magnitude to 'coefficient'.
private static boolean hasHeight(int[] polynomial, int coefficient) {
for ( int i = 0; i <= ( polynomial.length + 1 ) / 2; i++ ) {
if ( Math.abs(polynomial[i]) == coefficient ) {
return true;
}
}
return false;
}
// Return a string representation of 'polynomial'.
private static String toString(int[] polynomial) {
StringBuilder text = new StringBuilder();
for ( int i = 0; i < polynomial.length; i++ ) {
if ( polynomial[i] == 0 ) {
continue;
}
text.append(( polynomial[i] < 0 ) ? ( ( i == 0 ) ? "-" : " - " ) : ( ( i == 0 ) ? "" : " + " ));
final int exponent = polynomial.length - 1 - i;
if ( exponent > 0 && Math.abs(polynomial[i]) > 1 ) {
text.append(Math.abs(polynomial[i]));
}
text.append(( exponent > 1 ) ?
( "x^" + String.valueOf(exponent) ) : ( ( exponent == 1 ) ? "x" : Math.abs(polynomial[i]) ));
}
return text.toString();
}
// Return a list of the distinct prime factors of 'number'.
private static List<Integer> distinctPrimeFactors(int number) {
List<Integer> primeFactors = new ArrayList<Integer>();
for ( int divisor = 2; divisor * divisor <= number; divisor++ ) {
if ( number % divisor == 0 ) {
primeFactors.add(divisor);
}
while ( number % divisor == 0 ) {
number = number / divisor;
}
}
if ( number > 1 ) {
primeFactors.add(number);
}
return primeFactors;
}
private static final int PRIME_CERTAINTY = 15;
 
}
</syntaxhighlight>
<pre>
Task 1: Cyclotomic polynomials for n <= 30:
CP[1] = x - 1
CP[2] = x + 1
CP[3] = x^2 + x + 1
CP[4] = x^2 + 1
CP[5] = x^4 + x^3 + x^2 + x + 1
CP[6] = x^2 - x + 1
CP[7] = x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[8] = x^4 + 1
CP[9] = x^6 + x^3 + 1
CP[10] = x^4 - x^3 + x^2 - x + 1
CP[11] = x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[12] = x^4 - x^2 + 1
CP[13] = x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[14] = x^6 - x^5 + x^4 - x^3 + x^2 - x + 1
CP[15] = x^8 - x^7 + x^5 - x^4 + x^3 - x + 1
CP[16] = x^8 + 1
CP[17] = x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[18] = x^6 - x^3 + 1
CP[19] = x^18 + x^17 + x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[20] = x^8 - x^6 + x^4 - x^2 + 1
CP[21] = x^12 - x^11 + x^9 - x^8 + x^6 - x^4 + x^3 - x + 1
CP[22] = x^10 - x^9 + x^8 - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1
CP[23] = x^22 + x^21 + x^20 + x^19 + x^18 + x^17 + x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[24] = x^8 - x^4 + 1
CP[25] = x^20 + x^15 + x^10 + x^5 + 1
CP[26] = x^12 - x^11 + x^10 - x^9 + x^8 - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1
CP[27] = x^18 + x^9 + 1
CP[28] = x^12 - x^10 + x^8 - x^6 + x^4 - x^2 + 1
CP[29] = x^28 + x^27 + x^26 + x^25 + x^24 + x^23 + x^22 + x^21 + x^20 + x^19 + x^18 + x^17 + x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
CP[30] = x^8 + x^7 - x^5 - x^4 - x^3 + x + 1
 
Task 2: Smallest cyclotomic polynomial with n or -n as a coefficient:
CP[1] has a coefficient with magnitude 1
CP[105] has a coefficient with magnitude 2
CP[385] has a coefficient with magnitude 3
CP[1365] has a coefficient with magnitude 4
CP[1785] has a coefficient with magnitude 5
CP[2805] has a coefficient with magnitude 6
CP[3135] has a coefficient with magnitude 7
CP[6545] has a coefficient with magnitude 8
CP[6545] has a coefficient with magnitude 9
CP[10465] has a coefficient with magnitude 10
</pre>
 
=={{header|jq}}==
'''Adapted from the [[#Wren|Wren]] implementation of the Arndt algorithm'''
 
'''Works with jq, the C implementation of jq'''
 
'''Works with gojq, the Go implementation of jq'''
 
'''Works with jaq, the Rust implementation of jq'''
 
In this entry, a polynomial of degree n is represented by a JSON
array of length n+1 beginning with the leading coefficient.
 
For the second task, besides exploiting the fact that
CP[1] has height 1, the following program only assumes that the
cyclotomic polynomials are palindromic, but avoids recomputing them.
<syntaxhighlight lang="jq">
### Generic utilities
 
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;
 
# Return the maximum item in the stream assuming it is not empty:
def max(s): reduce s as $s (null; if . == null then $s elif $s > . then $s else . end);
 
# Truncated integer division (consistent with % operator).
# `round` is used for the sake of jaq.
def quo($x; $y): ($x - ($x%$y)) / $y | round;
 
### Primes
def is_prime:
. as $n
| if ($n < 2) then false
elif ($n % 2 == 0) then $n == 2
elif ($n % 3 == 0) then $n == 3
elif ($n % 5 == 0) then $n == 5
elif ($n % 7 == 0) then $n == 7
elif ($n % 11 == 0) then $n == 11
elif ($n % 13 == 0) then $n == 13
elif ($n % 17 == 0) then $n == 17
elif ($n % 19 == 0) then $n == 19
else sqrt as $s
| 23
| until( . > $s or ($n % . == 0); . + 2)
| . > $s
end;
 
# Emit an array of the distinct prime factors of 'n' in order using a wheel
# with basis [2, 3, 5], e.g. 44 | distinctPrimeFactors #=> [2,11]
def distinctPrimeFactors:
def augment($x): if .[-1] == $x then . else . + [$x] end;
def out($i):
if (.n % $i) == 0
then .factors += [$i]
| until (.n % $i != 0; .n = ((.n/$i)|floor) )
else .
end;
if . < 2 then []
else [4, 2, 4, 2, 4, 6, 2, 6] as $inc
| { n: .,
factors: [] }
| out(2)
| out(3)
| out(5)
| .k = 7
| .i = 0
| until(.k * .k > .n;
if .n % .k == 0
then .k as $k | .factors |= augment($k)
| .n = ((.n/.k)|floor)
else .k += $inc[.i]
| .i = ((.i + 1) % 8)
end)
| if .n > 1 then .n as $n | .factors |= augment($n) else . end
| .factors
end;
 
### Polynomials
def canonical:
if length == 0 then .
elif .[-1] == 0 then .[:-1]|canonical
else .
end;
 
# For pretty-printing the input array as the polynomial it represents
# e.g. [1,-1] => x-1
def pp:
def digits: tostring | explode[] | [.] | implode | tonumber;
def superscript:
if . <= 1 then ""
else ["\u2070", "\u00b9", "\u00b2", "\u00b3", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079"] as $ss
| reduce digits as $d (""; . + $ss[$d] )
end;
 
if length == 1 then .[0] | tostring
else reverse as $p
| reduce range(length-1; -1; -1) as $i ([];
if $p[$i] != 0
then (if $i > 0 then "x" else "" end) as $x
| ( if $i > 0 and ($p[$i]|length) == 1
then (if $p[$i] == 1 then "" else "-" end)
else ($p[$i]|tostring)
end ) as $c
| . + ["\($c)\($x)\($i|superscript)"]
else . end )
| join("+")
| gsub("\\+-"; "-")
end ;
 
def polynomialDivide($divisor):
. as $in
| ($divisor|canonical) as $divisor
| { curr: canonical}
| .base = ((.curr|length) - ($divisor|length))
| until( .base < 0;
(.curr[-1] / $divisor[-1]) as $res
| .result += [$res]
| .curr |= .[:-1]
| reduce range (0;$divisor|length-1) as $i (.;
.curr[.base + $i] += (- $res * $divisor[$i]) )
| .base += -1 )
| (.result | reverse) as $quot
| (.curr | canonical) as $rem
| [$quot, $rem];
 
# Call `round` for the sake of jaq
def exactDivision($numerator; $denominator):
($numerator | polynomialDivide($denominator))
| .[0]
| map(round);
 
def init($n; $value): [range(0;$n)|$value];
 
### Cyclotomic Polynomials
 
# The Cyclotomic Polynomial obtained from $polynomial
# by replacing x with x^$exponent
def substituteExponent($polynomial; $exponent):
init( ($polynomial|length - 1) * $exponent + 1; 0)
| reduce range(0; $polynomial|length) as $i (.; .[$i*$exponent] = $polynomial[$i]);
 
# Return the Cyclotomic Polynomial of order 'cpIndex' as a JSON array of coefficients,
# where, for example, the polynomial 3x^2 - 1 is represented by [3, 0, -1].
def cycloPoly($cpIndex):
{ polynomial: [1, -1] }
| if $cpIndex == 1 then .polynomial
elif ($cpIndex|is_prime) then [range(0; $cpIndex) | 1 ]
else .product = 1
| reduce ($cpIndex | distinctPrimeFactors[]) as $prime (.;
substituteExponent(.polynomial; $prime) as $numerator
| .polynomial = exactDivision($numerator; .polynomial)
| .product *= $prime )
| substituteExponent(.polynomial; quo($cpIndex; .product) )
end;
 
# The Cyclotomic Polynomial equal to $dividend / $divisor
def exactDivision($dividend; $divisor):
reduce range(0; 1 + ($dividend|length) - ($divisor|length)) as $i ($dividend;
if .[$i] != 0
then reduce range(1; $divisor|length) as $j (.;
.[$i+$j] = .[$i+$j] - $divisor[$j] * .[$i] )
else .
end)
| .[0: 1 + length - ($divisor|length)];
 
### The tasks
def task1($n):
"Task 1: Cyclotomic polynomials for n <= \($n):",
( range(1;$n+1) | "CP[\(lpad(2))]: \(cycloPoly(.)|pp)" );
 
# For range(1;$n+1) as $c, report the first cpIndex which has a coefficient
# equal in magnitude to $c, possibly reporting others as well.
def task2($n):
def height: max(.[]|length); # i.e. abs
# update .summary and .todo
def register($cpIndex):
cycloPoly($cpIndex) as $poly
| if ($poly|height) < .todo[0] then .
else # it is a palindrome so we can halve the checks
reduce ($poly | .[0: quo(length + 1; 2)][]|length|select(.>1)) as $c (.;
if .summary[$c|tostring] then .
else .summary[$c|tostring] = $cpIndex
| .todo -= [$c]
| debug
end)
end;
 
{cpIndex:1, summary: {"1": 1}, todo: [range(2; $n + 1)]}
| until(.todo|length == 0;
if .cpIndex|is_prime then . else register(.cpIndex) end
| .cpIndex += 1)
| .summary
| (keys | sort_by(tonumber)[]) as $key
| "CP[\(.[$key]|lpad(5))] has a coefficient with magnitude \($key)"
;
 
task1(30),
"",
task2(10)
</syntaxhighlight>
{{output}}
<pre>
Task 1: Cyclotomic polynomials for n <= 30:
CP[ 1]: x-1
CP[ 2]: x+1
CP[ 3]: x²+x+1
CP[ 4]: x²+1
CP[ 5]: x⁴+x³+x²+x+1
CP[ 6]: x²-x+1
CP[ 7]: x⁶+x⁵+x⁴+x³+x²+x+1
CP[ 8]: x⁴+1
CP[ 9]: x⁶+x³+1
CP[10]: x⁴-x³+x²-x+1
CP[11]: x¹⁰+x⁹+x⁸+x⁷+x⁶+x⁵+x⁴+x³+x²+x+1
CP[12]: x⁴-x²+1
CP[13]: x¹²+x¹¹+x¹⁰+x⁹+x⁸+x⁷+x⁶+x⁵+x⁴+x³+x²+x+1
CP[14]: x⁶-x⁵+x⁴-x³+x²-x+1
CP[15]: x⁸-x⁷+x⁵-x⁴+x³-x+1
CP[16]: x⁸+1
CP[17]: x¹⁶+x¹⁵+x¹⁴+x¹³+x¹²+x¹¹+x¹⁰+x⁹+x⁸+x⁷+x⁶+x⁵+x⁴+x³+x²+x+1
CP[18]: x⁶-x³+1
CP[19]: x¹⁸+x¹⁷+x¹⁶+x¹⁵+x¹⁴+x¹³+x¹²+x¹¹+x¹⁰+x⁹+x⁸+x⁷+x⁶+x⁵+x⁴+x³+x²+x+1
CP[20]: x⁸-x⁶+x⁴-x²+1
CP[21]: x¹²-x¹¹+x⁹-x⁸+x⁶-x⁴+x³-x+1
CP[22]: x¹⁰-x⁹+x⁸-x⁷+x⁶-x⁵+x⁴-x³+x²-x+1
CP[23]: x²²+x²¹+x²⁰+x¹⁹+x¹⁸+x¹⁷+x¹⁶+x¹⁵+x¹⁴+x¹³+x¹²+x¹¹+x¹⁰+x⁹+x⁸+x⁷+x⁶+x⁵+x⁴+x³+x²+x+1
CP[24]: x⁸-x⁴+1
CP[25]: x²⁰+x¹⁵+x¹⁰+x⁵+1
CP[26]: x¹²-x¹¹+x¹⁰-x⁹+x⁸-x⁷+x⁶-x⁵+x⁴-x³+x²-x+1
CP[27]: x¹⁸+x⁹+1
CP[28]: x¹²-x¹⁰+x⁸-x⁶+x⁴-x²+1
CP[29]: x²⁸+x²⁷+x²⁶+x²⁵+x²⁴+x²³+x²²+x²¹+x²⁰+x¹⁹+x¹⁸+x¹⁷+x¹⁶+x¹⁵+x¹⁴+x¹³+x¹²+x¹¹+x¹⁰+x⁹+x⁸+x⁷+x⁶+x⁵+x⁴+x³+x²+x+1
CP[30]: x⁸+x⁷-x⁵-x⁴-x³+x+1
 
Task 2: Smallest cyclotomic polynomial with n or -n as a coefficient:
CP[ 1] has a coefficient with magnitude 1
CP[ 105] has a coefficient with magnitude 2
CP[ 385] has a coefficient with magnitude 3
CP[ 1365] has a coefficient with magnitude 4
CP[ 1785] has a coefficient with magnitude 5
CP[ 2805] has a coefficient with magnitude 6
CP[ 3135] has a coefficient with magnitude 7
CP[ 6545] has a coefficient with magnitude 8
CP[ 6545] has a coefficient with magnitude 9
CP[10465] has a coefficient with magnitude 10
CP[10465] has a coefficient with magnitude 11
CP[10465] has a coefficient with magnitude 12
CP[10465] has a coefficient with magnitude 13
CP[10465] has a coefficient with magnitude 14
</pre>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">using Primes, Polynomials
# memoize cache for recursive calls
Line 2,760 ⟶ 3,242:
println("The cyclotomic polynomial Φ(", abs(n), ") has a coefficient that is ", n < 0 ? -i : i)
end
</langsyntaxhighlight>{{out}}
<pre>
First 30 cyclotomic polynomials:
Line 2,807 ⟶ 3,289:
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">import java.util.TreeMap
import kotlin.math.abs
import kotlin.math.pow
Line 3,263 ⟶ 3,745:
} else coefficient.toString() + "x^" + exponent
}
}</langsyntaxhighlight>
{{out}}
<pre>Task 1: cyclotomic polynomials for n <= 30:
Line 3,310 ⟶ 3,792:
 
=={{header|Maple}}==
<langsyntaxhighlight lang="maple">with(NumberTheory):
for n to 30 do lprint(Phi(n,x)) od:
 
Line 3,347 ⟶ 3,829:
[seq(ListTools:-SelectFirst(s->member(n,s),PhiSet,output=indices),n=1..20)];
#[1, 105, 385, 1365, 1785, 2805, 3135, 6545, 6545, 10465, 10465,
# 10465, 10465, 10465, 11305, 11305, 11305, 11305, 11305, 11305]</langsyntaxhighlight>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">Cyclotomic[#, x] & /@ Range[30] // Column
i = 1;
n = 10;
Line 3,371 ⟶ 3,853:
];
i++;
]</langsyntaxhighlight>
{{out}}
<pre>-1+x
Line 3,420 ⟶ 3,902:
We use Java algorithm with ideas from C#, D, Go and Kotlin. We have kept only algorithm number 2 as other algorithms are much less efficient. We have also done some Nim specific improvements in order to get better performances.
 
<langsyntaxhighlight Nimlang="nim">import algorithm, math, sequtils, strformat, tables
 
type
Line 3,754 ⟶ 4,236:
echo &"Φ{'(' & $n & ')':7} has coefficient with magnitude = {i}"
dec n
break</langsyntaxhighlight>
 
{{out}}
Line 3,805 ⟶ 4,287:
=={{header|PARI/GP}}==
Cyclotomic polynomials are a built-in function.
<langsyntaxhighlight lang="parigp">
for(n=1,30,print(n," : ",polcyclo(n)))
 
Line 3,811 ⟶ 4,293:
 
for(d=1,10,i=1; while(contains_coeff(i,d)==0,i=i+1);print(d," : ",i))
</syntaxhighlight>
</lang>
 
{{out}}<pre>
Line 3,858 ⟶ 4,340:
=={{header|Perl}}==
Conveniently, the module <code>Math::Polynomial::Cyclotomic</code> exists to do all the work. An <code>exponent too large</code> error prevents reaching the 10th step of the 2nd part of the task.
<langsyntaxhighlight lang="perl">use feature 'say';
use List::Util qw(first);
use Math::Polynomial::Cyclotomic qw(cyclo_poly_iterate);
Line 3,875 ⟶ 4,357:
$n++;
}
}</langsyntaxhighlight>
{{out}}
<pre>First 30 cyclotomic polynomials:
Line 3,923 ⟶ 4,405:
{{trans|Julia}}
Uses several routines from [[Polynomial_long_division#Phix]], tweaked slightly to check remainder is zero and trim the quotient.
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Cyclotomic_Polynomial.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
Line 4,038 ⟶ 4,520:
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<!--</langsyntaxhighlight>-->
{{out}}
If you disable the cheating, and if in a particularly self harming mood replace it with n+=1, you will get exactly the same output, eventually.<br>
Line 4,087 ⟶ 4,569:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from itertools import count, chain
from collections import deque
 
Line 4,208 ⟶ 4,690:
while want in c or -want in c:
print(f'C[{want}]: {n}')
want += 1</langsyntaxhighlight>
{{out}}
Only showing first 10 polynomials to avoid clutter.
Line 4,254 ⟶ 4,736:
 
Uses the same library as Perl, so comes with the same caveats.
<syntaxhighlight lang="raku" perl6line>use Math::Polynomial::Cyclotomic:from<Perl5> <cyclo_poly_iterate cyclo_poly>;
 
say 'First 30 cyclotomic polynomials:';
Line 4,277 ⟶ 4,759:
sub super ($str) {
$str.subst( / '^' (\d+) /, { $0.trans([<0123456789>.comb] => [<⁰¹²³⁴⁵⁶⁷⁸⁹>.comb]) }, :g)
}</langsyntaxhighlight>
<pre>First 30 cyclotomic polynomials:
Φ(1) = (x - 1)
Line 4,322 ⟶ 4,804:
 
=={{header|Sidef}}==
Built-in:
Solution based on polynomial interpolation (slow).
<syntaxhighlight lang="ruby">say "First 30 cyclotomic polynomials:"
<lang ruby>var Poly = require('Math::Polynomial')
Poly.string_config(Hash(fold_sign => true, prefix => "", suffix => ""))
 
func poly_interpolation(v) {
v.len.of {|n| v.len.of {|k| n**k } }.msolve(v)
}
 
say "First 30 cyclotomic polynomials:"
for k in (1..30) {
var a =say ("Φ(#{k+1}).of {= ", cyclotomic(k, _) })
var Φ = poly_interpolation(a)
say ("Φ(#{k}) = ", Poly.new(Φ...))
}
 
say "\nSmallest cyclotomic polynomial with n or -n as a coefficient:"
for n in (1..10) { # very slow
var k = (1..Inf -> first {|k|
poly_interpolation(cyclotomic(k+1).ofcoeffs.any { cyclotomic(k, _) }).first { tail.abs == n }
})
say "Φ(#{k}) has coefficient with magnitude #{n}"
}</langsyntaxhighlight>
 
Slightly faster solution, using the '''Math::Polynomial::Cyclotomic''' Perl module.
<lang ruby>var Poly = require('Math::Polynomial')
require('Math::Polynomial::Cyclotomic')
 
Poly.string_config(Hash(fold_sign => true, prefix => "", suffix => ""))
 
say "First 30 cyclotomic polynomials:"
for k in (1..30) {
say ("Φ(#{k}) = ", Poly.new.cyclotomic(k))
}
 
say "\nSmallest cyclotomic polynomial with n or -n as a coefficient:"
for n in (1..10) {
var p = Poly.new
var k = (1..Inf -> first {|k|
[p.cyclotomic(k).coeff].first { .abs == n }
})
say "Φ(#{k}) has coefficient with magnitude = #{n}"
}</lang>
 
{{out}}
Line 4,409 ⟶ 4,862:
^C
</pre>
 
=={{header|Visual Basic .NET}}==
{{trans|C++}}
<langsyntaxhighlight lang="vbnet">Imports System.Text
 
Module Module1
Line 4,893 ⟶ 5,347:
End Sub
 
End Module</langsyntaxhighlight>
{{out}}
<pre>Task 1: cyclotomic polynomials for n <= 30:
Line 4,940 ⟶ 5,394:
 
=={{header|Wren}}==
===Version 1===
{{trans|Go}}
{{libheader|Wren-traititerate}}
{{libheader|Wren-sort}}
{{libheader|Wren-math}}
{{libheader|Wren-fmt}}
Second part is very slow. Limited to first 7 to finish in a reasonable time - 5 minutes on my machine.
<langsyntaxhighlight ecmascriptlang="wren">import "./traititerate" for Stepped
import "./sort" for Sort
import "./math" for Int, Nums
import "./fmt" for Fmt
 
var algo = 2
Line 5,285 ⟶ 5,740:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 5,329 ⟶ 5,784:
CP[2805] has coefficient with magnitude = 6
CP[3135] has coefficient with magnitude = 7
</pre>
 
===Version 2===
{{trans|Java}}
A translation of the alternative version which completes the second part in about 33 seconds.
<syntaxhighlight lang="wren">import "./math" for Int
import "./fmt" for Fmt
 
class CP {
// Return the Cyclotomic Polynomial of order 'cpIndex' as a list of coefficients,
// where, for example, the polynomial 3x^2 - 1 is represented by the list [3, 0, -1].
static cycloPoly(cpIndex) {
var polynomial = [1, -1]
if (cpIndex == 1) return polynomial
if (Int.isPrime(cpIndex)) return List.filled(cpIndex, 1)
var primes = Int.distinctPrimeFactors(cpIndex)
var product = 1
for (prime in primes) {
var numerator = substituteExponent(polynomial, prime)
polynomial = exactDivision(numerator, polynomial)
product = product * prime
}
return substituteExponent(polynomial, Int.quo(cpIndex, product))
}
 
// Return the Cyclotomic Polynomial obtained from 'polynomial'
// by replacing x with x^'exponent'.
static substituteExponent(polynomial, exponent) {
var result = List.filled(exponent * (polynomial.count - 1) + 1, 0)
for (i in polynomial.count-1..0) result[i*exponent] = polynomial[i]
return result
}
 
// Return the Cyclotomic Polynomial equal to 'dividend' / 'divisor'.
// The division is always exact.
static exactDivision(dividend, divisor) {
var result = dividend.toList
for (i in 0..dividend.count - divisor.count) {
if (result[i] != 0) {
for (j in 1...divisor.count) {
result[i+j] = result[i+j] - divisor[j] * result[i]
}
}
}
return result[0..result.count - divisor.count]
}
 
// Return whether 'polynomial' has a coefficient of equal magnitude
// to 'coefficient'.
static hasHeight(polynomial, coefficient) {
for (i in 0..Int.quo(polynomial.count + 1, 2)) {
if (polynomial[i].abs == coefficient) return true
}
return false
}
}
 
System.print("Task 1: Cyclotomic polynomials for n <= 30:")
for (cpIndex in 1..30) {
Fmt.write("CP[$2d] = ", cpIndex)
Fmt.pprint("$d", CP.cycloPoly(cpIndex), "", "x")
}
 
System.print("\nTask 2: Smallest cyclotomic polynomial with n or -n as a coefficient:")
System.print("CP[ 1] has a coefficient with magnitude 1")
var cpIndex = 2
for (coeff in 2..10) {
while (Int.isPrime(cpIndex) || !CP.hasHeight(CP.cycloPoly(cpIndex), coeff)) {
cpIndex = cpIndex + 1
}
Fmt.print("CP[$5d] has a coefficient with magnitude $d", cpIndex, coeff)
}</syntaxhighlight>
 
{{out}}
<pre>
Task 1: Cyclotomic polynomials for n <= 30:
CP[ 1] = x - 1
CP[ 2] = x + 1
CP[ 3] = x² + x + 1
CP[ 4] = x² + 1
CP[ 5] = x⁴ + x³ + x² + x + 1
CP[ 6] = x² - x + 1
CP[ 7] = x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[ 8] = x⁴ + 1
CP[ 9] = x⁶ + x³ + 1
CP[10] = x⁴ - x³ + x² - x + 1
CP[11] = x¹⁰ + x⁹ + x⁸ + x⁷ + x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[12] = x⁴ - x² + 1
CP[13] = x¹² + x¹¹ + x¹⁰ + x⁹ + x⁸ + x⁷ + x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[14] = x⁶ - x⁵ + x⁴ - x³ + x² - x + 1
CP[15] = x⁸ - x⁷ + x⁵ - x⁴ + x³ - x + 1
CP[16] = x⁸ + 1
CP[17] = x¹⁶ + x¹⁵ + x¹⁴ + x¹³ + x¹² + x¹¹ + x¹⁰ + x⁹ + x⁸ + x⁷ + x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[18] = x⁶ - x³ + 1
CP[19] = x¹⁸ + x¹⁷ + x¹⁶ + x¹⁵ + x¹⁴ + x¹³ + x¹² + x¹¹ + x¹⁰ + x⁹ + x⁸ + x⁷ + x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[20] = x⁸ - x⁶ + x⁴ - x² + 1
CP[21] = x¹² - x¹¹ + x⁹ - x⁸ + x⁶ - x⁴ + x³ - x + 1
CP[22] = x¹⁰ - x⁹ + x⁸ - x⁷ + x⁶ - x⁵ + x⁴ - x³ + x² - x + 1
CP[23] = x²² + x²¹ + x²⁰ + x¹⁹ + x¹⁸ + x¹⁷ + x¹⁶ + x¹⁵ + x¹⁴ + x¹³ + x¹² + x¹¹ + x¹⁰ + x⁹ + x⁸ + x⁷ + x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[24] = x⁸ - x⁴ + 1
CP[25] = x²⁰ + x¹⁵ + x¹⁰ + x⁵ + 1
CP[26] = x¹² - x¹¹ + x¹⁰ - x⁹ + x⁸ - x⁷ + x⁶ - x⁵ + x⁴ - x³ + x² - x + 1
CP[27] = x¹⁸ + x⁹ + 1
CP[28] = x¹² - x¹⁰ + x⁸ - x⁶ + x⁴ - x² + 1
CP[29] = x²⁸ + x²⁷ + x²⁶ + x²⁵ + x²⁴ + x²³ + x²² + x²¹ + x²⁰ + x¹⁹ + x¹⁸ + x¹⁷ + x¹⁶ + x¹⁵ + x¹⁴ + x¹³ + x¹² + x¹¹ + x¹⁰ + x⁹ + x⁸ + x⁷ + x⁶ + x⁵ + x⁴ + x³ + x² + x + 1
CP[30] = x⁸ + x⁷ - x⁵ - x⁴ - x³ + x + 1
 
Task 2: Smallest cyclotomic polynomial with n or -n as a coefficient:
CP[ 1] has a coefficient with magnitude 1
CP[ 105] has a coefficient with magnitude 2
CP[ 385] has a coefficient with magnitude 3
CP[ 1365] has a coefficient with magnitude 4
CP[ 1785] has a coefficient with magnitude 5
CP[ 2805] has a coefficient with magnitude 6
CP[ 3135] has a coefficient with magnitude 7
CP[ 6545] has a coefficient with magnitude 8
CP[ 6545] has a coefficient with magnitude 9
CP[10465] has a coefficient with magnitude 10
</pre>
2,442

edits