bitDP 이야기
13442 단어 비트 연산
여러분이 가장 좋아하는 비트DP 이야기입니다.편집 거리(Edit Distance:ED)를 bitDP로 약간 계산하면
거리 편집
먼저 정의부터 시작한다.
편집 거리(ED; 레벤스타인 거리: Levennshtein Distance라고도 함)는 두 문자열 사이에 정의된 문자열을 다른 문자열로 변환할 때의 최소 {바꾸기, 삽입, 삭제} 횟수를 나타냅니다.
예를 들어
abcdefg
와 abxdeg
의 편집 거리는 2이고 부채의 교체는 1회c
→x
, 삽입은 0회, 삭제는 1회f
이다.일반적 으로 해답 하다
아시다시피 2차원적인 DP로 풀 수 있습니다.여기에는 점화 공식만 표시됩니다.
비트DP로 푸세요.
이미 알고 있는 비트 병렬 알고리즘Myers 알고리즘.일본어 해설 글을 많이 썼고 궁금한 사람도 많았어요.
1단원 1비트이기 때문에 그 SIMD보다 병행도가 높고, 덧셈 명령을 이용한 카드가 의존관계 검사를 해결하는 곳이 좋다.
LLCS도 풀 수 있을 것 같아요.
최장 공통 부분 열 길이(Length of Longgest Common Substing: LLCS)도 비슷한 2차원 DP로 문제를 풀 수 있습니다.이것도 인접한 DP 변수의 차가 {0, 1} 중 하나이기 때문에 편집 거리와 마찬가지로bitDP를 되돌릴 수 있습니다.현재 가장 아름다운 알고리즘은 왜냐하면인 것 같다.구상은 ED의 알고리즘과 같지만 하나의 변수(수평차분)를 반전시켜 연산 횟수를 줄인다.
아무튼 일단 이룰게요.
이 알고리즘의 강점은 모든 데이터를 레지스터에 저장한 상태에서 64개의 칸을 업데이트할 수 있다는 점이다.이 특징을 손상시키지 않기 위해서 나는 자세하게 기술할 것이다.
그러나 임의의 길이의 입력을 받아들이는 것은 매우 번거롭기 때문에 입력은 최대 64자만 입력할 수 있다.
uint64_t editdist(char const *a, uint64_t alen, char const *b, uint64_t blen);
라면 아마 실용적으로 사용할 수 있을 거예요.예를 들어 문장의 일부분을 잘라서 ED를 계산하는 경우zero-copy를 통해 실현할 수 있다.코드
풀버전 여기 있어요.
uint64_t editdist(
char const *a,
uint64_t alen,
char const *b,
uint64_t blen)
{
v32i8_t a1 = _loadu_v32i8(a), a2 = _loadu_v32i8(a + 32);
uint64_t ph = 0xffffffffffffffff, mh = 0;
for(char const *p = b; p < b + blen; p++) {
v32i8_t b = _set_v32i8(*p);
uint64_t eq = (_m(_eq_v32i8(b, a2))<<32) | _m(_eq_v32i8(b, a1));
uint64_t xh = eq | mh, xv = (((eq & ph) + ph) ^ ph) | eq;
uint64_t pv = mh | ~(xv | ph), mv = ph & xv;
pv<<=1; mv<<=1; pv |= 0x01ULL;
ph = mv | ~(xh | pv); mh = pv & xh;
}
uint64_t mask = (0x01ULL<<alen) - 1;
return(blen + popcnt(ph & mask) - popcnt(mh & mask));
}
uint64_t llcs(
char const *a,
uint64_t alen,
char const *b,
uint64_t blen)
{
v32i8_t a1 = _loadu_v32i8(a), a2 = _loadu_v32i8(a + 32);
uint64_t h = 0xffffffffffffffff;
for(char const *p = b; p < b + blen; p++) {
v32i8_t b = _set_v32i8(*p);
uint64_t eq = (_m(_eq_v32i8(b, a2))<<32) | _m(_eq_v32i8(b, a1));
uint64_t v = h & eq; h = (h + v) | (h - v);
}
uint64_t mask = (0x01ULL<<alen) - 1;
return(alen - popcnt(h & mask));
}
컴파일 결과
clang-3.9 -O3 -msse4.1 on mac.ED 설치의 내부 주기만 표시됩니다.의도대로 스토리지의 회피/재부팅이 손실되었습니다.
LBB0_2: ## =>This Inner Loop Header: Depth=1
movzbl (%rdx), %ebx
movd %ebx, %xmm5
pshufb %xmm4, %xmm5
movdqa %xmm5, %xmm6
pcmpeqb %xmm2, %xmm6
pmovmskb %xmm6, %ebx
movdqa %xmm5, %xmm6
pcmpeqb %xmm3, %xmm6
pmovmskb %xmm6, %ecx
shll $16, %ecx
orl %ebx, %ecx
shlq $32, %rcx
movdqa %xmm5, %xmm6
pcmpeqb %xmm0, %xmm6
pmovmskb %xmm6, %edi
pcmpeqb %xmm1, %xmm5
pmovmskb %xmm5, %ebx
shll $16, %ebx
orl %edi, %ebx
orq %rcx, %rbx
movq %rbx, %rcx
andq %rax, %rcx
addq %rax, %rcx
xorq %rax, %rcx
orq %rbx, %rcx
orq %r13, %rbx
movq %rcx, %rdi
orq %rax, %rdi
notq %rdi
orq %r13, %rdi
andq %rax, %rcx
addq %rcx, %rcx
leaq 1(%rdi,%rdi), %rdi
movq %rdi, %rax
orq %rbx, %rax
notq %rax
orq %rcx, %rax
andq %rdi, %rbx
incq %rdx
cmpq %r12, %rdx
movq %rbx, %r13
jb LBB0_2
끝말
내일(오늘)은 소@_primenumber 씨의 공동 비트 스캔 리버스라고 한다.
참고 문헌
Reference
이 문제에 관하여(bitDP 이야기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/ocxtal/items/ee454c975dec1771e0ab텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)