软件工程与应用第十二篇报告

2021SC@SDUSC

2021-12-19

第十二周完成事项

工作内容

本周的工作是继续分析剩余数系统的相关代码。首先回顾一下之前了解学习过的剩余数系统。

RNS——剩余数系统

与冗余数相反,剩余数表示系统(RNS,residue number system)是一种用较少的数表示较多的数的表示系统。RNS可显著提高信号处理应用中某些算法密集型场景的算法速度。此外,RNS也是研究快速算法极限理论的一个工具。

剩余数系统的作用是将原本比较大的数,使用多个相对小的数进行表示,这样在运算的时候,可以不必对原本比较大的数进行运算,对多个相对小的数进行运算可以加快运算速度。

代码分析

承接上周的工作进度,上周主要分析了RNSbase类的相关内容,包括RNSbase类的构造函数、复制构造函数、赋值构造函数以及一些对于类对象的判断修改的函数,本周将继续分析剩余数系统剩下的两个类之一,BaseConverter类。BaseConverter类的作用是进行RNSbase的转化。

首先我们来看一下BaseConverter类的全貌。

class BaseConverter
{
public:
	BaseConverter(const RNSBase &ibase, const RNSBase &obase, MemoryPoolHandle pool)
    	: pool_(std::move(pool)), ibase_(ibase, pool_), obase_(obase, pool_)
    {
		if (!pool_)
        {
        	throw std::invalid_argument("pool is uninitialized");
        }

        initialize();
    }

    SEAL_NODISCARD inline std::size_t ibase_size() const noexcept
    {
    	return ibase_.size();
    }

    SEAL_NODISCARD inline std::size_t obase_size() const noexcept
    {
        return obase_.size();
    }

    SEAL_NODISCARD inline const RNSBase &ibase() const noexcept
    {
        return ibase_;
    }

    SEAL_NODISCARD inline const RNSBase &obase() const noexcept
    {
        return obase_;
    }

    void fast_convert(ConstCoeffIter in, CoeffIter out, MemoryPoolHandle pool) const;

    oid fast_convert_array(ConstRNSIter in, RNSIter out, MemoryPoolHandle pool) const;

private:
	BaseConverter(const BaseConverter &copy) = delete;

    BaseConverter(BaseConverter &&source) = delete;

    BaseConverter &operator=(const BaseConverter &assign) = delete;

    BaseConverter &operator=(BaseConverter &&assign) = delete;

    void initialize();

    MemoryPoolHandle pool_;

    RNSBase ibase_;

    RNSBase obase_;

    Pointer<Pointer<std::uint64_t>> base_change_matrix_;
};

先分析一下BaseConverter类中的私有变量。

MemoryPoolHandle pool_;

RNSBase ibase_;

RNSBase obase_;

Pointer<Pointer<std::uint64_t>> base_change_matrix_;

pool_是内存池的句柄,用于对内存进行操作;ibase和obase分别是输入RNSbase和输出RNSbase;最后一个base_change_matrix是由指针的嵌套构成二维矩阵数组,主要负责RNSbase的变化。

BaseConverter(const BaseConverter &copy) = delete;

BaseConverter(BaseConverter &&source) = delete;

BaseConverter &operator=(const BaseConverter &assign) = delete;

BaseConverter &operator=(BaseConverter &&assign) = delete;

上面的分别是复制构造函数和赋值构造函数,用delete进行修饰,表示表示这个函数被定义为deleted,也就意味着这个成员函数不能再被调用,否则就会出错。

void BaseConverter::initialize()
{
	// Verify that the size is not too large
    if (!product_fits_in(ibase_.size(), obase_.size()))
    {
		throw logic_error("invalid parameters");
    }

    // Create the base-change matrix rows
    base_change_matrix_ = allocate<Pointer<uint64_t>>(obase_.size(), pool_);

    SEAL_ITERATE(iter(base_change_matrix_, obase_.base()), obase_.size(), [&](auto I) {
		// Create the base-change matrix columns
        get<0>(I) = allocate_uint(ibase_.size(), pool_);

        StrideIter<const uint64_t *> ibase_punctured_prod_array(ibase_.punctured_prod_array(), ibase_.size());
        SEAL_ITERATE(iter(get<0>(I), ibase_punctured_prod_array), ibase_.size(), [&](auto J) {
        // Base-change matrix contains the punctured products of ibase elements modulo the obase
        get<0>(J) = modulo_uint(get<1>(J), ibase_.size(), get<1>(I));
    	});
    });
}

