Thanks for the link. The code for circulant matrix generation :
def hankel(R,c,r): entries=c+r[1:]; return matrix(R, len(c), len(r), lambda i,j: entries[i+j])
def circulant(R,E): return hankel(R, E, E[-1:]+E[:-1])
doesn't return the _usual_ circulant matrix (as a result of successive right shifts) but rather a skew-circulant matrix :
# -------------------------------------------------------------------------------------------------------
def hankel(R,c,r): entries=c+r[1:]; return matrix(R, len(c), len(r), lambda i,j: entries[i+j])
def circulant(R,E): return hankel(R, E, E[-1:]+E[:-1])
R=ZZ
E=[42, 20, 13, 55]
print
print circulant(R, E)
# -------------------------------------------------------------------------------------------------------
outputing :
[42 20 13 55]
[20 13 55 42]
[13 55 42 20]
[55 42 20 13]
In fact, a circulant matrix is a special case of a Toeplitz matrix (not a Hankel Matrix). The correct code should look like this :
# -------------------------------------------------------------------------------------------------------
def toeplitz(R, c,r): return matrix(R,len(c), len(r), lambda i,j: c[i-j] if i>=j else r[j-i])
def circulant(R, E): return toeplitz(R, E[0:1]+E[-1:0:-1], E)
def hankel(R, c,r): entries=c+r[1:]; return matrix(R,len(c), len(r), lambda i,j: entries[i+j])
def skew_circulant(R,E): return hankel(R, E, E[-1:]+E[:-1])
R=ZZ
E=[42, 20, 13, 55]
print
print circulant(R, E)
print
print skew_circulant(R, E)
# -------------------------------------------------------------------------------------------------------
# -------------------------------------output ----------------------------------
[42 20 13 55]
[55 42 20 13]
[13 55 42 20]
[20 13 55 42]
[42 20 13 55]
[20 13 55 42]
[13 55 42 20]
[55 42 20 13]
# -------------------------------------------------------------------------------------------------------