• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Directed Graph

Status
Not open for further replies.
Level 31
Joined
Jul 10, 2007
Messages
6,306
Directed graph supporting both standard anonymous vertices and tabular keyed vertices with bitmask support along edges. Keyed breadth-first iterator support with correct expansion behavior. Phase 1 in compiler construction.



Example
Java:
   public static void main(String[] args)
{
   int privateAccessModifier = 0b11;
   int protectedAccessModifier = 0b10;
   int publicAccessModifier = 0b00;

   int scopeEdge = 0b001;
   int inheritanceEdge = 0b010;
   int symbolEdge = 0b100;

   Graph<Integer, Integer> graph = new Graph();
   Vertex<Integer, Integer> root = graph.getRoot();


   /*
            9 {
               private 10
               public 11
            }
            1 {
               private 2
               public 3
               public 4 extends public 9 {
                  private 8
                  private {
                     private 5
                     public 6
                     public 7
                  }
               }
            }
    */

   // searching for 11
   // our origin is 4
   // only search symbol edges

   Vertex<Integer, Integer>[] vertex = new Vertex[12];

   vertex[0] = new Vertex<Integer, Integer>(null, null);

   for (int i = 1; i <= 11; ++i)
   {
      vertex[i] = new Vertex<Integer, Integer>(i, i);
   }

   vertex[0].addExplicitEdge(symbolEdge, privateAccessModifier, publicAccessModifier, vertex[5]);
   vertex[0].addExplicitEdge(symbolEdge, publicAccessModifier, publicAccessModifier, vertex[6]);
   vertex[0].addExplicitEdge(symbolEdge, publicAccessModifier, publicAccessModifier, vertex[7]);
   vertex[0].addImplicitEdge(scopeEdge, privateAccessModifier, privateAccessModifier, vertex[4]);

   vertex[4].addExplicitEdge(symbolEdge, privateAccessModifier, publicAccessModifier, vertex[0]);
   vertex[4].addExplicitEdge(symbolEdge, privateAccessModifier, publicAccessModifier, vertex[8]);
   vertex[4].addImplicitEdge(scopeEdge, privateAccessModifier, privateAccessModifier, vertex[1]);
   vertex[4].addExplicitEdge(symbolEdge | scopeEdge | inheritanceEdge, publicAccessModifier, protectedAccessModifier, vertex[9]);
   vertex[4].addImplicitEdge(scopeEdge | inheritanceEdge, publicAccessModifier, protectedAccessModifier, vertex[9]);

   vertex[9].addExplicitEdge(symbolEdge, privateAccessModifier, publicAccessModifier, vertex[10]);
   vertex[9].addExplicitEdge(symbolEdge, publicAccessModifier, publicAccessModifier, vertex[11]);
   vertex[9].addImplicitEdge(scopeEdge, privateAccessModifier, privateAccessModifier, root);

   vertex[1].addExplicitEdge(symbolEdge, privateAccessModifier, publicAccessModifier, vertex[2]);
   vertex[1].addExplicitEdge(symbolEdge, publicAccessModifier, publicAccessModifier, vertex[3]);
   vertex[1].addExplicitEdge(symbolEdge | scopeEdge, publicAccessModifier, publicAccessModifier, vertex[4]);
   vertex[1].addImplicitEdge(scopeEdge, privateAccessModifier, privateAccessModifier, root);

   root.addExplicitEdge(symbolEdge | scopeEdge, publicAccessModifier, publicAccessModifier, vertex[1]);
   root.addExplicitEdge(symbolEdge | scopeEdge, publicAccessModifier, publicAccessModifier, vertex[9]);

   Graph.Iterator<Integer, Integer> iterator = new Graph.Iterator<>(symbolEdge, 0, vertex[4], 11);
   Graph.Iterator.Match<Integer, Integer> bestMatch = null;
   Graph.Iterator.Match<Integer, Integer> currentMatch;

   /*


            BRB

    */


   // a.b.c
   while (iterator.hasNext() && (bestMatch == null || !bestMatch.isLegal() || bestMatch.getDistance() > 0))
   {
      currentMatch = iterator.next();

      if (currentMatch != null && !currentMatch.getEdge().isImplicit() && currentMatch.getDistance() >= 0 && (bestMatch == null || (currentMatch.getDistance() > bestMatch.getDistance() && (bestMatch.isLegal() || !currentMatch.isLegal()))))
      {
         bestMatch = currentMatch;
      }
   }

   System.out.println(String.valueOf(bestMatch.getEdge().getDestination().getValue()) + " " + bestMatch.isLegal());
   }