接下来是BaseConverter类中的initialize函数,表示BaseConverter类的初始化。首先判断输入和输出的RNSbase变量大小是否匹配,不匹配会抛出异常。然后通过输出RNSbase变量和内存池句柄生成RNSbase的转换矩阵的行。接下来通过SEAL_ITERATE嵌套去生成RNSbase的转换矩阵的列。其中SEAL_ITERATE最后一项是定义了运算。

以上为BaseConverter类中private修饰的私有函数和变量,接下来继续分析使用public进行修饰的公开函数。

public:
	BaseConverter(const RNSBase &ibase, const RNSBase &obase, MemoryPoolHandle pool)
    	: pool_(std::move(pool)), ibase_(ibase, pool_), obase_(obase, pool_)
    {
		if (!pool_)
        {
        	throw std::invalid_argument("pool is uninitialized");
        }

        initialize();
    }

首先是BaseConverter类的构造函数。先判断内存池句柄是否初始化,然后调用私有函数initialize进行初始化。

SEAL_NODISCARD inline std::size_t ibase_size() const noexcept
{
    return ibase_.size();
}

SEAL_NODISCARD inline std::size_t obase_size() const noexcept
{
    return obase_.size();
}

SEAL_NODISCARD inline const RNSBase &ibase() const noexcept
{
    return ibase_;
}

SEAL_NODISCARD inline const RNSBase &obase() const noexcept
{
	return obase_;
}

然后是四个get方法,获取私有变量及其大小。

void fast_convert(ConstCoeffIter in, CoeffIter out, MemoryPoolHandle pool) const;

oid fast_convert_array(ConstRNSIter in, RNSIter out, MemoryPoolHandle pool) const;

最后是两个转换函数,实现系数和RNSbase的快速转换。

先来看一下fast_convert函数。

void BaseConverter::fast_convert(ConstCoeffIter in, CoeffIter out, MemoryPoolHandle pool) const
{
	size_t ibase_size = ibase_.size();
    size_t obase_size = obase_.size();

    SEAL_ALLOCATE_GET_COEFF_ITER(temp, ibase_size, pool);
    SEAL_ITERATE(
		iter(temp, in, ibase_.inv_punctured_prod_mod_base_array(), ibase_.base()), ibase_size,
        [&](auto I) { get<0>(I) = multiply_uint_mod(get<1>(I), get<2>(I), get<3>(I)); });

    // for (size_t j = 0; j < obase_size; j++)
    SEAL_ITERATE(iter(out, base_change_matrix_, obase_.base()), obase_size, [&](auto I) {
        get<0>(I) = dot_product_mod(temp, get<1>(I).get(), ibase_size, get<2>(I));
    });
}

首先获取ibase和obase两个RNSbase变量的大小,然后通过ibase的大小和内存池句柄初始化SESL的系数迭代器,最后通过两轮SEAL迭代分别进行乘法模和点乘模去更新最终需要的out结果。

