CODE C4.5

Code en langage C de l'algorithme (C4 5, i.e. ID3 amélioré) utilisé pour construire/induire

les arbres de décision (réseaux bayesiens) et les règles de comportement des acheteurs.
 

Principe

À partir d'un échantillon d'apprentissage composé d'une variable objectif ou variable prédite (type de produit acheté) et d'au moins une variable d'apprentissage ou variable prédictive , C4.5 produit un modèle de type arbre de décision. Ce modèle permet de prédire pour un individu la valeur estimée de la variable objectif en fonction des valeurs prise par les variables prédictives . L'algorithme C4.5 se base sur une mesure de l'entropie dans l'échantillon d'apprentissage pour produire le modèle (graphe d'induction). L'avantage du recours à l'entropie est que l'algorithme opère sur des données symboliques que ce soient des variables catégorielles (comme des couleurs) ou numériques discrètes (par exemple ). Le désavantage de la méthode est que pour préserver l'efficacité de l'apprentissage et la pertinence du modèle produit, les variables continues doivent être discrétisées avant la mise en œuvre de l'algorithme.
 

Code

 
/*
 * NeticaEx.c
 *
 * Extra and Example (external) Source Code for Netica API, version 1.05.
 *
 * Copyright (C) 1992-1997 by Norsys Software Corp.
 * The software in this file may be copied, modified, and/or included in
 * derivative works without charge or obligation.
 * Norsys makes no guarantee of continued support for this software.
 *
 */

#include "Netica.h"
#include "NeticaEx.h"

environ_ns *env;

/*_____________________________________________________________________________ main_ex
All programs using Netica API should contain code equivalent to this.
One possibility is to copy this code into your own routine named "main".
No Netica API function should be called before NewNeticaEnviron_bn or after
  CloseNetica_bn, and most of them must not be called before InitNetica_bn.
*/
#include

int main_ex (void){
    char mesg[MESG_LEN_ns];
    environ_ns *env;
    int res;
        
    env = NewNeticaEnviron_bn (NULL);    /* substitute your license string for NULL if desired */
    res = InitNetica_bn (&env, mesg);
    printf ("%s\n", mesg);
    if (res < 0)  exit (-1);
    /*
     *
     */
    res = CloseNetica_bn (env, mesg);
    printf ("%s\n", mesg);
    return (res < 0 ? -1 : 0);
    }

/*___________________________________________________________________________ NodeNamed
Like NodeNamed_bn, but generates an error if the name doesn't exist.
*/
node_bn *NodeNamed (char *node_name, net_bn *net){
    node_bn *node = NodeNamed_bn (node_name, net);
    if (node == NULL)
        ReportError (env, 0, ERROR_ERR,
                    "NodeNamed: There is no node named '%s' in network '%s'",
                     node_name, GetNetName_bn (net));
    return node;
}

/*________________________________________________________________________ EnterFinding
Like EnterFinding_bn, but is passed names (C strings) instead.
*/
void EnterFinding (char *node_name, char *state_name, net_bn *net){
    node_bn *node = NodeNamed (node_name, net);
    state_bn state = StateNamed_bn (state_name, node);
    EnterFinding_bn (node, state);
}

/*_______________________________________________________________________ GetNodeBelief
Like GetNodeBeliefs_bn, but is passed names (C strings) instead,
  and it returns the belief for a single state.
*/
double GetNodeBelief (char *node_name, char *state_name, net_bn *net){
    node_bn *node = NodeNamed (node_name, net);
    state_bn state = StateNamed_bn (state_name, node);
    return GetNodeBeliefs_bn (node) [state];
}
    
/*___________________________________________________________________ SetNodeStateNames
This wraps several calls to SetNodeStateName_bn into one.
For instance to give the node 'Weather' its 3 state names you could call:

    SetNodeStateNames (Weather, "sunny", "cloudy", "rainy");
*/
#include

