Sunday, March 29, 2009

Reading an article from bottom to top

This is what I often do to make my brain and imagination free from the idea of the article that the author tells as a *fact*. Since each article has its idea (otherwise it's a garbage), and in most cases it is written at the end, I can easily find the idea by just looking at the final part of the article and read the rest of the document thinking in what way the author is trying to convince the reader, not unquestioningly believing it. I do it not only when I see editorials, I do it whenever I feel "looks good but something is weird", or there are too many methods and everything looks fine by itself. I can take the idea, or ignore it, or modify it, or whatever.

Saturday, March 28, 2009

Beests came to Japan

Theo Jansen's strandbeests came to Japan!































So beautiful.















Basic idea (proportions are not correct).

Saturday, March 14, 2009

Simulating Maya Animation Curve calculation in C

It's a super old program I made for one of my friend.


#include <stdio.h>

int main(){

double x1, x2, x3, x4;
double y1, y2, y3, y4;
double t1x, t1y, t2x, t2y;
double scale;
double t, x, y;
double ax, bx, cx, dx;
double ay, by, cy, dy;

printf("Input start point and end point(P1, P4)\n");
scanf("%lf %lf %lf %lf", &x1, &y1, &x4, &y4);
printf("P1 = (%lf, %lf), P4 = (%lf, %lf)\n",
x1, y1, x4, y4);

//Input P1's keyTangent -q -ox, keyTangent -q -oy and
//P4's keyTangent -q -ix, keyTangent -q -iy values.
printf("Input outTangent of P1 and inTangent of P4\n");
scanf("%lf %lf %lf %lf", &t1x, &t1y, &t2x, &t2y);
printf("P1outTan = (%lf, %lf), P4inTan = (%lf, %lf)\n",
t1x, t1y, t2x, t2y);

//move x2 to the deviding point 1:3 between the start and end.
x2 = x1 + (x4 - x1) / 3;

//Change y2 to adjust the tangent.
scale = (x2 - x1) / t1x;
y2 = y1 + t1y * scale;

//move x3 to the deviding point 2:3 between the start and end.
x3 = x4 - (x4 - x1) / 3;
//Change y3 to adjust the tangent.
scale = (x4 - x3) / t2x;
y3 = y4 - t2y * scale;

while(1){
printf("Input curve parameter: ");
scanf("%lf", &t);

ax = - 1 * x1 + 3 * x2 - 3 * x3 + 1 * x4;
bx = 3 * x1 - 6 * x2 + 3 * x3 + 0 * x4;
cx = - 3 * x1 + 3 * x2 + 0 * x3 + 0 * x4;
dx = 1 * x1 + 0 * x2 - 0 * x3 + 0 * x4;

ay = - 1 * y1 + 3 * y2 - 3 * y3 + 1 * y4;
by = 3 * y1 - 6 * y2 + 3 * y3 + 0 * y4;
cy = - 3 * y1 + 3 * y2 + 0 * y3 + 0 * y4;
dy = 1 * y1 + 0 * y2 - 0 * y3 + 0 * y4;

x = ax * t*t*t + bx * t*t + cx * t + dx;
y = ay * t*t*t + by * t*t + cy * t + dy;

printf("x = %lf, y = %lf\n", x, y);
}

return 0;
}


----------------Test MEL Script----------------


//Set the unit to cm and second in Window->Settings/Preferences->Preferences
//before runnning the MEL script.

sphere;
currentTime 0;
setAttr "nurbsSphere1.tx" 0;
setKeyframe "nurbsSphere1.tx";
currentTime 1;
setKeyframe "nurbsSphere1.tx";
keyTangent -e -a -t 0 -outAngle 89.035812 -outWeight 1 nurbsSphere1_translateX ;
keyTangent -e -a -t 1 -inAngle 85.969596 -inWeight 1 nurbsSphere1_translateX ;

print "---tangents---\n";
selectKey -r -k -t 0 nurbsSphere1_translateX ;
print `keyTangent -q -ox`;
print `keyTangent -q -oy`;
selectKey -r -k -t 1 nurbsSphere1_translateX ;
print `keyTangent -q -ox`;
print `keyTangent -q -oy`;
print "---data---\n";
float $i;
for ($i = 0; $i <1.01; $i += 0.2){
currentTime $i;
print ( `currentTime -q`+ ": " + `getAttr "nurbsSphere1.tx"` + "\n");
}


----------------Result----------------
[Maya]

---tangents---
0.016827
0.999858
0.070286
0.997527
---data---
0: 0
0.2: 7.151379024
0.4: 7.193755345
0.6: 3.660442155
0.8: 0.08475264279
1: 0

[program]

Input start point and end point(P1, P4)
0 0 1 0
P1 = (0.000000, 0.000000), P4 = (1.000000, 0.000000)
Input outTangent of P1 and inTangent of P4
0.016827 0.999858 0.070286 0.997527
P1outTan = (0.016827, 0.999858), P4inTan = (0.070286, 0.997527)
Input curve parameter: 0.0
x = 0.000000, y = 0.000000
Input curve parameter: 0.2
x = 0.200000, y = 7.151585
Input curve parameter: 0.4
x = 0.400000, y = 7.193990
Input curve parameter: 0.6
x = 0.600000, y = 3.660601
Input curve parameter: 0.8
x = 0.800000, y = 0.084808
Input curve parameter: 1.0
x = 1.000000, y = -0.000000
Input curve parameter:

Wednesday, March 11, 2009

Slice object and Ellipsis


>>> class Array(list):
... def __getitem__(self, key):
... print "key:", key, type(key)
... def __getslice__(self, i, j):
... print "ij", i, j
...
>>> a = Array(range(10))
>>> a[0]
key: 0 <type int="">
>>> a[0:5]
ij 0 5
>>> a[0, 1, 2]
key: (0, 1, 2) <type tuple="">
>>> a[0:6:2]
key: slice(0, 6, 2) <type 'slice'>
>>> a[0:1, 3:4]
key: (slice(0, 1, None), slice(3, 4, None)) <type 'tuple'>
>>> slice(1,3), type(slice(1,3))
(slice(1, 3, None), <type 'slice'>)
>>> a[0, ..., 5]
key: (0, Ellipsis, 5) <type tuple="">
>>> Ellipsis, type(Ellipsis)
(Ellipsis, <type 'ellipsis'>)

hmmm...
(to be updated)

Tuesday, March 10, 2009

LLVM and Python

LLVM (Low Level Virtual Machine ) takes LLVM IR (intermediate representation), which is like an intermediate language and builds it after optimizing it. LLVM compile flow consists of roughly two parts, LLVM frontend, which is an IR generator, and backend, which generates build products. By choosing a frontend, you can compile your source code written in your favorite language (C++, Java, Python, ...) and by choosing a backend, you can decide what to build, native executable, Java byte code, Flash swf, ... As far as I know, there are two approaches to make a Python front end (different concept and different level of maturity), RPython in PyPy project and py2llvm. The objective of PyPy project is to make a Python compiler that can be used to write any programming languages in Python. py2llvm focuses on native build optimization (It uses single precision floating point for Python float to make use of SIMD optimization). Because LLVM IR is statically typed, both RPython and py2llvm are statically typed. Both are designed to be as similar to CPython as possible by introducing type inference, etc. but it's still different from CPython (RPython stands for Restricted Python) by its nature, so in many cases you cannot use Python standard libraries(*) nor third party tools without modifying it.

(*)They have ported most CPython standard libraries to RPython

I wonder if I can make a complete LLVM Python frontend. If I decomposite the bytecode execution part of the CPython interpreter (and initialization, thread context switching, exception, garbage collector, etc.etc.) and can implement it in LLVM IR, I think I may be able to make it. It can be dependent on CPython binary (Python2x/3.so/dll). It can be as slow as CPython. I think I would be lucky if it's a little bit faster but it's not the point. If I can make it, I may be able to merge it seamlessly with the existing Python frontend I have told above. You may think why not using ctypes etc. but the objective is making a full set Python compiler and it needs to be as user friendly as possible. I want to let the user make a RPython or py2llvm function that calls a function which uses a standard module, and it could call RPython or py2llvm function again which may raise exception, all without the user notice the difference (or in a way the user can use naturally and easily). By implementing some (or quite a lot) on the boundary of the two implementation such as type mapping, Depending on the implementation details of RPython and/or py2llvm it may not be impossible, at least technically.

It's just an obscure cloud of thought, not at all concrete, but I'm now having fun with the cloud of idea. RPython is a big one so first I'll take a close look at py2llvm.

Saturday, March 7, 2009

FUSE test implementation

















I made a test script with FusePython, referencing a couple of existing scripts (this one and this one). You can make a file e.g. www.google.co.jp and get the contents of the page from it. Internally it uses urllib2 module. Once it downloads the HTML it caches it in the memory.

To mount it,


python hohefs.py mountpoint

To unmount it,

fusermount -u mountpoint


It is not at all a good example. I just made it to see what it would be like to make a file system with FUSE. I didn't implement permission, I omitted lots of error checkings, and unlink equals to deleting a file, etc.etc.etc....

import fuse
from fuse import Fuse
from time import time
import sys
import urllib2

import stat # for file properties
import os # for filesystem modes (O_RDONLY, etc)
import errno # for error number codes (ENOENT, etc)
# - note: these must be returned as negatives

fuse.fuse_python_api = (0, 2)


class Mystdout():

def __init__(self, filename):
self.f = open(filename, 'w')

def write(self, text):
self.f.write(text)
self.f.flush()


class HoheStat(fuse.Stat):

def __init__(self):
self.st_mode = 0
self.st_ino = 0
self.st_dev = 0
self.st_nlink = 0
self.st_uid = 0
self.st_gid = 0
self.st_size = 0
self.st_atime = 0
self.st_mtime = 0
self.st_ctime = 0

def setStat(self, path):
st =os.stat(path)
self.st_mode = st[0]
self.st_ino = st[1]
self.st_dev = st[2]
self.st_nlink = st[3]
self.st_uid = st[4]
self.st_gid = st[5]
self.st_size = st[6]
self.st_atime = st[7]
self.st_mtime = st[8]
self.st_ctime = st[9]


class NullFS(Fuse):

def __init__(self, logfilename, mountpoint, *args, **kw):
Fuse.__init__(self, *args, **kw)
sys.stdout = Mystdout(logfilename)
self.__filestats = {}
s = self.__filestats['/'] = HoheStat()
s.setStat(mountpoint)
self.__docs ={}
print 'Init complete.'

def getattr(self, path):
print '*** getattr', path
return self.__filestats.get(path, -errno.ENOENT)

def readdir(self, path, offset):
print '*** readdir', path, offset
for r in self.__getFileNames(path) + ['.', '..']:
yield fuse.Direntry(r)

def getdir(self, path):
print '*** getdir', path
return map(lambda x: (x, 0), self.__getFileNames(path))

def mknod(self, path, mode, dev):
print '*** mknod', path, oct(mode), dev
st = HoheStat()
st.st_mode = stat.S_IFREG | mode
st.st_dev = dev
st.st_nlink = 1
st.st_size = 0
st.st_uid = os.getuid()
st.st_gid = os.getgid()
st.st_utime = time()
self.__filestats[path] = st

def utime (self, path, times):
print '*** utime', path, times
st = self.__filestats.get(path)
if st:
st.st_atime = times[0]
st.st_utime = times[1]

def read(self, path, length, offset):
print '*** read', path, length, offset
st = self.__filestats[path]
st.st_atime = time()
return self.__docs[path][offset:offset +length]

def open(self, path, flags):
print '*** open', path, flags
st = self.__filestats.get(path)
if not st:
return -errno.ENOENT

accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
if not (flags & accmode) in [os.O_RDONLY, os.O_WRONLY, os.O_RDWR]:
return -errno.EACCES

docs = self.__docs
if path in docs:
doc = docs[path]
else:
f = urllib2.urlopen("http:/" + path)
doc = f.read()
st.st_size = len(doc)
docs[path] = doc
#Oops I need to close f

def mkdir(self, path, mode):
print '*** mkdir', path, oct(mode)

st =self.__filestats.get(path)
if st:
return -errno.EEXIST

parentpath = os.path.dirname(path)
parentst = self.__filestats.get(parentpath)
if not parentst:
return -errno.ENOENT
if not parentst.st_mode & stat.S_IFDIR:
return -errno.ENOTDIR

st = HoheStat()
st.st_mode = stat.S_IFDIR | mode
st.st_dev = 0
st.st_nlink = 1
st.st_size = 0
st.st_uid = os.getuid()
st.st_gid = os.getgid()
st.st_utime = time()
self.__filestats[path] = st

def unlink(self, path):
print '*** unlink', path
if path in self.__filestats:
del self.__filestats[path]
docs =self.__docs
if path in docs:
del docs[path]
else:
return -errno.ENOENT

def rmdir(self, path):
print '*** rmdir', path
if self.__getFileNames(path):
return -errno.EEXIST
if path in self.__filestats:
del self.__filestats[path]
else:
return -errno.ENOENT

def rename(self, oldPath, newPath):
print '*** rename', oldPath, newPath
return -errno.ENOENT

def mythread(self):
print '*** mythread'
return -errno.ENOSYS

def chmod(self, path, mode):
print '*** chmod', path, oct(mode)
return -errno.ENOSYS

def chown(self, path, uid, gid):
print '*** chown', path, uid, gid
return -errno.ENOSYS

def fsync(self, path, isFsyncFile):
print '*** fsync', path, isFsyncFile
return -errno.ENOSYS

def link(self, targetPath, linkPath):
print '*** link', targetPath, linkPath
return -errno.ENOSYS

def readlink(self, path):
print '*** readlink', path
return -errno.ENOSYS

def release(self, path, flags):
print '*** release', path, flags
return 0
return -errno.ENOSYS

def statfs(self):
print '*** statfs'
return -errno.ENOSYS

def symlink(self, targetPath, linkPath):
print '*** symlink', targetPath, linkPath
return -errno.ENOSYS

def truncate(self, path, size):
print '*** truncate', path, size
return -errno.ENOSYS

def write(self, path, buf, offset):
print '*** write', path, buf, offset
return -errno.ENOSYS

def __getFileNames(self, currentpath):
filt = lambda(x): os.path.dirname(x) == currentpath
filesincurrent = filter(filt, self.__filestats)
if currentpath in filesincurrent:
filesincurrent.remove(currentpath)
return map(os.path.basename, filesincurrent)

if __name__ == '__main__':

usage="""
Userspace hello example

""" + Fuse.fusage

fs = NullFS(
"hohefs.log",
sys.argv[1],
version="%prog " + fuse.__version__,
usage=usage,
dash_s_do='setsingle')

fs.parse(values=fs, errex=1)
fs.main()

Thursday, March 5, 2009

Interested in FUSE

You can represent anything as a file system in FUSE(Filesystem in Userspace). For example you can make your own filesystem with which you can mount a Maya DAG tree to ~/mayadag. (mayadag is an empty directory) And you can enter the directory, rename the dag object or delete it in the unix shell, e.g. 'rm ~/mayadag/persp2' (I don't think it's useful though, it's just an example). I'll update this blog entry when I've made a test program. If FUSE is installed (probably it's installed already), you don't even need to be root to mount it, and you can write it in Python with FusePython :) Dokan is an equivalent for Windows.