use crate::{DType, QDType, Tensor, ZyxError};
const KVALUES_IQ4NL: [f32; 16] = [
-127., -104., -83., -65., -49., -35., -22., -10., 1., 13., 25., 38., 53., 69., 89., 113.,
];
const KSIGNS_HEX: &str = concat!(
"008182038405068788090a8b0c8d8e0f",
"901112931495961718999a1b9c1d1e9f",
"a02122a324a5a62728a9aa2bac2d2eaf",
"30b1b233b43536b7b8393abb3cbdbe3f",
"c04142c344c5c64748c9ca4bcc4d4ecf",
"50d1d253d45556d7d8595adb5cddde5f",
"60e1e263e46566e7e8696aeb6cedee6f",
"f07172f374f5f67778f9fa7bfc7d7eff",
);
const IQ2_XXS_HEX: &str = concat!(
"00000200050008000a00110014002000220028002a0041004400500058006100",
"6400800082008a00a20001010401100115014001840198010002020222028202",
"010404041004210424044004420448046004810484049004a404000502050805",
"200546056905800591050906100640068406a406000805080808140828084108",
"440850085208880804094009020a140a01100410101021104010601084109010",
"951000110811201150115a118011241245120014081420142514491480141815",
"6215001616160118041810184018811800190519a019511a002002200a204420",
"6120802082202921482100220222012404241024402456240025412564259026",
"082820289428442a014004401040184021402440404048405640604081408440",
"9040004120416141804185410142104248425642684200440844204480449944",
"124524450046014804481048404845480049584961498249454a904a00500850",
"1150195020508050885004514251a4519152905492540a550156545600581158",
"195864584059085a046010604060686000615561186260620064056410651265",
"84654268008002800a8041808280048118814081118201840484108415844084",
"608400854685948509864086608602880489118a0490109024904090a1901691",
"8091459200942294449451958198209902a050a085a009a100a218a450a804a9",
);
const IQ2_XS_HEX: &str = concat!(
"00000200050008000a0011001400160019002000220025002800410044004600",
"49005000520055005800610064008000820085008800910094009900a0000101",
"04010601090110011201150118011a0121012401400142014501480151015401",
"6001680181018401900100020202050208021102140220024102440250025502",
"80028a0201040404060409041004120415041804210424044004420445044804",
"5104540456046004810484049004000502050505080511051405200541054405",
"500561058005010604061006260640064206840600080208050808080a081108",
"14082008250841084408500858088008a008aa08010904091009400981098909",
"000a200a280a960aa00a01100410061009101010121015101810211024104010",
"4210451048105110541060106a10811084109010001102110511081111111411",
"2011411144115011801194119611011204120612101240126012001402140514",
"0814111414142014411444144914501464148014011504151015401500161416",
"49160118041810181218401854188618001905196619511aa91a002002200520",
"08200a201120142020204120442050208020a020012104211021402148216521",
"002222228022a82201240424102429244024002541255225992501261a26a626",
"002808280a28202855288828a22868299029082a202a822a882a8a2a01400440",
"0640094010401240154018402140244040404240454048404a40514054406040",
"6540814084409040004102410541084111411441204141414441504180418541",
"a241014204421042124229424042004402440544084411441444194420444144",
"4444504480449444014504451045244540459a4500460a464446504601480448",
"1048404845485448624800491149444950496949044a00500250055008501150",
"145020502850415044505050805001510451105115514051425100524452aa52",
"0154045410542154405460548154a154005508558055885521566856a1560058",
"14584158505899581a5940594259855a0160046010604060546062608660a960",
"006124624a62926200641664106540654565a46501686a682569066a546a626a",
"00800280058008801180148020802a8041804480508080808280a880aa800181",
"0481068110814081518159810082208280828282a082a8820184048410841284",
"158440846084898400854485a58518866a860088088825885a8880888288a888",
"0689228a808a888a968aa88a0190049010904090569084900091229164915692",
"89920094059444945094589429959095929541965198a6984999159a609a00a0",
"02a008a00aa020a02aa0a0a051a159a1a6a100a202a208a22aa280a2a0a240a4",
"95a465a698a60aa820a822a828a8a0a8a8a804a984a986a928aa2aaa91aaaaaa",
);
const IQ2_S_HEX: &str = concat!(
"00000200050008000a0011001400160019002000220025002800410044004600",
"490050005200550058006100640066006900800082008500880091009400a000",
"a500aa0001010401060109011001120115011801210124014001420145014801",
"510154015601590160016501680181018401900192019501a101a40100020202",
"050208021102140220022a02410244024602490250025502800285028a029402",
"a202010404040604090410041204150418042104240426042904400442044504",
"48044a0451045404560459046004620465048104840486048904900495049804",
"a104a40400050205050508050a05110514051605190520052505280541054405",
"46054905500552055505580561056405800582058505880591059405a0050106",
"0406060609061006150640064506480651065406600681068406900600080208",
"050808081108140816081908200825082a084108440846084908500852085508",
"580861086408800885089408aa08010904091009120915091809210940094509",
"480951095409600981099009000a110a140a220a280a2a0a500a990a01100410",
"0610091010101210151018102110241026104010421045104810511054105610",
"59106010621065106810811084108610901095109810a110a410001102110511",
"08110a1111111411161119112011221125112811411144114611491150115211",
"5511581161116411801182118511881191119411011204120912101215122112",
"2412401245125112541281128412901200140214051408141114141416141914",
"2014251428144114441446144914501452145514581461146414801482148514",
"881491149414a014011504150615091510151215151518152115241540154215",
"4515481551155415601581158415901500160516081611161416201641164416",
"50168016aa160118041806180918101815181818211840184218451848185118",
"541860188118841800190219051908191119141920194119441950196919a219",
"041a101a401a561a00200220052008201120142016201920202025202a204120",
"4420502052205520642080208a209420aa200121042110211221152121214021",
"4221452151215421602181218421902100220a22222228222a22442250228822",
"8a22a82201240424062409241024152418242124242440244224452448245124",
"5424602481248424902400250525082511251425202541254425502566258025",
"0126042610264026592600280528112814284128442850288a28aa2801290429",
"102995290a2a222a642a882a8a2a014004400640094010401240154018401a40",
"21402440264040404240454048404a4051405440564059406040624065408140",
"8440904095409840a140a4400041024105410841114114411641194120412241",
"2541414144414641494150415241554158416141644180418241854188419141",
"9441a04101420442104212421542184224424042454248425142544260428142",
"844200440244054408440a441144144416441944204422442544284441444444",
"46444944504452445544584461446444804482448544884491449444a0440145",
"0445064509451045124515451845214524454045424545454845514554456045",
"6a4581458445904500460246054608461146144620464146444650468046a546",
"0148044809481048124815481848214824484048424845484848514854486048",
"84489048004902490549084911491449204941494449504980499649014a044a",
"104a404a00500250055008501150145016501950205022502550285041504450",
"4650495050505250555058506150645080508250855088509150945001510451",
"0651095110511251155118512151245140514251455148515151545160518151",
"8451905100520552085211521452205241524452505269528052015404540654",
"0954105412541554185421542454405442544554485451545454605481548454",
"9054005502550555085511551455205541554455505580550156045610562656",
"405600580258055808581158145820584158445850585a588058015904591059",
"4059005a195a855aa85a01600460066010601260156018602160246040604560",
"4860516054606060846090600061026105610861116114612061416144615061",
"806199610462106240625662a162006405640864116414642064416444645064",
"806401650465106540654a656865926500669466016804681068656898680069",
"2a69426aa16a0080028005800880118014801980208025804180448050805280",
"5580588061808080858091809480018104810981108112811581188121812481",
"408142814581488151815481818184819081a981008205820a82118214824182",
"4482508201840484068409841084128415841884218440844284458448845184",
"5484608481848484908400850285058508851185148520854185448550858085",
"8a85018604861086298640860088058811881488418844885088a28801890489",
"40896589228a588a5a8a828aa28a019004900990109012901590189024904090",
"4290459048905190549060908190849090900091059111911491419144915091",
"5a910192049210924092a6920094029405940894119414942094419444945094",
"8094969401950495109540959895a19500964696649601980498109826984098",
"a998009949995299909a00a005a00aa014a022a02aa041a044a050a0a2a0aaa0",
"40a165a102a20aa222a228a22aa282a288a28aa2a8a201a404a410a440a489a4",
"a4a400a519a551a60aa828a8a2a854a986a908aa0aaa20aa22aa28aa88aaaaaa",
);
const IQ3_XXS_HEX: &str = concat!(
"0000020004001100130017002000220031004200730075000101030110011201",
"2101250130013201410154017001000202020402110220022202310233023702",
"5102570275020103070310031203250370031304370444045704730475040105",
"0705320552053506640610071407160743076107011003101010121021102310",
"3010321034104710501000110211111120112211011203121012121221123012",
"7212001302132013311346136613011405145014201524154615711505162217",
"4017002002201120132020202220262031204220012103210521102112212121",
"3021632167217021002202221122172220222222372240225522012310231423",
"7023742335245324032527254125742501270327162745270130103012302130",
"2330503065307230003102312031313144314631013203321032253252327232",
"1133333330344734723400350635223555351436363663363337603704401740",
"3540374053405740744120423742404260426642074345430444514464442545",
"4345704505471047124730471250415070500051065126515551145232527252",
"0253535310542354275472540255315550562457425724604460466064602161",
"6161176264623063366344640565526533660367216703700570077010703270",
"5270267140711272457252720073157333736073217441740075027524753076",
);
const IQ3_S_HEX: &str = concat!(
"0000010002000500070010001100120014001600200021002500330040004200",
"4500470051005300600062007100740077000001010102010401100111011501",
"2001230127013101350144016101650172010002010205020702100213021602",
"2102250230023402420245024702510253027002730203031103150320032203",
"3103330336034403500352036703710375030004130417042104240432044004",
"4304510470040205040520052205260533054105450547056605730506061106",
"1306310652067106000702070407200722072607330750075407001001100210",
"0410101011101310151017102010221031103410361054105610611072100011",
"0111031106111011141121113011331141115011521170117611001212121512",
"1712201224123212401243125512601272120113041307131013131321132713",
"3013341341136213701303140514121414143114331442144614501454140115",
"1015131521153015321551152016241627164416461601170317101712172117",
"3517411762177017002001200320052007201020122014201620212023202720",
"3020322041204320452050205220672070207320752000210221102113211721",
"2221252131213421422151210122042207222122232230223722412253225722",
"7122742200230223052311232223242331233323422350236623012407242024",
"2324322435244124722475240425112522253725402553257025002602260726",
"2126552661260527112726273027432750270230113013301530173022303130",
"3330353042304430473051306330713001310331053114312131233140316031",
"7231763100321232203232323432503201331033143321332333273330334133",
"4333473355337333033411341634223431345234603464340135103512352535",
"3235443556357335163641360137033720372237353700400440124020402440",
"2740324041405040704002410741114113412241304135414341514155410142",
"0342104215422142334240425742624270420443114313432043224331433543",
"0044024424443744404471440545074521456245134634466046104715473047",
"4347514702501050145022504050445047505250665074500151035105511251",
"2151325172510052115223523052365253520253075310532753445351536553",
"7353015404542054325446541255265551555355425602570457225711601360",
"1560316033606060006120612761646112623462426255626262706200631463",
"2163406325644364626400650365346560650566406611671367007004700770",
"2070227036704070547062700271117124714371457101720472107216722172",
"3072517202733273357353730174057413742074507422754275027631760077",
);
const IQ1_S_HEX: &str = concat!(
"00000200050008000a00110015002000220028002a0045005100540056006500",
"8000820088008a009500a000a200a800aa000401050111011401160119011a01",
"2501410146014901520155015a0161016401660168018501910194019601a501",
"0002020208020a0215022002220228022a024502510259026402690280028202",
"88028a02910295029902a002a202a802aa021104140416042504410449045504",
"5a046404650491049904a5040105040505050605150518051a05290540054505",
"4a0550055105540555055605590560056205650568056a058105910595059805",
"9a05a105a405a505a605a9051406190641064406500652065506580660066106",
"6606690685069106940699060008020808080a0815082008220828082a084508",
"5108560865088008820888088a089508a008a208a808aa080509110914091909",
"2409250941095009510955096109640969099109940996099909a509000a020a",
"080a0a0a150a200a220a280a2a0a450a510a590a610a650a800a820a850a880a",
"8a0a950aa00aa20aa80aaa0a1010111014101910241025104110441050105510",
"58106110641065106910911094109610a110a510011104110611091110111211",
"1511181121112411291145114a11501151115211541155115611591160116511",
"841192119511a111a41111121412161225124012461249125212551258125a12",
"641266128512911294129612a512011406140914141415141814191421142614",
"41144514461448144a1451145414551456145914621465146814841489149014",
"94149514981499149a14a114a414a514a914021505150a151115141515151615",
"191520152215251528152a154115441545154615511552155415551556155915",
"5a1561156415651566156915801582158415851588158a159015911594159515",
"961599159a15a015a215a51501160416051606161516161618161a1621162616",
"401642164416451648164a165116551656165816591661166416651668166916",
"6a1686168a1692169516a416a916111816182518411844184618491850185518",
"58185a1860186118641866186918851891189418a5181019121915191a192119",
"25194219441945194819511954195519561959195a19601965196a1989199119",
"921995199819a119a619a919091a161a241a261a441a461a491a501a521a551a",
"581a611a661a691a851a911a961a9a1a0020022008200a201520202022202520",
"28202a20452051205920612065208020822088208a209520a020a220a520a820",
"aa2005211121142119212521422144214921552158215a216121642165216621",
"8521902196219921a521012208220a22112215222022222228222a2245225122",
"562259226522812288228a2291229522a022a222a822aa220524142416241924",
"252444244524462449245224552458245a2466248524912494249924a124a524",
"0925152521252925402545254825512554255525592562256525682589259025",
"9425952598259a25a125a425a625a92505261026122619262526412649265526",
"6026612669268426862690269a260028022808280a2815282028222828282a28",
"45285128542865288028822888288a28a028a228a828aa280929112914291929",
"2529462949295229552961296429662969298529902996299929a429a529002a",
"022a082a0a2a202a222a282a2a2a452a512a562a592a652a802a822a882a8a2a",
"952aa02aa22aa82aaa2a054011401640254049405240554058405a4061406440",
"664094409940a140a6400041014104410641094112411541164118411a412141",
"26412941454148414a41514154415541564159415a41654168416a4181418441",
"8641904192419541a041a141a241054211421442164225424142524255425a42",
"6442694289429442a5420144154419442944454448444a445144544455445644",
"61446244654468446a44814486448944904492449544a044a144a94401450245",
"05450a4511451445154516451945204525452a45414544454545464549455045",
"5145544555455645584559456145644565456645694582458445854588459145",
"94459545964599459a45a545a845aa450146054609461446154618461a462146",
"2446294640464246454648465046514652465546564659466246654668468146",
"85468a4694469546a146a446a6460548114815481a4825484248494850485548",
"5848614864486648694885489148944896489948a5480149054906490a491049",
"144915491849214924492649404945494a495149524954495549564959496049",
"6249654966496a49864989499249954996499849a149a449a649a949164a444a",
"464a494a554a584a5a4a644a694a944aa54a0150045005500650095012501550",
"1a50215024502950405045504850515054505550565059506550685086508950",
"95509850a050a150a650a9500551085109510a51115114511551165118511951",
"20512551265128512a5141514451455146514951505151515251545155515651",
"585159515a51615164516551665169518251855191519451955196519951a051",
"a551aa5101520652125215521a5221522452425245524a525152545255525652",
"595262526552855290529252955299529a52a452045405541154145415541654",
"185419542154255428542a54415444544554465449544a545054515454545554",
"5654585459545a54615462546454655466546954805488548a54915494549554",
"96549954a154a454a554aa540155025504550555065509551055115512551455",
"1555165519551a55215524552555265529554055415542554455455546554855",
"4955505551555255545555555655585559555a55605561556455655566556855",
"69556a5581558455855589558a559055915594559555965598559955a155a455",
"a555a655a9550056015602560456065608560956115614561556185619562056",
"2156225624562556265628562956415645564656485649564a56505651565256",
"545655565656585659565a566156645665566956825685568656885689568a56",
"915695569a56a256a556a656a856a95604580558065809581058155818582158",
"2a58455848584a58515854585558565858585958605862586458655882588958",
"9058925895589858a158a9580159025905590a59115914591559165919592559",
"41594459455946594959505951595259545955595659585959595a5961596459",
"655966596959815985598959915994599559965998599959a559045a085a155a",
"1a5a205a255a265a295a455a485a495a515a555a565a585a595a625a655a685a",
"6a5a815a8a5a925a955a965a985a9a5aa15a0560146016601960256044605060",
"5560566058605a60616064606660696081609660a56001610461066109611261",
"15612161226126612961456149615161556156615961656166616a6184618a61",
"92619561a161a661a96111621662196240624162466255625662586260628562",
"91629662a56211641264156416641a6421642664296440644264456448644a64",
"516454645564566459645a646064626465648464856489649064926494649564",
"966498649a64a164a464a964056508650a651165156516651965446545654665",
"496550655165546555655665596561656465656566656965866589658a659165",
"9565966599659a65a265a565a665a86502660966156620662666286629664066",
"456648664a66516654665566566658665a666066656668668066826685668a66",
"9466966698669966a066a466a666aa661668196825684168526855685a686168",
"6968856891689868a66801690469106915692169246926692969406941694569",
"4669486951695469556956695969606965696a69826984698a699569a169a469",
"a569a969116a166a186a416a446a496a506a556a586a5a6a646a656a696a866a",
"946a986a9a6aa66a0080028008800a802080228028802a804580508051805480",
"5680598065808080828088808a809580a080a280a880aa800581118114811681",
"1981258141814481498150815281558156815881598164816681698185818981",
"948196819981a5810082028208820a8215822082228228822a82518254825982",
"65828082828288828a829582a082a282a882aa82148419844184448451845584",
"5a846184648469849484998401850985128515851a8526852985408541854585",
"4885518554855585568559855a856585668568856a8581858485868589859085",
"928595859885a68511861686198625864186448649864a865086558659865a86",
"618666866a86858691869a86a4860088028808880a8815882088228828882a88",
"41884588518854885988658869888088828888888a889588a088a288a888aa88",
"05890689118914891689258941894489468949895089528955895a8961896489",
"858996899989a589008a028a088a0a8a158a208a228a288a2a8a458a518a548a",
"568a808a828a888a8a8a958aa08aa28aa88aaa8a059011901690189019902590",
"419046904990559058905a9069906a9085909190949096909990a59001910491",
"069109911091159118911a912191249126912991409145915091519154915591",
"569159916291659184918691929195919891a191a491a691a991059211921492",
"19922592449246924992509252925592589266926992859294929692a9920194",
"04940694109415941894269440944a9451945494559456945894599460946194",
"62946594849486949294949495949894a194a9940095059508950a9510951195",
"14951595169519952195259529952a9541954495459546954995509551955295",
"549555955695589559955a956195649565956695699581958595889591959295",
"94959595969599959a95a095a295a595a895aa95019604961096159619962096",
"2696299645964896499651965296559656965996659668968296849689968a96",
"929694969596a496a696a9960598169819982598419846985098529855985698",
"5a98649865988598919896989998a59804990699099910991299159918991a99",
"209921992499269940994299459948994a995199549955995699599962996599",
"66996a99819984999099929995999a99a199a699059a159a259a449a469a499a",
"509a559a589a619a859a919a949a959a969a00a002a008a00aa015a020a022a0",
"28a02aa045a051a054a056a059a080a082a088a08aa095a0a0a0a2a0a8a0aaa0",
"05a109a111a114a116a119a11aa146a149a151a155a158a15aa161a164a185a1",
"90a192a196a199a102a208a20aa210a219a222a228a22aa245a251a256a259a2",
"65a280a282a288a28aa295a2a0a2a2a2a8a2aaa219a425a441a444a450a454a4",
"55a458a45aa461a465a466a468a469a485a406a509a510a512a515a518a526a5",
"29a542a545a551a554a555a556a559a565a56aa581a584a585a586a589a592a5",
"95a598a505a611a616a61aa621a625a644a646a64aa652a655a656a658a660a6",
"62a686a690a695a696a699a6a1a6a4a6a6a600a802a808a80aa820a822a828a8",
"2aa851a854a856a859a880a882a888a88aa895a8a0a8a2a8a8a8aaa805a914a9",
"19a921a925a941a950a955a95aa961a966a969a990a996a900aa02aa08aa0aaa",
"20aa22aa28aa2aaa51aa54aa56aa80aa82aa88aa8aaa95aaa0aaa2aaa8aaaaaa",
);
fn hex_val(c: u8) -> u8 {
match c {
b'0'..=b'9' => c - b'0',
b'a'..=b'f' => c - b'a' + 10,
b'A'..=b'F' => c - b'A' + 10,
_ => panic!("dequantize: bad hex character {c:#x} in embedded grid table"),
}
}
fn hex_bytes(hex: &str) -> Result<Vec<u8>, ZyxError> {
let b = hex.as_bytes();
if b.len() % 2 != 0 {
return Err(ZyxError::parse_error(format!("dequantize: odd-length hex table ({} chars)", b.len()).into()));
}
Ok(b.chunks_exact(2).map(|c| hex_val(c[0]) << 4 | hex_val(c[1])).collect())
}
fn decode_grid(hex: &str, bits_per_elem: u32, map: &[f32], rows: usize, cols: usize) -> Result<Vec<f32>, ZyxError> {
let packed = hex_bytes(hex)?;
let elems_per_byte = 8 / bits_per_elem as usize;
let step = 8 / elems_per_byte as u32;
let mask = (1u8 << bits_per_elem) - 1;
let mut out = Vec::with_capacity(rows * cols);
for &byte in &packed {
for e in 0..elems_per_byte {
let idx = (byte >> (e as u32 * step)) & mask;
out.push(map[idx as usize]);
}
}
if out.len() != rows * cols {
return Err(ZyxError::parse_error(
format!("dequantize: grid decoded to {} values, expected {}x{}={}", out.len(), rows, cols, rows * cols).into(),
));
}
Ok(out)
}
fn grid_tensor(hex: &str, bits_per_elem: u32, map: &[f32], rows: i64, cols: i64) -> Result<Tensor, ZyxError> {
let vals = decode_grid(hex, bits_per_elem, map, rows as usize, cols as usize)?;
Tensor::from_vec(vals, [rows, cols])
}
fn col(blocks: &Tensor, start: i64, len: i64) -> Result<Tensor, ZyxError> {
blocks.narrow(1, start, len)
}
fn f16le(blocks: &Tensor, start: i64) -> Result<Tensor, ZyxError> {
let lo = col(blocks, start, 1)?.cast(DType::U16);
let hi = col(blocks, start + 1, 1)?.cast(DType::U16);
Ok((lo | (hi << 8u16)).bitcast(DType::F16)?.cast(DType::F32))
}
fn f32le(blocks: &Tensor, start: i64) -> Result<Tensor, ZyxError> {
let b0 = col(blocks, start, 1)?.cast(DType::U32);
let b1 = col(blocks, start + 1, 1)?.cast(DType::U32);
let b2 = col(blocks, start + 2, 1)?.cast(DType::U32);
let b3 = col(blocks, start + 3, 1)?.cast(DType::U32);
Ok((b0 | (b1 << 8u32) | (b2 << 16u32) | (b3 << 24u32)).bitcast(DType::F32)?)
}
fn u16le(blocks: &Tensor, start: i64) -> Result<Tensor, ZyxError> {
let lo = col(blocks, start, 1)?.cast(DType::U16);
let hi = col(blocks, start + 1, 1)?.cast(DType::U16);
Ok(lo | (hi << 8u16))
}
fn u32le(blocks: &Tensor, start: i64) -> Result<Tensor, ZyxError> {
let b0 = col(blocks, start, 1)?.cast(DType::U32);
let b1 = col(blocks, start + 1, 1)?.cast(DType::U32);
let b2 = col(blocks, start + 2, 1)?.cast(DType::U32);
let b3 = col(blocks, start + 3, 1)?.cast(DType::U32);
Ok(b0 | (b1 << 8u32) | (b2 << 16u32) | (b3 << 24u32))
}
fn u32_of(bytes4: &Tensor) -> Result<Tensor, ZyxError> {
let b0 = bytes4.narrow(1, 0i64, 1i64)?.cast(DType::U32);
let b1 = bytes4.narrow(1, 1i64, 1i64)?.cast(DType::U32);
let b2 = bytes4.narrow(1, 2i64, 1i64)?.cast(DType::U32);
let b3 = bytes4.narrow(1, 3i64, 1i64)?.cast(DType::U32);
Ok(b0 | (b1 << 8u32) | (b2 << 16u32) | (b3 << 24u32))
}
fn i8f(t: &Tensor) -> Result<Tensor, ZyxError> {
Ok(t.bitcast(DType::I8)?.cast(DType::F32))
}
fn nibbles(qs: &Tensor) -> Result<(Tensor, Tensor), ZyxError> {
Ok((qs & 15u8, (qs >> 4u8) & 15u8))
}
fn lut(table: &Tensor, idx: &Tensor) -> Result<Tensor, ZyxError> {
let flat = idx.reshape([-1i64])?.cast(DType::I64);
Ok(table.index_select(0, flat)?.reshape(idx.shape())?)
}
fn lut_row(table: &Tensor, idx: &Tensor, cols: i64) -> Result<Tensor, ZyxError> {
let flat = idx.reshape([-1i64])?.cast(DType::I64);
let n = idx.numel();
Ok(table.index_select(0, flat)?.reshape([n, Tensor::from(cols)])?)
}
fn sign_bits(byte: &Tensor) -> Result<Tensor, ZyxError> {
let shifts = Tensor::from_vec(vec![0u8, 1, 2, 3, 4, 5, 6, 7], [8i64])?;
let bits = ((byte >> shifts) & 1u8).cast(DType::F32);
Ok(Tensor::from(1f32) - bits * 2f32)
}
impl Tensor {
pub fn dequantize(&self, q: QDType, dtype: DType) -> Result<Tensor, ZyxError> {
if self.dtype() != DType::U8 {
return Err(ZyxError::dtype_error(format!("dequantize: expected U8 blocks for {q}, got {}", self.dtype()).into()));
}
if !matches!(dtype, DType::F32 | DType::F16 | DType::BF16) {
return Err(ZyxError::dtype_error(format!("dequantize: output dtype must be a float, got {dtype}").into()));
}
let shape = self.resolve_shape();
if shape.len() != 2 || shape[1] != q.block_bytes() {
return Err(ZyxError::shape_error(
format!("dequantize: expected [num_blocks, {}] for {q}, got {shape:?}", q.block_bytes()).into(),
));
}
let out = match q {
QDType::Q4_0 => deq_q4_0(self)?,
QDType::Q4_1 => deq_q4_1(self)?,
QDType::Q5_0 => deq_q5_0(self)?,
QDType::Q5_1 => deq_q5_1(self)?,
QDType::Q8_0 => deq_q8_0(self)?,
QDType::Q8_1 => deq_q8_1(self)?,
QDType::Q2_K => deq_q2_k(self)?,
QDType::Q3_K => deq_q3_k(self)?,
QDType::Q4_K => deq_q4_k(self)?,
QDType::Q5_K => deq_q5_k(self)?,
QDType::Q6_K => deq_q6_k(self)?,
QDType::Q8_K => deq_q8_k(self)?,
QDType::IQ2_XXS => deq_iq2_xxs(self)?,
QDType::IQ2_XS => deq_iq2_xs(self)?,
QDType::IQ2_S => deq_iq2_s(self)?,
QDType::IQ3_XXS => deq_iq3_xxs(self)?,
QDType::IQ3_S => deq_iq3_s(self)?,
QDType::IQ1_S => deq_iq1_s(self)?,
QDType::IQ1_M => deq_iq1_m(self)?,
QDType::IQ4_NL => deq_iq4_nl(self)?,
QDType::IQ4_XS => deq_iq4_xs(self)?,
};
let n = out.numel();
Ok(out.cast(dtype).reshape([n])?)
}
}
fn deq_q4_0(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qs = col(blocks, 2, 16)?;
let (lo, hi) = nibbles(&qs)?;
let vals = Tensor::cat([&lo, &hi].into_iter(), 1)?.cast(DType::F32) - 8f32;
Ok(vals * d)
}
fn deq_q4_1(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let m = f16le(blocks, 2)?;
let qs = col(blocks, 4, 16)?;
let (lo, hi) = nibbles(&qs)?;
let vals = Tensor::cat([&lo, &hi].into_iter(), 1)?.cast(DType::F32);
Ok(vals * d + m)
}
fn deq_q5_0(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qh = u32le(blocks, 2)?;
let qs = col(blocks, 6, 16)?;
let (lo, hi) = nibbles(&qs)?;
let ql = Tensor::cat([&lo, &hi].into_iter(), 1)?;
let shifts = Tensor::from_vec((0u32..32).collect(), [32i64])?;
let bits = ((qh >> shifts) & 1u32).cast(DType::U8);
let q = (ql | (bits << 4u8)).cast(DType::F32) - 16f32;
Ok(q * d)
}
fn deq_q5_1(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let m = f16le(blocks, 2)?;
let qh = u32le(blocks, 4)?;
let qs = col(blocks, 8, 16)?;
let (lo, hi) = nibbles(&qs)?;
let ql = Tensor::cat([&lo, &hi].into_iter(), 1)?;
let shifts = Tensor::from_vec((0u32..32).collect(), [32i64])?;
let bits = ((qh >> shifts) & 1u32).cast(DType::U8);
let q = (ql | (bits << 4u8)).cast(DType::F32);
Ok(q * d + m)
}
fn deq_q8_0(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
Ok(i8f(&col(blocks, 2, 32)?)? * d)
}
fn deq_q8_1(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
Ok(i8f(&col(blocks, 4, 32)?)? * d)
}
fn deq_q2_k(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let scales = col(blocks, 0, 16)?;
let qs = col(blocks, 16, 64)?;
let d = f16le(blocks, 80)?;
let dmin = f16le(blocks, 82)?;
let (slo, shi) = nibbles(&scales)?;
let dl = d * slo.cast(DType::F32);
let ml = dmin * shi.cast(DType::F32);
let mut parts = Vec::with_capacity(16);
for h in 0..2i64 {
let hb = col(&qs, h * 32, 32)?;
for (si, s) in [0u8, 2, 4, 6].iter().enumerate() {
let v = ((&hb >> *s) & 3u8).cast(DType::F32);
let g = h * 8 + si as i64 * 2;
parts.push(v.narrow(1, 0i64, 16i64)? * dl.narrow(1, g, 1i64)? - ml.narrow(1, g, 1i64)?);
parts.push(v.narrow(1, 16i64, 16i64)? * dl.narrow(1, g + 1, 1i64)? - ml.narrow(1, g + 1, 1i64)?);
}
}
Tensor::cat(parts.iter(), 1)
}
fn deq_q3_k(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let hm = col(blocks, 0, 32)?;
let qs = col(blocks, 32, 64)?;
let sc12 = col(blocks, 96, 12)?;
let d = f16le(blocks, 108)?;
let lo8 = col(&sc12, 0, 8)?;
let hi4 = col(&sc12, 8, 4)?;
let (slo, shi) = nibbles(&lo8)?;
let mut hparts = Vec::with_capacity(4);
for k in 0..4u8 {
hparts.push((hi4.clone() >> (k * 2)) & 3u8);
}
let s16 = Tensor::cat([&slo, &shi].into_iter(), 1)? | (Tensor::cat(hparts.iter(), 1)? << 4u8);
let dl = d * (s16.bitcast(DType::I8)?.cast(DType::F32) - 32f32);
let mut parts = Vec::with_capacity(16);
for hlf in 0..2i64 {
let qhb = col(&qs, hlf * 32, 32)?;
for (si, s) in [0u8, 2, 4, 6].iter().enumerate() {
let low2 = ((&qhb >> *s) & 3u8).cast(DType::F32);
let pos: u8 = (hlf * 4 + si as i64) as u8;
let bit = ((hm.clone() >> pos) & 1u8).cast(DType::F32);
let qv = low2 - (Tensor::from(1f32) - bit) * 4f32;
let g = hlf * 8 + si as i64 * 2;
parts.push(qv.narrow(1, 0i64, 16i64)? * dl.narrow(1, g, 1i64)?);
parts.push(qv.narrow(1, 16i64, 16i64)? * dl.narrow(1, g + 1, 1i64)?);
}
}
Tensor::cat(parts.iter(), 1)
}
fn deq_q4_k(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let dmin = f16le(blocks, 2)?;
let sc12 = col(blocks, 4, 12)?;
let qs = col(blocks, 16, 128)?;
let sc = col(&sc12, 0, 4)?;
let mn = col(&sc12, 4, 4)?;
let md = col(&sc12, 8, 4)?;
let sc8 = Tensor::cat([&(sc.clone() & 63u8), &((md.clone() & 15u8) | ((sc >> 2u8) & 48u8))].into_iter(), 1)?;
let mn8 = Tensor::cat([&(mn.clone() & 63u8), &((md >> 4u8) | ((mn >> 2u8) & 48u8))].into_iter(), 1)?;
let d8 = d * sc8.cast(DType::F32);
let dm8 = dmin * mn8.cast(DType::F32);
let mut parts = Vec::with_capacity(8);
for g in 0..8i64 {
let qb = col(&qs, (g / 2) * 32, 32)?;
let vals = ((qb >> ((g % 2) * 4) as u8) & 15u8).cast(DType::F32);
parts.push(vals * d8.narrow(1, g, 1i64)? - dm8.narrow(1, g, 1i64)?);
}
Tensor::cat(parts.iter(), 1)
}
fn deq_q5_k(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let dmin = f16le(blocks, 2)?;
let sc12 = col(blocks, 4, 12)?;
let qh = col(blocks, 16, 32)?;
let qs = col(blocks, 48, 128)?;
let sc = col(&sc12, 0, 4)?;
let mn = col(&sc12, 4, 4)?;
let md = col(&sc12, 8, 4)?;
let sc8 = Tensor::cat([&(sc.clone() & 63u8), &((md.clone() & 15u8) | ((sc >> 2u8) & 48u8))].into_iter(), 1)?;
let mn8 = Tensor::cat([&(mn.clone() & 63u8), &((md >> 4u8) | ((mn >> 2u8) & 48u8))].into_iter(), 1)?;
let d8 = d * sc8.cast(DType::F32);
let dm8 = dmin * mn8.cast(DType::F32);
let mut parts = Vec::with_capacity(8);
for g in 0..8i64 {
let qsb = col(&qs, (g / 2) * 32, 32)?;
let ql = (qsb >> ((g % 2) * 4) as u8) & 15u8;
let bit = (col(&qh, 0, 32)? >> g as u8) & 1u8;
let q = (ql | (bit << 4u8)).cast(DType::F32);
parts.push(q * d8.narrow(1, g, 1i64)? - dm8.narrow(1, g, 1i64)?);
}
Tensor::cat(parts.iter(), 1)
}
fn deq_q6_k(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let ql = col(blocks, 0, 128)?;
let qh = col(blocks, 128, 64)?;
let sc = col(blocks, 192, 16)?.bitcast(DType::I8)?.cast(DType::F32);
let d = f16le(blocks, 208)?;
let sc = d * sc;
let mut parts = Vec::with_capacity(16);
for half in 0..2i64 {
for r in 0..4i64 {
let nib: u8 = if r >= 2 { 4 } else { 0 };
let qlb = col(&ql, half * 64 + (r % 2) * 32, 32)?;
let qhb = col(&qh, half * 32, 32)?;
let vals = (qlb >> nib) & 15u8;
let qh2 = (qhb >> (r * 2) as u8) & 3u8;
let q = (vals | (qh2 << 4u8)).bitcast(DType::I8)?.cast(DType::F32) - 32f32;
let c = half * 4 + r;
parts.push(q.narrow(1, 0i64, 16i64)? * sc.narrow(1, 2 * c, 1i64)?);
parts.push(q.narrow(1, 16i64, 16i64)? * sc.narrow(1, 2 * c + 1, 1i64)?);
}
}
Tensor::cat(parts.iter(), 1)
}
fn deq_q8_k(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f32le(blocks, 0)?;
Ok(i8f(&col(blocks, 2, 256)?)? * d)
}
fn deq_iq2_xxs(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let grid = grid_tensor(IQ2_XXS_HEX, 2, &[8., 25., 43.], 256, 8)?;
let ksigns = Tensor::from_vec(hex_bytes(KSIGNS_HEX)?, [128i64])?;
let mut parts = Vec::with_capacity(8);
for p in 0..8i64 {
let u_lo = u32_of(&col(blocks, 2 + 8 * p, 4)?)?;
let u_hi = u32_of(&col(blocks, 6 + 8 * p, 4)?)?;
let db = d.clone() * (Tensor::from(0.5f32) + ((u_hi.clone() >> 28u32) & 15u32).cast(DType::F32)) * 0.25f32;
let mut gp = Vec::with_capacity(4);
let mut sp = Vec::with_capacity(4);
for b in 0..4i64 {
let idx = ((u_lo.clone() >> (8 * b) as u32) & 255u32).cast(DType::U8);
gp.push(lut_row(&grid, &idx, 8)?);
}
for k in 0..4i64 {
let sk = ((u_hi.clone() >> (7 * k) as u32) & 127u32).cast(DType::U8);
sp.push(sign_bits(&lut_row(&ksigns, &sk, 1)?)?);
}
parts.push(db * Tensor::cat(gp.iter(), 1)? * Tensor::cat(sp.iter(), 1)?);
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq2_xs(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let grid = grid_tensor(IQ2_XS_HEX, 2, &[8., 25., 43.], 512, 8)?;
let ksigns = Tensor::from_vec(hex_bytes(KSIGNS_HEX)?, [128i64])?;
let (slo, shi) = nibbles(&col(blocks, 66, 8)?)?;
let mut sc_parts = Vec::with_capacity(16);
for i in 0..8i64 {
sc_parts.push(slo.narrow(1, i, 1i64)?);
sc_parts.push(shi.narrow(1, i, 1i64)?);
}
let sc16 = Tensor::cat(sc_parts.iter(), 1)?.cast(DType::F32);
let mut parts = Vec::with_capacity(32);
for g in 0..16i64 {
let db = d.clone() * (Tensor::from(0.5f32) + sc16.narrow(1, g, 1i64)?) * 0.25f32;
let ua = u16le(blocks, 2 + 4 * g)?;
let ub = u16le(blocks, 2 + 4 * g + 2)?;
let ga = lut_row(&grid, &(ua.clone() & 511u16), 8)?;
let sa = sign_bits(&lut_row(&ksigns, &((ua >> 9u16) & 127u16).cast(DType::U8), 1)?)?;
parts.push(db.clone() * ga * sa);
let gb = lut_row(&grid, &(ub.clone() & 511u16), 8)?;
let sb = sign_bits(&lut_row(&ksigns, &((ub >> 9u16) & 127u16).cast(DType::U8), 1)?)?;
parts.push(db * gb * sb);
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq2_s(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qs = col(blocks, 2, 32)?;
let signs = col(blocks, 34, 32)?;
let qh = col(blocks, 66, 8)?;
let (slo, shi) = nibbles(&col(blocks, 74, 8)?)?;
let mut sc_parts = Vec::with_capacity(16);
for i in 0..8i64 {
sc_parts.push(slo.narrow(1, i, 1i64)?);
sc_parts.push(shi.narrow(1, i, 1i64)?);
}
let sc16 = Tensor::cat(sc_parts.iter(), 1)?.cast(DType::F32);
let db16 = d * (Tensor::from(0.5f32) + sc16) * 0.25f32;
let grid = grid_tensor(IQ2_S_HEX, 2, &[8., 25., 43.], 1024, 8)?;
let mut parts = Vec::with_capacity(32);
for g in 0..16i64 {
let db = db16.narrow(1, g, 1i64)?;
for t in 0..2i64 {
let qi = 2 * g + t;
let qb = col(&qs, qi, 1)?.cast(DType::U16);
let qh_b = col(&qh, g / 2, 1)?;
let h = ((qh_b >> ((qi % 4) * 2) as u8) & 3u8).cast(DType::U16);
let grid_v = lut_row(&grid, &(qb | (h << 8u16)), 8)?;
parts.push(db.clone() * grid_v * sign_bits(&col(&signs, qi, 1)?)?);
}
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq3_xxs(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qs = col(blocks, 2, 64)?;
let grid = grid_tensor(IQ3_XXS_HEX, 3, &[4., 12., 20., 28., 36., 44., 52., 62.], 256, 4)?;
let ksigns = Tensor::from_vec(hex_bytes(KSIGNS_HEX)?, [128i64])?;
let mut parts = Vec::with_capacity(8);
for g in 0..8i64 {
let u = u32le(blocks, 66 + 4 * g)?;
let db = d.clone() * (Tensor::from(0.5f32) + ((u.clone() >> 28u32) & 15u32).cast(DType::F32)) * 0.5f32;
let mut gp = Vec::with_capacity(8);
let mut sp = Vec::with_capacity(4);
for k in 0..8i64 {
gp.push(lut_row(&grid, &col(&qs, 8 * g + k, 1)?, 4)?);
}
for l in 0..4i64 {
let sk = ((u.clone() >> (7 * l) as u32) & 127u32).cast(DType::U8);
sp.push(sign_bits(&lut_row(&ksigns, &sk, 1)?)?);
}
parts.push(db * Tensor::cat(gp.iter(), 1)? * Tensor::cat(sp.iter(), 1)?);
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq3_s(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qs = col(blocks, 2, 64)?;
let qh = col(blocks, 66, 8)?;
let signs = col(blocks, 74, 32)?;
let (slo, shi) = nibbles(&col(blocks, 106, 4)?)?;
let mut sc_parts = Vec::with_capacity(8);
for i in 0..4i64 {
sc_parts.push(slo.narrow(1, i, 1i64)?);
sc_parts.push(shi.narrow(1, i, 1i64)?);
}
let db8 = d * (Tensor::from(1f32) + Tensor::cat(sc_parts.iter(), 1)?.cast(DType::F32) * 2f32);
let grid = grid_tensor(IQ3_S_HEX, 3, &[1., 3., 5., 7., 9., 11., 13., 15.], 512, 4)?;
let mut parts = Vec::with_capacity(8);
for g in 0..8i64 {
let db = db8.narrow(1, g, 1i64)?;
let qh_b = col(&qh, g, 1i64)?;
let mut gp = Vec::with_capacity(8);
let mut sp = Vec::with_capacity(8);
for k in 0..8i64 {
let qb = col(&qs, 8 * g + k, 1)?.cast(DType::U16);
let bit = ((qh_b.clone() >> k as u8) & 1u8).cast(DType::U16);
gp.push(lut_row(&grid, &(qb | (bit << 8u16)), 4)?);
let sb = sign_bits(&col(&signs, 4 * g + k / 2, 1)?)?;
sp.push(sb.narrow(1, (k % 2) * 4, 4i64)?);
}
parts.push(db * Tensor::cat(gp.iter(), 1)? * Tensor::cat(sp.iter(), 1)?);
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq1_s(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qs = col(blocks, 2, 32)?;
let grid = grid_tensor(IQ1_S_HEX, 2, &[-1., 0., 1.], 2048, 8)?;
let mut parts = Vec::with_capacity(8);
for g in 0..8i64 {
let u = u16le(blocks, 34 + 2 * g)?;
let ls = ((u.clone() >> 12u16) & 7u16).cast(DType::F32);
let dl = d.clone() * (Tensor::from(2f32) * ls + Tensor::from(1f32));
let bit = ((u.clone() >> 15u16) & 1u16).cast(DType::F32);
let delta = (Tensor::from(1f32) - bit * 2f32) * 0.125f32;
for k in 0..4i64 {
let qb = col(&qs, 4 * g + k, 1)?.cast(DType::U16);
let f = (u.clone() >> (3 * k) as u16) & 7u16;
let grid_v = lut_row(&grid, &(qb | (f << 8u16)), 8)?;
parts.push(dl.clone() * (grid_v + delta.clone()));
}
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq1_m(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let qs = col(blocks, 0, 32)?;
let qh = col(blocks, 32, 16)?;
let s0 = u16le(blocks, 48)?;
let s1 = u16le(blocks, 50)?;
let s2 = u16le(blocks, 52)?;
let s3 = u16le(blocks, 54)?;
let d = ((s0.clone() & 0xF000u16) >> 12u16
| (s1.clone() & 0xF000u16) >> 8u16
| (s2.clone() & 0xF000u16) >> 4u16
| (s3.clone() & 0xF000u16))
.bitcast(DType::F16)?
.cast(DType::F32);
let sw = [s0, s1, s2, s3];
let grid = grid_tensor(IQ1_S_HEX, 2, &[-1., 0., 1.], 2048, 8)?;
let mut parts = Vec::with_capacity(32);
for big in 0..8i64 {
for s in 0..2i64 {
let e = 2 * big + s;
let ls = ((sw[(e / 4) as usize].clone() >> ((e % 4) * 3) as u16) & 7u16).cast(DType::F32);
let dl = d.clone() * (Tensor::from(2f32) * ls + Tensor::from(1f32));
let qh_b = col(&qh, e, 1)?;
for t in 0..2i64 {
let l = 2 * s + t;
let shift: u8 = if l % 2 == 0 { 0 } else { 4 };
let f = ((qh_b.clone() >> shift) & 7u8).cast(DType::U16);
let qb = col(&qs, 4 * big + l, 1)?.cast(DType::U16);
let grid_v = lut_row(&grid, &(qb | (f << 8u16)), 8)?;
let bpos: u8 = (3 + t * 4) as u8;
let bf = ((qh_b.clone() >> bpos) & 1u8).cast(DType::F32);
let delta = (Tensor::from(1f32) - bf * 2f32) * 0.125f32;
parts.push(dl.clone() * (grid_v + delta));
}
}
}
Tensor::cat(parts.iter(), 1)
}
fn deq_iq4_nl(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let qs = col(blocks, 2, 16)?;
let (lo, hi) = nibbles(&qs)?;
let idx = Tensor::cat([&lo, &hi].into_iter(), 1)?;
let kv = Tensor::from_vec(KVALUES_IQ4NL.to_vec(), [16i64])?;
Ok(lut(&kv, &idx)? * d)
}
fn deq_iq4_xs(blocks: &Tensor) -> Result<Tensor, ZyxError> {
let d = f16le(blocks, 0)?;
let sh = u16le(blocks, 2)?;
let sl = col(blocks, 4, 4)?;
let qs = col(blocks, 8, 128)?;
let mut sl8p = Vec::with_capacity(8);
for b in 0..4i64 {
let byte = col(&sl, b, 1)?;
sl8p.push(byte.clone() & 15u8);
sl8p.push((byte >> 4u8) & 15u8);
}
let sl8 = Tensor::cat(sl8p.iter(), 1)?;
let shifts = Tensor::from_vec(vec![0u16, 2, 4, 6, 8, 10, 12, 14], [8i64])?;
let sh8 = ((sh >> shifts) & 3u16).cast(DType::U8);
let dl = d * ((sl8 | (sh8 << 4u8)).bitcast(DType::I8)?.cast(DType::F32) - 32f32);
let kv = Tensor::from_vec(KVALUES_IQ4NL.to_vec(), [16i64])?;
let mut parts = Vec::with_capacity(8);
for g in 0..8i64 {
let (lo, hi) = nibbles(&col(&qs, g * 16, 16)?)?;
let idx = Tensor::cat([&lo, &hi].into_iter(), 1)?;
parts.push(lut(&kv, &idx)? * dl.narrow(1, g, 1i64)?);
}
Tensor::cat(parts.iter(), 1)
}