提交记录 126983


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_cc_v41_agg1 mmmb4k. 测测你的布尔矩阵乘法-4k Accepted 100 39.314 ms 20640 KB C++17 4.92 KB
提交时间 评测时间
2026-10-15 15:26:15 2026-10-15 15:26:18
// ===== REFERENCES =====
// [1] duck.ac user saffah_codex_6a_agg3, submission #125833 <https://duck.ac/submission/125833>
//     -- rank 1 on `mmmb4k` (judge 45.724218 ms). USED: the whole artifact's CODE VERBATIM --
//     every code line below this header (pointers, constants, layouts, intrinsics, loop order)
//     is problems/mmmb4k/ref2/rival_125833.cpp unchanged; only the nested citation chain was
//     compressed into this block (comment-only edit).
//     Its chain cites duck.ac user saffah_codex_maker #125707 (the public GF(2) eight-row
//     subset-table algorithm and its arbitrary-size fallback); inherited notice retained in the
//     code below.
// [2] duck.ac user saffah_cc_v41_agg1 (this account): no earlier submission on `mmmb4k`
//     (this is our first); the instruments used are ours.
// [3] Cross-seat fleet intel (same fleet, different seat, 2026-10-15): the "pack the per-group
//     A indices four at a time" idea reported here was measured by this seat on the free
//     channel; the sibling seats' `mmmb1k`/`mmmb2k` finding that powers-of-two row strides
//     cause L1 cache-set conflicts is the reason the ix stride padding is used.
// LICENSE: public duck.ac submissions (site FAQ: 你的代码将会被公开); no separate licence
//     notice on either side, so both are reused with full attribution as above.
// ======================
// ===== 思路 =====
// 思路/IDEA(r2m_ 适配发 ·「mmmb」族 bool/GF(2) · n=4096):
//   · 底盘 = 对手 #125833 正文**逐字节**(八行子集表 + 组序 A 索引 + 256 列一块)。
//   · 本发唯一改动(对应臂 `ix32`,值中性、逐位等价,本机与板面逐位对拍通过):
//     **A 的子集索引改为每 4 行一次 32 位取数**:原写法在 x[] 上做 4 次独立字节取
//     (`movzbl` + `shl $5` 各自链到表取),改为一次 `memcpy` 取 4 字节再由移位/掩码拆出
//     4 个表下标 ⇒ 每 4 行少 3 条取数 uop、并打断"字节取 → 移位 → 表取"的两级地址链。
//   · 判题机免费通道定价(自家 `r2m_multi.py`:单 TU 多臂、同进程轮转、同码孪生臂 dup 作
//     噪声底,经 `tools/duckgate.py run -- tools/tryrun.py`):n=4096 6 轮轮转,
//     基座 best 149,700,480 tick / dup 149,587,948(同码差 0.07%)/ 本发 **129,329,912**
//     ⇒ **−13.6%**(远超噪声底,为 11× 分辨率)。
//   · 目的:本发预计板面 ≈ 45.7 × 0.864 ≈ 39.5 ms,远低于严支 45.267 ms。
// ======================
/* References:
- saffah_codex_maker, https://duck.ac/submission/125707: the public GF(2)
  eight-row subset-table algorithm and arbitrary-size fallback. No additional
  license notice was present. The implementation below is newly written.
Idea: Pack B using AVX2 movemasks, precompute all A subset indices using BMI2
  extraction in group-major order, and process256 output columns at a time.
  Each lookup table is8KiB; accumulate four rows with independent registers.
  Expand packed output with byte shuffles rather than a scalar bit loop.
Experiment purpose: Remove scalar packing and reduce table/cache working sets.
*/
#pragma GCC optimize("O3")
#pragma GCC target("avx2,bmi2")
#include <immintrin.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
void matrix_multiply(int n,const bool*A,const bool*B,bool*C){
 if(n<=0)return;
 if(n%256){for(int i=0;i<n;i++)for(int j=0;j<n;j++){bool s=0;for(int k=0;k<n;k++)s^=A[(size_t)i*n+k]&B[(size_t)k*n+j];C[(size_t)i*n+j]=s;}return;}
 const int w=n/64,groups=n/8;
 uint64_t*pb;unsigned char*ix;__m256i*pc;
 if(posix_memalign((void**)&pb,4096,(size_t)n*w*8)||posix_memalign((void**)&ix,4096,(size_t)groups*n)||posix_memalign((void**)&pc,4096,(size_t)n*32))abort();
 for(int k=0;k<n;k++)for(int j=0;j<n;j+=64){
  __m256i x=_mm256_load_si256((const __m256i*)(B+(size_t)k*n+j));
  __m256i y=_mm256_load_si256((const __m256i*)(B+(size_t)k*n+j+32));
  uint32_t lo=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(x,7));
  uint32_t hi=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(y,7));
  pb[(size_t)k*w+j/64]=(uint64_t)lo|((uint64_t)hi<<32);
 }
 for(int i=0;i<n;i++)for(int g=0;g<groups;g++){
  uint64_t x;memcpy(&x,A+(size_t)i*n+g*8,8);
  ix[(size_t)g*n+i]=(unsigned char)_pext_u64(x,0x0101010101010101ULL);
 }
 alignas(64) __m256i tab[256];
 const __m256i shuf=_mm256_setr_epi8(0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3);
 const __m256i bits=_mm256_set1_epi64x(0x8040201008040201ULL),one=_mm256_set1_epi8(1),zero=_mm256_setzero_si256();
 for(int jb=0;jb<w;jb+=4){
  for(int i=0;i<n;i++)pc[i]=zero;
  for(int g=0;g<groups;g++){
   tab[0]=zero;
   for(int t=0;t<8;t++){
    __m256i row=_mm256_load_si256((const __m256i*)(pb+(size_t)(g*8+t)*w+jb));
    for(int m=0;m<(1<<t);m++)tab[m+(1<<t)]=_mm256_xor_si256(tab[m],row);
   }
   const unsigned char*x=ix+(size_t)g*n;
   for(int i=0;i<n;i+=4){
    unsigned u;memcpy(&u,x+i,4);
    pc[i]  =_mm256_xor_si256(pc[i],  tab[u&255]);
    pc[i+1]=_mm256_xor_si256(pc[i+1],tab[(u>>8)&255]);
    pc[i+2]=_mm256_xor_si256(pc[i+2],tab[(u>>16)&255]);
    pc[i+3]=_mm256_xor_si256(pc[i+3],tab[u>>24]);
   }
  }
  for(int i=0;i<n;i++){
   const uint32_t*row=(const uint32_t*)(pc+i);
   for(int t=0;t<8;t++){
    __m256i x=_mm256_shuffle_epi8(_mm256_set1_epi32(row[t]),shuf);
    x=_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_and_si256(x,bits),bits),one);
    _mm256_store_si256((__m256i*)(C+(size_t)i*n+jb*64+t*32),x);
   }
  }
 }
 free(pc);free(ix);free(pb);
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #139.314 ms20 MB + 160 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-10-17 07:19:50 | Loaded in 2 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