Tag Archives: Human nature

Adding human nature to code: ego, emotions, luck, purpose, relationships and dreaming

3 Jul

The heuristic part of the A* Search algorithm guides the code to make choices that will lead it to the cheapest path to the goal. Code that has a human to guide it will increase the chances the code will make choices that will lead it to the correct solution. Making the code as human-like as possible by adding human nature to the code will give the code human-like awareness while making choices while solving problems.

“Can code make choices that are always correct?  Can the code be made lucky?”  The answer is, no, but the code’s chances of making the correct choices can be increased by making the code as human-like as possible, assuming the human-like qualities given to the code aren’t based on an unlucky person.  A lucky person creates his own luck by maximizing the positive aspects of human nature as described in the following sections in this post: Ego, Emotions, Luck, Purpose, Relationships and Dreaming.

Ego
Sense of self: Code maintains an internal model that represents the machine’s place in the world. A model of the world is easier to examine and alter than the actual world the code is in. Sense of self is constantly changing as the world around the machine changes which affects the choices the code makes when solving problems. Allow the code to learn from new environments as they happen. To allow the code to learn from new environments as they happen, use online machine learning. This will let new data to be added to the existing machine learning model instead of throwing out the model then relearning everything again.

For example, the method feedCodesEgo in the code listed below sets up the graph data structure, the code’s internal model of the world.

Emotion
Keep the code happy by eliminating invalid states. Invalid states = conflict = unhappy emotion. Eliminating invalid states makes the code easier to solve. Use Boolean Satisfiability Solvers or Bloom Filters to filter out invalid states so the code makes only choices that are influenced by happy emotions. See Purpose below.

For example, the method makeCodeHappy in the code listed below keeps the code happy by avoiding burned out cities in the graph data structure.

Luck
Ideally the code will make a choice that is always correct. To have the code determine which choice has the greatest chance of being part of the solution, calculate Naive Bayes probabilities. Examining only the choices that are more likely to solve the problem is easier than examining every choice in the problem.

For example, the method makeCodeLucky in the code listed below makes the code lucky by calling method SetUpDataSet to learn the features of the cities in the graph data structure so Naive Bayes probabilities can be calculated. The code determines what category a city in the graph is in (car-friendly, pedestrian-friendly, etc.) by assigning a city to a category that has the highest probability of being that type of city based on the city’s features.

Improve the code’s luck

Markov Decision Processes (MDP): use to represent internal hidden interactions with states and probabilities that reveal the intermediate interactions with the world. Use MDP so the code can be aware that its choices affect not only the system that it is in, but also the outside world. The world only sees the beginning and ending interactions with the code (the final result), not the hidden internal interactions / states with the code and the world. Just like how people only see what we choose to reveal to them, not our private thoughts. Use Markov Decision Processes to find not just the best journey from the Beginning to the End, but the best journey from the Beginning through intermediate states to the End so the effect of hidden intermediate interactions are taken into account.

Different situations (work vs. social vs. private) = different internal hidden interactions with the world. How someone chooses to interact with the world depends on the situation the person is in. How we react to someone socially is different than how we react in a work situation. Maintain the changes made to the code’s way ot interacting with the external world with a changing internal representation of the world so the code can make different choices depending on the situation it is in.

Purpose
Just like people, code needs a goal and an understanding of the word; otherwise, no purpose or point in attempting to solve the problem. Having a purpose makes the problem easier to solve by examining only some of the choices, instead all of the choices in the problem.
The code can’t go through its life as a partially created person; otherwise, a dysfunctional behavior in code would result. The code needs all human traits using different techniques so the code can make the choices that will lead it to the solution of a problem.

For example, the method giveCodePurpose in the code listed below gives the code a new purpose in life: try to reach city 8.

Traits: Does the code choose to be greedy (greedy algorithms) or patient enough to see if there is a better solution (knapsack algorithm)?

For example, the method BFS in the code listed below is neither greedy or patient, it is biased. It treats all cities around the current node in the search differently depending on whether or not the city is probably the type of city that the code is searching for.

Paradigm: The model of the sub goal’s world that give direction to the goal. Since a person’s view of the world should not be not rigid throughout life, neither should the code’s or the choices the code makes. Use online machine learning so the sub goal’s model improves over time. Online machine learning allows a model to learn in just one forward pass and one backward pass so it’s efficient for paradigms to change.

