RESEARCH PROGRESS REPORT

Computer Aided Surgery Incorporated

300 East 33rd Street, Suite 4N

New York, New York 10016 USA

Telephone: 1 (212) 686 8748

Fax: 1 (212) 448 0261

E-mail: Karron@casi.net

Report Title: Digital Morse Theory Research Technical Report #01

Date of Publication: 01/28/99 2:06 AM.

Address: 300 E. 33rd St., Suite 4N, New York, NY 10016 USA.

Telephone/Fax: (212) 686-8748, (212) 448-0261.

Internet: http://www.casi.net/

Research Technical Progress Report #01 for

DARPA CONTRACT DAAH01–98–C R195

Prepared by D. B. Karron, Ph.D.

Principle Investigator

(I-81) DFAR :252.227-7036 The Contractor, Computer Aided Surgery, Inc., hereby declares that, to the best of its knowledge and belief, the technical data delivered herewith under contract No. DAAH01-98-CR195 is complete, accurate, and complies with all requirements of the contract. Thursday, January 28, 1999

(I-82) DFAR: 252.235-7010 (a)This material is based upon work supported by the Defense Advanced Research Projects Administration (DARPA), Defense Sciences Office (DSO) under contract No. DAAH01-98-CR195. (b) Opinions, findings and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the view of the United States Government, the Department of Defense (DoD), DARPA/DSO.

(I-83) DFAR: 252.247-7042 (Notification of Transportation by Sea) Supplies utilized in this effort were NOT transported by Sea / Ocean going freighter.

(D-1) DFAR: 52.208-4700 (NO Pentachlorophenol (PCP)) PCP is NOT was used in this packaging.

(H-2) DFAR: 52.239-4702 (Year 2000 Compliance) This software is Year 2000 (Y2K) compliant.

  1. Abstract
  2. This is the first progress report regarding our new effort to write demonstration programs illustrating principles of Digital Morse Theory. We have written prototype software to build criticality graphs for DNA binding affinity trees at different at all affinity values. We have also written C++ software classes to permit building criticality graphs in 2d gray pixel levels. Though much more work remains, adequate progress has been made in illustrating the disparate application areas of Digital Morse Theory in data exploration.

  3. Discussion
    1. Visible Human Data radiologic Image contouring and region identification using Digital Morse Theory.
    2. Our work to date has focused on building a strong software foundation for the programming effort that we expect will follow using multiple graduate students and programmers. Our goal in this phase of the effort is to start the software effort off on a robust multi threaded shared memory programming model. This base can support many analysis processes that will join a pool of pixels and decomposition tree data that is always resident in shared memory. Our focus is NOT on the pixels, but rather on the Morse decomposition of the pixels. All subsequent operations will be on the decomposed data, instead of the raw pixels.

      Indeed, once we have proven a robust Morse decomposition kernel, we no longer will keep pixels in memory at all. Looking at images derived form the Morse decomposed data will be indistinguishable from raw pixel images except in the way that the images scale at different resolutions.

      Our software effort is being supported also in part with software and technical support from Silicon Graphics, Inc. and from the newly founded Scriptics Corporation. We are building our software effort using the TCL scripting language developed by John Ousterhout, Ph.D. for GUI development. We are looking forward to using extensions of the TK GUI library for both data display and control. We also anticipate modifying the GUI’s to include MUI’s (Musical User Interfaces), building on our previous effort in Tactical Audio. There is much in image understanding that can be learned from using musical understanding that has yet to be explored. A Morse Decomposition of an image is directly analogous to a Schenkerian Analysis of a musical composition.

      The skeletal framework of our system consists of a group of Tk/Tcl GUI’s that directly manipulate shared memory values. The shared memory segment is allocated using the SGI Arena memory allocation package. This shared memory is memory mapped to a file that is the external handle that all client processes attach to. As this code is being designed to run on a supercomputer in parallel, each process checks for locked code segments and is synchronized by barriers. We have found that the GUI and interaction code makes very heavy use of a single CPU. We are writing this code with the expectation that we will move to a multi-user CPU system as the effort matures. We are also working with Scriptics to improve the Tk display code so that it is not such a CPU hog. We have selected Tk/Tcl because we intend to us it as a research tool, not just a GUI library. We have already made a number of modifications to the Tk/Tcl public source code to manage shared memory access that we hope will become incorporated into the public distributions.

      Major modules and classes under development at this time include:

      Shared Memory root:

      This instances a new shared memory segment and file.

      It also remains running as a ‘heartbeat’ process to keep the shared memory segment active and alive in the CPU in the event that there are no other processes keeping the segment alive (a ‘keep alive’ process)

      Pixel Loader:

      This loads into memory raw pixels. By reading the magic numbers and the file image header, we hope to automatically interpret what kind of image we have loaded in order to display it. In the all too frequent case of loading an unknown image format, we can cohere an image out of the display or the graph by adjusting the pixel properties mask, and the rows and columns. My goal here is to make an ‘Image Analysis break out box’; a tool for peering into unknown image formats that recovers essential image format information such as rows, columns, pixel size, and such. As we develop experience with a variety of different image formats, we can build ‘magic’ tables to distinguish each image format automatically.

      Display Window:

      We will use one window for both 2d-slice display and 3d-isosurface display. We will be able to pull back in three dimensions and continuously transition from a pixel display to a isosurface display in 2 and three dimensions. Our goal there is to show that there is a continuous relationship between the 2d Digital Morse Theory decomposition and the 3d Digital Morse Theory decomposition.

       

      Graph Window:

      This window displays the DMT criticality graph of the ROI shown in the Display Window. This window will have the practical application of being able to select objects in the 2 or three dimensional scene without problems in bigger objects obscuring enclosed objects and object crowding. Indeed, these are major problems in any 3d display picking system. Frequently, the details you want to zoom in on are only 1 or 2 pixels big on the display. A side benefit is that we can do picking and selecting on 4, and more dimensional data without having multiple orthogonal display windows.

       

       

      Overall design is to focus on decomposition of different and varied datasets into one, registered, DMT decomposition and a graph (tree) representation for further exploration by haptic, graphics, and sound exploration.

       

    3. The Hierarchicalization of DNA-Binding Drug Affinity Data using an Application of Digital Morse Theory.

