codegen.py

来自「CVXMOD is a Python-based tool for expres」· Python 代码 · 共 986 行 · 第 1/2 页

PY
986
字号
        print 'Generating reduced Newton system coefficient matrix.'        (ASATnum, s, ss, p) = self.multstuff(A, AT, m, n)        dt['CM_ASAT'] = s        dt['CM_ASAT_size'] = len(ss)        # Reverse the permutation. Ran into a weird bug when trying a fancier        # scheme of inverting the permutation.        pinv = [None,]*len(p)        for i in range(len(p)):            pinv[p[i]] = i        print 'Generating code for b = A*gh.'        s = ''        # Take note of the (inverse) permutation p.        for i in range(m):            d = 0            for j in range(n):                if (p[i], j) in A:                    d = d - A[p[i],j]*gh[j]            s += 'CM_b[%d] = %s;\n' % (i, exprtoC(d))        dt['CM_b'] = s        print 'Generating Cholesky factorization and solution code:'        (d, (L, ssL, KL)) = self.cholsolve(ASATnum, ss)        dt.update(d)        print 'Generating code for dx.'        s = ''        w = optvar('CM_w', m, 1)        for i in range(n):            d = 0            for j in range(m):                if (i, j) in AT:                    # Take note of the (inverse) permutation p.                    d = d + AT[i,j]*w[pinv[j]]            s += 'CM_dx[%d] = -CM_h[%d]*(%s + CM_g[%d]);\n' % (i, i, exprtoC(d), i)        dt['CM_dx'] = s        writecode(self.outdir, self.skel, 'fastacent.c', dt)    def fastbarr(self, As, bs, cs, m, n, p, suffix=''):        dt = {}        dt['header'] = header()        dt['m'] = value(m)        dt['n'] = value(n)        dt['p'] = value(p)        dt['suffix'] = suffix        print 'Generating code for fast barrier method:'        print 'Framing objective.'        cs = value(cs)        s = ''        for i in range(n):            s += 'CM_c[%d] = %s;\n' % (i, exprtoC(cs[i]))        dt['CM_c'] = s        print 'Creating method signature.'        if getparams(self.p):            dt['params'] = ', '.join(['double *%s' % x for x in \                                      bylowerstr(getparams(self.p))])            dt['params'] += ','        else:            dt['params'] = ''        print 'Inspecting problem structure.'        A = nzentries(As)        AT = nzentries(tp(As))        # Create a gh optvar simply to make it easy to convert the multiplication.        gh = optvar('CM_gh', n, 1)                # Now multiply and solve.        print 'Generating reduced Newton system coefficient matrix.'        (ASATnum, s, ss, p) = self.multstuff(A, AT, m, n)        dt['CM_ASAT'] = s        dt['CM_ASAT_size'] = len(ss)        # Reverse the permutation. Ran into a weird bug when trying a fancier        # scheme of inverting the permutation.        pinv = [None,]*len(p)        for i in range(len(p)):            pinv[p[i]] = i        print 'Generating code for b = A*gh.'        s = ''        # Take note of the (inverse) permutation p.        for i in range(m):            d = 0            for j in range(n):                if (p[i], j) in A:                    d = d - A[p[i],j]*gh[j]            s += 'CM_b[%d] = %s;\n' % (i, exprtoC(d))        dt['CM_b'] = s        print 'Generating Cholesky factorization and solution code:'        (d, (L, ssL, KL)) = self.cholsolve(ASATnum, ss)        dt.update(d)        print 'Generating code for dx.'        s = ''        w = optvar('CM_w', m, 1)        for i in range(n):            d = 0            for j in range(m):                if (i, j) in AT:                    # Take note of the (inverse) permutation p.                    d = d + AT[i,j]*w[pinv[j]]            s += 'CM_dx[%d] = -CM_h[%d]*(%s + CM_g[%d]);\n' % (i, i, exprtoC(d), i)        dt['CM_dx'] = s        writecode(self.outdir, self.skel, 'fastbarr.c', dt,                  outname='fastbarr%s.c' % suffix)    def testwithdata(self, dispvars=False):        p = self.p        d = {}        d['header'] = header()        d['dims'] = joinlist(bylowerstr(getdims(p)), True)        d['params'] = joinlist(bylowerstr(getparams(p)), True)        d['optvars'] = joinlist(bylowerstr(getoptvars(p)), True)        d['numvars'] = str(len(getoptvars(p)))        # jem: making the assumption that optvars order will be sorted like        # this.        s = ''        i = 0        for x in bylowerstr(getoptvars(p)):            s += 'outvar %s;\n%s = vars[%d];\n' % (str(x), str(x), i)            i += 1        d['namevars'] = s        s = joinlist(bylowerstr(getdims(p)) + bylowerstr(getparams(p)), True)        d['tsf_args'] = s        # jemjemjem.        #if dispvars:        #    d['tsf_args'] = s        #// Display the variables.        #pm(x->val, x->m, x->n);        #pm(y->val, y->m, y->n);        writecode(self.outdir, self.skel, 'testwithdata.c', d)    def backsubs(self, L, n, ssL):        # Include an implicit transpose here. ie, L is a lower triangular        # version of an upper triangular matrix.        s = ''        for i in range(n - 1, -1, -1):            #s += 'CM_w[%d] = CM_x[%d];\n' % (i, i)            for j in range(i + 1, n):                if not iszero(L[j,i]):                    s += 'CM_w[%d] -= CM_L[%s]*CM_w[%d];\n' % (i, ssL[j,i], j)        return s    def forwardsubs(self, L, n, ssL):        s = ''        for i in range(n):            s += 'CM_w[%d] = CM_b[%d];\n' % (i, i)            for j in range(0, i):                if not iszero(L[i,j]):                    s += 'CM_w[%d] -= CM_L[%s]*CM_w[%d];\n' % (i, ssL[i,j], j)        return s    def cholsolve(self, Anum, ssA):        n = rows(Anum)        (L, ssL, KL, Aclean) = self.cholss(Anum, ssA)        dt = {}        dt['CM_L_size'] = KL        print '- code for Cholesky factorization.'        dt['chol'] = self.chol(Aclean, n, ssA, ssL)        print '- code for forward substitution.'        dt['forwardsubs'] = self.forwardsubs(L, n, ssL)        print '- code for back substitution.'        dt['backsubs'] = self.backsubs(L, n, ssL)        return (dt, (L, ssL, ssA))    def chol(self, A, n, ssA, ssL):        v = [None,]*n        d = [None,]*n        L = {}        d[0] = nze()        s = 'CM_d[0] = CM_ASAT[%d];\n' % ssA[0,0]        for i in range(1, n):            L[i,0] = A[i,0]# / d[0]            if (i,0) in ssA:                s += 'CM_L[%d] = CM_ASAT[%d] / CM_d[0];\n' % (ssL[i,0], ssA[i,0])        for j in range(1, n):            for i in range(j):                v[i] = L[j,i]*d[i]                if isnonzero(L[j,i]) and isnonzero(d[i]):                    s += 'CM_v[%d] = CM_L[%d]*CM_d[%d];\n' % (i, ssL[j,i], i)            v[j] = A[j,j]            s += 'CM_v[%d] = CM_ASAT[%d];\n' % (j, ssA[j,j])            for i in range(j):                v[j] = v[j] - L[j,i]*v[i]                if isnonzero(L[j,i]*v[i]):                    s += 'CM_v[%d] -= CM_L[%d]*CM_v[%d];\n' % (j, ssL[j,i], i)            d[j] = v[j]            s += 'CM_d[%d] = CM_v[%d];\n' % (j, j)            if j < n - 1:                for i in range(j + 1, n):                    L[i,j] = A[i,j]                    if (i,j) in ssL:                        if isnonzero(A[i,j]):                            s += 'CM_L[%d] = CM_ASAT[%d];\n' % (ssL[i,j], ssA[i,j])                        else:                            s += 'CM_L[%d] = 0;\n' % ssL[i,j]                    else:                        continue                    for k in range(j):                        L[i,j] = L[i,j] - L[i,k]*v[k]                        if isnonzero(L[i,k]*v[k]):                            s += 'CM_L[%d] -= CM_L[%d]*CM_v[%d];\n' % (ssL[i,j], ssL[i,k], k)                    if isnonzero(L[i,j]):                        s += 'CM_L[%d] /= CM_v[%d];\n' % (ssL[i,j], j)        # Implicitly assuming CM_L_{ii} = 1 for all i.        return s    def cholss(self, Anum, ssA):        # Returns (L, Lss) where Lss[i,j] returns the index to store L[i,j].        # L[i,j] = nze() or 0.        # Note: implicit about the fact that L_{ii} = 1 for all i.        n = rows(Anum)        # Work from a clean A.        A = sparsedict()        for i in range(n):            for j in range(i + 1):                if isnonzero(Anum[i,j]):                    A[i,j] = nze()        v = [None,]*n        d = [None,]*n        L = sparsedict()        d[0] = A[0,0]        for i in range(1, n):            L[i,0] = A[i,0]        for j in range(1, n):            for i in range(j):                v[i] = L[j,i]*d[i]            v[j] = A[j,j]            for i in range(j):                v[j] = v[j] - L[j,i]*v[i]            d[j] = v[j] # will probably be translated directly.            if j < n - 1:                for i in range(j + 1, n):                    L[i,j] = A[i,j]                    for k in range(j):                        L[i,j] = L[i,j] - L[i,k]*v[k]        # Compute (simple) storage scheme for L.        k = 0        ssL = {}        Lclean = sparsedict()        for i in range(n):            for j in range(n):                if isnonzero(L[i,j]):                    ssL[i,j] = k                    Lclean[i,j] = nze()                    k += 1        KL = k        return (Lclean, ssL, KL, A)    def cholmoddata(self, Anum):        # jem: temporary function.        # jem: later need to store only one half of A: pick which!        d = {}        d['header'] = header()        # There must be a better way of doing this.        n = rows(Anum)        s = ''        s += 'int *Ai = At->i;\n'        s += 'int *Aj = At->j;\n'        s += 'double *Ax = At->x;\n'        k = 0        for i in range(n):            for j in range(i, n):                if isnonzero(Anum[i,j]):                    s += 'Ai[%d] = %d; ' % (k, i)                    s += 'Aj[%d] = %d; ' % (k, j)                    s += 'Ax[%d] = %.7g;\n' % (k, Anum[i,j])                    k += 1        s = 'At = cholmod_allocate_triplet(%d, %d, %d, 1, CHOLMOD_REAL, &common);\n' % \                (n, n, k) + s        s = 'cholmod_triplet *At;\n' + s        s += 'At->nnz = %d;\n' % k        d['At'] = s        writecode(self.outdir, self.skel, 'cholmod_data.h', d)    def choldata(self, Anum, bnum, n):        # jem: later need to store only one half of A: pick which!        d = {}        d['header'] = header()        ssA = self.cholss(Anum, True)        s = ''        for (i, j) in sorted(ssA.keys()):            s += 'A[%d] = %.7g;\n' % (ssA[i, j], Anum[i,j])        d['A'] = s        s = ''        for i in range(n):            s += 'b[%d] = %.7g;\n' % (i, bnum[i])        d['b'] = s        writecode(self.outdir, self.skel, 'chol_data.h', d)    def backsubsdata(self, L, ss, b):        # jem: temporary function.        d = {}        d['header'] = header()        (dss, K) = ss        b = param('b', value=b)        # Reverse the role of the keys and values.        dss2 = {}        for k in dss.keys():            dss2[dss[k]] = k        s = ''        for k in range(K):            s += 'L[%d] = %.7g;\n' % (k, L[dss2[k]])        d['L'] = s        d['b'] = self.declarematrix(b)        writecode(self.outdir, self.skel, 'backsubs_data.h', d)    def multstuff(self, A, AT, m, n):        """Multiplies and stuffs matrices."""        # Make a sparse mask of rn. Use A*A'.        Am = zeros(m, n)        for k in A.keys():            Am[k] = 1        Am = Am*tp(Am)        p = order(Am)        Ao = Am[p,p]        # Design a simple storage scheme for Ao.        k = 0        ss = {}        for (i, j) in zip(Ao.I, Ao.J):            if i >= j:                ss[i,j] = k                k += 1        # Find reduced Newton system matrix ASAT.        d = {}        ASAT = {}        # Write some code.        h = param('CM_h', m, 1)        for i in range(m):            ip = p[i]            for j in range(i + 1):                jp = p[j]                for k in range(n):                    if (ip,k) in A and (k,jp) in AT:                        if ss[i,j] not in d:                            d[ss[i,j]] = exprtoC(A[ip,k] * h[k] * AT[k,jp])                        else:                            d[ss[i,j]] += ' + ' + exprtoC(A[ip,k] * h[k] * AT[k,jp])        s = ''        for k in sorted(d.keys()):            s += 'CM_ASAT[%d] = %s;\n' % (k, d[k])        return (Ao, s, ss, p)    def sparsematrixvec(self, ss, m, n, A, x, b):        """Provides explicit C code for multiplying A*x, where ss is the        storage scheme for a sparse matrix A, and x and b are both strings."""        A = nzentries(A)        x = optvar(x, n)        for i in range(m):            d = 0            for j in range(n):                if (i, j) in ss:                    d = d + A[i,j]*x[j]                    print A[i,j]                    print d            print '%s[%d] = %s;' % (b, i, exprtoC(d))    def getss(self, A):        # Design a simple storage scheme for Ao.        m, n = value(size(A))        A = nzentries(A)        # Make a sparse mask of A.        Am = zeros(m, n)        for k in A.keys():            Am[k] = 1        k = 0        ss = {}        for (i, j) in zip(Am.I, Am.J):            if i >= j:                ss[i,j] = k                k += 1        return ssdef withheading(s):    return s.rstrip() + '\n' + '-'*len(s.rstrip()) + '\n'def header():    s = '// CVXMOD code generation.\n'    s += '// Produced by CVXMOD, %s.\n' % strftime("%Y-%m-%d %H:%M:%S")    s += '// CXVMOD is Copyright (C) 2006-2008 Jacob Mattingley.\n'    return sdef writecode(outdir, skeleton, inname, d, outname=None):    if outname is None:        outname = inname    infile = open(os.path.join(skeleton, inname))    outname = os.path.join(outdir, outname)    outfile = open(outname, 'w')    print 'Writing to %s.' % outname    ril = re.compile('(CVXMOD_IL_(\\w+))')    rwl = re.compile('(\s*)CVXMOD_WL_(\\w+);?')    ind = ''    for l in infile:        # Test for inline tags. Only one allowed max, per line.        g = ril.search(l)        # Test for whole line tags. These take on the same indent as the tag.        h = rwl.search(l)        if g:            try:                outfile.write(l[:g.start(1)] + str(d[g.group(2)]) + l[g.end(1):])            except KeyError:                Jwarn('could not match tag: ' + g.group(2))                outfile.write(l[:-1] + ' // XXX failed to match tag.\n')        elif h:            try:                for l2 in d[h.group(2)].splitlines():                    outfile.write(h.group(1) + l2 + '\n')            except KeyError:                Jwarn('could not match tag: ' + h.group(2))                outfile.write(l[:-1] + ' // XXX failed to match tag.\n')        else:            outfile.write(ind + l)    infile.close()    outfile.close()

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?