Changing paradigms affect emotion: When a sub goal is in its own world it can’t see the overall goal (missing the forest for the trees). Use pre-determined points / conditions in the problem for sub goals to hook into the model for guidance in making choices that will lead it to the goal. See Relationships below. This influences the emotional arc of the code’s existence / the changing definition of what is an invalid state.

For example, the method maintainCodesRelationships in the code listed below lets the sub goal know that a city in the graph data structure is now burned out. Burned out cities make the code unhappy (invalid conditions = conflict) so a new route must be calculated around those cities to make the code happy again.

Can’t force people to change: There has to be an incident that makes people want to change, the same is true of code. Need to define conditions in a sub goal’s model that causes it to choose to change its model of the goal. Example- there hasn’t been any progress in the sub goal in reaching the goal or the sub goal’s calculations are getting worse at modeling the goal. Use online machine learning to determine if a sub goal can’t reach its goal if it continues as it is. This will force the code to change its plan / model on how to reach the goal.

The code’s life is a series of sequences leading to a goal. Break goal up into sub goals that are easier to model and solve. However, each sub goal isn’t always a smaller, easier to solve version of the overall goal just like life isn’t a sequence of challenges where everything goes your way. Each sub goal could be a different scenario that helps or sets the sub goal back from reaching its goal. If the sub goal is set back from reaching its goal, then it learns to make choices to prevent the setback from happening again. A scenario either contributes to the goal or proves that the scenario doesn’t help solve the goal. See Dreaming below.

For example, the method letCodeDream in the code listed below lets the sub goal imagine then trying unsuccessfully to reach city 7 by unicycle instead of by car. This sequence sets the code back from reaching its goal, but it doesn’t stop the code from trying to reach its goal.

Relationships
Hermit code doesn’t do as well as code that communicates with other code. Need relationships between the sub goals and the goal to unify what the sub goals are trying to achieve so they can make the correct choices. Actors check with their agent to check if there is a better acting deal so have the sub goals check with their agent to see if there is a better model and possible solution of the problem that was learned by the other sub goals or if the definition of the problem has changed since the sub goal last checked with its agent. Examining only the choices that could lead to a better solution makes the problem easier to solve than examining all of the choices in the problem.

For example, the method maintainCodesRelationships in the code listed below lets the sub goal know that a city in the graph data structure is now burned out so a new route must be calculated.

Dreaming
Let the code dream of a new world. Create new data that represents an altered state of the sub goal then check if it creates a previously unknown choice that improves the chance of the code solving the problem. Examining a previously unknown choice makes the problem easier to solve by adding a choice that eliminates more than one choice in the problem. Use online machine learning to determine if the data representing the altered state of the sub goal can be added to the model or if the dream should be rejected as not being useful in reaching the goal.

For example, the method letCodeDream in the code listed below lets the sub goal imagine then trying to reach city 7 by unicycle instead of by car.

THE CODE

The code below traverses a directed graph using breadth first search. While traversing the graph, Naive Bayes probabilities are used to determine what category a node is in by assigning a node to a class that has the maximum probability which is computed as:
P(f|c)P(c)
where f = feature of the node
c = category
If a node does not belong to the desired category, then ignore that node during the search. This results in traversing only those nodes with the highest probability of being a node with the desired category.

Output of code:
Fed the code’s ego by creating a model of its world.
Code is now happy by avoiding burned-out cities.
Code is now lucky by learning the cities’ features.
Car-friendly cities: 2 4 (Avoiding burned-out city 6) 5 7
Change in purpose: try to reach city 8.
Car-friendly cities: 2 4 (Avoiding burned-out city 6) 5 7 8
Maintain code’s relationships. Result: now know city 7 is burned-out.
Car-friendly cities: 2 4 (Avoiding burned-out city 6) 5 (Avoiding burned-out city 7)
Can no longer reach city 8 because city 7 is now burned out
Code is dreaming of changing city 5 to a unicycle-friendly city so it can reach city 7 by unicycle
Car-friendly cities: 2 4 (Avoiding burned-out city 6) (Avoiding burned-out city 7)
Pedestrian-friendly cities: 1 3
Even with a unicycle-friendly city on the way to city 7, still can’t reach city 7
Code is waking up from the dream.
Car-friendly cities: 2 4 (Avoiding burned-out city 6) 5 (Avoiding burned-out city 7)
Pedestrian-friendly cities: 1 3

using System;
using System.Collections.Generic;