We developed an implementation of Digital Morse Theory as a means to visualize DNA-binding drug affinities over the set of 256 4-base pair oligonucleotides (e.g. AAAA-TTTT). This exercise was intended to demonstrate the wide-applicability of Digital Morse Theory-related concepts to the hierarchical ordering of information.

Our technique is derived from the insight that it is possible to construct a tree representation given an arbitrary set of 4-base pair oligonucleotides (e.g. AAAA, CCAA, CGTT, TAAA), for example:

Accordingly, it is possible to construct an array of affinity trees by varying a threshold through a data-set of affinity rankings for the entire set of 256 4-base pair oligonucleotides. The resulting array of trees, or meta-tree, would be constructed by appending only those trees for a particular threshold level where the total accumulated number of terminals changes.

We implemented this technique as a set of C++ classes. The code implementing these classes and descriptions of their functions follows below. In our class-naming system, we prefix the name of each class by the letters "AT", standing for "Affinity Tree".

 

      1. An Example Program Using the ATMetatree Class

The following code illustrates a simple utilization of the ATMetatree class. The function of this utilization may be summarized as follows:

//////////////////////////////////////////////////////////////////////

//

// TestATMetatree.cpp

//

//////////////////////////////////////////////////////////////////////

#include <iostream.h>

#include "ATMetatree.cpp"

//////////////////////////////////////////////////////////////////////

// main

//////////////////////////////////////////////////////////////////////

void main(void){

unsigned int x=0;

experiment settings; //the experiment settings structure

settings.datafile="Data\\netro.txt";

settings.increment=1; //the threshold increment

settings.integer=true;

atmetatree metatree(settings); //create the metatree

cout<<"total sub-trees: "<<metatree.m_trees<<"\n";

cout<<"view sub-tree: "; cin>>x; //prompt

while(x<metatree.m_trees){ //step through the metatree

for(int i=0;i<4;i++){ //step through the hypercube

for(int j=0;j<4;j++){

for(int k=0;k<4;k++){

for(int l=0;l<4;l++){

if(metatree.m_metatree[x]->m_hypercube[i][j][k][l]>-1)

cout<<i<<j<<k<<l<<"\n";

}

}

}

}

cout<<"view sub-tree: "; cin>>x; //prompt

}

}

 

      1. Implementation of the ATMetatree Class

The ATMetatree class provides an interface to the lower-level classes, as well as an array to contain the set of subsidiary affinity trees. The function of this class may be summarized as follows:

//////////////////////////////////////////////////////////////////////

//

// atmetatree.cpp: implementation of the atmetatree class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(_ATMETATREE_CPP_INCLUDED_)

#define _ATMETATREE_CPP_INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif

//////////////////////////////////////////////////////////////////////

//

//////////////////////////////////////////////////////////////////////

#include "ATData.cpp"

#include "ATTree.cpp"

//////////////////////////////////////////////////////////////////////