void SetNodeStateNames (node_bn *node, ...){
    state_bn state, numstates = GetNodeNumberStates_bn (node);
    va_list ap;
    va_start (ap, node);
    for (state = 0;  state < numstates;  state++)
        SetNodeStateName_bn (node, state, va_arg (ap, char*));
    va_end (ap);
}

/*________________________________________________________________________ SetNodeProbs
This routine is meant to be a more convenient (but slower) version of
  SetNodeProbs_bn.  Its first argument is the node whose probabilities we are setting.
  This is followed by the names of the conditioning states of its parents as C strings.
  Finally comes a list of doubles, being the probabilities for each of the states of
  the node.
For example:   SetNodeProbs (Temperature, "Windy", "Low", 0.6, 0.3, 0.1);
  means that the probability that Temperature is in its first state given that its
  first parent is in state "Windy" and its second parent is in state "Low" is 0.6,
  the probability its in its second state is 0.3, and that its in its third state is 0.1.
Since the function prototype uses "...", you must be very careful to pass doubles
  for the probabilities (e.g. passing 0 instead of 0.0 will get you in trouble).
If time efficiency is critical, and you must set large probability tables,
  use SetNodeProbs_bn directly instead of this routine.
___________*/

#include
#define ARR_SIZE 20

void SetNodeProbs (node_bn *node, ...){
    state_bn parent_states[ARR_SIZE];
    prob_bn probs[ARR_SIZE];
    char *statename;
    state_bn state, numstates = GetNodeNumberStates_bn (node);
    const nodelist_bn *parents = GetNodeParents_bn (node);
    int pn, numparents = LengthNodeList_bn (parents);
    va_list ap;
    if (numstates > ARR_SIZE || numparents > ARR_SIZE){
        ReportError_ns (env, 0, XXX_ERR, "SetNodeProbs: Array size defined too small");
        return;
    }
    va_start (ap, node);
    for (pn = 0;  pn < numparents;  pn++){
        statename = va_arg (ap, char*);
        if (statename[0] == '*')  parent_states[pn] = WILDCARD_STATE;
        else parent_states[pn] = StateNamed_bn (statename, NthNode_bn (parents, pn));
    }
    for (state = 0;  state < numstates;  state++)
        probs[state] = (prob_bn) va_arg (ap, double);
    va_end (ap);
    SetNodeProbs_bn (node, parent_states, probs);
}

void SetNodeFuncValue (node_bn *node, double value, ...){
    char *statename;
    state_bn parent_states[ARR_SIZE];
    const nodelist_bn *parents = GetNodeParents_bn (node);
    int pn, numparents = LengthNodeList_bn (parents);
    va_list ap;
    if (numparents > ARR_SIZE){
        ReportError_ns (env, 0, XXX_ERR, "SetNodeFuncValue: Array size defined too small");
        return;
    }
    va_start (ap, value);
    for (pn = 0;  pn < numparents;  pn++){
        statename = va_arg (ap, char*);
        if (statename[0] == '*')  parent_states[pn] = WILDCARD_STATE;
        else parent_states[pn] = StateNamed_bn (statename, NthNode_bn (parents, pn));
    }
    va_end (ap);
    SetNodeFuncValue_bn (node, parent_states, value);
}

#undef ARR_SIZE

/*____________________________________________________________________ MakeProbsUniform
Gives the passed node a uniform conditional probability distribution
  (i.e. all the probabilities the same).
*/
#include

void MakeProbsUniform (node_bn *node){
    int st, num_states  = GetNodeNumberStates_bn (node);
    int pn, num_parents = LengthNodeList_bn (GetNodeParents_bn (node));
    prob_bn  *uniform = malloc (num_states  * sizeof (prob_bn));
    state_bn *pstates = malloc (num_parents * sizeof (state_bn));
    for (st = 0;  st < num_states;  ++st)  uniform[st] = (prob_bn) (1.0 / num_states);
    for (pn = 0;  pn < num_parents; ++pn)  pstates[pn] = WILDCARD_STATE;
    SetNodeProbs_bn (node, pstates, uniform);
    free (uniform);  free (pstates);
}