Java:
package com.nes.sym.graph;

import java.util.*;

// anonymous edges ALWAYS require bitmask
// keyed do not require bitmask for iterator or search
// for search, find the BEST match
// any legal match is better than an illegal match, but an illegal match due to insufficient bitmask is better than nothing

public class Graph<K extends Comparable, V>
{
   private Vertex<K, V> root;

   public Graph()
   {
      root = new Vertex<K, V>(null, null);
   }

   public Vertex<K, V> getRoot()
   {
      return root;
   }

   // between each search, need to store the privileges by the new origin
   // whenever a new origin is returned, check if that origin already exists and use the privileges
   // that were previously assigned to that origin if it does already exist
   // this is to prevent privileges from being stripped when they shouldn't be
   // single search is ok. Multi-search requires history.
   public static class Iterator<K extends Comparable, V> implements java.util.Iterator
   {
      @Override
      public void remove()
      {

      }

      public static class SearchResult<K extends Comparable, V>
      {
         private Stack<Match<K, V>> matches;
         private Map<Vertex<K, V>, Integer> maskTable;

         public SearchResult()
         {
            matches = new Stack<>();
            maskTable = new HashMap<>();
         }

         public Stack<Match<K, V>> getMatches()
         {
            return matches;
         }

         public Map<Vertex<K, V>, Integer> getMaskTable()
         {
            return maskTable;
         }
      }

      public SearchResult<K, V> search(int edgeTypeMask, int bitmask, Vertex<K, V> origin, Collection<K> keys)
      {
         Graph.Iterator<Integer, Integer> iterator = new Graph.Iterator<>(symbolEdge, 0, vertex[4], 11);
         Graph.Iterator.Match<Integer, Integer> bestMatch = null;
         Graph.Iterator.Match<Integer, Integer> currentMatch;

         SearchResult<K, V> searchResult = new SearchResult<>();
         searchResult.getMaskTable().put(origin, bitmask);

         for (K key : keys)
         {

         }

         // a.b.c
         while (iterator.hasNext() && (bestMatch == null || !bestMatch.isLegal() || bestMatch.getDistance() > 0))
         {
            currentMatch = iterator.next();

            if (currentMatch != null && !currentMatch.getEdge().isImplicit() && currentMatch.getDistance() >= 0 && (bestMatch == null || (currentMatch.getDistance() > bestMatch.getDistance() && (bestMatch.isLegal() || !currentMatch.isLegal()))))
            {
               bestMatch = currentMatch;
            }
         }

         System.out.println(String.valueOf(bestMatch.getEdge().getDestination().getValue()) + " " + bestMatch.isLegal());
      }

      public static class Match<K extends Comparable, V>
      {
         private int bitmask;
         private boolean legal;
         private int distance;
         private Edge<K, V> edge;

         public void setBitmask(int bitmask)
         {
            this.bitmask = bitmask;
         }

         public int getBitmask()
         {
            return bitmask;
         }

         public boolean isLegal()
         {
            return legal;
         }

         public void isLegal(boolean legality)
         {
            this.legal = legality;
         }

         public void setDistance(int distance)
         {
            this.distance = distance;
         }

         public int getDistance()
         {
            return distance;
         }

         public void setEdge(Edge<K, V> edge)
         {
            this.edge = edge;
         }

         public Edge<K, V> getEdge()
         {
            return edge;
         }

