hash_base = 2^64;
init_h = 5381;

split_Z(n) =
{
    my (bits = 8, base = 2^bits, sgn = sign(n) % base, res = []);
    n = abs(n);
    while (n != 0,
           res = concat(res, bitand(n, base - 1));
           n = shift(n, -bits));
    res = concat(res, sgn);
}

glue(h, a) = bitand((((h << 5) + h) + a), hash_base - 1);

hash_Z(n) =
{
    my (v = split_Z(n), h = init_h);
    for (i = 1, #v, h = glue(h, v[i]));
    h;
}

hash_ZX(pol) =
{
    my (v = Vec(pol), h = init_h);
    for (i = 1, #v, h = glue(h, hash_Z(v[i])));
    h;
}


check_disc(D, hash, seed = 0) =
{
   if (seed == 0, setrand(seed));
   if (hash_ZX(polclass(D[1], D[2])) != hash,
       error("Wrong class polynomial for D = ", D[1], ", inv = ", D[2]));
}

{
D = [[[-3, 0], 199415601],
     [[-4, 0], 392824566],
     [[-7, 0], 392666638],
     [[-8, 0], 392685999],
     [[-11, 0], 392619250],
     [[-20, 0], 427908603366],
     [[-23, 0], 466294765623259],
     [[-39, 0], 16505852200663133551],
     [[-47, 0], 6402944422652024363],
     [[-87, 0], 4174888675786545598],
     [[-71, 0], 9700283236680509421],
     [[-95, 0], 13008454496997756490],
     [[-56, 0], 11998671908550620494],
     [[-264, 0], 12912619012374504058],
     [[-152, 0], 10731008721722142465],
     [[-3792, 0], 7620467061686776546],
     [[-7139, 0], 12274439570299924406],
     [[-163, 0], 249740438023929931],
     [[-24, 0], 7166885172778],
     [[-40, 0], 236296854599224],
     [[-131, 0], 8331420221009258450],
     [[-451, 0], 14359598510137794606],
     [[-356, 0], 4527984144770046237],
     [[-120, 0], 6891115741722954474],
     [[-311, 0], 15021837413190908510],
     [[-335, 0], 17672415898312866530],
     [[-519, 0], 13506744947615842737],
     [[-84, 0], 4664273993601588884],
     [[-271, 0], 4652420391100252414],
     [[-167, 0], 2826053336532203363],
     [[-231, 0], 6425030865187792225],
     [[-280, 0], 6063510379317462346],
     [[-251, 0], 5232582682029074054],
     [[-1620, 0], 1232737106430825415],
     [[-391, 5], 14572212426390106882],
     [[-20111, 1], 5411404000905873008],
     [[-392, 5], 1938827148297849283],
     [[-343, 1], 257546238364177159],
     [[-2783, 1], 10996804753710941904],
     [[-391, 1], 12637340198398619526],
     [[-5599, 1], 15562216764308300369]];

for (i = 1, #D, check_disc(D[i][1], D[i][2]));

DR = [[[-75, 0], 7797221584007659, 376671349665989785645468855509664073846994182881400101766546260394720617934366189060409433769160357181533432220573885805924825693540852008021952564459774590810585211475243394327684717245750110745945026072328072760225571953639433771639283459668005522842154890829456908826675941553773883099694408386765914172430146193260890042281309331937613624260297092915479077192844416843235737033853226359061755041806842898913531132580673421160537655521664429456369047671439914653309055536929498242296184145972586723145667150625185761830949962500298373529056584928040536064567524870263474685887743703040527814911203719509822876332870699144742892184561609398829910546156826731793518047498225315541275444481177788292169213637463551669277949522309499858775613218022974443961718597909705550334907908272096681310881421925063809112518357896869373327907899703426268496281560228765042197657321214742009561132906624005191491690624145861907151224119699824761808776256630533762728719441507893787757775848664794475988539811278575134333922682568740464050564864294502794430114540622076105981748851862287121587354249984704456793486070616857344028549087804854311807866277937114409612028264996212844411377427435191858159128965207532045931755537411540995454270687742541089492939476560082],
      [[-243, 0], 10890205224450786941, 819816539003337703951551030334491985811219590735808650180084142425889087428278968474816967078788694496520947544632247845148293960128431184216429913375564738983435120171372870463833059539919475240115755341447859856740148463438091631147817394080277037577189318264494706821721345983257007207604976565659002445459533752756403439594595147954877184727959282333598933690523890222486574862338277271651603375551722191624435592552060776002053134461739050123189055598823370045610053376263074127907593363552123382309729600820747663525085476951111221315643502593164457035295391801162246544107314533457417879806021098968509300182682540829561660369718219958918702187270446232698794813755480218436460242299594360809397850298336439084244705407778140537600292162873108406078811122401339560541945962750458360813545456362536413450759306402982253681310730782288761995853476768379157689767510249258235383040592111399964287410641000424797854996084393758288398059903384898037630395150017169041181270749377250772914279451145788567644479020046227191205609636239269452021245993971524029995510112434006315050031017396470300928176256241735855429441793194487014544763039598262470846572824386988540861783118073704736780177053813565445211750595008551163984105886194036038475757862082957],
      [[-588, 0], 879637271447453785, 722172781875446948725027515502840397805803222574263498938157594834753683539692286353539379550260903961870953681724730652335944539054343214809842109182109376376073404934944783430561780090926711128352240351787729618963067414744940653491552049787247397068335298858059915825702852961307136083870626600760767835946633951456834700248463253765418088580513814400067434333278000748727896494114214077094766308557268821917667449381466097345351641374194851269731747888023854019055881132865422068901694215525217069307365686664460579110497068925420022191531596796819270908424786079485895699300312731851621077417224747357440195326283221688405149148310871267542131565275881843830667704094780810055193197890989350423968947844027604016370949415740373443463212927661990707144843034492549347563234263847345087343863729913728036463982329922404548652813756727386840999876115923084606166024940965586010450200229416349092936572815279513133323207117397659789511994921332289638592093388560749212300029278651884171306493436892928038820455609679624565527968832712465530213919299178940798157452403212185383817925419187972425719729474468729656592316632439083960654603463616738116233198556419632548161066690834007443366276926895963450902134482716015380443358800099100412263111150979648],
      [[-1936, 0], 12042224483327737942, 1216866102333088130226524487913144208763734959917103691345969409207516868291718354363183168079965162895868164110454068295852403913687063897316076456732180244314693491111859072668845951826176461315221230058882016799221709155152952471964012736330885451089911136340521851921137288731711645985018653207987024594821449521955479976072917497655704811136469355917733730202537028759098395693891168127853723688728461687547524692980924681009739778062916688599274600924902816402188733597929385212483531422542423979111917373373585978124654150004913998429781081552019917407337230736817542160592949209643774691682024891032738521704689750777805611535687724288457092597016530770301762651133083255869909365609188976361538992126091328095544442922892343390321793772426187309802431464642021666763994457491312667884863871652314337261276496152417457940894836459814316686634775678387158467697914839871436783832178376515625541434789638029419363540511603683658124001143169292488167504419402598460417472547700995407928658213724085415458907242448196429214332894114471850475375711280198098487532816256589287927692486819421805100968297601956068629138524802993613615898230916542578235706687386704879350698179214328913835629864793298388274831137006096634798081307397384701672353002489976]];

for (i = 1, #DR, check_disc(DR[i][1], DR[i][2], DR[i][3]));

my (got_err = 0);
iferr(polclass(-5), err, got_err = 1, errname(err) == "e_DOMAIN");
if ( ! got_err, error("No error when given non discriminant"));

if (variable(polclass(-7, , 'z)) != 'z, error("Didn't use user-provided variable"));
}
