Fast building SMILES structure viewer with Dingo and WPF

Indigo is recently introduced as open-source chemoinformatics toolkit <1>, <2>.

Dingo is a molecule and reaction rendering library included in Indigo and with .NET C# wrapper to make it possible for me to build a WPF app with it. Dingo and WPF make things so simple.

Amazing feeling to stand on the giant’s shoulder. Not too much code pasted here

Compound class to transform SMILES to Bitmap objects with Dingo

    public class Compound
    {
        public String smi{ get; set;}
        public Compound(String smiles)
        {
            smi = smiles;
        }
        public BitmapSource bmp {
            get{
                return Smi2Bitmap(smi, 160, 160);
            }
        }
        public static BitmapSource loadBitmap(System.Drawing.Bitmap source)
        {
            return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(source.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        }
        public static BitmapSource Smi2Bitmap(String smi, int Width, int Height)
        {
            Dingo dg = new Dingo();
            dg.loadMolecule(smi);
            dg.setBackgroundColor(System.Drawing.Color.White);
            System.Drawing.Bitmap bmp = dg.renderToBitmap(Width, Height);
            return loadBitmap(bmp);
        }
    }

SMILES file reader

    public class SMIReader: System.Collections.IEnumerable
    {
        private StreamReader sr;
        public SMIReader(String path)
        {
            sr = new StreamReader(path);
        }
        public IEnumerator GetEnumerator()
        {
            String line;
            while ((line = sr.ReadLine()) != null)
            {
                yield return new Compound(line.Split('\t')[0].Split(' ')[0]);
            }
        }
    }

XAML code of the listbox

Notes: To show as many structure pictures blocks on screen the WrapPanel is used as ItemsPanel. This depresses performance for large file that all SMILES are read in but lazy loaded in the default StackPanel mode.

            <ListBox Name="list1" Height="539" Width="790"
                     ItemTemplate="{StaticResource MolListboxTemplate}"
                     ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                     IsSynchronizedWithCurrentItem ="True">
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel/>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
            </ListBox>

Item template of the listbox to support structure images displaying

    <Window.Resources>
        <DataTemplate x:Key="MolListboxTemplate">
            <WrapPanel Margin="3">
                <StackPanel>
                    <Image Source="{Binding bmp}" Height="160" Width="160"></Image>
                    <TextBox Text="{Binding smi}" Width="160"></TextBox>
                </StackPanel>
            </WrapPanel>
        </DataTemplate>
    </Window.Resources>

Button event to trigger databinding

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            ofd.Filter = "SMILES file(*.smi)|*.smi";
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                String path = ofd.FileName;
                textBlock1.Text = path;
                list1.ItemsSource = new nchem.SMIReader(path);
            }
        }

Done.

SQL Server CLR的进程和线程

结论

  • SQL Server CLR是一个多线程运行的环境。
  • 静态变量等线程安全问题,在CLR环境中存在。

摘录《Professional SQL Server™ 2005 CLR Programming》

SQL Server 2005 hosts the CLR in a “sandbox”-like environment in-process to itself, as you can see Figure 1-2. When a user requests a SQL CLR object for the first time, SQL Server will load the .NET execution engine mscoree.dll (which is the CLR) into memory. 

实验

CLR代码

public partial class ProcessThread
{
    public static int static_i=0;

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlString PID()
    {
        return  Process.GetCurrentProcess().Id.ToString();
    }

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlString TID()
    {
        return AppDomain.GetCurrentThreadId().ToString()+ ":"+
            System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
    }

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlString StaticI()
    {
        return (static_i++).ToString();
    }

};

安装CLR的SQL代码

CREATE ASSEMBLY sqlclr_test
FROM 'C:\SQLCLR\bin\Release\sqlclr.dll'
WITH permission_set = UNSAFE;
GO

create function fn_processid () returns nvarchar(max)
as external name sqlclr_test.ProcessThread.PID
GO
create function fn_threadid () returns nvarchar(max)
as external name sqlclr_test.ProcessThread.TID
GO
create function fn_statici () returns nvarchar(max)
as external name sqlclr_test.ProcessThread.StaticI
GO