//

//////////////////////////////////////////////////////////////////////

#define __noligos__ 256

//////////////////////////////////////////////////////////////////////

// experiment settings structure

//////////////////////////////////////////////////////////////////////

typedef struct _proc{

char *datafile;

double threshold;

double increment;

bool precision;

bool chirality;

bool resulttype; //false tree, true metatree

char *outputname;

bool format; //false text, true tex

bool multifile;

bool printtermvals;

bool timestamp;

}proc;

//////////////////////////////////////////////////////////////////////

// atmetatree

//////////////////////////////////////////////////////////////////////

class atmetatree

{

private:

atdata *m_data; //the data

public:

bool m_err;

attree *m_metatree[__noligos__]; //the metatree

unsigned int m_trees; //the number of trees

double m_datamax; //the max val of the data array

public:

atmetatree(proc);

virtual ~atmetatree();

};

//////////////////////////////////////////////////////////////////////

// atmetatree::atmetatree

//////////////////////////////////////////////////////////////////////

atmetatree::atmetatree(proc settings){

m_trees=0;

m_datamax=0;

atdata m_data(settings.datafile);

int currentterms=0,returnterms=0;

if(!settings.precision) //convert to int

for(int i=0;i<__noligos__;i++)

m_data.m_data[i]=(int)m_data.m_data[i];

for(int i=0;i<__noligos__;i++) //find the data global max

m_datamax=(m_data.m_inbuf[i]>m_datamax)?m_data.m_inbuf[i]:m_datamax;

for(double threshold=0;threshold<=m_datamax;threshold+=settings.increment){

returnterms=0; //lowpass filter

for(int i=0;i<__noligos__;i++){

if(m_data.m_inbuf[i]<threshold){ //all data below threshold

m_data.m_data[i]=m_data.m_inbuf[i];

returnterms++;

} else m_data.m_data[i]=-1; //flag as null

}

if(currentterms<returnterms){

m_metatree[m_trees]=new attree(&m_data);

m_metatree[m_trees]->m_threshold=threshold;

currentterms=returnterms;

m_trees++;

}

}

}

//////////////////////////////////////////////////////////////////////

// attree::~atmetatree

//////////////////////////////////////////////////////////////////////

atmetatree::~atmetatree(){

}

//////////////////////////////////////////////////////////////////////

#undef __noligos__

#endif // !defined(_ATMETATREE_CPP_INCLUDED_)