然后是fast_convert_array函数。

        void BaseConverter::fast_convert_array(ConstRNSIter in, RNSIter out, MemoryPoolHandle pool) const
        {
#ifdef SEAL_DEBUG
            if (in.poly_modulus_degree() != out.poly_modulus_degree())
            {
                throw invalid_argument("in and out are incompatible");
            }
#endif
            size_t ibase_size = ibase_.size();
            size_t obase_size = obase_.size();
            size_t count = in.poly_modulus_degree();

            // Note that the stride size is ibase_size
            SEAL_ALLOCATE_GET_STRIDE_ITER(temp, uint64_t, count, ibase_size, pool);

            SEAL_ITERATE(
                iter(in, ibase_.inv_punctured_prod_mod_base_array(), ibase_.base(), size_t(0)), ibase_size,
                [&](auto I) {
                    // The current ibase index
                    size_t ibase_index = get<3>(I);

                    if (get<1>(I).operand == 1)
                    {
                        // No multiplication needed
                        SEAL_ITERATE(iter(get<0>(I), temp), count, [&](auto J) {
                            // Reduce modulo ibase element
                            get<1>(J)[ibase_index] = barrett_reduce_64(get<0>(J), get<2>(I));
                        });
                    }
                    else
                    {
                        // Multiplication needed
                        SEAL_ITERATE(iter(get<0>(I), temp), count, [&](auto J) {
                            // Multiply coefficient of in with ibase_.inv_punctured_prod_mod_base_array_ element
                            get<1>(J)[ibase_index] = multiply_uint_mod(get<0>(J), get<1>(I), get<2>(I));
                        });
                    }
                });

            SEAL_ITERATE(iter(out, base_change_matrix_, obase_.base()), obase_size, [&](auto I) {
                SEAL_ITERATE(iter(get<0>(I), temp), count, [&](auto J) {
                    // Compute the base conversion sum modulo obase element
                    get<0>(J) = dot_product_mod(get<1>(J), get<1>(I).get(), ibase_size, get<2>(I));
                });
            });
        }

首先判断输入和输出的多项式模数是否相等,如果不等则抛出异常。

#ifdef SEAL_DEBUG
            if (in.poly_modulus_degree() != out.poly_modulus_degree())
            {
                throw invalid_argument("in and out are incompatible");
            }
#endif

然后获取ibase和obase的大小以及in的多项式模数,通过in的多项式模数、ibase_size和内存池句柄去初始化SEAL的步伐迭代器。

size_t ibase_size = ibase_.size();
size_t obase_size = obase_.size();
size_t count = in.poly_modulus_degree();

// Note that the stride size is ibase_size
SEAL_ALLOCATE_GET_STRIDE_ITER(temp, uint64_t, count, ibase_size, pool);

最后分别通过(in,ibase)和(out,base_change_matrix,obase)进行SEAL_ITERATE嵌套迭代完成最后的更新。

SEAL_ITERATE(
	iter(in, ibase_.inv_punctured_prod_mod_base_array(), ibase_.base(), size_t(0)), ibase_size,
    [&](auto I) {
		// The current ibase index
        size_t ibase_index = get<3>(I);

        if (get<1>(I).operand == 1)
        {
			// No multiplication needed
            SEAL_ITERATE(iter(get<0>(I), temp), count, [&](auto J) {
				// Reduce modulo ibase element
                get<1>(J)[ibase_index] = barrett_reduce_64(get<0>(J), get<2>(I));
            });
        }
        else
        {
            // Multiplication needed
            SEAL_ITERATE(iter(get<0>(I), temp), count, [&](auto J) {
                 // Multiply coefficient of in with ibase_.inv_punctured_prod_mod_base_array_ element
                 get<1>(J)[ibase_index] = multiply_uint_mod(get<0>(J), get<1>(I), get<2>(I));
            });
        }
});

SEAL_ITERATE(iter(out, base_change_matrix_, obase_.base()), obase_size, [&](auto I) {
	SEAL_ITERATE(iter(get<0>(I), temp), count, [&](auto J) {
		// Compute the base conversion sum modulo obase element
        get<0>(J) = dot_product_mod(get<1>(J), get<1>(I).get(), ibase_size, get<2>(I));
    });
});

最后可以说明一下,这里的SEAL_ITERATE迭代器与我们熟知的for循环时一样的,区别不过是通过最后的[&](auto I)规定一种迭代的运算,所以没有在过多的展开对于迭代操作的分析。

总结

本周基本完成了对于剩余数系统的分析,下一周将对RNS进行扫尾以及总结这一学期的所学内容。

通过学习和分析RNS,明白了如何加快运算速度。目前软件工程应用与实践这门课程也逐渐进入尾声,通过这一学期的学习,掌握了如何对于一门新的方向进行着手,为以后的发展奠定了基础。

最后,感谢孔老师的指导,感谢戴老师和其他审核老师的阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值