namespace HappyLuckyCode
{
    class Program
    {
        static void Main(string[] args)
        {
        CityGraph graph = new CityGraph(10);
        feedCodesEgo(ref graph);
        makeCodeHappy(ref graph);
        makeCodeLucky(ref graph);

        int desiredCategory = 1;    // Search only for car-friendly cities
        Console.Write("Car-friendly cities: ");
        graph.BFS(desiredCategory);
        Console.WriteLine();

        giveCodePurpose(ref graph);

        Console.Write("Car-friendly cities: ");
        graph.BFS(desiredCategory);
        Console.WriteLine();

        maintainCodesRelationships(ref graph);

        Console.Write("Car-friendly cities: ");
        graph.BFS(desiredCategory);
        Console.WriteLine();
        Console.WriteLine("Can no longer reach city 8 because city 7 is now burned out");

        letCodeDream(ref graph);

        Console.Write("Car-friendly cities: ");
        graph.BFS(desiredCategory);
        Console.WriteLine();
        Console.Write("Pedestrian-friendly cities: ");
        desiredCategory = 0;        // Search only for pedestrian-friendly cities
        graph.BFS(desiredCategory);
        Console.WriteLine();            
        Console.WriteLine("Even with a unicycle-friendly city on the way to city 7, still can't reach city 7");

        codeStopsDreaming(ref graph);

        Console.Write("Car-friendly cities: ");
        desiredCategory = 1;    // Search only for car-friendly cities
        graph.BFS(desiredCategory);
        Console.WriteLine();

        Console.Write("Pedestrian-friendly cities: ");
        desiredCategory = 0;        // Search only for pedestrian-friendly cities
        graph.BFS(desiredCategory);
        Console.WriteLine();
    }

    static void makeCodeHappy(ref CityGraph graph)
    {
        const bool NO_FEATURE = false;

        // Avoid burned-out cities
        graph.citiesToAvoid(new bool[] {NO_FEATURE,NO_FEATURE,NO_FEATURE,NO_FEATURE});
        Console.WriteLine("Code is now happy by avoiding burned-out cities.");
    }

    static void makeCodeLucky(ref CityGraph graph)
    {
        graph.SetUpDataSet();
        Console.WriteLine("Code is now lucky by learning the cities' features.");
    }

    static void feedCodesEgo(ref CityGraph graph)
    {
        // Feed the code's ego by setting up the nodes of the world.
        // Set up a the graph where each node represents a city.
        // Each city can have up to four features:  WALKWAYS, BIKEPATHS, PARKS, TAXIS.

        const bool WALKWAYS = true, BIKEPATHS = true, PARKS = true, TAXIS = true;
        const bool NO_FEATURE = false;

        // Pedestrian-friendly:    {WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE}});     
        // Car-friendly:        {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}
        // Burned out:        {NO_FEATURE,NO_FEATURE,NO_FEATURE,NO_FEATURE}
        graph.addEdge(0, new NodeData { Id=1, features = new bool[] {WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE}});    
        graph.addEdge(0, new NodeData { Id=2, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}});       
        graph.addEdge(1, new NodeData { Id=3, features = new bool[] {WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE}});
        graph.addEdge(2, new NodeData { Id=4, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}});
        graph.addEdge(2, new NodeData { Id=6, features = new bool[] {NO_FEATURE,NO_FEATURE,NO_FEATURE,NO_FEATURE}});
        graph.addEdge(4, new NodeData { Id=5, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}});
        graph.addEdge(4, new NodeData { Id=7, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}}); // originally car-friendly
        graph.addEdge(3, new NodeData { Id=5, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}});
        graph.addEdge(6, new NodeData { Id=7, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}}); // originally car-friendly
        graph.addEdge(5, new NodeData { Id=7, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}}); // originally car-friendly
        Console.WriteLine("Fed the code's ego by creating a model of its world.");
    }

    static void giveCodePurpose(ref CityGraph graph)
    {
        const bool WALKWAYS = true, BIKEPATHS = true, PARKS = true, TAXIS = true;
        const bool NO_FEATURE = false;

        graph.addEdge(7, new NodeData { Id=8, features = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS}});
        Console.WriteLine("Change in purpose: try to reach city 8.");
    }

    static void maintainCodesRelationships(ref CityGraph graph)
    {
        // Model is updated to reflect that city 7 is now burned-out

        graph.changeFeaturesOfCity7();
        Console.WriteLine("Maintain code's relationships.  Result: now know city 7 is burned-out.");
    }

    static void letCodeDream(ref CityGraph graph)
    {
        // Code detetermines if a unicycle-friendly city on the way
        // to city 7 allows city 7 to be reached.

        Console.WriteLine("Code is dreaming of changing city 5 to a unicycle-friendly city so it can reach city 7 by unicycle");

        // The end result is shown below.  To determine what to change
        // in the dream, look at the features of a city and determine
        // what features could be changed.

        graph.changeFeaturesOfCity5();
    }

    static void codeStopsDreaming(ref CityGraph graph)
    {
        // Change the features of city 5 back to what it was before dreaming

        Console.WriteLine("Code is waking up from the dream.");
        graph.stopDreamingOfCity5();
    }
}