/*_____________________________________________________________________ GetNodeAllProbs
Puts all the conditional probabilities of 'node' into the array 'probs'.
If 'node' doesn't have any cond probs, 'probs' will be left unchanged.
You could allocate 'probs' as follows:
  probs = malloc (SizeCartesianProduct (GetNodeParents_bn (node)) *
                  GetNodeNumberStates_bn (node) * sizeof (prob_bn));
*/
void GetNodeAllProbs (node_bn *node, prob_bn *probs){
    int num_states  = GetNodeNumberStates_bn (node);
    int num_parents = LengthNodeList_bn (GetNodeParents_bn (node));
    state_bn st, *parent_states = calloc (num_parents, sizeof (state_bn));
    while (1){
        const prob_bn *vecp = GetNodeProbs_bn (node, parent_states);
        if (!vecp)  break;
        for (st = 0;  st < num_states;  st++)
            *probs++ = *vecp++;
        if (NextStates (parent_states, GetNodeParents_bn (node)))  break;
        if (GetError_ns (env, ERROR_ERR, NULL))  break;
    }
    free (parent_states);
}

/*_____________________________________________________________________ SetNodeAllProbs
Sets all the probabilities of 'node' based on the array 'probs'.
You could use this routine in combination with GetNodeAllProbs to
  save and restore probability tables, but be careful that the network
  connectivity, and the number of states of nodes, doesn't change between calls.
*/
void SetNodeAllProbs (node_bn *node, const prob_bn *probs){
    int num_states  = GetNodeNumberStates_bn (node);
    int num_parents = LengthNodeList_bn (GetNodeParents_bn (node));
    state_bn *parent_states = calloc (num_parents, sizeof (state_bn));
    while (1){
        SetNodeProbs_bn (node, parent_states, probs);
        if (NextStates (parent_states, GetNodeParents_bn (node)))  break;
        probs += num_states;
        if (GetError_ns (env, ERROR_ERR, NULL))  break;
    }
    free (parent_states);
}

/*________________________________________________________________ SizeCartesianProduct
Returns the size of the cartesian product of the states of nodes,
  or 0 if one of nodes is continuous and not discretized.
Returns DBL_MAX if the size is greater than DBL_MAX (this type of overflow is not
  uncommon, since the values returned can be very large).
*/
#include

double SizeCartesianProduct (const nodelist_bn *nodes){
    double size = 1;
    int nn;
    for (nn = 0;  nn < LengthNodeList_bn (nodes);  nn++){
        int num_states = GetNodeNumberStates_bn (NthNode_bn (nodes, nn));
        if (num_states == 0)  return 0;
        if (num_states + 1 > DBL_MAX / size)  return DBL_MAX;
        size *= num_states;
        }
    return size;
}

/*_________________________________________________________________________ ReportError
Like ReportError_ns, but with printf style arguments for the error message.
You must be very careful that your error message length is limited so that it
  doesn't run over the declared buffer size, which you may want to make a little
  bigger or smaller.
For an example of its use, see the code for the "NodeNamed" function, in NeticaEx.c.
*/
#include

report_ns *ReportError (environ_ns *env, int number, errdanger_ns danger, const char *mesg, ...){
    va_list ap;
    char buf[400];
    va_start (ap, mesg);
    vsprintf (buf, mesg, ap);
    va_end (ap);
    return  ReportError_ns (env, number, danger, buf);
}

/*__________________________________________________________________ PositionInNodeList
To return the index of node in the list nodes (first is 0).
This can also be used to test if node is a member of list nodes,
  since this returns -1 iff it isn't.
*/
int PositionInNodeList (const node_bn *node, const nodelist_bn *nodes){
    int i, num = LengthNodeList_bn (nodes);
    for (i = 0;  i < num;  i++)
        if (NthNode_bn (nodes, i) == node)
            return i;
    return -1;
}