//////////////////////////////////////////////////////////////////////

 

      1. Implementation of the ATData Class
      2. The ATData class provides the basic functionality to load and parse a data-set. The data file format consists of a table of 256 floating point values that represent the percent rank for the oligonucleotide corresponding to that index.

        //////////////////////////////////////////////////////////////////////

        //

        // ATData.cpp: Data handler for ATParser %R affinity data.

        //

        //////////////////////////////////////////////////////////////////////

        //

        #if !defined(AFX_ATDATA_CPP__CC7B9F23_DE01_11D1_BF09_006097958E47__INCLUDED_)

        #define AFX_ATDATA_CPP__CC7B9F23_DE01_11D1_BF09_006097958E47__INCLUDED_

        #if _MSC_VER >= 1000

        #pragma once

        #endif

        //////////////////////////////////////////////////////////////////////

        //

        //////////////////////////////////////////////////////////////////////

        #include <io.h>

        #include <stdio.h>

        //////////////////////////////////////////////////////////////////////

        //

        //////////////////////////////////////////////////////////////////////

        #define __noligos__ 256

        #define __linebuf__ 80

        //////////////////////////////////////////////////////////////////////

        // atdata

        //////////////////////////////////////////////////////////////////////

        class atdata

        {

        public:

        bool m_err; //file read error flag

        double m_inbuf[__noligos__]; //the raw data buffer

        double m_data[__noligos__]; //the filtered data buffer

        public:

        atdata(char*);

        virtual ~atdata();

        };

        //////////////////////////////////////////////////////////////////////

        // atdata::atdata

        //////////////////////////////////////////////////////////////////////

        atdata::atdata(char *datafile){

        FILE *stream; //pointer to the file stream

        char lbuffer[__linebuf__]; //line buffer

        if(!(_access(datafile,0))&&!(_access(datafile,4))){ //init if file exists

        for(int i=0;i<__linebuf__;i++) lbuffer[i]=NULL; //init line buffer

        for(i=0;i<__noligos__;i++) m_inbuf[i]=m_data[i]=0; //init buffers

        if((stream=fopen(datafile,"r"))!=NULL){ //open the file stream for reading

        m_err=false;

        for(i=0;i<__noligos__,!feof(stream);i++){ //read 256 if not end of file

        if((fgets(lbuffer,__linebuf__,stream))!=NULL) //read a line

        sscanf(lbuffer,"%lf",&m_inbuf[i]); //append to the raw data buffer

        if(ferror(stream)){

        m_err=true; //set error on the file stream

        break;

        }

        for(int j=0;j<__linebuf__;j++) lbuffer[j]=NULL; //reset the line buffer

        }

        } else m_err=true;

        fclose(stream); //close the file stream

        } else m_err=true;

        }

        //////////////////////////////////////////////////////////////////////

        // atdata::~atdata

        //////////////////////////////////////////////////////////////////////

        atdata::~atdata(){

        }

        //////////////////////////////////////////////////////////////////////

        #undef __noligos__

        #undef __linebuf__

        #endif // !defined(AFX_ATDATA_CPP__CC7B9F23_DE01_11D1_BF09_006097958E47__INCLUDED_)

        //////////////////////////////////////////////////////////////////////

         

         

      3. Implementation of the ATTree Class
      4. The ATTtree class forms a tree representation for a given set of oligonucleotides. For convenience, the tree representation is embedded within a hypercube.

        //////////////////////////////////////////////////////////////////////

        //

        // attree.cpp: implementation of the attree class.

        //

        //////////////////////////////////////////////////////////////////////

        #if !defined(AFX_ATTREE_CPP__CC7B9F23_DE01_11D1_BF09_006097958E49__INCLUDED_)

        #define AFX_ATTREE_CPP__CC7B9F23_DE01_11D1_BF09_006097958E49__INCLUDED_

        #if _MSC_VER >= 1000

        #pragma once

        #endif

        //////////////////////////////////////////////////////////////////////

        //

        //////////////////////////////////////////////////////////////////////

        #include "ATCode.cpp"

        #include "ATData.cpp"

        //////////////////////////////////////////////////////////////////////

        //

        //////////////////////////////////////////////////////////////////////

        #define __base__ 4

        #define __noligos__ 256

        //////////////////////////////////////////////////////////////////////

        // attree declaration

        //////////////////////////////////////////////////////////////////////

        class attree

        {

        public:

        double m_threshold; //the threshold at which the tree is in evidence

        double m_hypercube

        [__base__]

        [__base__]

        [__base__]

        [__base__]; //hypercube containing the tree

        int m_terminals; //number of terminals in the hypercube

        public:

        attree(atdata*);

        virtual ~attree();

        };

        //////////////////////////////////////////////////////////////////////

        // attree implementation

        //////////////////////////////////////////////////////////////////////

        attree::attree(atdata *data){

        atcode code; //create a new code object

        m_terminals=0; //there are no terminals as yet

        for(int i=0;i<__base__;i++){ //init the hypercube

        for(int j=0;j<__base__;j++){

        for(int k=0;k<__base__;k++){

        for(int l=0;l<__base__;l++){

        m_hypercube[i][j][k][l]=NULL;

        }

        }

        }

        }

        for(i=0;i<__noligos__;i++){

        if(data->m_data[i]>-1){ //insert oligonucleotide if data not null

        code.code(i);

        m_hypercube

        [code.m_num[0]]

        [code.m_num[1]]

        [code.m_num[2]]

        [code.m_num[3]]=data->m_data[i]; //add terminal

        m_terminals++;

        }

        }

        }

        //////////////////////////////////////////////////////////////////////

        // attree::~attree

        //////////////////////////////////////////////////////////////////////

        attree::~attree(){

        }

        //////////////////////////////////////////////////////////////////////

        #undef __base__

        #undef __noligos__

        #endif // !defined(AFX_ATTREE_CPP__CC7B9F23_DE01_11D1_BF09_006097958E49__INCLUDED_)

        //////////////////////////////////////////////////////////////////////

         

         

      5. Implementation of the ATCode Class

The ATCode class provides basic functionality for generating and manipulating 4-base pair oligonucleotides, or 4-digit quaternary words, given a decimal representation from (e.g. 0-255).

//////////////////////////////////////////////////////////////////////

//

// atcode.cpp: implementation of the atcode class.

// create and manipulate a 4-base pair oligonucleotide

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_ATCODE_CPP__CC7B9F27_DE01_11D1_BF09_006097958E47__INCLUDED_)

#define AFX_ATCODE_CPP__CC7B9F27_DE01_11D1_BF09_006097958E47__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif

//////////////////////////////////////////////////////////////////////

//

//////////////////////////////////////////////////////////////////////