         @Override
         public Match<K, V> clone()
         {
            Match<K, V> match = new Match<>();

            match.bitmask = bitmask;
            match.legal = legal;
            match.distance = distance;
            match.edge = edge;

            return match;
         }
      }

      public static class Path<K extends Comparable, V>
      {
         private Collection<Edge<K, V>> frontier;
         private int bitmask;

         public Collection<Edge<K, V>> getFrontier()
         {
            return frontier;
         }

         public void setFrontier(Collection<Edge<K, V>> frontier)
         {
            this.frontier = frontier;
         }

         public int getBitmask()
         {
            return bitmask;
         }

         public void setBitmask(int bitmask)
         {
            this.bitmask = bitmask;
         }
      }

      private Match<K, V> match;
      private Collection<Path<K, V>> frontier;
      private java.util.Iterator<Path<K, V>> frontierPathIterator;
      private java.util.Iterator<Edge<K, V>> frontierEdgeIterator;

      private Path<K, V> currentPath;

      private K key;
      private int edgeTypeMask;

      public Iterator(int edgeTypeMask, int bitmask, Vertex<K, V> origin, K key)
      {
         this.key = key;
         this.edgeTypeMask = edgeTypeMask;

         match = new Match<>();
         match.setBitmask(bitmask);
         match.setDistance(-1);
         match.isLegal(false);
         match.setEdge(null);

         frontier = new LinkedList<>();
         Path<K, V> path = new Path<>();
         path.setBitmask(bitmask);
         path.setFrontier(new LinkedList<>());
         frontier.add(path);

         origin.getEdges(key, path.getFrontier());
         origin.getEdges(origin, bitmask, path.getFrontier());

         frontierPathIterator = frontier.iterator();
         currentPath = frontierPathIterator.next();
         frontierEdgeIterator = currentPath.getFrontier().iterator();
      }

      private boolean nextEdge()
      {
         Edge<K, V> edge;
         int distance;
         boolean search = true;

         while (frontierEdgeIterator.hasNext() && search)
         {
            edge = frontierEdgeIterator.next();

            if ((edge.getEdgeTypeMask() & this.edgeTypeMask) == edge.getEdgeTypeMask())
            {
               if (edge.isImplicit())
               {
                  match.setEdge(edge);
                  match.setBitmask(currentPath.getBitmask());
                  match.isLegal(true);
                  match.setDistance(-1);

                  search = false;
               }
               else
               {
                  distance = edge.getDestination().getKey().compareTo(key);

                  if (distance >= 0)
                  {
                     match.setEdge(edge);
                     match.setBitmask(currentPath.getBitmask());
                     match.isLegal(edge.canCross(currentPath.getBitmask()));
                     match.setDistance(distance);

                     search = false;
                  }
               }
            }
         }

         return !search;
      }

      private void expandFrontier()
      {
         Collection<Path<K, V>> nextFrontier = new LinkedList<>();
         Path<K, V> nextPath;

         for (Path<K, V> path : frontier)
         {
            for (Edge<K, V> edge : path.getFrontier())
            {
               if (edge.isImplicit() && (edge.getEdgeTypeMask() & this.edgeTypeMask) == edge.getEdgeTypeMask())
               {
                  nextPath = new Path<>();

                  nextPath.setFrontier(new LinkedList<>());
                  nextPath.setBitmask(edge.cross(path.getBitmask()));

                  // nextPath.getBitmask is the calculated bitmask as a result of crossing the edge
                  edge.getDestination().getEdges(key, nextPath.getFrontier());
                  edge.getDestination().getEdges(edge.getOrigin(), nextPath.getBitmask(), nextPath.getFrontier());

                  if (!nextPath.getFrontier().isEmpty())
                  {
                     nextFrontier.add(nextPath);
                  }
               }
            }
         }

         frontier = nextFrontier;
         frontierPathIterator = frontier.iterator();
      }