/*_________________________________________________________________________ DeleteLinks
Removes all links from node 'parent' to node 'child' (usually there is
  only 0 or 1 link).
It iterates backwards through the list of parents, since each time a link is removed,
  the indexes of all the links following it changes.
*/
void DeleteLinks (node_bn *parent, node_bn *child){
    int pn;
    const nodelist_bn *parents = GetNodeParents_bn (child);
    for (pn = LengthNodeList_bn (parents) - 1;  pn >= 0;  pn--)
        if (NthNode_bn (parents, pn) == parent)
            DeleteLink_bn (pn, child);
}

/*_________________________________________________________________ DeleteLinksEntering
Removes all links entering the passed node.
*/
void DeleteLinksEntering (node_bn *child){
    int pn, num_parents = LengthNodeList_bn (GetNodeParents_bn (child));
    for (pn = 0;  pn < num_parents;  pn++)
        DeleteLink_bn (0, child);       /* 0 since indexes change with each deletion */
}

/*____________________________________________________________________ SwitchNodeParent
Like SwitchNodeParent_bn, but accepts the parent node instead of a
  link index.
Switches the link from parent -> child to go from new_parent -> child.
Assumes there is already exactly one link from parent to child.
*/
void SwitchNodeParent (node_bn *parent, node_bn *child, node_bn *new_parent){
    int link_index = PositionInNodeList (parent, GetNodeParents_bn (child));
    SwitchNodeParent_bn (link_index, child, new_parent);
}

/*_________________________________________________________________________ DeleteNodes
Removes all of 'nodes' from their net, and frees them and node list 'nodes'.
*/
void DeleteNodes (nodelist_bn *nodes){
    int i, num = LengthNodeList_bn (nodes);
    for (i = 0;  i < num;  i++){
        node_bn *node = NthNode_bn (nodes, i);
        SetNthNode_bn (nodes, i, NULL);                /* so node list stays legal */
        DeleteNode_bn (node);
    }
    FreeNodeList_bn (nodes);
}

/*__________________________________________________________________ IsLinkDisconnected
Returns whether link 'link_index' entering 'node' is disconnected.
*/
bool_ns IsLinkDisconnected (int link_index, const node_bn *node){
    const node_bn *parent = NthNode_bn (GetNodeParents_bn (node), link_index);
    return GetNodeKind_bn (parent) == DISCONNECTED_NODE;
}


/*=====================================================================*/


/*__________________________________________________________________________ NextStates
STATES is a list of node states, one for each node of NODES.
This cycles through all possible configurations (i.e. elements of the cartesian
product) of STATES, odometer style, with the last state changing fastest.
It returns TRUE when all the configurations have been examined (i.e., when it
"rolls over" to all zeros again).
Don't forget to initialize STATES before calling it the first time (usually
to all zeros).
*/
bool_ns NextStates (state_bn *states, const nodelist_bn *nodes){
    int nn;
    for (nn = LengthNodeList_bn (nodes) - 1;  nn >= 0;  nn--){
        if (++states[nn] < GetNodeNumberStates_bn (NthNode_bn (nodes, nn)))
            return FALSE;
        states[nn] = 0;
        }
    return TRUE;
    }

/*_______________________________________________________________________ ChangeFinding
This routine may be useful if we are not sure whether node
  already has a finding, but if it does we just want to override it.
*/
void ChangeFinding (node_bn *node, state_bn state){
    RetractNodeFindings_bn (node);
    EnterFinding_bn (node, state);
}

/*_______________________________________________________________________ TransferNodes
This transfers nodes from the net they are in to new_net,
  and returns a new list of the new nodes in the same order as they
  appeared in nodes.  The old list is freed.
In the process each node in nodes is freed, and a new one created,
  so be sure you don't have any dangling pointers to the old nodes.
Don't forget to free the nodelist_bn returned when you are done with it.
*/
nodelist_bn *TransferNodes (nodelist_bn *nodes, net_bn *new_net){
    int nn, num_nodes = LengthNodeList_bn (nodes);
    nodelist_bn *new_nodes = DuplicateNodes_bn (nodes, new_net);
    for (nn = 0;  nn < num_nodes;  nn++)
        DeleteNode_bn (NthNode_bn (nodes, nn));
    FreeNodeList_bn (nodes);         /* because its full of invalid pointers */
    return new_nodes;
}

