~ubuntu-branches/ubuntu/feisty/openbabel/feisty

« back to all changes in this revision

Viewing changes to src/base.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Banck
  • Date: 2006-05-14 19:46:01 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060514194601-h3j1wovvc42cigxl
Tags: 2.0.1-1
* New upstream release. (Closes: #341628)
* debian/patches/04_zipstream_fix.diff: Removed, applied upstream.
* debian/rules (DEB_MAKE_CHECK_TARGET): Readded.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/**********************************************************************
2
2
base.cpp - Base classes to build a graph
3
 
 
 
3
 
4
4
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5
 
Some portions Copyright (c) 2001-2003 by Geoffrey R. Hutchison
6
 
 
 
5
Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
 
6
 
7
7
This file is part of the Open Babel project.
8
8
For more information, see <http://openbabel.sourceforge.net/>
9
 
 
 
9
 
10
10
This program is free software; you can redistribute it and/or modify
11
11
it under the terms of the GNU General Public License as published by
12
12
the Free Software Foundation version 2 of the License.
13
 
 
 
13
 
14
14
This program is distributed in the hope that it will be useful,
15
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
18
***********************************************************************/
19
19
 
20
20
#include "babelconfig.h"
21
 
 
22
21
#include "base.h"
23
22
 
24
23
#if HAVE_IOSTREAM
35
34
 
36
35
using namespace std;
37
36
 
38
 
namespace OpenBabel {
39
 
 
 
37
//! Global namespace for all Open Babel code
 
38
namespace OpenBabel
 
39
{
 
40
/*
40
41
bool OBGraphBase::Match(OBGraphBase &g,bool singleMatch)
41
42
{
42
 
        SetFinishedMatch(false);
43
 
        SetSingleMatch(singleMatch);
44
 
        ClearMatches();
45
 
        g.SetVisitLock(true);
46
 
        g.ResetVisitFlags();
47
 
 
48
 
        OBNodeBase *node;
49
 
        OBNodeBase *seed = GetFirstSeed();
50
 
        vector<OBNodeBase*>::iterator i;
51
 
 
52
 
        for (node = g.Begin(i);node;node = g.Next(i))
53
 
                if (!node->Visit && seed->Eval(node))
54
 
                {
55
 
                        node->Visit = true;
56
 
                        seed->SetMatch(node);
57
 
                        Match(g,BgnMatch(),BgnMatch()->second.begin());
58
 
                        seed->SetMatch((OBNodeBase*)NULL);
59
 
                        node->Visit = false;
60
 
                        if (SingleMatch() && FinishedMatch()) break;
61
 
                }
62
 
 
63
 
        g.SetVisitLock(false);
64
 
 
65
 
        return(FinishedMatch());
 
43
    SetFinishedMatch(false);
 
44
    SetSingleMatch(singleMatch);
 
45
    ClearMatches();
 
46
    g.SetVisitLock(true);
 
47
    g.ResetVisitFlags();
 
48
 
 
49
    OBNodeBase *node;
 
50
    OBNodeBase *seed = GetFirstSeed();
 
51
    vector<OBNodeBase*>::iterator i;
 
52
 
 
53
    for (node = g.Begin(i);node;node = g.Next(i))
 
54
        if (!node->Visit && seed->Eval(node))
 
55
        {
 
56
            node->Visit = true;
 
57
            seed->SetMatch(node);
 
58
            Match(g,BgnMatch(),BgnMatch()->second.begin());
 
59
            seed->SetMatch((OBNodeBase*)NULL);
 
60
            node->Visit = false;
 
61
            if (SingleMatch() && FinishedMatch())
 
62
                break;
 
63
        }
 
64
 
 
65
    g.SetVisitLock(false);
 
66
 
 
67
    return(FinishedMatch());
66
68
}
67
69
 
68
70
bool OBGraphBase::Match(OBGraphBase &g,
69
 
                                                        vector<pair<OBNodeBase*,vector<OBEdgeBase*> > >::iterator i,
70
 
                                                        vector<OBEdgeBase*>::iterator j)
 
71
                        vector<pair<OBNodeBase*,vector<OBEdgeBase*> > >::iterator i,
 
72
                        vector<OBEdgeBase*>::iterator j)
71
73
{
72
 
        //bail if only one match has been requested
73
 
        if (SingleMatch() && FinishedMatch()) return(true);
74
 
        
75
 
        //full match completed
76
 
        if (i == EndMatch() || (j == i->second.end() && (i+1) == EndMatch())) 
77
 
        {
78
 
                SetFinishedMatch(true);
79
 
                OBNodeBase *node;
80
 
                vector<OBNodeBase*> vn;
81
 
                vector<OBNodeBase*>::iterator i;
82
 
                for (node = Begin(i);node;node = Next(i))
83
 
                        vn.push_back(node->GetMatch());
84
 
                PushBack(vn);
85
 
                
86
 
                return(true);
87
 
        }
88
 
 
89
 
        //handle next seed of disconnected pattern
90
 
        if (j == i->second.end()) 
91
 
        {
92
 
                i++;
93
 
                OBNodeBase *node;
94
 
                OBNodeBase *seed = i->first;
95
 
                vector<OBNodeBase*>::iterator k;
96
 
                for (node = g.Begin(k);node;node = g.Next(k))
97
 
                        if (!node->Visit && seed->Eval(node))
98
 
                        {
99
 
                                node->Visit = true;
100
 
                                seed->SetMatch(node);
101
 
                                Match(g,i,i->second.begin());
102
 
                                seed->SetMatch((OBNodeBase*)NULL);
103
 
                                node->Visit = false;
104
 
                                if (SingleMatch() && FinishedMatch()) break;
105
 
                        }       
106
 
                return(true);
107
 
        }
108
 
 
109
 
        OBEdgeBase *edge = *j++;
110
 
        if (edge->IsClosure()) //check to see if matched atoms are bonded
111
 
        {
112
 
                if (edge->GetBgn()->GetMatch()->IsConnected(edge->GetEnd()->GetMatch()))
113
 
                        Match(g,i,j);
114
 
        }
115
 
        else //bond hasn't been covered yet
116
 
        {
117
 
                OBNodeBase *nbr;
118
 
                OBNodeBase *curr = edge->GetBgn();
119
 
                OBNodeBase *next = edge->GetEnd(); 
120
 
                OBNodeBase *match = curr->GetMatch();
121
 
                vector<OBEdgeBase*>::iterator k;
122
 
        
123
 
                for (nbr = match->BeginNbr(k);nbr;nbr = match->NextNbr(k))
124
 
                        if (!nbr->Visit && next->Eval(nbr) && edge->Eval(*k))
125
 
                        {
126
 
                                nbr->Visit = true;
127
 
                                next->SetMatch(nbr);
128
 
                                Match(g,i,j);
129
 
                                next->SetMatch(NULL);
130
 
                                nbr->Visit = false;
131
 
                        }
132
 
        }
133
 
 
134
 
        return(false);
 
74
    //bail if only one match has been requested
 
75
    if (SingleMatch() && FinishedMatch())
 
76
        return(true);
 
77
 
 
78
    //full match completed
 
79
    if (i == EndMatch() || (j == i->second.end() && (i+1) == EndMatch()))
 
80
    {
 
81
        SetFinishedMatch(true);
 
82
        OBNodeBase *node;
 
83
        vector<OBNodeBase*> vn;
 
84
        vector<OBNodeBase*>::iterator i;
 
85
        for (node = Begin(i);node;node = Next(i))
 
86
            vn.push_back(node->GetMatch());
 
87
        PushBack(vn);
 
88
 
 
89
        return(true);
 
90
    }
 
91
 
 
92
    //handle next seed of disconnected pattern
 
93
    if (j == i->second.end())
 
94
    {
 
95
        i++;
 
96
        OBNodeBase *node;
 
97
        OBNodeBase *seed = i->first;
 
98
        vector<OBNodeBase*>::iterator k;
 
99
        for (node = g.Begin(k);node;node = g.Next(k))
 
100
            if (!node->Visit && seed->Eval(node))
 
101
            {
 
102
                node->Visit = true;
 
103
                seed->SetMatch(node);
 
104
                Match(g,i,i->second.begin());
 
105
                seed->SetMatch((OBNodeBase*)NULL);
 
106
                node->Visit = false;
 
107
                if (SingleMatch() && FinishedMatch())
 
108
                    break;
 
109
            }
 
110
        return(true);
 
111
    }
 
112
 
 
113
    OBEdgeBase *edge = *j++;
 
114
    if (edge->IsClosure()) //check to see if matched atoms are bonded
 
115
    {
 
116
        if (edge->GetBgn()->GetMatch()->IsConnected(edge->GetEnd()->GetMatch()))
 
117
            Match(g,i,j);
 
118
    }
 
119
    else //bond hasn't been covered yet
 
120
    {
 
121
        OBNodeBase *nbr;
 
122
        OBNodeBase *curr = edge->GetBgn();
 
123
        OBNodeBase *next = edge->GetEnd();
 
124
        OBNodeBase *match = curr->GetMatch();
 
125
        vector<OBEdgeBase*>::iterator k;
 
126
 
 
127
        for (nbr = match->BeginNbr(k);nbr;nbr = match->NextNbr(k))
 
128
            if (!nbr->Visit && next->Eval(nbr) && edge->Eval(*k))
 
129
            {
 
130
                nbr->Visit = true;
 
131
                next->SetMatch(nbr);
 
132
                Match(g,i,j);
 
133
                next->SetMatch(NULL);
 
134
                nbr->Visit = false;
 
135
            }
 
136
    }
 
137
 
 
138
    return(false);
135
139
}
136
 
 
 
140
*/
137
141
OBNodeBase *OBGraphBase::Begin(vector<OBNodeBase*>::iterator &i)
138
142
{
139
 
        i = _vatom.begin();
140
 
        return((i != _vatom.end()) ? *i : NULL);
 
143
    i = _vatom.begin();
 
144
    return((i != _vatom.end()) ? *i : NULL);
141
145
}
142
146
 
143
147
OBNodeBase *OBGraphBase::Next(vector<OBNodeBase*>::iterator &i)
144
148
{
145
 
        i++;
146
 
        return((i != _vatom.end()) ? *i : NULL);
 
149
    i++;
 
150
    return((i != _vatom.end()) ? *i : NULL);
147
151
}
148
152
 
149
 
OBEdgeBase *OBGraphBase::Begin(vector<OBEdgeBase*>::iterator &i) 
 
153
OBEdgeBase *OBGraphBase::Begin(vector<OBEdgeBase*>::iterator &i)
150
154
{
151
 
        i = _vbond.begin();
152
 
        return((i != _vbond.end()) ? *i : NULL);
 
155
    i = _vbond.begin();
 
156
    return((i != _vbond.end()) ? *i : NULL);
153
157
}
154
158
 
155
159
OBEdgeBase *OBGraphBase::Next(vector<OBEdgeBase*>::iterator &i)
156
160
{
157
 
        i++;
158
 
        return((i != _vbond.end()) ? *i : NULL);
 
161
    i++;
 
162
    return((i != _vbond.end()) ? *i : NULL);
159
163
}
160
164
 
161
165
OBNodeBase *OBNodeBase::BeginNbr(vector<OBEdgeBase*>::iterator &i)
162
166
{
163
 
        i = _vbond.begin();
 
167
    i = _vbond.begin();
164
168
 
165
 
        if (i == _vbond.end()) return(NULL);
166
 
        return((this == (*i)->GetBgn()) ? (*i)->GetEnd() : (*i)->GetBgn());
 
169
    if (i == _vbond.end())
 
170
        return(NULL);
 
171
    return((this == (*i)->GetBgn()) ? (*i)->GetEnd() : (*i)->GetBgn());
167
172
}
168
173
 
169
174
OBNodeBase *OBNodeBase::NextNbr(vector<OBEdgeBase*>::iterator &i)
170
175
{
171
 
        i++;
172
 
        if (i == _vbond.end()) return(NULL);
173
 
        return((this == (*i)->GetBgn()) ? (*i)->GetEnd() : (*i)->GetBgn());
 
176
    i++;
 
177
    if (i == _vbond.end())
 
178
        return(NULL);
 
179
    return((this == (*i)->GetBgn()) ? (*i)->GetEnd() : (*i)->GetBgn());
174
180
}
175
181
 
176
182
void OBNodeBase::SetParent(OBGraphBase *p)
177
183
{
178
 
        _parent = p;
 
184
    _parent = p;
179
185
}
180
186
 
181
187
void OBEdgeBase::SetParent(OBGraphBase *p)
182
188
{
183
 
        _parent = p;
 
189
    _parent = p;
184
190
}
185
191
 
186
192
bool OBNodeBase::IsConnected(OBNodeBase *nb)
187
193
{
188
 
        vector<OBEdgeBase*>::iterator i;
189
 
        for (i = _vbond.begin();i != _vbond.end();i++)
190
 
                if (nb == (*i)->GetBgn() || nb == (*i)->GetEnd())
191
 
                        return(true);
 
194
    vector<OBEdgeBase*>::iterator i;
 
195
    for (i = _vbond.begin();i != _vbond.end();i++)
 
196
        if (nb == (*i)->GetBgn() || nb == (*i)->GetEnd())
 
197
            return(true);
192
198
 
193
 
        return(false);
 
199
    return(false);
194
200
}
195
201
 
196
202
void OBGraphBase::ResetVisitFlags()
197
203
{
198
 
        OBNodeBase *nb;
199
 
        vector<OBNodeBase*>::iterator i;
200
 
        for (nb = Begin(i);nb;nb = Next(i)) nb->Visit = false;
 
204
    OBNodeBase *nb;
 
205
    vector<OBNodeBase*>::iterator i;
 
206
    for (nb = Begin(i);nb;nb = Next(i))
 
207
        nb->Visit = false;
201
208
 
202
 
        OBEdgeBase *eb;
203
 
        vector<OBEdgeBase*>::iterator j;
204
 
        for (eb = Begin(j);eb;eb = Next(j)) eb->Visit = false;
 
209
    OBEdgeBase *eb;
 
210
    vector<OBEdgeBase*>::iterator j;
 
211
    for (eb = Begin(j);eb;eb = Next(j))
 
212
        eb->Visit = false;
205
213
}
206
214
 
207
215
bool OBGraphBase::SetVisitLock(bool v)
208
216
{
209
 
        if (v && _vlock) return(false);
210
 
        _vlock = v;
211
 
        return(true);
 
217
    if (v && _vlock)
 
218
        return(false);
 
219
    _vlock = v;
 
220
    return(true);
212
221
}
213
222
 
214
223
/*! \mainpage
215
 
  \section intro Introduction
216
 
 
217
 
  (portions adapted from the OELib primer, written by Matt Stahl, Open
218
 
   Eye Scientific Software, Inc.)
219
 
 
220
 
It is fair to say that Open Babel (and before it, OELib) is a direct
221
 
result of the original Babel. Programmers have long known that
222
 
application development is facilitated by building software on top of
223
 
libraries rich in functionality. Babel was the first experience for
224
 
Matt Stahl in designing a molecule library. In addition to developing
225
 
Babel, Pat Walters and Matt developed `OBabel' at Vertex
226
 
Pharmaceuticals. OBabel was the first attempt at developing an 
227
 
object oriented molecule library. Although OBabel was a successful
228
 
project, Matt's departure from Vertex Pharmaceuticals provided a great
229
 
opportunity to include much of what I had learned in previous projects
230
 
into a new molecule class library. OELib was then designed to be flexible,
231
 
extensible, portable, and efficient class library for processing small
232
 
molecules.
233
 
 
 
224
 
 
225
  \section intro Introduction and History
 
226
 
 
227
It is fair to say that Open Babel is a direct result of the original Babel.
 
228
Application development is facilitated
 
229
by building software on top of libraries rich in functionality. Babel
 
230
was the first experience for Matt Stahl in designing a molecule
 
231
library. In addition to developing Babel, Pat Walters and Matt
 
232
developed `OBabel' at Vertex Pharmaceuticals, a first
 
233
attempt at developing an object oriented molecule library.
 
234
Matt later designed a new molecule class library, OELib -- designed
 
235
to be flexible, extensible, portable, and efficient.
 
236
 
234
237
OELib was released under the GNU General Public License (GPL) by Matt Stahl
235
238
and Open Eye Scientific Software, Inc. to take advantage of many of
236
 
the "great minds writing chemical software." Eventually Open Eye
237
 
decided to write a next-generation class library as proprietary
238
 
software. The result was that Open Babel took up where OELib left off,
239
 
using the existing GPL version of OELib, and has continued to evolve
240
 
and improve.
241
 
 
242
 
There are several advantages to having the source code to Open Babel
243
 
available. First, development time can be shortened by basing projects
244
 
on Open Babel. Many chemical and molecular concepts and code are
245
 
already implemented. The fewer people who have to reinvent the wheel
246
 
(or the function), the better. Second, as free software, hopefully 
247
 
other programmers will contribute to the project.
248
 
 
 
239
the "great minds writing chemical software." Open Babel took up where
 
240
OELib and Babel left off, starting from the existing GPL version of
 
241
OELib, and has continued to evolve and improve into a separate
 
242
high-quality chemistry class library and tool. Open Babel is now a
 
243
separate project and library and has changed considerably from the OELib days.
 
244
 
249
245
Thanks to all who have helped with Babel, OBabel, OELib and Open Babel.
250
246
The list is long and growing.
251
 
 
 
247
 
252
248
  \section pointers Key Modules
253
 
 
 
249
 
254
250
The heart of Open Babel lies in the \link OpenBabel::OBMol OBMol\endlink, 
255
251
\link OpenBabel::OBAtom OBAtom\endlink, and 
256
252
\link OpenBabel::OBBond OBBond\endlink classes,
259
255
designed to store the basic information
260
256
in a molecule and to perceive information about a molecule.
261
257
 
262
 
 
263
 
transformations and automatic perception of properties is performed in a 
264
 
"lazy" manner. That is, until you call for partial atomic charges, no 
265
 
charges are calculated. This ensures faster transformations of chemical data
266
 
calculated.
 
258
One of the key philosophies in the code is that transformations and
 
259
automatic perception of properties are performed in a <a href="http://en.wikipedia.org/wiki/Lazy_evaluation">"lazy"</a>
 
260
manner. That is, until you call for partial atomic charges, no
 
261
charges are calculated. This ensures faster transformations of
 
262
chemical data -- properties that are not needed for your code will
 
263
typically not be calculated. When such data is needed, appropriate
 
264
routines are called, and a "flag" is set (e.g., via OBMol::SetFlag
 
265
or OBAtom::SetFlag etc.) so that the code is only run once.
 
266
 
 
267
Arbitrary custom data and text descriptors can be stored in any atom,
 
268
bond, molecule, or residue using the \link OpenBabel::OBGenericData
 
269
OBGenericData\endlink or \link OpenBabel::OBPairData
 
270
OBPairData\endlink classes.
 
271
 
 
272
Conversion between various chemical file formats is accomplished through
 
273
the \link OpenBabel::OBConversion OBConversion\endlink and \link 
 
274
OpenBabel::OBFormat OBFormat\endlink classes, often through use of the \link 
 
275
OpenBabel::OBMoleculeFormat OBMoleculeFormat\endlink subclass which is designed
 
276
for easy read/write access to one or more \link OpenBabel::OBMol OBMol\endlink
 
277
objects. The philosophy of the file format codes is to parse as much
 
278
chemical information from a given file as possible (no data left
 
279
behind) and ideally any perception or transformations will occur when
 
280
writing to some other format later.
267
281
 
268
282
*/
269
283
 
270
284
} // namespace OpenBabel
271
285
 
 
286
//! \file base.cpp
 
287
//! \brief Implementation of base classes.