      private void nextPath()
      {
         if (!frontierPathIterator.hasNext())
         {
            expandFrontier();

            if (frontierPathIterator.hasNext())
            {
               currentPath = frontierPathIterator.next();
               frontierEdgeIterator = currentPath.getFrontier().iterator();
            }
            else
            {
               currentPath = null;
            }
         }
         else
         {
            currentPath = frontierPathIterator.next();
            frontierEdgeIterator = currentPath.getFrontier().iterator();
         }
      }

      public Match<K, V> next()
      {
         boolean foundMatch = false;

         while (hasNext() && !(foundMatch = nextEdge()))
         {
            nextPath();
         }

         return foundMatch? match.clone() : null;
      }

      public boolean hasNext()
      {
         return !frontier.isEmpty();
      }
   }
}

Java:
package com.nes.sym.graph;

import java.util.*;

public class Vertex<K extends Comparable,  V>
{
   private Collection<Edge<K, V>> edgeCollection;
   private Map<K, Collection<Edge<K, V>>> edgeMap;

   private final Collection<Edge<K, V>> empty = new Vector<Edge<K, V>>(0);

   private final K key;
   private final V value;

   public Vertex(K key, V value)
   {
      edgeCollection = new LinkedList<Edge<K, V>>();
      edgeMap = new HashMap<K, Collection<Edge<K, V>>>();

      this.key = key;
      this.value = value;
   }

   public K getKey()
   {
      return key;
   }
   public V getValue() { return value; }

   public void getEdges(Vertex<K, V> origin, int bitmask, Collection<Edge<K, V>> edges)
   {
      for (Edge<K, V> edge : edgeCollection)
      {
         if (edge.canCross(bitmask) && !origin.equals(edge.getDestination()))
         {
            edges.add(edge);
         }
      }
   }

   public void getEdges(K key, Collection<Edge<K, V>> edges)
   {
      if (key != null)
      {
         edges.addAll(edgeMap.getOrDefault(key, empty));
      }
   }

   public void addExplicitEdge(int edgeTypeMask, int requiredBitMask, int assignedBitMask, Vertex<K, V> vertex)
   {
      if (vertex.key != null)
      {
         Collection<Edge<K, V>> edges = edgeMap.getOrDefault(vertex.key, null);

         if (edges == null)
         {
            edges = new LinkedList<>();
            edgeMap.put(vertex.key, edges);
         }

         edges.add(new Edge<K, V>(edgeTypeMask, false, requiredBitMask, assignedBitMask, this, vertex));
      }
   }

   public void addImplicitEdge(int edgeTypeMask, int requiredBitMask, int assignedBitMask, Vertex<K, V> vertex)
   {
      edgeCollection.add(new Edge<K, V>(edgeTypeMask, true, requiredBitMask, assignedBitMask, this, vertex));
   }
}

Java:
package com.nes.sym.graph;

/**
* Created by nessy on 5/29/2017.
*/
public class Edge<K extends Comparable, V>
{
   private final int requiredBitMask;
   private final int assignedBitMask;
   private final boolean implicit;
   private final Vertex<K, V> origin;
   private final Vertex<K, V> destination;
   private final int edgeTypeMask;

   public Edge(int edgeTypeMask, boolean implicit, int requiredBitmask, int assignedBitMask, Vertex<K, V> origin, Vertex<K, V> destination)
   {
      this.requiredBitMask = requiredBitmask;
      this.assignedBitMask = assignedBitMask;

      this.implicit = implicit;

      this.origin = origin;
      this.destination = destination;
      this.edgeTypeMask = edgeTypeMask;
   }

   public boolean canCross(int bitmask)
   {
      return (bitmask & requiredBitMask) == requiredBitMask;
   }

   public int cross(int bitmask)
   {
      return bitmask & assignedBitMask;
   }

   public int getEdgeTypeMask()
   {
      return edgeTypeMask;
   }

   public Vertex<K, V> getOrigin()
   {
      return origin;
   }

   public Vertex<K, V> getDestination()
   {
      return destination;
   }

   public boolean isImplicit()
   {
      return implicit;
   }
}
 
Last edited:
Status
Not open for further replies.
Top