#include <math.h>

//////////////////////////////////////////////////////////////////////

//

//////////////////////////////////////////////////////////////////////

#define __base__ 4

#define __ascii_a__ 65

#define __ascii_c__ 67

#define __ascii_g__ 71

#define __ascii_t__ 84

//////////////////////////////////////////////////////////////////////

// atcode class

//////////////////////////////////////////////////////////////////////

class atcode

{

private:

int m_base;

public: //public duplicate copy of m_oligos

bool m_chirality; //true if dna, false if rna

int m_decimal; //oligonucleotide decimal representation

int m_num[__base__]; //oligonucleotide zero-offset quaternary representation

char m_sym[__base__]; //oligonucleotide ascii word representation

public:

atcode();

atcode(int);

atcode(int,bool);

private:

int wrap(int);

void quaternate(int);

public:

void code(int);

void code(bool);

void code(int,bool);

virtual ~atcode();

};

//////////////////////////////////////////////////////////////////////

// atcode::atcode()

//////////////////////////////////////////////////////////////////////

atcode::atcode(){

m_base=__base__; //set the global oligonucleotide length in base-pairs

m_chirality=true; //default as chirality

}

//////////////////////////////////////////////////////////////////////

// atcode::atcode(int)

//////////////////////////////////////////////////////////////////////

atcode::atcode(int decimal){

m_base=__base__; //set the global oligonucleotide length in base-pairs

m_decimal=wrap(decimal); //prevent overflow/underflow

m_chirality=true; //default as chirality

quaternate(m_decimal); //generate the quaternary representation

}

//////////////////////////////////////////////////////////////////////

// atcode::atcode(int,bool)

//////////////////////////////////////////////////////////////////////

atcode::atcode(int decimal,bool chirality){

m_base=__base__;

m_decimal=wrap(decimal);

m_chirality=chirality;

quaternate(m_decimal);

}

//////////////////////////////////////////////////////////////////////

// atcode::wrap

//////////////////////////////////////////////////////////////////////

int atcode::wrap(int decimal){

if(decimal<0) decimal=abs(decimal);

if(decimal>255) decimal%=256;

return(decimal);

}

//////////////////////////////////////////////////////////////////////

// atcode::quaternate

//////////////////////////////////////////////////////////////////////

void atcode::quaternate(int decimal){

m_decimal=decimal; //save a copy of decimal; decimal is sacrificial

int a=3,c=2,g=1,t=0; //default 5'-3'

if(!m_chirality){a=0;c=1;g=2;t=3;} //3'-5' if false

for(int i=0;i<__base__;m_num[i++]=0); //init num to zero set

//cheapo conversion from decimal to quaternary

if(decimal>=64){ //t's place

m_num[t]=decimal/64;

decimal%=64;

} if(decimal>=16){ //g's place

m_num[g]=decimal/16;

decimal%=16;

} if(decimal>=4){ //c's place

m_num[c]=decimal/4;

decimal%=4;

} if(decimal>=0) //a's place

m_num[a]=decimal;

for(i=0;i<4;i++){ //format as ascii

switch(m_num[i]){

case 0:m_sym[i]=__ascii_a__;break;

case 1:m_sym[i]=__ascii_c__;break;

case 2:m_sym[i]=__ascii_g__;break;

case 3:m_sym[i]=__ascii_t__;break;

}

}

}

//////////////////////////////////////////////////////////////////////

// atcode::code(int)

//////////////////////////////////////////////////////////////////////

void atcode::code(int decimal){

m_decimal=wrap(decimal);

quaternate(m_decimal);

}

//////////////////////////////////////////////////////////////////////

// atcode::code(bool)

//////////////////////////////////////////////////////////////////////

void atcode::code(bool chirality){

m_chirality=chirality;

quaternate(m_decimal);

}

//////////////////////////////////////////////////////////////////////

// atcode::code(int,bool)

//////////////////////////////////////////////////////////////////////

void atcode::code(int decimal,bool chirality){

m_decimal=wrap(decimal);

m_chirality=chirality;

quaternate(m_decimal);

}

//////////////////////////////////////////////////////////////////////

// atcode::~atcode

//////////////////////////////////////////////////////////////////////

atcode::~atcode(){

}

//////////////////////////////////////////////////////////////////////

#undef __base__

#undef __ascii_a__

#undef __ascii_c__

#undef __ascii_g__

#undef __ascii_t__

#endif // !defined(AFX_ATCODE_CPP__CC7B9F27_DE01_11D1_BF09_006097958E47__INCLUDED_)

//////////////////////////////////////////////////////////////////////