今天记录下一个spdz开源库里的while_do函数的用法
测试版本0.3.0
while_do函数的介绍:
一句一句解释一下
While-do loop. :函数是用来做while循环的。
The decorator requires an initialization, :解释器需要一个初始化,可以理解为在这里为循环赋初始状态(值)
and the loop body function must return a suitable input for condition.:loop body也是一个函数,它被while_do函数修饰,可以理解为循环体也作为一个参数被传入while_do函数里执行。如果不懂可以百度下python中@函数修饰符的作用
。
Parameters
condition – function returning public integer (regint/cint/int):字面翻译是条件
的意思,实际应该是一个函数
,这个函数执行的是某个条件的判断。(不要疑惑,我们在小学二年级就学过,python的函数的传参也可以传函数。)
args – arguments given to condition and loop body:一些参数,这些参数被用在条件函数和循环体。可以用来给解释器初始化。
函数的实现源代码:
def while_do(condition, *args):
def decorator(loop_body):
while_loop(loop_body, condition, *args)
return loop_body
return decorator
源代码不多说了。
官方给的实例:
@while_do(lambda x: x < 10, regint(0))
def f(i):
...
return i + 1
lambda
:是python内置的一个表达式语法,不熟悉的同学可以百度下。在这个例子中就是判断传入的参数x是否小于10
regint(0)
:表示初始值为0。也就是一开始i=0
。regint是spdz库定义的一个类型,没看过可以暂时放一放,可以把它看作int
def f(i)
:定义了一个循环体函数
return i+1
:循环体函数返回了i+1
实例代码的运行流程:
i
被赋予初值i=0
...
做了某些操作- 返回了i+1
- 判断i+1是否<10
- 若小于10,继续执行循环体函数
- 若大于等于10跳出循环,结束
等价代码:
while i<10:
...
i = i + 1
上手实例:快速排序
原始的python语法实现:
def insertsort(a, low, high):
for i in range(low + 1, high):
j = i
while j > 0 and a[j] < a[j - 1]:
a[j], a[j - 1] = a[j - 1], a[j]
j -= 1
我们根据上面的代码,转换成按照spdz库语法写的代码。
def insertsort(a,low,high):
@for_range(low+1,high)
def _(i):
@while_do(lambda j:j>0, i)
def _(j):
a[j],a[j-1] = cond_swap(a[j],a[j-1])
return j-1
for_range
就是for循环,没见过的小伙伴可以跳过,我们这里主要讲while_do的用法。
直接看最里面的while层。
- 为循环体的j赋初值
j=i
a[j],a[j-1] = cond_swap(a[j],a[j-1])
这个是spdz定义的函数,如果aj<aj-1就交换两个元素;否则,不交换两个元素的值。return j-1
:让j的值减一- 判断j是否大于0,不满足则跳出循环。
另一个版本: 将lambda替换成了函数
def insertsort1(a,low,high):
@for_range(low+1,high)
def _(i):
def jian(k):
return k>0
@while_do(jian, i)
def _(j):
a[j],a[j-1] = cond_swap(a[j],a[j-1])
return j-1
完整的测试代码:test.mpc
a = Array(10,sint)
a.assign([45,65,1,427,11,54,154,254,96,47])
print_ln("a = %s",a.reveal())
low = 0
high = 10
def insertsort(a,low,high):
@for_range(low+1,high)
def _(i):
@while_do(lambda j:j>0, i)
def _(j):
a[j],a[j-1] = cond_swap(a[j],a[j-1])
return j-1
def insertsort1(a,low,high):
@for_range(low+1,high)
def _(i):
def jian(k):
return k>0
@while_do(jian, i)
def _(j):
a[j],a[j-1] = cond_swap(a[j],a[j-1])
return j-1
insertsort1(a,low,high)
print_ln("a = %s",a.reveal())
a.sort()
print_ln("a = %s",a.reveal())
编译:./compile.py -F 64 test
执行:Scripts/run-online.sh test
运行结果:
Running /home/spdz030/Scripts/../Player-Online.x 0 test -pn 16118 -h localhost -N 2
Running /home/spdz030/Scripts/../Player-Online.x 1 test -pn 16118 -h localhost -N 2
a = [45, 65, 1, 427, 11, 54, 154, 254, 96, 47]
a = [427, 254, 154, 96, 65, 54, 47, 45, 11, 1]
REWINDING - ONLY FOR BENCHMARKING
a = [1, 11, 45, 47, 54, 65, 96, 154, 254, 427]
The following timing is exclusive preprocessing.
Time = 0.0522126 seconds
Data sent = 0.423992 MB in ~892 rounds (party 0)
Global data sent = 0.847968 MB (all parties)
This program might benefit from some protocol options.
Consider adding the following at the beginning of 'test.mpc':
program.use_edabit(True)
更新
传两个参数
def jian(i):
return (i[0]<10).bit_and(i[1]<10)
@while_do(jian, [regint(0),regint(0)])
def f(k):
print_ln("%s,%s",k[0],k[1])
return k+1