/*_____________________________________________________________________________ DupNode
Handy function to duplicate a single node within its network.
*/
node_bn *DupNode (node_bn *node){
    return DuplicateNode (node, GetNodeNet_bn (node));
}

/*_______________________________________________________________________ DuplicateNode
Handy function to duplicate a single node into a new network.
*/
node_bn *DuplicateNode (node_bn *node, net_bn *new_net){
    node_bn *new_node;
    nodelist_bn *newnodes, *nodes = NewNodeList_bn (1, env);
    SetNthNode_bn (nodes, 0, node);
    newnodes = DuplicateNodes_bn (nodes, new_net);
    new_node = NthNode_bn (newnodes, 0);
    FreeNodeList_bn (nodes);
    FreeNodeList_bn (newnodes);
    return new_node;
}

/*________________________________________________________________________ DuplicateNet
Duplicates a whole network.
Every field is duplicated, except a new name is passed (you could pass
  GetNetName_bn(net) if you wanted that duplicated as well).
It just copies the user-data pointer, but you may want to duplicate the data itself
  (some pointers within it may have to be resolved in a similar style as ElimOrder
  list).
*/
net_bn *DuplicateNet (net_bn *net, const char *newname){
    nodelist_bn *neworder;
    net_bn *new_net = NewNet_bn (newname, env);
    nodelist_bn *new_nodes = DuplicateNodes_bn (GetNetNodes_bn (net), new_net);

    neworder = MapNodeList (GetNetElimOrder_bn (net), new_net);
    SetNetElimOrder_bn (new_net, neworder);
    FreeNodeList_bn (neworder);

    FreeNodeList_bn (new_nodes);
    SetNetAutoUpdate_bn (new_net, GetNetAutoUpdate_bn (net));
    SetNetTitle_bn (new_net, GetNetTitle_bn (net));
    SetNetComment_bn (new_net, GetNetComment_bn (net));
    SetNetUserData_bn (new_net, 0, GetNetUserData_bn (net, 0));
    return new_net;
}

/*_____________________________________________________________ MapNode ___ MapNodeList
Returns the node from network DEST_NET which is equivalent to NODE passed.
Equivalency is determined by the nodes having the same name.
This routine may seem like an inefficient way to map nodes, but since NodeNamed_bn
  uses a hashing table, it scales okay to large networks.
MapNodeList does the same thing for a whole list of nodes.  Don't forget to free the
  node list it returns.
*/
node_bn *MapNode (const node_bn *node, const net_bn *dest_net){
    return NodeNamed_bn (GetNodeName_bn (node), dest_net);
}

nodelist_bn *MapNodeList (const nodelist_bn *nodes, const net_bn *dest_net){
    node_bn *oldnode, *newnode;
    nodelist_bn *new_nodes;
    int nn, numnodes = LengthNodeList_bn (nodes);
    if (nodes == NULL)  return NULL;
    new_nodes = NewNodeList_bn (numnodes, env);
    for (nn = 0;  nn < numnodes;  nn++){
        oldnode = NthNode_bn (nodes, nn);
        newnode = NodeNamed_bn (GetNodeName_bn (oldnode), dest_net);
        SetNthNode_bn (new_nodes, nn, newnode);
    }
    return new_nodes;
}