测试用查询命令

select
    dbo.fn_processid() as [ProcessID],
    dbo.fn_threadid()  as [ThreadID],
    dbo.fn_statici()   as [StaticI]

返回结果

ProcessID ThreadID StaticI
1608 5820:4 11

系统进程截图 (Process Explorer) 

线程模型

现象 

  1. 每次执行查询命令,得到的ThreadID会发生变化,在SQL Server的进程包含的线程池中轮转。
  2. 每次执行查询命令,不论是否同一个线程,StaticI的值会增加。
  3. SQL Server的用户进程(登录),与所执行的线程编号几乎没有关系。

 

化学信息软件开发工具时间线

http://www.dalkescientific.com/writings/diary/archive/2008/09/20/euroqsar.html 

Gridview排序和分页的基本机制

排序

  • 客户端PostBack。
  • 在Sorting事件中,取得排序的列及排序方向。
  • 调用DataSource的排序方法。
  • 重新DataBind

分页

  • Gridview读取全部的数据源数据。
  • 在PageIndexChanging事件中,取得要前往的页编号(e.NewPageIndex)
  • 数据绑定前,设置PageIndex属性,实现分页。

也就是说,分页完全是在ASP.NET中进行的,对于大量数据集就会有性能问题。
解:

下载Google App Engine站点的代码

GAE到目前为止并没有提供从站点上下载或备份代码的功能,本地的开发代码一旦丢失或损坏,就会有无法恢复的麻烦。所以本地代码用SVN之类的管理工具管理起来是很必要的。
Manatlan编写了一个工具,可以将整个GAE站点的代码打成zip包下载。是一个很简单的过程

      在根目录下根据manatlan的代码建立zipme.py。
      在app.yaml中加入handles: - url: /zipme script: zipme.py。
      访问youapp.appspot.com/zipme即可。

这个程序会通过google的身份认证来判断访问者是不是管理员。而且对于各个版本的代码,也可以分别下载了。
不过不能直接访问代码的确是GAE的明显缺陷。

  • 代码可能损坏或丢失而无法恢复
  • 使得合作开发模式也并不灵光,开发者之间需要其他渠道交换和维护代码。
  • 代码的版本和发布的版本不好对应。

所以相信这个问题很快会解决掉,至少能和Google Code结合在一起,代码管理和发布管理的功能集成起来。

Access中的事件和委托

实际上对.Net中的“委托(delegate)”的概念并不很懂。如果仅理解成自定义事件的话,在Access中也可以部分实现。

窗体2中的自定义事件FireFromF2被窗体1捕获处理,参数被传递。用法很简单,注意WithEvents关键字的使用。

accessevent1.png
accesseventf1.png

accesseventf21.png

上面的例子要求先f2开启状态下再打开f1才能成功注册事件(原因见最后的总结)。如果是子窗体的事件,就简单一些,应用更常见。

accesseventf31.png

总结

  • WithEvents设置了事件监听的钩子,这个钩子针对的是Object,是实例,而不是Class或类型。
  • 所以可以监听Application这样的全局物件,也可以监听某个具体的Form。但是不能对所有的Form(Access.Form类型)起作用。
  • VBA中不支持自动的up-casting;WithEvents也不支持对象数组。所以后期绑定的方法也基本行不通。

自动单元测试框架, PyUnit, tsqlunit, xUnit framework

Notes on Python自动单元测试框架

from widget import Widget
import unittest

class WidgetTestCase(unittest.TestCase):                   # 测试例(test case)
    def setUp(self):                                       # 测试前的初始化工作。
                                                           # 声明在unittest.TestCase中,自动调用。
        self.widget = Widget()
    def tearDown(self):                                    # 测试后的清理工作。
        self.widget = None

    def testSize(self):                                    # 自定义的测试方法。
        self.assertEqual(self.widget.getSize(), (40, 40))  # assertEqual是TestCase提供的工具。

    def testColor(self):                                   # 一个测试例中可以定义多个测试方法函数。
                                                           # 默认的测试方法函数名为runTest
        pass

