Skip to content
Snippets Groups Projects
Select Git revision
  • 0318bd7e87d7cae8f4cd5cbda1cb429641325547
  • master default protected
  • github/fork/hrani/master
  • github/fork/dilawar/master
  • chamcham
  • chhennapoda
  • wheel
  • 3.2.0-pre0
  • v3.1.3
  • 3.1.2
  • 3.1.1
  • chamcham-3.1.1
  • 3.1.0
  • ghevar_3.0.2_pre2
  • ghevar_3.0.2
15 results

MdiArea.py

Blame
  • Wildcard.cpp 27.13 KiB
    /**********************************************************************
    ** This program is part of 'MOOSE', the
    ** Messaging Object Oriented Simulation Environment.
    **           Copyright (C) 2003-2007 Upinder S. Bhalla. and NCBS
    ** It is made available under the terms of the
    ** GNU Lesser General Public License version 2.1
    ** See the file COPYING.LIB for the full notice.
    **********************************************************************/
    
    #include "header.h"
    #include <stdio.h>
    #include "Neutral.h"
    #include "Shell.h"
    #include "Wildcard.h"
    // #define NOINDEX (UINT_MAX - 2)
    
    static int wildcardRelativeFind( ObjId start, const vector< string >& path,
                                     unsigned int depth, vector< ObjId >& ret );
    
    static unsigned int findBraceContent( const string& path,
                                          string& beforeBrace, string& insideBrace );
    
    static bool matchName( ObjId id, unsigned int index,
                           const string& beforeBrace, const string& insideBrace );
    
    // static bool matchBeforeBrace( ObjId id, const string& name );
    
    static bool matchInsideBrace( ObjId id, const string& inside );
    /**
     * wildcardFieldComparison returns true if the value of the
     * specified field matches the value in the comparsion string mid.
     * Format is FIELD(name)=val
     * If the format or the value does not match, return 0
     */
    static bool wildcardFieldComparison( ObjId oid, const string& mid )
    {
        // where = could be the usual comparison operators and val
        // could be a number. No strings yet
    
        string::size_type pos = mid.find(')');
        if ( pos == string::npos )
            return 0;
        string fieldName = mid.substr( 0, pos );
        string::size_type pos2 = mid.find_last_of( "=<>" );
        if ( pos2 == string::npos )
            return 0;
        string op = mid.substr( pos + 1, pos2 - pos );
    
        string testValue = mid.substr( pos2 + 1 );
    
        if ( testValue.length() == 0 )
            return 0;
    
        /*
        const Finfo* f = id()->findFinfo( fieldName );
        if ( !f )
        	return 0;
    
        string actualValue;
        bool ret = f->strGet( id.eref(), actualValue );
        */
        string actualValue;
    
        bool ret = SetGet::strGet( oid, fieldName, actualValue );
        if ( ret == 0 )
            return 0;
        if ( op == "==" || op == "=" )
            return ( testValue == actualValue );
        if ( op == "!=" )
            return ( testValue != actualValue );
    
        double v1 = atof( actualValue.c_str() );
        double v2 = atof( testValue.c_str() );
        if ( op == ">" )
            return ( v1 > v2 );
        if ( op == ">=" )
            return ( v1 >= v2 );
        if ( op == "<" )
            return ( v1 < v2 );
        if ( op == "<=" )
            return ( v1 <= v2 );
    
        return 0;
    }
    
    /**
     * Does the wildcard find on a single path
     */
    static int innerFind( const string& path, vector< ObjId >& ret)
    {
        if ( path == "/" || path == "/root")
        {
            ret.push_back( Id() );
            return 1;
        }
    
        vector< string > names;
        vector< vector< unsigned int > > indices;
        bool isAbsolute = Shell::chopString( path, names, '/' );
        ObjId start; // set to root id.
        if ( !isAbsolute )
        {
            Shell* s = reinterpret_cast< Shell* >( ObjId().data() );
            start = s->getCwe();
        }
    
        /*
        if ( path[0] == '/' ) {
        // separateString puts in a blank first entry if the first char
        // is a separator.
        separateString( path.substr( 1 ) , names, "/" );
        } else {
        Shell* s = reinterpret_cast< Shell* >( Id.eref().data() );
        separateString( path, names, "/" );
        start = s->getCwe();
        }
        */
        return wildcardRelativeFind( start, names, 0, ret );
    }
    
    /*
    static int wildcardRelativeFind( Id start, const vector< string >& path,
    		unsigned int depth, vector< Id >& ret )
    		*/
    
    /**
     * This is the basic wildcardFind function, working on a single
     * tree. It adds entries into the vector 'ret' with Ids found according
     * to the path string. It preserves the order of the returned Ids
     * as the order of elements traversed in the search. It does NOT
     * eliminate duplicates. This is a depth-first search.
     * Note that it does the dumb but backward compatible thing with
     * Ids of arrays: it lists every entry.
     *
     * It returns the number of Ids found here.
     */
    int simpleWildcardFind( const string& path, vector< ObjId >& ret)
    {
        if ( path.length() == 0 )
            return 0;
        unsigned int n = ret.size();
        vector< string > wildcards;
        Shell::chopString( path, wildcards, ',' );
        // separateString( path, wildcards, "," );
        vector< string >::iterator i;
        for ( i = wildcards.begin(); i != wildcards.end(); ++i )
            innerFind( *i, ret );
    
        return ret.size() - n;
    }
    
    static void myUnique(vector<ObjId>& ret)
    {
        sort(ret.begin(), ret.end());
        unsigned int i, j;
        j = 0;
        for (i = 1; i < ret.size(); i++)
        {
            if (ret[j] != ret[i])
            {
                ret[++j] = ret[i];
            }
        }
        j++;
        if (j < ret.size())
            ret.resize(j);
    }
    
    int wildcardFind(const string& path, vector<ObjId>& ret)
    {
        ret.resize( 0 );
        simpleWildcardFind( path, ret );
        myUnique( ret );
        return ret.size();
    }
    
    /**
     * 	singleLevelWildcard parses a single level of the path and returns all
     * 	ids that match it. If there is a suitable doublehash, it will recurse
     * 	into child elements.
     * 	Returns # of ids found.
     */
    int singleLevelWildcard( ObjId start, const string& path, vector< ObjId >& ret )
    {
        if ( path.length() == 0 )
            return 0;
        unsigned int nret = ret.size();
    
        string beforeBrace;
        string insideBrace;
        // This has to handle ghastly cases like foo[][FIELD(x)=12.3]
        unsigned int index = findBraceContent( path, beforeBrace, insideBrace );
        if ( beforeBrace == "##" )
            // recursive.
            return allChildren( start, index, insideBrace, ret );
    
        vector< Id > kids;
        Neutral::children( start.eref(), kids );
        vector< Id >::iterator i;
        for ( i = kids.begin(); i != kids.end(); i++ )
        {
            if ( matchName( ObjId( *i, ALLDATA ),
                            index, beforeBrace, insideBrace ) )
            {
                if ( index == ALLDATA )
                {
                    for ( unsigned int j = 0; j < i->element()->numData(); ++j )
                        ret.push_back( ObjId( *i, j ) );
                }
                else if ( i->element()->hasFields() && index < i->element()->numField( start.dataIndex ) )
                {
                    ret.push_back( ObjId( *i, start.dataIndex, index ) );
                }
                else if ( !i->element()->hasFields() && index < i->element()->numData() )
                {
                    ret.push_back( ObjId( *i, index ) );
                }
            }
        }
    
        return ret.size() - nret;
    }
    
    /**
     * Parses the name and separates out the stuff before the brace,
     * the stuff inside it, and if present, the index which is also in a
     * brace. Returns the index, and if not found, zero.
     * Assume order is
     * foo[index][insideBrace]
     * or foo[index]
     * or foo[insideBrace]
     * or foo
     *
     * Note that for the index, an empty [] means ALLDATA, but the
     * absence of the braces altogether means zero.
     *
     * Note also that if the name ends in the wildcard '#', then we assume
     * that all indices are OK, unless overridden by a subsequent specific
     * index via braces.
     * So foo# gives all indices
     * but foo#[3] only gives index == 3.
     */
    unsigned int findBraceContent( const string& path, string& beforeBrace,
                                   string& insideBrace )
    {
        int index = 0;
        beforeBrace = "";
        insideBrace = "";
    
        if ( path.length() == 0 )
            return 0;
        vector< string > names;
        Shell::chopString( path, names, '[' );
        if ( names.size() == 0 )
            return 0;
        if ( names.size() >= 1 )
            beforeBrace = names[0];
        unsigned int len = beforeBrace.length();
        if ( len > 0 && beforeBrace[len -1] == '#' )
            index = ALLDATA;
        if ( names.size() >= 2 )
        {
            const string& n = names[1];
            if ( n == "]" )   // A [] construct means use all indices.
            {
                index = ALLDATA;
            }
            else if ( isdigit( n[0] ) )
            {
                index = atoi( n.c_str() );
            }
            else     // some complicated text construct for the brace
            {
                insideBrace = n.substr( 0, n.length() - 1 );
                return index;
            }
            if ( names.size() == 3 )   // name[number][another_string]
            {
                string n1 = names[2].substr( 0, names[2].length() - 1 );
                insideBrace = n1;
            }
        }
        return index;
    }
    
    /**
     * Compares the various parts of the wildcard name with the id
     * Indexing is messy here because we may refer to any of 3 things:
     * - Regular array indexing
     * - Wildcards within the braces
     * - Simple elements with index as part of their names.
     */
    bool matchName( ObjId id, unsigned int index,
                    const string& beforeBrace, const string& insideBrace )
    {
        string temp = id.element()->getName();
        if ( temp.length() <= 0 )
        {
            return false;
        }
    
        // if ( index == ALLDATA || index == id.dataIndex ) {
        if ( matchBeforeBrace( id, beforeBrace ) )
        {
            if ( insideBrace.length() == 0 )
            {
                return true;
            }
            else
            {
                return matchInsideBrace( id, insideBrace );
            }
        }
        // }
        return 0;
    }
    
    /**
     * matchInsideBrace checks for element property matches
     * Still has some legacy hacks for reading GENESIS code.
     */
    bool matchInsideBrace( ObjId id, const string& inside )
    {
        /* Map from Genesis class names to Moose class names */
        // const map< string, string >& classNameMap = sliClassNameConvert();
        if ( inside == "" )
            return true; // empty means that there is no condition to apply.
    
        if ( inside.substr(0, 4 ) == "TYPE" ||
                inside.substr(0, 5 ) == "CLASS" ||
                inside.substr(0, 3 ) == "ISA" )
        {
            string::size_type pos = inside.rfind( "=" );
            if ( pos == string::npos )
                return false;
            bool isEquality = ( inside[ pos - 1 ] != '!' );
            string typeName = inside.substr( pos + 1 );
            if ( typeName == "membrane" )
                typeName = "Compartment";
    
            if ( inside.substr( 0, 5 ) == "CLASS" && typeName == "channel" )
                typeName = "HHChannel";
    
            bool isEqual;
            if ( inside.substr( 0, 3 ) == "ISA" )
            {
                isEqual = id.element()->cinfo()->isA( typeName );
            }
            else
            {
                isEqual = ( typeName == id.element()->cinfo()->name() );
            }
            /*
            map< string, string >::const_iterator iter = classNameMap.find( typeName );
            if ( iter != classNameMap.end() )
            	isEqual = ( iter->second == id()->className() );
            else
            	isEqual = ( typeName == id()->className() );
            	*/
    
            return ( isEqual == isEquality );
        }
        else if ( inside.substr( 0, 6 ) == "FIELD(" )
        {
            if ( id.dataIndex == ALLDATA )
            {
                return wildcardFieldComparison( id.id, inside.substr( 6 ) );
            }
            else
            {
                return wildcardFieldComparison( id, inside.substr( 6 ) );
            }
        }
    
        return false;
    }
    
    /**
     * Returns true if the name matches the wildcard string. Doesn't care about
     * following characters in 'name'. Single character wildcards are
     * indicated with '?'
     */
    bool alignedSingleWildcardMatch( const string& name, const string& wild )
    {
        unsigned int len = wild.length();
        if ( name.length() < len )
            return false;
        for ( unsigned int i = 0; i < len; i++ )
        {
            if ( wild[i] != '?' && name[i] != wild[i] )
                return false;
        }
        return true;
    }
    
    /**
     * Returns start index for match between string and wildcard using '?' to
     * indicate single character matches.
     * Scans forward along 'name' until it finds a match, or gives up.
     * The entire wildcard must be matched, otherwise returns ~0U
     * findWithSingleCharWildcard( "abc", 0, "a?c" ): return 0;
     * findWithSingleCharWildcard( "xyzabc", 1, "a?c" ): return 3;
     * findWithSingleCharWildcard( "xyzabb", 1, "a?c" ): return ~0U;
     */
    unsigned int findWithSingleCharWildcard(
        const string& name, unsigned int start, const string& wild )
    {
        unsigned int len = wild.length();
        if ( len + start > name.length() )
            return ~0;
        unsigned int end = 1 + name.length() - len;
        for ( unsigned int i = start; i < end; ++i )
        {
            if ( alignedSingleWildcardMatch( name.substr(i), wild ) )
                return i;
        }
        return ~0;
    }
    
    /**
     * matchBeforeBrace checks to see if the wildcard string 'name' matches
     * up with the name of the id.
     * Rules:
     *      # may be used at multiple places in the wildcard.
     *      It substitutes for any number of characters.
     *
     * 		? may be used any number of times in the wildcard, and
     * 		must substitute exactly for characters.
     *
     * 		If bracesInName, then the Id name itself includes braces.
     */
    bool matchBeforeBrace( ObjId id, const string& wild )
    {
        if ( wild == "#" || wild == "##" )
            return true;
    
        string ename = id.element()->getName();
        if ( wild == ename )
            return true;
    
        // Check if the wildcard string has any # or ? symbols.
        if ( wild.find_first_of( "#?" ) == string::npos )
            return false;
    
        // Break the 'wild' into the sections that must match, at the #s.
        // Then go through each of these sections doing a match to ename.
        // If not found, then return false.
        vector< string > chops;
        Shell::chopString( wild, chops, '#' );
        unsigned int prev = 0;
        unsigned int start = 0;
    
        for ( vector< string >::iterator
                i = chops.begin(); i != chops.end(); ++i )
        {
            start = findWithSingleCharWildcard( ename, prev, *i );
            if ( start == ~0U )
                return false;
            if ( prev == 0 && start > 0 && wild[0] != '#' )
                return false;
            prev = start + i->length();
        }
        return true;
    
        /*
    
        string::size_type pre = name.find( "#" );
        string::size_type post = name.rfind( "#" );
    
        // # may only be used once in the wildcard, but substitutes for any
        // number of characters.
        if ( pre != string::npos && post == pre ) {
        	if ( ename.length() < ( name.length() - post - 1 ) )
        			return false;
        	unsigned int epos = ename.length() - ( name.length() - post - 1 );
        	return ( name.substr( 0, pre ) == ename.substr( 0, pre ) &&
        		name.substr( post + 1 ) == ename.substr( epos ) );
        }
    
        // ? may be used any number of times in the wildcard, and
        // must substitute exactly for characters.
        if ( name.length() != ename.length() )
        	return 0;
        for ( unsigned int i = 0; i < name.length(); i++ )
        	if ( name[i] != '?' && name[i] != ename[i] )
        		return false;
        return true;
        */
    }
    
    /**
     * Recursive function to compare all descendants and cram matches into ret.
     * Returns number of matches.
     */
    int allChildren( ObjId start,
                     unsigned int index, const string& insideBrace, vector< ObjId >& ret )
    {
        unsigned int nret = ret.size();
        vector< Id > kids;
        Neutral::children( start.eref(), kids );
        vector< Id >::iterator i;
        for ( i = kids.begin(); i != kids.end(); i++ )
        {
            if ( i->element()->hasFields() )
            {
                if ( matchInsideBrace( *i, insideBrace ) )
                {
                    if ( index == ALLDATA )
                    {
                        ObjId oid( *i, start.dataIndex );
                        ret.push_back( oid );
                    }
                    else if (index < i->element()->numField( start.dataIndex ) )
                    {
                        ObjId oid( *i, start.dataIndex, index );
                        ret.push_back( oid );
                    }
                }
            }
            else
            {
                for ( unsigned int j = 0; j < i->element()->numData(); ++j )
                {
                    ObjId oid( *i, j );
                    allChildren( oid, index, insideBrace, ret );
                    if ( (index == ALLDATA || index == j) && matchInsideBrace( oid, insideBrace ) )
                        ret.push_back( oid );
                }
            }
        }
        return ret.size() - nret;
    }
    
    /**
     * This is the main recursive function of the wildcarding scheme.
     * It builds a wildcard list based on path. Puts found Ids into ret,
     * and returns # found.
     * The start ObjId is one that already matches.
     * depth is the position on the path.
     * This should work for multi-node wildcard searches since it only
     * refers to messaging and basic Element information that is present on
     * all nodes.
     */
    int wildcardRelativeFind( ObjId start, const vector< string >& path,
                              unsigned int depth, vector< ObjId >& ret )
    {
        int nret = 0;
        vector< ObjId > currentLevelIds;
        if ( depth == path.size() )
        {
            if ( ret.size() == 0 || ret.back() != start )
            {
                ret.push_back( start );
            }
            return 1;
        }
    
        if ( singleLevelWildcard( start, path[depth], currentLevelIds ) > 0 )
        {
            vector< ObjId >::iterator i;
            for ( i = currentLevelIds.begin(); i != currentLevelIds.end(); ++i )
                nret += wildcardRelativeFind( *i, path, depth + 1, ret );
        }
        return nret;
    }
    
    void wildcardTestFunc( ObjId* elist, unsigned int ne, const string& path )
    {
        vector< ObjId > ret;
        simpleWildcardFind( path, ret );
        if ( ne != ret.size() )
        {
            cout << "!\nAssert	'" << path << "' : expected " <<
                 ne << ", found " << ret.size() << "\n";
            assert( 0 );
        }
        sort( ret.begin(), ret.end() );
        for ( unsigned int i = 0; i < ne ; i++ )
        {
            if ( elist[ i ] != ret[ i ] )
            {
                cout << "!\nAssert	" << path << ": item " << i <<
                     ": " << elist[i].element()->getName() << " != " <<
                     ret[i].element()->getName() << "\n";
                assert( 0 );
            }
        }
        cout << ".";
    }
    
    void testWildcard()
    {
        unsigned long i;
        string bb;
        string ib;
        i = findBraceContent( "foo[23][TYPE=Compartment]", bb, ib );
        assert( bb == "foo" );
        assert( i == 23 );
        assert( ib == "TYPE=Compartment" );
        i = findBraceContent( "foo[][TYPE=Channel]", bb, ib );
        assert( i == ALLDATA );
        assert( bb == "foo" );
        assert( ib == "TYPE=Channel" );
        i = findBraceContent( "foo[TYPE=membrane]", bb, ib );
        assert( i == 0 );
        assert( bb == "foo" );
        assert( ib == "TYPE=membrane" );
        i = findBraceContent( "bar[]", bb, ib );
        assert( i == ALLDATA );
        assert( bb == "bar" );
        assert( ib == "" );
        i = findBraceContent( "zod[24]", bb, ib );
        assert( i == 24 );
        assert( bb == "zod" );
        assert( ib == "" );
    
        i = findBraceContent( "zod#", bb, ib );
        assert( i == ALLDATA );
        assert( bb == "zod#" );
        assert( ib == "" );
        i = findBraceContent( "zod#[]", bb, ib );
        assert( i == ALLDATA );
        assert( bb == "zod#" );
        assert( ib == "" );
        i = findBraceContent( "zod#[ISA=hippo]", bb, ib );
        assert( i == ALLDATA );
        assert( bb == "zod#" );
        assert( ib == "ISA=hippo" );
        i = findBraceContent( "zod#[3]", bb, ib );
        assert( i == 3 );
        assert( bb == "zod#" );
        assert( ib == "" );
        i = findBraceContent( "zod##", bb, ib );
        assert( i == ALLDATA );
        assert( bb == "zod##" );
        assert( ib == "" );
    
        bool ret = alignedSingleWildcardMatch( "a123456", "a123" );
        assert( ret == true );
        ret = alignedSingleWildcardMatch( "a123456", "1234" );
        assert( ret == false );
        ret = alignedSingleWildcardMatch( "a123456", "?1234" );
        assert( ret == true );
        ret = alignedSingleWildcardMatch( "a123456", "a????" );
        assert( ret == true );
        ret = alignedSingleWildcardMatch( "a123456", "??2??" );
        assert( ret == true );
        ret = alignedSingleWildcardMatch( "a123456", "??3??" );
        assert( ret == false );
        ret = alignedSingleWildcardMatch( "a1", "a?" );
        assert( ret == true );
    
        unsigned int j = findWithSingleCharWildcard( "a12345678", 0, "a123" );
        assert( j == 0 );
        j = findWithSingleCharWildcard( "a12345678", 0, "123" );
        assert( j == 1 );
        j = findWithSingleCharWildcard( "a12345678", 0, "?123" );
        assert( j == 0 );
        j = findWithSingleCharWildcard( "a12345678", 0, "?23456?" );
        assert( j == 1 );
        j = findWithSingleCharWildcard( "a12345678", 0, "??6?" );
        assert( j == 4 );
    
        Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
        Id a1 = shell->doCreate( "Neutral", Id(), "a1", 1 );
        Id c1 = shell->doCreate( "Arith", a1, "c1", 1 );
        Id c2 = shell->doCreate( "Arith", a1, "c2", 1 );
        Id c3 = shell->doCreate( "Arith", a1, "c3", 1 );
        Id cIndex = shell->doCreate( "Neutral", a1, "c4", 1 );
        Id c5 = shell->doCreate( "Neutral", a1, "Seg5_apical_1234_spine_234",1);
    
        ret = matchBeforeBrace( a1, "a1" );
        assert( ret );
        ret = matchBeforeBrace( a1, "a2" );
        assert( ret == 0 );
        ret = matchBeforeBrace( a1, "a?" );
        assert( ret == 1 );
        ret = matchBeforeBrace( a1, "?1" );
        assert( ret == 1 );
        ret = matchBeforeBrace( a1, "??" );
        assert( ret == 1 );
        ret = matchBeforeBrace( a1, "#" );
        assert( ret == 1 );
        ret = matchBeforeBrace( a1, "a#" );
        assert( ret == 1 );
        ret = matchBeforeBrace( a1, "#1" );
        assert( ret == 1 );
    
        ret = matchBeforeBrace( cIndex, "c4" );
        assert( ret == 1 );
        ret = matchBeforeBrace( cIndex, "##" );
        assert( ret == 1 );
        ret = matchBeforeBrace( cIndex, "#4" );
        assert( ret == 1 );
        ret = matchBeforeBrace( cIndex, "#" );
        assert( ret == 1 );
        ret = matchBeforeBrace( cIndex, "?4" );
        assert( ret == 1 );
        ret = matchBeforeBrace( cIndex, "c1" );
        assert( ret == 0 );
        ret = matchBeforeBrace( cIndex, "c?" );
        assert( ret == 1 );
        ret = matchBeforeBrace( cIndex, "??" );
        assert( ret == 1 );
    
        ret = matchBeforeBrace( c5, "Seg?_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#Seg?_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#?_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#5_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#e?5_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#e5_apical_#_spine_#" );
        assert( ret == false );
        ret = matchBeforeBrace( c5, "#Seg5_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#Seg#_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "Seg#_apical_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "Seg#_a????l_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "#?_a????l_#_spine_#" );
        assert( ret == true );
        ret = matchBeforeBrace( c5, "Seg?_a?????l_#_spine_#" );
        assert( ret == false );
        ret = matchBeforeBrace( c5, "Seg#_spine_#" );
        assert( ret == true );
    
    
        ret = matchInsideBrace( a1, "TYPE=Neutral" );
        assert( ret );
        ret = matchInsideBrace( a1, "TYPE==Neutral" );
        assert( ret );
        ret = matchInsideBrace( a1, "CLASS=Neutral" );
        assert( ret );
        ret = matchInsideBrace( a1, "ISA=Neutral" );
        assert( ret );
        ret = matchInsideBrace( a1, "CLASS=Neutral" );
        assert( ret );
        ret = matchInsideBrace( a1, "TYPE!=Channel" );
        assert( ret );
        ret = matchInsideBrace( a1, "CLASS!=Channel" );
        assert( ret );
        ret = matchInsideBrace( a1, "ISA!=Channel" );
        assert( ret );
        ret = matchInsideBrace( c3, "ISA==Neutral" ); // Everything is a Neutral
        assert( ret );
        ret = matchInsideBrace( c3, "ISA=Arith" );
        assert( ret );
        ret = matchInsideBrace( c3, "TYPE=membrane" );
        assert( !ret );
    
        Field<double>::set( ObjId( c3, 0 ), "outputValue", 123.5 );
        ret = matchInsideBrace( c3, "FIELD(outputValue)=123.5" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)==123.5" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)!=123.4" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)>123.4" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)<123.6" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)>=123.4" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)<=123.6" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)>=123.5" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)<=123.5" );
        assert( ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)==123.4" );
        assert( !ret );
        ret = matchInsideBrace( c3, "FIELD(outputValue)<123.4" );
        assert( !ret );
    
    
        ObjId el1[] = { ObjId(), a1, c1 };
        wildcardTestFunc( el1, 3, "/,/a1,/a1/c1" );
        ObjId el3[] = { c1, c2, c3, cIndex };
        wildcardTestFunc( el3, 4, "/a1/c#" );
        wildcardTestFunc( el3, 3, "/a1/c#[TYPE=Arith]" );
    
        ObjId el2[ 100 ];
        for ( i = 0 ; i < 100; i++ )
        {
            char name[10];
            sprintf( name, "ch%ld", i );
            el2[i] = shell->doCreate( "Annotator", c1, name, 1 );
            //el2[i] = Neutral::create( "HHChannel", name, c1->id(), Id::scratchId() );
            Field< double >::set( ObjId( el2[i], 0 ), "z", i );
        }
    
        wildcardTestFunc( el2, 100, "/a1/c1/##" );
        wildcardTestFunc( el2, 100, "/a1/c1/#" );
    
        wildcardTestFunc( el2, 0, "/a1/##[TYPE=IntFire]" );
        wildcardTestFunc( el2, 100, "/a1/##[TYPE=Annotator]" );
        wildcardTestFunc( el2, 50, "/a1/c1/##[][FIELD(z)<50]" );
    
        // Here we set up some thoroughly ugly nesting.
        // Note the sequence: The wildcarding goes depth first,
        // and then in order of creation.
        ObjId el4[12];
        i = 0;
        el4[i] = shell->doCreate( "IntFire", el2[0], "g0", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[1], "g1", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[1], "g2", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[2], "g3", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[2], "g4", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[4], "g5", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[5], "g6", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[6], "g7", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[1], "g8", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", el2[1], "g9", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", c2, "g10", 1 );
        ++i;
        el4[i] = shell->doCreate( "IntFire", c3, "g11", 1 );
        ++i;
    
        wildcardTestFunc( el4, 12, "/a1/##[TYPE=IntFire]" );
        wildcardTestFunc( el4, 12, "/##[TYPE=IntFire]" );
    
        // Here I test wildcards with array Elements.
        Id x = shell->doCreate( "Arith", a1, "x", 5 );
        Id y = shell->doCreate( "Arith", ObjId( x, 2 ), "y", 5 );
        Id z = shell->doCreate( "Arith", ObjId( y, 3 ), "z", 5 );
        vector< ObjId > vec;
        simpleWildcardFind( "/a1/x[]/##", vec );
        assert( vec.size() == 10 );
        vec.clear();
        simpleWildcardFind( "/a1/x[]/##,/a1/x[]", vec );
        assert( vec.size() == 15 );
        vec.clear();
        simpleWildcardFind( "/a1/x[2]/y[]", vec );
        assert( vec.size() == 5 );
    
        // Here I test exclusive wildcards, should NOT get additional terms.
        Id xyzzy = shell->doCreate( "Arith", a1, "xyzzy", 5 );
        Id xdotp = shell->doCreate( "Arith", a1, "x.P", 5 );
        vec.clear();
        simpleWildcardFind( "/a1/x", vec );
        assert( vec.size() == 1 );
        vec.clear();
        simpleWildcardFind( "/a1/x[0]", vec );
        assert( vec.size() == 1 );
        vec.clear();
        simpleWildcardFind( "/a1/x[2]", vec );
        assert( vec.size() == 1 );
        vec.clear();
        simpleWildcardFind( "/a1/x[]", vec );
        assert( vec.size() == 5 );
    
        //a1.destroy();
        shell->doDelete( a1 );
        cout << "." << flush;
    }