/*________________________________________________________________________ MapNodeList1
This does the same sort of thing as MapNodeList, but defines the mapping
  in terms of 2 matching lists of nodes, rather than identical node names in different
  networks.  It is useful when the names of matching nodes might be different
  (e.g. duplicating into a network which already has nodes with the same names),
  or when duplicating within one network.
WARNING: This modifies the user-data slots, so if you are already using them, you
  should change this routine to just use a field of the structure you have at each
  node's user-data slot.
To compare with MapNodeList, see how DuplicateNet uses that routine, and compare with:

net_bn *DuplicateNet (net_bn *net, const char *newname){
    nodelist_bn *neworder;
    net_bn *new_net = NewNet_bn (newname, env);
    const nodelist_bn *oldnodes = GetNetNodes_bn (net);
    nodelist_bn *newnodes = DuplicateNodes_bn (oldnodes, new_net);

    neworder = MapNodeList1 (GetNetElimOrder_bn (net), oldnodes, newnodes);
    SetNetElimOrder_bn (new_net, neworder);
    FreeNodeList_bn (neworder);
    ...
____________*/

nodelist_bn *MapNodeList1 (const nodelist_bn *nodes, const nodelist_bn *src_nodes, const nodelist_bn *dest_nodes){
    nodelist_bn *new_nodes;
    int nn, numnodes = LengthNodeList_bn (src_nodes);
    if (nodes == NULL)  return NULL;
    for (nn = 0;  nn < numnodes;  nn++)
        SetNodeUserData_bn (NthNode_bn (src_nodes, nn), 0, NthNode_bn (dest_nodes, nn));    // src_nodes[nn].userdata = dest_nodes[nn]
    numnodes = LengthNodeList_bn (nodes);
    new_nodes = NewNodeList_bn (numnodes, env);
    for (nn = 0;  nn < numnodes;  nn++)
        SetNthNode_bn (new_nodes, nn, GetNodeUserData_bn (NthNode_bn (nodes, nn), 0));      // new_nodes[nn] = nodes[nn].userdata
    return new_nodes;
}

/*__________________________________________________________________________ AbsorbNode
Handy function to absorb a single node.
*/
void AbsorbNode (node_bn *node){
    nodelist_bn *nodes = NewNodeList_bn (1, env);
    SetNthNode_bn (nodes, 0, node);
    AbsorbNodes_bn (nodes);
}

/*______________________________________________________________________ FadeProbsNodes
The following does the same fading for a list of nodes:
*/
void FadeProbsNodes (const nodelist_bn *nodes, double degree){
    int nn, num = LengthNodeList_bn (nodes);
    for (nn = 0;  nn < num;  nn++)
        FadeProbs_bn (NthNode_bn (nodes, nn), degree);
}

/*__________________________________________________________________ PrintNeticaVersion
Don't call this routine until the global variable env has been
  initialized by a call to NewNeticaEnviron_bn in the normal way.
*/
void PrintNeticaVersion (void){
    const char *version;
    GetNeticaVersion_bn (env, &version);
    printf ("Version of Netica running: %s\n", version);
}

/*__________________________________________________________________ RemoveNodeFromList
To remove the first occurrence of some node from the list.
*/
void RemoveNodeFromList (node_bn *node, nodelist_bn *nodes){
    int i, num = LengthNodeList_bn (nodes);
    for (i = 0;  i < num;  i++)
        if (NthNode_bn (nodes, i) == node){
            RemoveNthNode_bn (nodes, i);
            return;
        }
}

/*___________________________________________________________________ RemoveNthNodeFast
This achieves the same purpose as RemoveNthNode_bn.
Since removing the last node is fastest, this will execute
  more quickly (for long lists), but the order won't be maintained.
*/
void RemoveNthNodeFast (int index, nodelist_bn *nodes){
    node_bn *lastnode = RemoveNthNode_bn (nodes, INT_MAX);
    SetNthNode_bn (nodes, index, lastnode);
}

/*_______________________________________________________________________ PrintNodeList
Prints out the names of the nodes in the list passed to it.
*/
void PrintNodeList (nodelist_bn *nodes){
    int nn, numnodes = LengthNodeList_bn (nodes);
    for (nn = 0;  nn < numnodes;  ++nn){
        if (nn != 0)  printf (", ");
        printf ("%s", GetNodeName_bn (NthNode_bn (nodes, nn)));
    }
}

