/*
 * For each label of the graph, we attach a list of s-root vertices to it, these vertices have no s-contained parents.
 */
void AdjacenceListsGRAPH_BOOST::buildLabelRootMap(AdjacenceListsGRAPH & graph){

	std::map<int,std::vector<int>> * labelVertexList = graph.getLabelVertexList();
	std::map<int,std::vector<int>> * labelContainmentRootList = graph.getLabelContainmentRootList();

	for(std::map<int,std::vector<int>>::iterator labelVertexIterator = labelVertexList->begin(); labelVertexIterator != labelVertexList -> end(); labelVertexIterator++){

		labelContainmentRootList->insert(std::pair<int, std::vector<int>>(labelVertexIterator->first,std::vector<int>()));
		std::map<int,std::vector<int>>::iterator newLabelContainmentRoots = labelContainmentRootList->find(labelVertexIterator->first);

		for(std::vector<int>::iterator vertexIterator = labelVertexIterator->second.begin(); vertexIterator != labelVertexIterator->second.end(); vertexIterator ++){
			if(graph.getVertexAddressByVertexId(*vertexIterator)->sIndegree != 0){
				continue;
			}
			newLabelContainmentRoots->second.push_back(*vertexIterator);
		}

	}
}
void CacheResultsTest::computeCLLRetrivingPerfor(int queryGraphId, std::vector<std::vector<CacheEmbeddingNode *>> * cachedLinkedLists, double *  linkedListRetriTime) {

	AdjacenceListsGRAPH * queryGraph = &(*queryGraphVector)[queryGraphId];

	comboVertexMapping = new CacheEmbeddingNode*[queryGraph->getComboGraph()->size()];
	for (int i = 0; i < queryGraph->getComboGraph()->size(); i++) {
		comboVertexMapping[i] = NULL;
	}

	TimeUtility llTime;
	llTime.StartCounterMill();
	CacheEmbeddingNode * comboVertexStarting = (*cachedLinkedLists)[queryGraphId][queryGraph->getDFSComboVertexOrder()->at(0)];
	while (comboVertexStarting != NULL) {
		comboVertexMapping[queryGraph->getDFSComboVertexOrder()->at(0)] = comboVertexStarting;
		recursiveEnumLinkedLists(1, queryGraph);
		comboVertexStarting = comboVertexStarting->adj;
	}
	(*linkedListRetriTime) += llTime.GetCounterMill();

	delete[] comboVertexMapping;
}
void TurboIsoBoostedMQO::execute() {
	// we precompuete a matching order here.
	computeMatchingOrder();

	if (jointNodeMatchingOrder.size() != jointGraph->jointNodes.size()) {
		/*
		* some joint node doesn't have any candidates
		*/
		return;
	}


	JointGraphNode & jointNode = jointGraph->jointNodes[jointNodeMatchingOrder[0].jointNodeId];

	if (jointNode.parentId != -1) {
		AdjacenceListsGRAPH * parentGraph = NULL;
		// the starting node represents a parent graph
		if (jointNode.parentId < queryGraphVector->size()) {
			parentGraph = &(*queryGraphVector)[jointNode.parentId];
		}
		else {
			parentGraph = &(*newlyGeneratedGraphVector)[jointNode.parentId - queryGraphVector->size()];
		}

		/*
		* enumerate the embeddings from the cache
		*/
		CacheRetrieval * cacheRetrieval = new CacheRetrieval(dataGraph, resultCaches);
		std::vector<std::vector<CacheEmbeddingNode *>> candidates;
		cacheRetrieval->retrieveEmbeddingCandidate(queryGraph, parentGraph, &jointNode, &jointNodeMatchingOrder[0], embedding, &inverseEmbedding, &candidates);

		cout << "Start from Parent, candidate size: " << candidates.size() << endl << endl;

		for (std::vector<std::vector<CacheEmbeddingNode *>>::iterator candidateIter = candidates.begin(); candidateIter != candidates.end(); candidateIter++) {
			if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
				needReturn = true;
				return;
			}

			map<int, int> updatedQueryVertexMap;
			for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) {
				if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
					needReturn = true;
					return;
				}

				// each combo node corresponding to cache embedding node which contains multiple matched data vertices
				ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId];
				for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) {

					int dataVertexId = (*candidateIter)[comboNodeId]->comboMappingVertices[comboVertexIter];
					int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]];
					if (embedding[queryVertexId] == -1) {
						updateState(queryVertexId, dataVertexId);
						updatedQueryVertexMap.insert(std::pair<int, int>(dataVertexId, queryVertexId));
					}
				}
			}
			// next iteration
			resuriveSearch(1);
			// recover the last 
			for (map<int, int>::iterator updatedVIter = updatedQueryVertexMap.begin(); updatedVIter != updatedQueryVertexMap.end(); updatedVIter++) {
				restoreState(updatedVIter->first, updatedVIter->second);
			}
		}


		delete cacheRetrieval;
	}
	else {
		// the starting node represents a stand alone vertex
		AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointNode.mapping[0]);
		std::map<int, std::vector<int>>::iterator candidates = dataGraph->getLabelVertexList()->find(queryVertex->label);
		for (vector<int>::iterator candidateIter = candidates->second.begin(); candidateIter != candidates->second.end(); candidateIter++) {

			if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
				needReturn = true;
				return;
			}

			// start with each candidate
			if (degreeFilter(queryVertex->id, *candidateIter)) {
				updateState(queryVertex->id, *candidateIter);
				resuriveSearch(1);
				restoreState(queryVertex->id, *candidateIter);
			}
		}
	}
}
/*
* Given a PCM. we pre-compute a matching order here.
* to use the exploration similar to turboIso. we can define a BFS order
*/
void TurboIsoBoostedMQO::computeMatchingOrder() {

	//build candidate size map
	vector<std::pair<int, int>> inverseMap;

	for (size_t nodeIndex = 0; nodeIndex < jointGraph->jointNodes.size(); nodeIndex++) {
		int parentId = jointGraph->jointNodes[nodeIndex].parentId;
		if (parentId != -1) {
			inverseMap.push_back(std::pair<int, int>((*numberOfEmbeddings)[parentId], nodeIndex));
		}
		else {
			AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointGraph->jointNodes[nodeIndex].mapping[0]);
			std::map<int, std::vector<int>>::iterator candidates = dataGraph->getLabelVertexList()->find(queryVertex->label);
			if (candidates != dataGraph->getLabelVertexList()->end()) {
				inverseMap.push_back(std::pair<int, int>(candidates->second.size(), nodeIndex));
			}
			else {
				return;
			}
		}
	}
	std::sort(inverseMap.begin(), inverseMap.end());


	// bfs order, start from the minimum size cache
	bool * flags = new bool[jointGraph->jointNodes.size()];
	for (int i = 0; i < jointGraph->jointNodes.size(); i++) {
		flags[i] = false;
	}
	queue<int> visited;


	JointNodeOrderNode startNodeOrderNode;
	//@debug
	for (size_t i = 0; i < jointGraph->jointNodes.size(); i++) {
		if (jointGraph->jointNodes[i].parentId != -1) {
			visited.push(i);
			flags[i] = true;
			startNodeOrderNode.jointNodeId = i;
			break;
		}
	}

	/*jointNodeOrderNode.jointNodeId = inverseMap[0].second;
	visited.push(inverseMap[0].second);
	flags[inverseMap[0].second] = true;*/
	jointNodeMatchingOrder.push_back(startNodeOrderNode);

	while (!visited.empty()) {
		int nodeId = visited.front();
		visited.pop();

		for (size_t nodeIndex = 0; nodeIndex < jointGraph->jointNodes.size(); nodeIndex++) {
			if (!flags[nodeIndex] && jointGraph->edge(nodeIndex, nodeId)) {

				flags[nodeIndex] = true;
				visited.push(nodeIndex);

				JointNodeOrderNode nextJointNodeOrderNode;
				nextJointNodeOrderNode.jointNodeId = nodeIndex;
				jointNodeMatchingOrder.push_back(nextJointNodeOrderNode);
			}
		}
	}
	delete[] flags;

	/*
	* add the common or connected already mapped query vertices
	*/
	for (int i = 0; i < jointNodeMatchingOrder.size(); i++) {

		JointNodeOrderNode & i_jointNodeOrderNode = jointNodeMatchingOrder[i];
		JointGraphNode & i_jointGraphNode = jointGraph->jointNodes[i_jointNodeOrderNode.jointNodeId];



	}

	/*
	* add the common or connected already mapped query vertices
	*/
	for (int i = 0; i < jointNodeMatchingOrder.size(); i++) {

		JointNodeOrderNode & i_jointNodeOrderNode = jointNodeMatchingOrder[i];
		JointGraphNode & i_jointGraphNode = jointGraph->jointNodes[i_jointNodeOrderNode.jointNodeId];


		/*
		* initialize it
		*/
		for (int mappingIdex = 0; mappingIdex < i_jointGraphNode.mapping.size(); mappingIdex++) {
			i_jointNodeOrderNode.preConnectedMappedVertex.push_back(vector<int>());
			i_jointNodeOrderNode.preMultiCoveredVertex[mappingIdex] = -1;
			i_jointNodeOrderNode.uncoveredEdges.push_back(std::map<int, vector<int>>());
		}

		for (int j = 0; j < i; j++) {

			JointNodeOrderNode & j_jointNodeOrderNode = jointNodeMatchingOrder[j];
			JointGraphNode & j_jointGraphNode = jointGraph->jointNodes[j_jointNodeOrderNode.jointNodeId];

			if (jointGraph->edge(i_jointNodeOrderNode.jointNodeId, j_jointNodeOrderNode.jointNodeId)) {

				// if these two joint node has edges
				for (int i_mappingIdex = 0; i_mappingIdex < i_jointGraphNode.mapping.size(); i_mappingIdex++) {
					// for each of the vertex within this joint node
					for (int j_mappingIdex = 0; j_mappingIdex < j_jointGraphNode.mapping.size(); j_mappingIdex++) {
						if (i_jointGraphNode.mapping[i_mappingIdex] == j_jointGraphNode.mapping[j_mappingIdex]) {
							// this two joint node covered a common query vertex

							i_jointNodeOrderNode.preMultiCoveredVertex[i_mappingIdex] = j_jointGraphNode.mapping[j_mappingIdex];
							if (i_jointNodeOrderNode.preConnectedMappedVertex[i_mappingIdex].size() > 0) {
								i_jointNodeOrderNode.preConnectedMappedVertex[i_mappingIdex].swap(vector<int>());
							}
							break;
						}
						else if (queryGraph->edge(i_jointGraphNode.mapping[i_mappingIdex], j_jointGraphNode.mapping[j_mappingIdex])) {
							i_jointNodeOrderNode.preConnectedMappedVertex[i_mappingIdex].push_back(j_jointGraphNode.mapping[j_mappingIdex]);
						}
					}
				}
			}
		}
	}
	/*
	* add uncovered query vertices
	*/
	for (int i = 0; i < jointNodeMatchingOrder.size(); i++) {

		JointNodeOrderNode & jointNodeOrderNode = jointNodeMatchingOrder[i];
		JointGraphNode & jointGraphNode = jointGraph->jointNodes[jointNodeOrderNode.jointNodeId];

		AdjacenceListsGRAPH * parentGraph = NULL;
		if (jointGraphNode.parentId >= queryGraphVector->size()) {
			parentGraph = &(*newlyGeneratedGraphVector)[jointGraphNode.parentId - queryGraphVector->size()];
		}
		else {
			parentGraph = &(*queryGraphVector)[jointGraphNode.parentId];
		}
		std::vector<ComboNODE> * comboGraph = parentGraph->getComboGraph();
		for (int i_comboIndex = 0; i_comboIndex < comboGraph->size(); i_comboIndex++) {
			for (int j_comboIndex = i_comboIndex + 1; j_comboIndex < comboGraph->size(); j_comboIndex++) {


				for (std::vector<int>::iterator i_comboVerIter = (*comboGraph)[i_comboIndex].queryVertices.begin(); i_comboVerIter != (*comboGraph)[i_comboIndex].queryVertices.end(); i_comboVerIter++) {
					for (std::vector<int>::iterator j_comboVerIter = (*comboGraph)[j_comboIndex].queryVertices.begin(); j_comboVerIter != (*comboGraph)[j_comboIndex].queryVertices.end(); j_comboVerIter++) {

						if (!parentGraph->edge(*i_comboVerIter, *j_comboVerIter)) {
							if (queryGraph->edge(jointGraphNode.mapping[*i_comboVerIter], jointGraphNode.mapping[*j_comboVerIter])) {
								// this is a uncovered edge
								std::map<int, vector<int>>::iterator uncoverIter = jointNodeOrderNode.uncoveredEdges[*i_comboVerIter].find(j_comboIndex);
								if (uncoverIter == jointNodeOrderNode.uncoveredEdges[*i_comboVerIter].end()) {
									vector<int> uncoverConV;
									uncoverConV.push_back(jointGraphNode.mapping[*j_comboVerIter]);
									jointNodeOrderNode.uncoveredEdges[*i_comboVerIter].insert(std::pair<int, vector<int>>(*i_comboVerIter, uncoverConV));
								}
								else {
									uncoverIter->second.push_back(jointGraphNode.mapping[*j_comboVerIter]);
								}
							}
						}
					}
				}

			}
		}
	}
}
void TurboIsoBoostedMQO::resuriveSearch(int matchingOrderIndex) {
	if (recursiveCallsNo++ >= GlobalConstant::G_enoughRecursiveCalls) {
		(*numberOfEmbeddings)[queryGraph->graphId] = -1;
		needReturn = true;
		return;
	}

	if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
		needReturn = true;
		return;
	}

	if (matchingOrderIndex == jointNodeMatchingOrder.size()) {
#ifdef DEBUG
		cout << "Find a Embedding for query " << queryGraph->graphId << "{";
		for (int i = 0; i < queryGraph->getNumberOfVertexes(); i++) {
			cout << embedding[i] << " ";
		}
		cout << " } " << endl;
#endif
		(*numberOfEmbeddings)[queryGraph->graphId] ++;
		// already reached to the last node. a full embedding was found
		if (needSaveCache) {
			ComboLinkedLists::addEmbeddingToCache(resultCaches, queryGraph, embedding);
		}
	}
	else {
		JointGraphNode & jointNode = jointGraph->jointNodes[jointNodeMatchingOrder[matchingOrderIndex].jointNodeId];

		if (jointNode.parentId != -1) {
			/*
			* the next joint node represents a parent graph, we enumerate the candaite and for each candidate, we try to go to next iteration
			*/
			AdjacenceListsGRAPH * parentGraph = NULL;
			if (jointNode.parentId < queryGraphVector->size()) {
				parentGraph = &(*queryGraphVector)[jointNode.parentId];
			}
			else {
				parentGraph = &(*newlyGeneratedGraphVector)[jointNode.parentId - queryGraphVector->size()];
			}

			/*
			* enumerate the embeddings from the cache
			*/
			CacheRetrieval * cacheRetrieval = new CacheRetrieval(dataGraph, resultCaches);
			std::vector<std::vector<CacheEmbeddingNode *>> candidates;
			cacheRetrieval->retrieveEmbeddingCandidate(queryGraph, parentGraph, &jointNode, &jointNodeMatchingOrder[matchingOrderIndex], embedding, &inverseEmbedding, &candidates);

			for (std::vector<std::vector<CacheEmbeddingNode *>>::iterator candidateIter = candidates.begin(); candidateIter != candidates.end(); candidateIter++) {

				if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
					needReturn = true;
					return;
				}

				map<int, int> updatedQueryVertexMap;
				for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) {
					if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
						needReturn = true;
						return;
					}

					// each combo node corresponding to cache embedding node which contains multiple matched data vertices
					ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId];
					for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) {

						int dataVertexId = (*candidateIter)[comboNodeId]->comboMappingVertices[comboVertexIter];
						int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]];
						if (embedding[queryVertexId] == -1) {
							updateState(queryVertexId, dataVertexId);
							updatedQueryVertexMap.insert(std::pair<int, int>(queryVertexId, dataVertexId));
						}
					}
				}
				// next iteration
				resuriveSearch(matchingOrderIndex + 1);
				// recover the last 
				for (map<int, int>::iterator updatedVIter = updatedQueryVertexMap.begin(); updatedVIter != updatedQueryVertexMap.end(); updatedVIter++) {
					restoreState(updatedVIter->first, updatedVIter->second);
				}
			}

			delete cacheRetrieval;
		}
		else {
			/*
			* the next node represents a stand alone query vertex.
			* stand alone query vertex cannot be matched before. so no need to ensure multi-map consistency
			*/
			AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointNode.mapping[0]);

			JointGraphNode & parentJointNode = jointGraph->jointNodes[jointNodeMatchingOrder[matchingOrderIndex - 1].jointNodeId];
			AdjacenceListsGRAPH::Vertex * parentMap = NULL;
			if (parentJointNode.parentId == -1) {
				// its parent is a stand alone vertex, we just get the mapped datavertex of its parent
				parentMap = dataGraph->getVertexAddressByVertexId(embedding[parentJointNode.mapping[0]]);
			}
			else {
				// its parent is a parent graph, we get a already mapped data vertex of a query vertex which is connected to this vertex
				for (size_t queryVertexIndex = 0; queryVertexIndex <= queryGraph->getNumberOfVertexes(); queryVertexIndex++) {
					if (embedding[queryVertexIndex] != -1 && queryGraph->edge(queryVertex->id, queryVertexIndex)) {
						parentMap = dataGraph->getVertexAddressByVertexId(embedding[queryVertexIndex]);
						break;
					}
				}
			}
			/*
			* we get is parent joint node, as its parent node has already been matched. we can use exploration to get the candidates
			*/
			std::map<int, std::vector<int>>::iterator exploreCandidates = parentMap->labelVertexList.find(queryVertex->label);
			if (exploreCandidates == parentMap->labelVertexList.end()) {
				// no candidate found
				return;
			}
			else {
				for (vector<int>::iterator candidateIter = exploreCandidates->second.begin(); candidateIter != exploreCandidates->second.end(); candidateIter++) {
					if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
						needReturn = true;
						return;
					}

					if (degreeFilter(queryVertex->id, *candidateIter) && isJoinable(queryVertex->id, *candidateIter)) {
						updateState(queryVertex->id, *candidateIter);
						resuriveSearch(matchingOrderIndex + 1);
						restoreState(queryVertex->id, *candidateIter);
					}
				}
			}
		}
	}
}
Exemplo n.º 6
0
/*
* With the partial embeddings ready for this query graph, we are ready to process the joining process
* The joining process is also a recursively enumeration process
*/
void RecurParEmbConstruct::recursiveComputePartialEmbedding(int matchedToOrderIndex, int selfJoinOrderIndex) {
    if ((*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS || (*numberOfEmbeddings)[queryGraph->graphId]==-1) {
        return;
    }
    /*****************************************
    * Terminate conditions *
    *****************************************/
    if (mappedDataVertexSet.size() == queryGraph->getNumberOfVertexes()) {
        if (checkPartialEmbeddingUncoveredEdge()) {
            /*
            * We got a full embedding by only use the caches. Add it.
            */
            (*numberOfEmbeddings)[queryGraph->graphId] ++;
            /*
            * We cache the results if and only if it has some children
            */
            if ((*patternContainmentMap)[queryGraph->graphId].children.size() != 0) {
                cachedResultLists->addEmbeddingToCache(queryGraph, partialEmbedding);
            }
        }
        return;
    }
    if (matchedToOrderIndex == joiningOrder->size()) {
        /*
        * we iterate to the end of all its minimum query cover parents
        */
        if (matchedToOrderIndex > 0 && mappedDataVertexSet.size() == 0) {
            /*
            * it has parents, however, we cannot get any partial embedding from its parent caches, that means, the query graph wouldn't have any embeddings
            */
            return;
        }
        else {
            /*
            * @subgraph isomorphism. pass it
            * We only save the cache results if and only if this graph has pcm children
            */
            if (checkPartialEmbeddingUncoveredEdge()) {
                // Call subgraph isomorphism algorithm
                runSubgraphIsomorphismSearch();
            }
            return;
        }
    }


    /*****************************************
    * Set the parent graph in this round
    *****************************************/
    int parentQueryGraphId = joiningOrder->at(matchedToOrderIndex);
    AdjacenceListsGRAPH * parentQueryGraph = NULL;
    if (parentQueryGraphId < queryGraphVector->size()) {
        parentQueryGraph = &(*queryGraphVector)[parentQueryGraphId];
    }
    else {
        parentQueryGraph = &(*newlyGeneratedGraphVector)[parentQueryGraphId - queryGraphVector->size()];
    }
    std::vector<int> * parentDFSComboVertexOrder = parentQueryGraph->getDFSComboVertexOrder();
    std::vector<ComboNODE> * parentComboGraph = parentQueryGraph->getComboGraph();

    /*
    * Find the mappings of this parent graph
    */
    std::map<int, std::vector<std::vector<int>>>::iterator vertexMappingMapIterator = (*patternContainmentMap)[parentQueryGraphId].containmentRelationshipMappingLists.find(queryGraph->graphId);
    /*
    * The mapping from the parent graph to this graph: (0->? 1->? 2->?)
    */
    std::vector<int> * vertexMappingList = &vertexMappingMapIterator->second[selfJoinOrderIndex];


    std::vector<EmbeddingNode *> parentComboEmbedding;
    for (int i = 0; i<parentComboGraph->size(); i++) {
        parentComboEmbedding.push_back(NULL);
    }

    /*****************************************
    * Prepare for Next recursieve query round
    *****************************************/
    if (selfJoinOrderIndex == vertexMappingMapIterator->second.size() - 1) {
        matchedToOrderIndex++;
        selfJoinOrderIndex = 0;
    }
    else {
        selfJoinOrderIndex++;
    }


    /*****************************************
    * enumerate and compose the cached embeddings
    *****************************************/
    EmbeddingNode * rootsMatchedVertices = (*comboLinkedLists)[parentQueryGraphId][0];

    int * updatedVertexId = new int[5];
    for (int i = 0; i<5; i++) {
        updatedVertexId[i] = -1;
    }

    while (rootsMatchedVertices != NULL) {

        if ((*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS || (*numberOfEmbeddings)[queryGraph->graphId]==-1) {
            return;
        }

        //1. Make sure no data vertices can be used multiple times AND the same data vertex to each query vertex
        bool isJoinable = true;
        for (int i = 0; i<(*parentComboGraph)[0].queryVertices.size(); i++) {

            int mappedQueryVertex = (*vertexMappingList)[(*parentComboGraph)[0].queryVertices[i]];

            if (partialEmbedding[mappedQueryVertex] != -1) {
                // same data vertex to each query vertex
                if (partialEmbedding[mappedQueryVertex] != rootsMatchedVertices->comboMappingVertices[i]) {
                    isJoinable = false;
                    break;
                }
            }
            else {
                if (mappedDataVertexSet.find(rootsMatchedVertices->comboMappingVertices[i]) == mappedDataVertexSet.end()) {
                    // no data vertices can be used multiple times
                    partialEmbedding[mappedQueryVertex] = rootsMatchedVertices->comboMappingVertices[i];
                    mappedDataVertexSet.insert(rootsMatchedVertices->comboMappingVertices[i]);

                    updatedVertexId[i] = mappedQueryVertex;
                }
                else {
                    isJoinable = false;
                    break;
                }
            }
        }

        if (isJoinable) {
            //2. start iteratiing inner embeddings
            parentComboEmbedding[(*parentDFSComboVertexOrder)[0]] = rootsMatchedVertices;
            enumberateEmbeddingLinkedList(1, matchedToOrderIndex, selfJoinOrderIndex, parentComboGraph, parentDFSComboVertexOrder, vertexMappingList, &parentComboEmbedding);
        }

        //3. restore to initial status
        for (int i = 0; i<5; i++) {
            if (updatedVertexId[i] != -1) {

                mappedDataVertexSet.erase(partialEmbedding[updatedVertexId[i]]);

                partialEmbedding[updatedVertexId[i]] = -1;

                updatedVertexId[i] = -1;
            }
        }

        //4. next root trial
        rootsMatchedVertices = rootsMatchedVertices->adj;

    }

    //5. release memory
    delete[] updatedVertexId;
}
void TurboIsoMQO::resuriveSearch(int matchingOrderIndex) {
	if (recursiveCallsNo++ >= GlobalConstant::G_enoughRecursiveCalls) {
		(*numberOfEmbeddings)[queryGraph->graphId] = -1;
		needReturn = true;
		return;
	}
	
	if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
		needReturn = true;
		return;
	}

	if (matchingOrderIndex == jointNodeMatchingOrder.size()) {
#ifdef DEBUG
		cout << "Find a Embedding for query " << queryGraph->graphId << "{";
		for (int i = 0; i < queryGraph->getNumberOfVertexes(); i++) {
			cout << embedding[i] << " ";
		}
		cout << " } " << endl;
#endif
		(*numberOfEmbeddings)[queryGraph->graphId] ++;
		// already reached to the last node. a full embedding was found
		if (needSaveCache) {
			ComboLinkedLists::addEmbeddingToCache(resultCaches, queryGraph, embedding);
		}
	}
	else {
		JointGraphNode & jointNode = jointGraph->jointNodes[jointNodeMatchingOrder[matchingOrderIndex].jointNodeId];

		if (jointNode.parentId != -1) {
			/*
			 * the next joint node represents a parent graph, we enumerate the candaite and for each candidate, we try to go to next iteration
			 */
			AdjacenceListsGRAPH * parentGraph = NULL;
			if (jointNode.parentId < queryGraphVector->size()) {
				parentGraph = &(*queryGraphVector)[jointNode.parentId];
			}
			else {
				parentGraph = &(*newlyGeneratedGraphVector)[jointNode.parentId - queryGraphVector->size()];
			}

			/*
			 * enumerate the embeddings from the cache
			 */
			CacheRetrieval * cacheRetrieval = new CacheRetrieval(dataGraph, resultCaches);
			std::vector<std::vector<CacheEmbeddingNode *>> candidates;
			cacheRetrieval->retrieveEmbeddingCandidate(queryGraph, parentGraph, &jointNode, &jointNodeMatchingOrder[matchingOrderIndex], embedding, &inverseEmbedding, &candidates);

			cout << "Candidate Size: " << candidates.size() << endl;

			/*
			 * will be updated query vertex
			 */
			vector<int> updatingQueryVertex;
			for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) {
				ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId];
				for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) {
					int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]];
					if (embedding[queryVertexId] == -1) {
						updatingQueryVertex.push_back(queryVertexId);
					}
				}
			}


			for (std::vector<std::vector<CacheEmbeddingNode *>>::iterator candidateIter = candidates.begin(); candidateIter != candidates.end(); candidateIter++) {
				
				if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
					needReturn = true;
					return;
				}
				for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) {
					// each combo node corresponding to cache embedding node which contains multiple matched data vertices
					ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId];
					for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) {

						int dataVertexId = (*candidateIter)[comboNodeId]->comboMappingVertices[comboVertexIter];
						int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]];
						if (embedding[queryVertexId] == -1) {
							updateState(queryVertexId, dataVertexId);
						}
					}
				}
				// next iteration
				resuriveSearch(matchingOrderIndex + 1);

				// recover the last
				for (vector<int>::iterator updatedVIter = updatingQueryVertex.begin(); updatedVIter != updatingQueryVertex.end(); updatedVIter++) {
					restoreState(*updatedVIter);
				}
			}
			delete cacheRetrieval;
		}
		else {
			/* 
			 * the next node represents a stand alone query vertex.
			 * stand alone query vertex cannot be matched before. so no need to ensure multi-map consistency
			 */
			AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointNode.mapping[0]);
			std::vector<int> * candidates = NULL;

			if (matchingOrderIndex == 0) {
				// the starting vertex cannot use exploration
				std::map<int, std::vector<int>>::iterator candidateIter = dataGraph->getLabelVertexList()->find(queryVertex->label);
				if (candidateIter == dataGraph->getLabelVertexList()->end()) {
					return;
				}

				candidates = &candidateIter->second;
			}
			else {
				/*
				 * the following vertex use candidate exploration from its mapped parents.
				 * we explore a connected, already mapped query vertex which generate minimum number of candidates.
				 */
				int minCandidateSize = INT_MAX;
				for (size_t queryVertexIndex = 0; queryVertexIndex <= queryGraph->getNumberOfVertexes(); queryVertexIndex++) {
					if (embedding[queryVertexIndex] != -1 && queryGraph->edge(queryVertex->id, queryVertexIndex)) {
						AdjacenceListsGRAPH::Vertex * alreadyMappedDataVer = dataGraph->getVertexAddressByVertexId(embedding[queryVertexIndex]);
						std::map<int, std::vector<int>>::iterator candidateIter = alreadyMappedDataVer->labelVertexList.find(queryVertex->label);
						if (candidateIter == alreadyMappedDataVer->labelVertexList.end()) {
							return;
						}
						else {
							if (candidateIter->second.size() < minCandidateSize) {
								minCandidateSize = candidateIter->second.size();
								candidates = &candidateIter->second;
							}
						}
					}
				}
			}
			/*
			 * for each of the candidates, we further iterate
			 */
			for (vector<int>::iterator candidateIter = candidates->begin(); candidateIter != candidates->end(); candidateIter++) {
				if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) {
					needReturn = true;
					return;
				}

				if (degreeFilter(queryVertex->id, *candidateIter) && isJoinable(queryVertex->id, *candidateIter)) {
					updateState(queryVertex->id, *candidateIter);
					resuriveSearch(matchingOrderIndex + 1);
					restoreState(queryVertex->id);
				}
			}
		}
	}
}