001package org.biopax.paxtools.query.algorithm; 002 003 004import org.biopax.paxtools.query.model.GraphObject; 005import org.biopax.paxtools.query.model.Node; 006 007import java.util.HashMap; 008import java.util.HashSet; 009import java.util.Map; 010import java.util.Set; 011 012/** 013 * Finds the paths from a specified source set of states or entities to a 014 * specified target set of states or entities within the boundaries of a 015 * specified length limit. Takes source set, target set, type of distance 016 * limit, distance limit and strict value. Based on these parameters, the 017 * interactions within source set and within target set may be omitted and/or 018 * "shortest+k" may be used as length limit. 019 * 020 * @author Ozgun Babur 021 * @author Merve Cakir 022 */ 023public class PathsFromToQuery 024{ 025 /** 026 * The set of nodes from which the paths of interests should start. 027 */ 028 private Set<Node> sourceSet; 029 030 /** 031 * The set of nodes to which the paths of interests should arrive. 032 */ 033 private Set<Node> targetSet; 034 035 /** 036 * True if length limit is used, false if shortes+k is used. 037 */ 038 private LimitType limitType; 039 040 /** 041 * Based on the limitType, given integer may be used directly as stop 042 * distance or may be added up with the shortest path's length and used as 043 * stop distance. 044 */ 045 private int stopDistance; 046 047 /** 048 * When true, the interactions within source set and within target set are 049 * not involved in result set. 050 */ 051 private boolean strict; 052 053 /** 054 * This is a hard-coded limit to use with the shortest_plus_k limit. If there is no shortest 055 * path between the given nodes, the algorithm should not try to traverse all the graph. So this 056 * shortest path search limit will make sure that the algorithm will not search for indefinitely 057 * for the shortest path. 058 */ 059 private static final int LIMIT_FOR_SP_SEARCH = 25; 060 061 /** 062 * Constructor with parameters. 063 * @param sourceSet source set 064 * @param targetSet target set 065 * @param limitType normal limit or shortest + k type limit 066 * @param stopDistance search limit 067 * @param strict whether we want to extend and result path towards other source and targets 068 */ 069 public PathsFromToQuery(Set<Node> sourceSet, 070 Set<Node> targetSet, 071 LimitType limitType, 072 int stopDistance, 073 boolean strict) 074 { 075 assert limitType != null : "limitType should be specified"; 076 077 this.sourceSet = sourceSet; 078 this.targetSet = targetSet; 079 this.limitType = limitType; 080 this.stopDistance = stopDistance; 081 this.strict = strict; 082 } 083 084 /** 085 * Executes the algorithm. 086 * @return paths from sources to targets 087 */ 088 public Set<GraphObject> run() 089 { 090 /** 091 * Candidate contains all the graph objects that are the results of BFS. 092 * Eliminating nodes from candidate according to their labels will 093 * yield result. 094 */ 095 Map<GraphObject, Integer> candidate = new HashMap<GraphObject, Integer>(); 096 Set<GraphObject> result = new HashSet<GraphObject>(); 097 098 BFS bfsFwd = null; 099 BFS bfsRev = null; 100 101 if (limitType == LimitType.NORMAL && !strict) 102 { 103 bfsFwd = new BFS(sourceSet, null, Direction.DOWNSTREAM, stopDistance); 104 bfsRev = new BFS(targetSet, null, Direction.UPSTREAM, stopDistance); 105 } 106 else if (limitType == LimitType.NORMAL && strict) 107 { 108 bfsFwd = new BFS(sourceSet, targetSet, Direction.DOWNSTREAM, stopDistance); 109 bfsRev = new BFS(targetSet, sourceSet, Direction.UPSTREAM, stopDistance); 110 } 111 else if (limitType == LimitType.SHORTEST_PLUS_K && !strict) 112 { 113 bfsFwd = new BFS(sourceSet, null, Direction.DOWNSTREAM, LIMIT_FOR_SP_SEARCH); 114 bfsRev = new BFS(targetSet, null, Direction.UPSTREAM, LIMIT_FOR_SP_SEARCH); 115 } 116 else if (limitType == LimitType.SHORTEST_PLUS_K && strict) 117 { 118 bfsFwd = new BFS(sourceSet, targetSet, Direction.DOWNSTREAM, LIMIT_FOR_SP_SEARCH); 119 bfsRev = new BFS(targetSet, sourceSet, Direction.UPSTREAM, LIMIT_FOR_SP_SEARCH); 120 } 121 122 candidate.putAll(bfsFwd.run()); 123 candidate.putAll(bfsRev.run()); 124 125 int limit = stopDistance; 126 127 if(limitType == LimitType.NORMAL) 128 { 129 /** 130 * Only the graph objects whose sum of two search labels being 131 * smaller than or equal to the distance limit will be in the result. 132 */ 133 for (GraphObject go : candidate.keySet()) 134 { 135 if ((bfsFwd.getLabel(go) + bfsRev.getLabel(go)) <= limit) 136 { 137 result.add(go); 138 } 139 } 140 } 141 else 142 { 143 int shortestPath = Integer.MAX_VALUE; 144 145 /** 146 * Summing up the labels of two search will give the length of the 147 * path that passes through that particular graph object and the 148 * minimum of those lengths will be the length of the shortest path. 149 */ 150 for (GraphObject go : candidate.keySet()) 151 { 152 if ((bfsFwd.getLabel(go) + bfsRev.getLabel(go)) <= shortestPath) 153 { 154 shortestPath = (bfsFwd.getLabel(go) + bfsRev.getLabel(go)); 155 } 156 } 157 158 limit = shortestPath + stopDistance; 159 160 // Proceed only if there is a shortest path found 161 162 if (shortestPath < Integer.MAX_VALUE / 2) 163 { 164 /** 165 * Only the graph objects whose sum of two search labels being 166 * smaller than or equal to the "shortest + limit" will be in the 167 * result. 168 */ 169 for (GraphObject go : candidate.keySet()) 170 { 171 if ((bfsFwd.getLabel(go) + bfsRev.getLabel(go)) <= limit) 172 { 173 result.add(go); 174 } 175 } 176 } 177 } 178 179 Set<Node> ST = new HashSet<Node>(sourceSet); 180 ST.addAll(targetSet); 181 182 CycleBreaker breaker = new CycleBreaker(result, ST, limit); 183 breaker.breakCycles(); 184 185 Prune prune = new Prune(result, ST); 186 prune.run(); 187 188 return result; 189 } 190}