/*_________________________________________________________________________ PrintErrors
This prints messages for all the serious errors currently registered with
  the environment in global variable 'env'.
*/
void PrintErrors (void){
    report_ns *error = NULL;
    while (1) {
        error = GetError_ns (env, ERROR_ERR, error);
        if (!error)  break;
        printf ("%d - %s\n", (int) ErrorNumber_ns (error), ErrorMessage_ns (error));
    }
}

/*_________________________________________________________________________ ClearErrors
Removes and frees all errors recorded with environment env
  which are as serious as danger, or less serious.
Does the same function as ClearErrors_ns, but is less efficient.
*/
void ClearErrors (environ_ns *env, errdanger_ns danger){
    report_ns *error = NULL;
    while (1){
        error = GetError_ns (env, NOTHING_ERR, error);
        if (error == NULL)  break;
        if (ErrorDanger_ns (error) <= danger)
            ClearError_ns (error);
    }
}

/*____________________________________________________________________ CountCasesInFile
Counts the number of cases in a case file.
This is not very efficient; if you just needed the number of cases it would be better
  to just count the number of relevant lines in the file.  However, if you wanted to
  filter out some cases, or count categories of cases, this will make a good template.
*/
long CountCasesInFile (stream_ns *casefile){
    nodelist_bn *empty_nodes = NewNodeList_bn (0, env);
    long numcases = 0;
    caseposn_bn caseposn = FIRST_CASE;
    while (1){
        ReadCase_bn (&caseposn, casefile, empty_nodes, NULL, NULL);
        if (caseposn == NO_MORE_CASES)  break;
        numcases++;
        caseposn = NEXT_CASE;
        if (GetError_ns (env, ERROR_ERR, NULL))  break;
    }
    FreeNodeList_bn (empty_nodes);
    return numcases;
}


/*======================= NOT IN REFERENCE MANUAL ========================*/


/*_________________________________________________________________ DisconnectNodeGroup
This disconnects a group of nodes from the rest of the network,
  without removing any of the links between members of the group,
  and returns a new list of the new nodes in the same order as they
  appeared in nodes.  The old list nodes is freed.
In the process each node in nodes is freed, and a new one created,
  so be sure you don't have any dangling pointers to the old nodes.
It uses TransferNodes, which is defined in the example above.
*/
nodelist_bn *DisconnectNodeGroup (nodelist_bn *nodes){
    net_bn *net, *scratch_net;
    nodelist_bn *new_nodes;
    int num_nodes = LengthNodeList_bn (nodes);
    if (num_nodes == 0)  return nodes;     /* otherwise next line will fail */
    net = GetNodeNet_bn (NthNode_bn (nodes, 0));
    scratch_net = NewNet_bn ("temp", env);
    new_nodes = TransferNodes (nodes, scratch_net);
    new_nodes = TransferNodes (new_nodes, net);
    FreeNodeList_bn (nodes);               /* because its full of invalid pointers */
    FreeNet_bn (scratch_net);
    return new_nodes;
}

/*____________________________________________________________________ NodeListToString
Returns a freshly allocated, null terminated, C char string containing
  the names of all the nodes in the passed list, separated by commas.
This may be useful during development / debugging.
Don't forget to free the string returned, using 'free'.
*/
#include

char *NodeListToString (const nodelist_bn *nodes){
    int nn, num_nodes = LengthNodeList_bn (nodes);
    char *str = malloc (num_nodes * (NAME_MAX_ns + 2) + 1);
    char *pstr = str;
    if (str == NULL)  return NULL;                           /* out of memory */
    for (nn = 0;  nn < num_nodes;  nn++){
        if (NthNode_bn (nodes, nn) != NULL){
            const char *node_name = GetNodeName_bn (NthNode_bn (nodes, nn));
            strcpy (pstr, node_name);
            pstr += strlen (node_name);
            }
        if (nn < num_nodes - 1)  {*pstr++ = ',';  *pstr++ = ' ';}
        }
    *pstr = '\0';                                            /* null terminate */
    return str;
}



 

Contact

© 2014 Tous droits réservés.

Créer un site internet gratuitWebnode