• Orthogonal table 实现理论


    Orthogonal table

     

    概述
    正交试验中使用的正交表的生成过程其实就是一个加法Abel群的生成过程。对于m水平表而言,为了方便起见我们对水平表的每个元素均做的处理,任取其中的任意两列则一定具有完全对:

    这说明a和b都是一个分量包含0~m-1的列向量,并且有:

    也就是说在 或者 也都具有完全对。

    至此我们可以定义加法:

    对于标准表而言,若a和b是标准表的 2 个列,那么也一定是标准表的一个列。

    有限Abel群的基底
    考虑到标准表中任取 2 列的完全对出现的次数都是均等的 , 因此的列总是以

    中的元素为基础关于运算生成的,其中 是矩阵的Kronecker乘积。

    有限Abel群的子群

    G是以为基底,关于运算生成的Abel群,则G明显是拥有众多Abel子群的,例如在确定G的基底是

    的情况下,显然:

    G的子群。现在我们扩展一下这个系列。令:

    此时都是G的m阶循环子群。

    构造

    Step1.K的全体元素就是正交表的所有列。正交试验标准表可按此法构造。

    Step2.若有 ,则说明第i列和第j列对应放置交互作用的列应该是第列。正交试验表头可按照此法构造。

    后记

    此法没有涉及任何的枚举过程,计算出的正交表和表头表的生成速度比正常枚举法要快非常多,正常的单线程运行此算法,一个行数和列数均在200以上的正交表只需要1秒不到就能算出。

    值得注意的是Step2中所描述的正交表表头并非是一定能以此法完整的构造出的,因为Step2中的等号并非一定成立。为什么会出现这种情况呢,原因就是因为的构造方式并不能保证对于任意的i和j 都能找到使得Step2中等号都的成立。按照道理来说我们需要找一个只由构造出的循环群,如果这样的都能满足Step2中的等式,则正交表头可完整构造出来

    Python Code(import numpy)

      1 class OrthogonalTableMap():
      2     
      3     def __init__(self, level, time):
      4         self.m = level
      5         self.time = time
      6         n = self.m**(time + 1)
      7         k = (n - 1)//(self.m - 1)
      8         
      9         # 构造self.base,self.base的元素与加法群的基底一一对应
     10         self.base = [numpy.zeros(n, numpy.int)]
     11         for j in range(0, time + 1):
     12             mat1 = numpy.ones(self.m**j, numpy.int)
     13             mat2 = numpy.linspace(1, self.m, self.m, dtype = numpy.int)
     14             mat3 = numpy.ones(self.m**(time - j), numpy.int)
     15             self.base.append(numpy.kron(numpy.kron(mat1, mat2), mat3) - 1)
     16         self.base = self.base[1:len(self.base)+1]
     17         
     18         # 构造正交表self.table和记录每列群属性的self.dir
     19         self.dir = [numpy.zeros((time + 1, self.m - 1), numpy.int)]
     20         self.dir[0][0, 0] = 1
     21         for j in range(1, self.m - 1):
     22             self.dir[0][:, j] = (j + 1)*self.dir[0][:, 0]%self.m
     23         
     24         self.table = [self.base[0]]
     25         for j in range(1, time + 1):
     26             self.table.append(self.base[j])
     27             
     28             self.dir.append(numpy.zeros((time + 1, self.m - 1), numpy.int))
     29             self.dir[-1][j, 0] = 1
     30             for k in range(1, self.m - 1):
     31                 self.dir[-1][:, k] = (k + 1)*self.dir[-1][:, 0]%self.m
     32             
     33             for k in range(0, len(self.table) - 1):
     34                 for s in range(1, self.m):
     35                     self.table.append((s*self.table[k] + self.base[j])%self.m)
     36                     
     37                     self.dir.append(numpy.zeros((time + 1, self.m - 1), numpy.int))
     38                     self.dir[-1][:, 0] = s*self.dir[k][:,0]
     39                     self.dir[-1][j, 0] += 1
     40                     self.dir[-1][:, 0] = self.dir[-1][:, 0]%self.m
     41                     for t in range(1, self.m - 1):
     42                         self.dir[-1][:, t] = (t + 1)*self.dir[-1][:, 0]%self.m
     43                         
     44         # 将self.base和self.table以矩阵形式表示,并且+1还原
     45         temp = numpy.zeros((n, len(self.base)), numpy.int)
     46         for j in range(0, len(self.base)):
     47             temp[:, j] = self.base[j]
     48         self.base = temp + 1
     49         temp = numpy.zeros((n, len(self.table)), numpy.int)
     50         for j in range(0, len(self.table)):
     51             temp[:, j] = self.table[j]
     52         self.table = temp + 1
     53         
     54         # self.hash_dir的一个元素都是self.table的一个列对应的群成员的hash值集合
     55         self.hash_dir = self.hash_function()
     56         
     57         self.error = 0
     58         
     59     def hash_function(self):
     60         # 制作hash函数将self.dir所包含的信息处理成数据类型为numpy.int的基本元素的集合簇输出
     61         mat = numpy.ones((1, self.time + 1), numpy.int)
     62         for j in range(1, self.time + 1):
     63             mat[0, j] *= self.m**j
     64         hash_dir = self.dir.copy()
     65         for j in range(0, len(self.dir)):
     66             hash_dir[j] = set(numpy.dot(mat, self.dir[j]).reshape(self.m - 1))
     67             
     68         return hash_dir
     69     
     70     def hash_add(self, var_set, format_check = True):
     71         # 制作与向量加法对应在hash映射下的加法hash_add
     72         if format_check:
     73             if len(var_set)<2:
     74                 print("Error:var_set should at least has 2 elements.")
     75             if max(var_set)>len(self.hash_dir) or min(var_set)<0:
     76                 print("Error:var_set's elements should between 0~len(hash_dir).")
     77         arg_set = numpy.array(var_set)
     78         
     79         var_out = 0
     80         for j in range(0, self.time + 1):
     81             temp = 0
     82             for k in range(0, len(var_set)):
     83                 temp += arg_set[k]//self.m**(self.time - j)
     84             var_out += (temp%self.m)*self.m**(self.time - j)
     85             arg_set = arg_set%self.m**(self.time - j)
     86             
     87         return var_out
     88     
     89     def hash_set_add(self, sets_ind, end_set = None):
     90         # 定义hash后的self.dir的集合对应在hash映射下的加法hash_set_add
     91         if len(sets_ind)==0:
     92             set_num = list()
     93             for j in range(0, len(self.hash_dir)):
     94                 if len(self.hash_dir[j]&end_set)>0:
     95                     set_num.append(j)
     96             return set_num
     97         
     98         if end_set is None:
     99             if len(sets_ind)<2:
    100                 print("Error:set_ind should at least has 2 elements.")
    101             end_set = self.hash_dir[sets_ind[-1]]
    102             sets_ind.pop()
    103         
    104         temp_set = list()
    105         for j in self.hash_dir[sets_ind[-1]]:
    106             for k in end_set:
    107                 temp_set.append(self.hash_add([j, k], format_check = False))
    108         end_set = set(temp_set)
    109         sets_ind.pop()
    110         
    111         return self.hash_set_add(sets_ind, end_set)
    112     
    113     def title(self):
    114         # 使用矩阵title表示带有多因素交互作用的表头,若没有成功找到所有子群则修改self.error = 1
    115         title = numpy.zeros((len(self.hash_dir)*(self.m - 1), 
    116                                   len(self.hash_dir)), numpy.int)
    117         try:
    118             for j in range(0, len(self.hash_dir)):
    119                 title[(self.m - 1)*j:(self.m - 1)*(j + 1), j] = j + 1
    120                 for k in range(j + 1, len(self.hash_dir)):
    121                     temp = numpy.array(self.hash_set_add([j, k])).reshape(self.m -1)
    122                     title[(self.m - 1)*j:(self.m - 1)*(j + 1), k] = temp +1
    123             self.error = 0
    124         except ValueError:
    125             self.error = 1
    126         return title

    Demo

    3水平13因素正交表(表头数据依赖于列排序,列排序不一定和文献资料一样,如需对照请自行重新排序对照)

    ex = OrthogonalTableMap(3,2)
    
    print("table = ")
    print(ex.table)
    print("title = ")
    print(ex.title())

    声明

    本文由Hamilton算符”原创,未经博主允许不得转载!

  • 相关阅读:
    开发网站邮件发送模块
    HttpModule的Init事件
    一个产品留言统计查寻的分析比较
    Js中清空文件上传字段(input type=file )
    Asp.net生成Excel报表
    jQuery与开发的相关js文件包含顺序
    trycatch 与 Response.End()
    asp.net2.0中的Usercontrol动态创建
    客户javascript端验证图片文件大小与规格使用Image对象
    JQuery 常用代码收集
  • 原文地址:https://www.cnblogs.com/Hamilton-Operator/p/6420048.html
Copyright © 2020-2023  润新知