// Each node has an id and an array of features
struct NodeData
{
    public int Id { get; set; }
    public bool[] features { get; set; }
}

// Use an adjacency list to represent the connections to the nodes in the graph.
class CityGraph
{
    const bool WALKWAYS = true, BIKEPATHS = true, PARKS = true, TAXIS = true;
    const bool NO_FEATURE = false;
    const int NUMBER_OF_FEATURES = 4;

     int[,] SummaryOfData = new int[4,5];

    private int numberOfNodes;
    private List<NodeData>[] adj;
    private bool[] featuresToAvoid;

    public CityGraph(int maxNum)
    {
        numberOfNodes = maxNum;
        adj = new List<NodeData>[maxNum];
        for (int i = 0; i < maxNum; i++)
            adj[i] = new List<NodeData>();
    }

    public void addEdge(int vertex, NodeData adjacentNode)
    {
        adj[vertex].Add(adjacentNode);
    }

    public void stopDreamingOfCity5()
    {
        // Change city 5 back to a car-friendly city.
        // bool[] newFeatures = new bool[] {NO_FEATURE,BIKEPATHS,PARKS,TAXIS};
        // Same features as a pedestrian-friendly city.

        NodeData city = adj[4][0];  // The first city 4 leads to is city 5
        adj[4][0].features[0] = NO_FEATURE;
        adj[4][0].features[1] = BIKEPATHS;
        adj[4][0].features[2] = PARKS;
        adj[4][0].features[3] = TAXIS;
    }

    public void changeFeaturesOfCity5()
    {
        // Change city 5 from a car-friendly city to a Unicycle-friendly city.            //
        // bool[] newFeatures = new bool[] {WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE};
        // Same features as a pedestrian-friendly city.

        NodeData city = adj[4][0];  // The first city 4 leads to is city 5
        adj[4][0].features[0] = WALKWAYS;
        adj[4][0].features[1] = BIKEPATHS;
        adj[4][0].features[2] = PARKS;
        adj[4][0].features[3] = NO_FEATURE;
    }

    public void changeFeaturesOfCity7()
    {
        // Change city 7 to a burned out city so it has the following features:
        // bool[] newFeatures = new bool[] {NO_FEATURE,NO_FEATURE,NO_FEATURE,NO_FEATURE};

        NodeData city = adj[4][1];  // The second city 4 leads to is city 7
        bool[] cityFeatures = city.features;
        for (int i = 0; i < NUMBER_OF_FEATURES; i++)
        {
            adj[4][1].features[i] = NO_FEATURE;
        }
    }

    public void citiesToAvoid(bool[] features)
    {
        this.featuresToAvoid = features;
    }

    public bool[] getFeaturesToAvoid()
    {
        return this.featuresToAvoid;
    }