def suite():                                               # 测试集(test suite)
    suite = unittest.TestSuite()                           # 函数返回TestSuite的测试集实例。
    suite.addTest(WidgetTestCase("testSize"))              # 测试集中加入测试方法。
                                                           # 多个测试方法组成一个测试集。
                                                           # 可以用unittest.makeSuite批量添加测试方法。
    return suite

if __name__ == "__main__":
    unittest.main(defaultTest = 'suite')                   # 执行测试
                                                           # 也可自定义执行测试的Runner
                                                           #     runner = unittest.TextTestRunner()
                                                           #     runner.run(suite)

自动生成测试例,批量测试

借鉴JUnit框架上的一个方案,用程序生成一个足够大的测试集。Write a suite( ) method that iterates through all of your
input data, creating a unique instance of your test case for each
unique input. The data is passed to the test cases through the
constructor, which stores the data in instance fields so it is
available to the test methods.

A similar solution,
pyUnit and dynamic test functions .

如果像我这样需要一个测试集,可以自动的无穷尽的pop出各种各样的,甚至是随机的测试例,或者是测试例的参数,而不是预先在测试集中(内存中)建立好所有的测试例,可以利用TestSuite的Iterator的特性实现。

TestRunner中的run方法,对TestSuite来说,仅仅是调用了其test方法。

class TextTestRunner:
    """ ... """
    def run(self, test):
        "Run the given test case or test suite."
        result = self._makeResult()
        startTime = time.time()
        test(result)
        stopTime = time.time()
        timeTaken = stopTime - startTime
        result.printErrors()
    """ ... """

所以可以重载TestSuite类,生成支持Iterator的测试集,自动生成测试例。代码如下

import unittest
class TheTestCase(unittest.TestCase):
    def __init__(self, n):
        unittest.TestCase.__init__(self)
        self.n = n
    def runTest(self):
        assert( self.n>3 )

class MyTestSuite(unittest.TestSuite):
    def __init__(self):
        unittest.TestSuite.__init__(self)
        self.i = 0
        self.N = 5
    def __iter__(self):
        return self

    def next(self):
        self.i += 1
        if self.i > self.N: raise StopIteration
        return TheTestCase(self.i)

    def run(self, result):
        for test in self:
            if result.shouldStop:
                break
            test(result)
        return result

def suite():
    return MyTestSuite()

if __name__=='__main__':
    unittest.main(defaultTest='suite')

xUnit Framework

结合这个tsqlunit框架 (不是很实用),可以粗略总结xUnit Framework构建的单元测试框架里的一些要点。

  • 集中格式化输出显示(PRINT)测试结果及报告。
  • 通过测试集、测试例组织管理测试代码,重用测试代码。
  • 自动加载测试例。
  • 统一测试例的接口(包括异常抛出),简化测试例编写。

关系数据库中存储操作树形结构

关系数据库中树形结构的存储,决定因素是对于设计的系统,在此树形结构上的操作是什么。尤其对于节点数较大的树形关系,操作性能肯定是第一考虑因素。当然也和树的具体特典有关系,比如是“扁平型”的还是“纵深型”的。最近的工作涉及到一棵近百万个节点的树,一点总结稍作笔记。

树形结构常见操作

下面的操作大部分从MySQL文档中摘录。

  1. 遍历
  2. Finding all Child nodes / 取得所有的下级节点
  3. Find the Immediate Subordinates of a Node
  4. Finding all the Leaf Nodes / 取得所有下级叶子节点
  5. Depth of a Sub-Tree / 取得子树的深度
  6. Aggregate Functions in a Nested Set
  7. Retrieving a Single Path (all ancestors nodes) / 取得当前节点到根节点的路径
  8. Finding the Depth of the Nodes. 相当于7,找到所有父节点。
  9. Adding New Nodes
  10. Deleting Nodes

可简单分类为

  • 向下搜索(1,2,3,4,5,6)
  • 向上搜索(7,8)
  • 修改(9,10)

其中3和2,4等在不同数据结构基础上的实现中,非常不同。以下分别对几种常见的表示方法,作个简单总结。

