Skip to content

Commit 86229d7

Browse files
committed
Implement Karatsuba's multiplication algorithm
We cannot accomplish a reduction in bit widths for we do not know upfront whether computing z_0 (the product of the lower halves) requires less than the full bit width to represent its multiplication result.
1 parent f597716 commit 86229d7

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

src/solvers/flattening/bv_utils.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,8 @@ bvt bv_utilst::dadda_tree(const std::vector<bvt> &pps)
925925
// with Dadda's reduction yields the most consistent performance improvement
926926
// while not regressing substantially in the matrix of different benchmarks and
927927
// CaDiCaL and MiniSat2 as solvers.
928-
#define RADIX_MULTIPLIER 8
928+
// #define RADIX_MULTIPLIER 8
929+
#define USE_KARATSUBA
929930
#ifdef RADIX_MULTIPLIER
930931
# define DADDA_TREE
931932
#endif
@@ -1821,6 +1822,53 @@ bvt bv_utilst::unsigned_multiplier(const bvt &_op0, const bvt &_op1)
18211822
}
18221823
}
18231824

1825+
bvt bv_utilst::unsigned_karatsuba_multiplier(const bvt &_op0, const bvt &_op1)
1826+
{
1827+
if(_op0.size() != _op1.size())
1828+
return unsigned_multiplier(_op0, _op1);
1829+
1830+
const std::size_t op_size = _op0.size();
1831+
// only use this approach for powers of two
1832+
if(op_size == 0 || (op_size & (op_size - 1)) != 0)
1833+
return unsigned_multiplier(_op0, _op1);
1834+
1835+
const std::size_t half_op_size = op_size >> 1;
1836+
1837+
// The need to use a full multiplier for z_0 means that we will not actually
1838+
// accomplish a reduction in bit width.
1839+
bvt x0{_op0.begin(), _op0.begin() + half_op_size};
1840+
x0.resize(op_size, const_literal(false));
1841+
bvt x1{_op0.begin() + half_op_size, _op0.end()};
1842+
// x1.resize(op_size, const_literal(false));
1843+
bvt y0{_op1.begin(), _op1.begin() + half_op_size};
1844+
y0.resize(op_size, const_literal(false));
1845+
bvt y1{_op1.begin() + half_op_size, _op1.end()};
1846+
// y1.resize(op_size, const_literal(false));
1847+
1848+
bvt z0 = unsigned_multiplier(x0, y0);
1849+
bvt z2 = unsigned_karatsuba_multiplier(x1, y1);
1850+
1851+
bvt z0_half{z0.begin(), z0.begin() + half_op_size};
1852+
bvt z2_plus_z0 = add(z2, z0_half);
1853+
z2_plus_z0.resize(half_op_size);
1854+
1855+
bvt x0_half{x0.begin(), x0.begin() + half_op_size};
1856+
bvt xdiff = add(x0_half, x1);
1857+
// xdiff.resize(half_op_size);
1858+
bvt y0_half{y0.begin(), y0.begin() + half_op_size};
1859+
bvt ydiff = add(y1, y0_half);
1860+
// ydiff.resize(half_op_size);
1861+
1862+
bvt z1 = sub(unsigned_karatsuba_multiplier(xdiff, ydiff), z2_plus_z0);
1863+
for(std::size_t i = 0; i < half_op_size; ++i)
1864+
z1.insert(z1.begin(), const_literal(false));
1865+
// result.insert(result.end(), z1.begin(), z1.end());
1866+
1867+
// z1.resize(op_size);
1868+
z0.resize(op_size);
1869+
return add(z0, z1);
1870+
}
1871+
18241872
bvt bv_utilst::unsigned_multiplier_no_overflow(
18251873
const bvt &op0,
18261874
const bvt &op1)
@@ -1871,7 +1919,11 @@ bvt bv_utilst::signed_multiplier(const bvt &op0, const bvt &op1)
18711919
bvt neg0=cond_negate(op0, sign0);
18721920
bvt neg1=cond_negate(op1, sign1);
18731921

1922+
#ifdef USE_KARATSUBA
1923+
bvt result = unsigned_karatsuba_multiplier(neg0, neg1);
1924+
#else
18741925
bvt result=unsigned_multiplier(neg0, neg1);
1926+
#endif
18751927

18761928
literalt result_sign=prop.lxor(sign0, sign1);
18771929

@@ -1939,7 +1991,12 @@ bvt bv_utilst::multiplier(
19391991
switch(rep)
19401992
{
19411993
case representationt::SIGNED: return signed_multiplier(op0, op1);
1994+
#ifdef USE_KARATSUBA
1995+
case representationt::UNSIGNED:
1996+
return unsigned_karatsuba_multiplier(op0, op1);
1997+
#else
19421998
case representationt::UNSIGNED: return unsigned_multiplier(op0, op1);
1999+
#endif
19432000
}
19442001

19452002
UNREACHABLE;

src/solvers/flattening/bv_utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class bv_utilst
7979
bvt shift(const bvt &op, const shiftt shift, const bvt &distance);
8080

8181
bvt unsigned_multiplier(const bvt &op0, const bvt &op1);
82+
bvt unsigned_karatsuba_multiplier(const bvt &op0, const bvt &op1);
8283
bvt signed_multiplier(const bvt &op0, const bvt &op1);
8384
bvt multiplier(const bvt &op0, const bvt &op1, representationt rep);
8485
bvt multiplier_no_overflow(

0 commit comments

Comments
 (0)