    // During the traversal, avoid nodes that have the probability of being not desirable. 
    public void BFS(int desiredCategory)
    {
        NodeData sourceNode;

        bool[] visited = new bool[numberOfNodes];
        for (int i = 0; i < numberOfNodes; i++)
            visited[i] = false;

        Queue<NodeData> q = new Queue<NodeData>();

        visited[0] = true;
        // Start at node 0
        q.Enqueue(new NodeData { Id=0, features = new bool[] {WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE}});

        while (q.Count > 0)
        {
            sourceNode = (NodeData)q.Peek();
            q.Dequeue();

            int skip = 0;
            bool[] cityFeatures = sourceNode.features;
            bool[] avoidFeatures = getFeaturesToAvoid();
            for (int i = 0; i < NUMBER_OF_FEATURES; i++)
            {
                if (cityFeatures[i] == avoidFeatures[i])
                {
                    skip++;
                }
            }

            // skip a city if all features are false
            if (skip == NUMBER_OF_FEATURES)
            {
                Console.Write("(Avoiding burned-out city {0}) ", sourceNode.Id);
                continue;
            }

            for (int i = 0; i < adj[sourceNode.Id].Count; i++)
            {
                NodeData adjacent = adj[sourceNode.Id][i];
                if (!visited[adjacent.Id])
                {
                    visited[adjacent.Id] = true;
                    // Avoid undesirable cities during the breadth first search.
                    int category = FindCategoryWithHighestProbability(desiredCategory, adjacent.features);
                    if (category != desiredCategory)
                        continue;

                    // Avoid unhappy cities
                    skip = 0;
                    avoidFeatures = getFeaturesToAvoid();
                    for (int ii = 0; ii < NUMBER_OF_FEATURES; ii++)
                    {
                        if (adjacent.features[ii] == avoidFeatures[ii])
                        {
                            skip++;
                        }
                    }

                    // skip a city if all features are false
                    if (skip == NUMBER_OF_FEATURES)
                    {
                        Console.Write("(Avoiding burned-out city {0}) ", adjacent.Id);
                        continue;
                    }
                    Console.Write("{0} ", adjacent.Id);
                    q.Enqueue(adjacent);
                }
            }
        }
    }

    public void SetUpDataSet()
    {
            // Simulate a survey was taken of 1700 cities to find what cities are friendly to
            // pedestrians, cars or unicycles.
            // The columns of the array represent features:
            // WALKWAYS, BIKEPATHS, PARKS, TAXIS, Category.
            int[,] Data = new int[1700,5];

            // Set up data for pedestrian-friendly cities
            // Features of pedestrian-friendly cities:  WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE
            int pedestrianCount = 0;
            int pedestrianWalkways = 0;
            int pedestrianBikepaths = 0;
            int pedestrianParks = 0;
            int pedestrianTaxis = 0;            
            for (int i = 0; i < 500; i++)
            {
                if (pedestrianWalkways < 450)   Data[i,0] = 1;
                if (pedestrianBikepaths < 350)  Data[i,1] = 1;
                if (pedestrianParks < 500)      Data[i,2] = 1;
                Data[i,3] = 0;
                Data[i,4] = 0;  // pedestian-friendly
                pedestrianWalkways++;
                pedestrianBikepaths++;
                pedestrianParks++;
                pedestrianTaxis++;
            }
            // Set up data for car-friendly cities
            // Features of pedestrian-friendly cities:  NO_FEATURE,BIKEPATHS,PARKS,TAXIS
            int carCount = 0;
            int carWalkways = 0;
            int carBikepaths = 0;
            int carParks = 0;
            int carTaxis = 0;
            for (int i = 500; i < 1500; i++)
            {
                Data[i,0] = 0;
                if (carBikepaths < 200)  Data[i,1] = 1;
                if (carParks < 300)      Data[i,2] = 1;
                if (carParks < 1000)      Data[i,3] = 1;
                Data[i,4] = 1;  // car-friendly
                carWalkways++;
                carBikepaths++;
                carParks++;
                carTaxis++;
            }
            // set up data for unicycle-friendly cities
            // Features of unicycle-friendly cities:  WALKWAYS,BIKEPATHS,PARKS,NO_FEATURE
            int unicycleCount = 0;
            int unicycleWalkways = 0;
            int unicycleBikepaths = 0;
            int unicycleParks = 0;
            int unicycleTaxis = 0;
            for (int i = 1500; i < 1700; i++)
            {
                if (unicycleWalkways < 150) Data[i,0] = 1;
                if (unicycleBikepaths < 200)  Data[i,1] = 1;
                if (unicycleParks < 50)      Data[i,2] = 1;
                Data[i,3] = 0;
                Data[i,4] = 2;  // unicycle-friendly
                unicycleWalkways++;
                unicycleBikepaths++;
                unicycleParks++;
                unicycleTaxis++;
            }

            // ================================================================
            // Create a summary of the data so probabilities can be calculated.
            // ================================================================

            // Get the counts of the features for pedestrian=friendly cities
            pedestrianCount = 0;
            pedestrianWalkways = 0;
            pedestrianBikepaths = 0;
            pedestrianParks = 0;
            pedestrianTaxis = 0;
            for (int i = 0; i < 1700; i++)
            {
                if (Data[i,4] == 0) // pedestrian-friendly city
                {
                    pedestrianCount++;
                    if (Data[i,0] == 1) pedestrianWalkways++;
                    if (Data[i,1] == 1) pedestrianBikepaths++;
                    if (Data[i,2] == 1) pedestrianParks++;
                    if (Data[i,3] == 1) pedestrianTaxis++;
                }
            }
            // Get the counts of the features for car=friendly cities
            carCount = 0;
            carWalkways = 0;
            carBikepaths = 0;
            carParks = 0;
            carTaxis = 0;            
            for (int i = 0; i < 1700; i++)
            {
                if (Data[i,4] == 1) // car-friendly city
                {
                    carCount++;
                    if (Data[i,0] == 1) carWalkways++;
                    if (Data[i,1] == 1) carBikepaths++;
                    if (Data[i,2] == 1) carParks++;
                    if (Data[i,3] == 1) carTaxis++;
                }
            }            
            // Get the counts of the features for unicycle=friendly cities
            unicycleCount = 0;
            unicycleWalkways = 0;
            unicycleBikepaths = 0;
            unicycleParks = 0;
            unicycleTaxis = 0;
            for (int i = 0; i < 1700; i++)
            {
                if (Data[i,4] == 2) // unicycle-friendly city
                {
                    unicycleCount++;
                    if (Data[i,0] == 1) unicycleWalkways++;
                    if (Data[i,1] == 1) unicycleBikepaths++;
                    if (Data[i,2] == 1) unicycleParks++;
                    if (Data[i,3] == 1) unicycleTaxis++;
                }
            }  
            

            // The first row of the array SummaryOfData shows that out of 500 pedestrian-friendly cities,
            //      450 of the 500 cities had walkways
            //      350 of the 500 cities had bike paths
            //      500 of the 500 cities had parks
            //      0 of the 500 cities had taxis
            SummaryOfData = new int[4,5]{
                {pedestrianWalkways,pedestrianBikepaths,pedestrianParks,pedestrianTaxis,pedestrianCount},    // first row:   class = pedestrian-friendly
                {carWalkways,carBikepaths,carParks,carTaxis,carCount},  // second row:  class = car-friendly
                {unicycleWalkways,unicycleBikepaths,unicycleParks,unicycleTaxis,unicycleCount},     // third row:   class = unicycle-friendly
                {pedestrianWalkways + carWalkways + unicycleWalkways,
                 pedestrianBikepaths + carBikepaths + unicycleBikepaths,
                 pedestrianParks + carParks + unicycleParks,
                 pedestrianTaxis + carTaxis + unicycleTaxis,
                 pedestrianCount + carCount + unicycleCount} // fourth row:  totals
            };
    }