线性表示

         A
       / | \
      B  C  D
        /|   \
       E  F   G

A(B, C(E, F), D(G,),)

相当于宽度优先的遍历。
“线性表示”的意思是说,在一行文本中,表示整个复杂结构。也许可以用在数据压缩上吧,基本上与这里讲述的关系数据库关系不大。

node-id & parent-node-id

最常见的表示方法,represents a hierarchy is by using parent child relationship
在关系数据库中,一行数据表示树中的一个节点(后面叙述的结构均是如此)。这一行中存储当前节点的ID(NodeId)和它的父节点的ID(ParentNodeId),因为每个节点的父节点是唯一的。在这两个ID上做索引。

此种结构最利于临近层次的节点搜索(常见操作之3)。对于节点的增删修改(常见操作之9,10),也很容易,只要修改单个节点的属性即可。

操作3(Find the Immediate Subordinates of a Node)在展示树型数据时很有用。比如动态展开节点。实际上很多树形控件,其数据结构也正是这样的。比如YUI的TreeView ;MSComctlLib.TreeCtrl;Graphviz;ASP.NET中的Tree view等等。

对于操作2,4,7,8,在SQL Server中可以使用Inline Table-valued FunctionsMultistatement Table-valued Functions 递归调用实现。当然性能上会有损失。

Deep-first Tree

 

Depth-First Traversal


  A B C D E F G
node-id 1 2 3 4 5 6 7
most-right-child-id 7 2 5 4 5 7 7

Deep-first结构中,每条Node记录需要包含node-id和most-right-child-id。

常见操作2,4,7,8可以高效实现。但是对于操作3(immediately children),实现起来比较难,不如parent/child的容易、高效。可以结合使用。

–Get the path from the root to the given node:
SELECT t1.*
FROM employee t1, employee t2
WHERE t1.nodeindex <= i
AND t1.rightchildindex >= t2.rightchildindex
AND t2.nodeindex = i;

增删修改操作性能消耗比较大。

-- Insert a node as a child of i: UPDATE employee
SET employee.nodeindex = employee.nodeindex + 1
WHERE employee.nodeindex > parentnode;

UPDATE employee
SET employee.rightchildindex = employee.rightchildindex + 1
WHERE employee.rightchildindex >= parentnode;

INSERT INTO employee
(nodeindex, rightchildindex, NAME, comments)
VALUES (parentnode + 1, parentnode + 1, nodename, nodecomments);

-- Delete the node with NodeIndex i: DELETE employee
WHERE employee.nodeindex = i;

UPDATE employee
SET employee.nodeindex = employee.nodeindex - 1
WHERE employee.nodeindex > i;

UPDATE employee
SET employee.rightchildindex = employee.rightchildindex - 1
WHERE employee.rightchildindex > i;

Nested set, 节点左右边缘

左边缘作为node-id,同时记录right-extent。与Deep-first Tree等价。
 

-- All Leaf nodes (an item with any children) can be
-- identified by Left = Right - 1
SELECT * FROM Employee WHERE [LeftExtent] = [RightExtent] - 1

Build a deep-first tree from parent child relationship

Python code

#{
def process_node( catid ):
    n = retrieve_node( catid )
    dfid = global_increased_id()                # with a increased id
    most_right_child_dfid = dfid
    for child in retrieve_children( n ):
        most_right_child_dfid = process_node( child )
    upd_to_db( catid, dfid, most_right_child_dfid )
    print dfid
    return most_right_child_dfid

The WITH keyword in SQL Server 2005/2008

在SQL Server 2005及以上的版本的中,加入了WITH这个关键字。WITH关键字定义了匿名函数,通过表达式形成表定义common table expression (CTE),而且可以递归。而 node-id & parent-node-id 模型中的“取得当前节点到根节点的路径”操作,就需要对表值函数进行递归调用。用WITH关键字进行递归操作的例子如下

 

with HierarchyCTE (NID, PID, Lvl) as
 (select NodeID, ParentID, 0
 from dbo.Hierarchy
 where NodeID = @NodeID_in
 union all
 select NodeID, ParentID, Lvl + 1
 from dbo.Hierarchy
 inner join HierarchyCTE
 on PID = NodeID)
