Generating Python Code for Matrix Inner Product in SQLite Database

Pada waktu event wordcampid yang lalu saya sempat menulis kode untuk melakukan pencarian citra dari database (image retrieval). Kodenya ditulis ketika agak senggang atau ketika topik pembicaraannya tidak terlalu menarik. Saya menggunakan fitur berupa matriks 8×8 yang disimpan dalam database SQLite. Pada intinya saya berniat melakukan inner (dot) product melalui pernyataan SQL (supaya sekalian diurutin dan dibatasi top N😀 ). Awalnya senang-senang saja, lama-lama saya bosan juga kalau harus mengetik 64 field dan 64 parameter untuk setiap fungsi (ada 3 fungsi yaitu mendefinisikan table, insert, dan find). jadi totalnya 64 x 5 = 320 field harus saya ketik manual. Saya tidak pakai perulangan karena malas melihat kode berisi penempelan string kala itu. Hari berikutnya akhirnya saya menulis kode untuk mengotomatisasi pekerjaan tersebut (bayangkan kalau saya ubah eksperimennya jadi fitur berukuran 12×12 atau 25×25).

Kode yang saya tulis ketika dijalankan akan menghasilkan file teks berisi kode python yang spesifik dengan dimensi matriks yang menjadi parameter.

def genmat(la):
    result = []
    for i in xrange(0,la[0]):
        if len(la)==1:
            result += [["%s" % i]]
        else:
            row = ["%s" % i]
            tmp = genmat(la[1:])
            for x in tmp:
                result += [row+x]
    return result

def setup(n, output="Test", tablename="vec", cols=[], classprefix="DocSearch"):
    classname=classprefix+output
    fpy = open(output+".py", "w")
    if len(cols)==0:
        cols = [("id", "INTEGER PRIMARY KEY"), ("desc", "CHAR(255)")]
    lcols = []
    try:
        dim = len(n)
        vcols = genmat(n)
    except:
        dim = 1
        vcols = genmat([n])
    for f in vcols:
        lcols += [("v"+"_".join(f), "DOUBLE NOT NULL")]
    scols = ", ".join(["%s %s" % (c, t) for c, t in lcols+cols])
    fpy.write("""
import sqlite3

class %s:
    def __init__(self, dbname="db%s.db"):
        self.db = dbname
        self.con = sqlite3.connect(self.db)
        
    def setup(self):
        self.con.execute("CREATE TABLE %s (%s)")
        self.con.commit()
    """ % (classname, output, tablename, scols))

    acols = ", ".join(["%s" % (c) for c, t in cols])
    icols = ", ".join(["%s" % (c) for c, t in lcols+cols])
    ivcols = ", ".join(["?"]*(len(lcols)+len(cols)))
    _ipcols = []
    for f in vcols:
        _ipcols += ["f"+"".join(["["+v+"]" for v in f])]
    ipcols = ", ".join(_ipcols)
    fpy.write("""    
    def insert(self, f, %s):
        self.con.execute("INSERT INTO %s (%s) VALUES (%s)" %s (%s, %s))
        self.con.commit()
    """ % (acols, tablename, icols, ivcols, "%", ipcols, acols))
    
    qcols = ", ".join(["%s*%s" % (c, "?") for c, t in lcols])
    fpy.write("""    
    def query(self, f):
        c = self.con.cursor()
        c.execute("SELECT (%s) as dot, %s FROM %s ORDER BY dot DESC" %s (%s))
        rows = c.fetchall()
        return rows
    """ % (qcols, acols, tablename, "%", ipcols))
    
    fpy.write("""

if __name__=="__main__":
    search = %s()
    search.setup()
    """ % (classname))
    fpy.close()
   
if __name__=="__main__":
    setup(3, "1x3")
    setup([2,2], "2x2")
    setup([8,8], "8x8")
    #print genmat([2,2])
    

Kode di atas juga berisi contoh penggunaan fungsi untuk berbagai dimensi (misal 1xn, mxn, mxnxsxtx…xz). Contoh keluaran untuk matriks 2×2 seperti berikut:

import sqlite3

class DocSearch2x2:
    def __init__(self, dbname="db2x2.db"):
        self.db = dbname
        self.con = sqlite3.connect(self.db)
        
    def setup(self):
        self.con.execute("CREATE TABLE vec (v0_0 DOUBLE NOT NULL, v0_1 DOUBLE NOT NULL, v1_0 DOUBLE NOT NULL, v1_1 DOUBLE NOT NULL, id INTEGER PRIMARY KEY, desc CHAR(255))")
        self.con.commit()
        
    def insert(self, f, id, desc):
        self.con.execute("INSERT INTO vec (v0_0, v0_1, v1_0, v1_1, id, desc) VALUES (?, ?, ?, ?, ?, ?)" % (f[0][0], f[0][1], f[1][0], f[1][1], id, desc))
        self.con.commit()
        
    def query(self, f):
        c = self.con.cursor()
        c.execute("SELECT (v0_0*?, v0_1*?, v1_0*?, v1_1*?) as dot, id, desc FROM vec ORDER BY dot DESC" % (f[0][0], f[0][1], f[1][0], f[1][1]))
        rows = c.fetchall()
        return rows
    

if __name__=="__main__":
    search = DocSearch2x2()
    search.setup()
    

Kode di atas masih bisa dikembangkan lagi, misalnya untuk interface basisdata lain seperti mysql atau postgreS atau menggunakan SQLAlchemy. Oya, saya juga lupa, kode untuk Update belum ada😀 .

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s