    // The greatest probability determines the category the node is in.
    public int FindCategoryWithHighestProbability()
    {
            const bool WALKWAYS = true, BIKEPATHS = true, PARKS = true, TAXIS = true;
            float probability = 1.0F, maxProbability = 0.0F;
            int CategoryMaxProbability = -1;

            for (int i = 0; i < rows - 1; i++)
            {
                probability = 1.0F;
                for (int j = 0; j < cols - 1; j++)
                {
                    // Include a feature in the probability calculation
                    // only if the node has that feature.
                    if (features[j] == NO_FEATURE)                    
                        continue;
                    // P(f|c) - HOW OFTEN A FEATURE OCCURRED IN A CATEGORY OF CITY
                    if (desiredCategory == 0   // pedestrian-friendly cities
                        && (features[j] == WALKWAYS ||
                            features[j] == BIKEPATHS ||
                            features[j] == PARKS))
                        probability *= (float)SummaryOfData[i, j]/(float)SummaryOfData[i, cols-1];
                    
                    else if (desiredCategory == 1   // car-friendly cities
                        && (features[j] == TAXIS))
                        probability *= (float)SummaryOfData[i, j]/(float)SummaryOfData[i, cols-1];
                }
                // P(f|c)P(c) - HOW OFTEN A CATEGORY OCCURRED IN ALL CITIES
                probability *= (float)((float)SummaryOfData[i, cols-1] / (float)SummaryOfData[rows-1, cols-1]);
                if (probability > maxProbability)
                {
                    maxProbability = probability;
                    CategoryMaxProbability = i;
                }
            }
           
            return CategoryMaxProbability;
   }    
}

}