select *
from HierarchyCTE

References

 

 

Access (Jet SQL)中的function

MS Access是一种桌面型数据库引擎,基于Microsoft Jet database engine。一般用在很轻量级的应用上,以“方便”著称。其实某些方面也很强大,因为Jet SQL是有VBA集成在里面的。在写一些SQL作为query的时候,曾经因为发现Jet SQL内置的函数很少,而写了很多Dirty code。起码来说,没看到任何可用于非线性的计算函数(比如计算个人所得税时需要用到)。和T-SQL比较起来差的很远。直到最近发现可以使用VBA在SQL中,才发现这些问题不但可以解决,而且更容易了。

The Microsoft Jet database engine uses the Microsoft® Visual Basic® for Applications (or VBA) expression service to perform simple arithmetic and function evaluation. All of the operators used in Microsoft Jet SQL expressions (except Between, In, and Like) are defined by the VBA expression service. In addition, the VBA expression service offers over 100 VBA functions that you can use in SQL expressions.

SQL中的Function可以这样分为两种:Calculating fields和 SQL aggregate。自定义的聚集函数在SQL Server 2000里面也不支持,要到SQL Server 2005中才有。Calculating fields却可以利用VBA做出很多的扩展。

工具太容易上手,反而会使用户认识不到它全面的功能。微软的Office就是一个例子。

北京个人所得税计算的JET SQL Query:

SELECT
SalaryRMB,
IIF(SalaryRMB>1600,
    (SalaryRMB-1600)*
       IIF(SalaryRMB>=21600,0.25,
         IIF(SalaryRMB>=6600,0.20,
           IIF(SalaryRMB>=3600,0.15,
             IIF(SalaryRMB>=2100,0.10,0.05)  ) ))
      -IIF(SalaryRMB>=21600,1375,
         IIF(SalaryRMB>=6600,375,
           IIF(SalaryRMB>=3600,125,
             IIF(SalaryRMB>=2100,25, 0) ))),
0) AS SalaryTaxRMB
FROM tb_Salary

抽象归纳数据结构,重用算法

有一句古语

程序 = 数据结构 + 算法

说得还是有深意的。在接触C++、面向对象、STL、Design pattern、消息机制等等技术过程中,逐渐发现,它们都包含围绕着那句古语而展开的思路,目的是重用

一般来说,都是对不同的数据结构(类型),应用同一个算法。算法被重用。

template method这个pattern是个典型的例子。

template method

基类(Abstract class)中的TemplateMethod()是个算法。这个算法对于所有派生类(Concrete class)都可以重用。

STL中很明确地实现了这个概念,对不用的container,算法都可以实现。

不论是template、inherintance还是任何其他的机制实现的重用,约束都是把代码重用到一类有相同接口(interface)的结构上

也就是说,把需要研究、表达、操作的对象,抽象出他们的共同特征(也就是接口),然后归纳为一个类别之后,就可以把同样的方法和手段,无差别应用到所有这个类别中所有的实例上了。这是就是重用的思想。是个个门类的科学技术的最重要的思路。

最近接触一些应用了消息机制的工作,归纳起来看,也可以把消息机制看作一种类似的抽象与重用的例子。消息循环是一个算法,它负责取从消息队列中出消息,然后把它实现执行。之所以能够执行是因为每个接受消息的object都可以把消息映射到对应的消息处理函数上,这些函数的接口固定。于是根据不同的消息,不同的程序就被执行了。整个消息队列机制实现了在一个任务(task/thread)中,用有限的代码(消息循环),无限地执行动态演变的程序。强大的算法,不是吗?

消息处理的接口,是个一致的接口。消息处理者之间也可以互相调用(SendMessage),避免了调用函数时要遵守的复杂的函数prototype,也不必因为函数prototype的更改影响其他程序。实现重用了。

Next Page »

Random posts

  • 哈尔滨的空气比北京好主要因为森林
  • Web interface provided on SQLMOL
  • 抽象归纳数据结构,重用算法
  • Moved from Blogger to Wordpress
  • 结婚照