<commit_before>"""
Some code to wrap the C++ code for graph matching in GraphM
""" 
import subprocess
import numpy 
import os 
import sys 
import tempfile
import logging 
from apgl.graph import SparseGraph, VertexList
from apgl.util.Parameter import Parameter
from apgl.util.Util import Util
from apgl.data.Standardiser import Standardiser 

class GraphMatch(object): 
    def __init__(self, algorithm="PATH", alpha=0.5, featureInds=None, useWeightM=True):
        """
        Intialise the matching object with a given algorithm name, alpha 
        which is a trade of between matching adjacency matrices and vertex labels, 
        and featureInds which is an option array of indices to use for label 
        matching. 
        """
        Parameter.checkFloat(alpha, 0.0, 1.0)
        Parameter.checkClass(algorithm, str)
        
        self.algorithm = algorithm 
        self.alpha = alpha 
        self.maxInt = 10**9 
        self.featureInds = featureInds 
        self.useWeightM = useWeightM 
        #Gamma is the same as dummy_nodes_c_coef for costing added vertex labels         
        self.gamma = 0.0
        #Same as dummy_nodes_fill 
        self.rho = 0.5 
        
    def match(self, graph1, graph2): 
        """
        Take two graphs are match them. The two graphs must be AbstractMatrixGraphs 
        with VertexLists representing the vertices.  
        
        :param graph1: A graph object 
        
        :param graph2: The second graph object to match 
        
        :return permutation: A vector of indices representing the matching of elements of graph1 to graph2 
        :return distance: The graph distance list [graphDistance, fDistance, fDistanceExact] 
        """
        #Deal with case where at least one graph is emty 
        if graph1.size == 0 and graph2.size == 0: 
            permutation = numpy.array([], numpy.int)
            distanceVector = [0, 0, 0]  
            time = 0 
            return permutation, distanceVector, time 
        elif graph1.size == 0 or graph2.size == 0: 
            if graph1.size == 0: 
                graph1 = SparseGraph(VertexList(graph2.size, graph2.getVertexList().getNumFeatures()))
            else: 
                graph2 = SparseGraph(VertexList(graph1.size, graph1.getVertexList().getNumFeatures()))        
        
        numTempFiles = 5
        tempFileNameList = []         
        
        for i in range(numTempFiles): 
            fileObj = tempfile.NamedTemporaryFile(delete=False)
            tempFileNameList.append(fileObj.name) 
            fileObj.close() 
               
        configFileName = tempFileNameList[0]
        graph1FileName = tempFileNameList[1]
        graph2FileName = tempFileNameList[2]
        similaritiesFileName = tempFileNameList[3]
        outputFileName = tempFileNameList[4]

        if self.useWeightM:         
            W1 = graph1.getWeightMatrix()
            W2 = graph2.getWeightMatrix()
        else: 
            W1 = graph1.adjacencyMatrix()
            W2 = graph2.adjacencyMatrix()
        
        numpy.savetxt(graph1FileName, W1, fmt='%.5f')
        numpy.savetxt(graph2FileName, W2, fmt='%.5f')
        
        #Compute matrix similarities 
        C = self.vertexSimilarities(graph1, graph2)
        numpy.savetxt(similaritiesFileName, C, fmt='%.5f')
        
        #Write config file 
        configFile = open(configFileName, 'w')
        
        configStr = "graph_1=" + graph1FileName + " s\n"
        configStr +="graph_2=" + graph2FileName + " s\n"
        configStr +="C_matrix=" + similaritiesFileName + " s\n"
        configStr +="algo=" + self.algorithm + " s\n"
        configStr +="algo_init_sol=unif s\n"
        configStr +="alpha_ldh=" + str(self.alpha) + " d\n"
        configStr +="cdesc_matrix=A c\n"
        configStr +="cscore_matrix=A c\n"
        configStr +="hungarian_max=10000 d\n"
        configStr +="algo_fw_xeps=0.01 d\n"
        configStr +="algo_fw_feps=0.01 d\n"
        configStr +="dummy_nodes=0 i\n"
        configStr +="dummy_nodes_fill=" + str(self.rho) + " d\n"
        configStr +="dummy_nodes_c_coef=" + str(self.gamma) + " d\n"
        configStr +="qcvqcc_lambda_M=10 d\n"
        configStr +="qcvqcc_lambda_min=1e-5 d\n"
        configStr +="blast_match=0 i\n"
        configStr +="blast_match_proj=0 i\n"
        configStr +="exp_out_file=" + outputFileName + " s\n"
        configStr +="exp_out_format=Compact Permutation s\n"
        configStr +="verbose_mode=0 i\n"
        configStr +="verbose_file=cout s\n"
        
        configFile.write(configStr)
        configFile.close()
        
        fnull = open(os.devnull, 'w')
        #This is a bit hacky 
        try: 
            argList = ["/home/charanpal/local/bin/graphm", configFileName] 
            subprocess.call(argList, stdout = fnull, stderr = fnull)    
        except OSError: 
            argList = ["/home/dhanjalc/local/bin/graphm", configFileName] <commit_msg>Update path <commit_after>"""
Some code to wrap the C++ code for graph matching in GraphM
""" 
import subprocess
import numpy 
import os 
import sys 
import tempfile
import logging 
from apgl.graph import SparseGraph, VertexList
from apgl.util.Parameter import Parameter
from apgl.util.Util import Util
from apgl.data.Standardiser import Standardiser 

class GraphMatch(object): 
    def __init__(self, algorithm="PATH", alpha=0.5, featureInds=None, useWeightM=True):
        """
        Intialise the matching object with a given algorithm name, alpha 
        which is a trade of between matching adjacency matrices and vertex labels, 
        and featureInds which is an option array of indices to use for label 
        matching. 
        """
        Parameter.checkFloat(alpha, 0.0, 1.0)
        Parameter.checkClass(algorithm, str)
        
        self.algorithm = algorithm 
        self.alpha = alpha 
        self.maxInt = 10**9 
        self.featureInds = featureInds 
        self.useWeightM = useWeightM 
        #Gamma is the same as dummy_nodes_c_coef for costing added vertex labels         
        self.gamma = 0.0
        #Same as dummy_nodes_fill 
        self.rho = 0.5 
        
    def match(self, graph1, graph2): 
        """
        Take two graphs are match them. The two graphs must be AbstractMatrixGraphs 
        with VertexLists representing the vertices.  
        
        :param graph1: A graph object 
        
        :param graph2: The second graph object to match 
        
        :return permutation: A vector of indices representing the matching of elements of graph1 to graph2 
        :return distance: The graph distance list [graphDistance, fDistance, fDistanceExact] 
        """
        #Deal with case where at least one graph is emty 
        if graph1.size == 0 and graph2.size == 0: 
            permutation = numpy.array([], numpy.int)
            distanceVector = [0, 0, 0]  
            time = 0 
            return permutation, distanceVector, time 
        elif graph1.size == 0 or graph2.size == 0: 
            if graph1.size == 0: 
                graph1 = SparseGraph(VertexList(graph2.size, graph2.getVertexList().getNumFeatures()))
            else: 
                graph2 = SparseGraph(VertexList(graph1.size, graph1.getVertexList().getNumFeatures()))        
        
        numTempFiles = 5
        tempFileNameList = []         
        
        for i in range(numTempFiles): 
            fileObj = tempfile.NamedTemporaryFile(delete=False)
            tempFileNameList.append(fileObj.name) 
            fileObj.close() 
               
        configFileName = tempFileNameList[0]
        graph1FileName = tempFileNameList[1]
        graph2FileName = tempFileNameList[2]
        similaritiesFileName = tempFileNameList[3]
        outputFileName = tempFileNameList[4]

        if self.useWeightM:         
            W1 = graph1.getWeightMatrix()
            W2 = graph2.getWeightMatrix()
        else: 
            W1 = graph1.adjacencyMatrix()
            W2 = graph2.adjacencyMatrix()
        
        numpy.savetxt(graph1FileName, W1, fmt='%.5f')
        numpy.savetxt(graph2FileName, W2, fmt='%.5f')
        
        #Compute matrix similarities 
        C = self.vertexSimilarities(graph1, graph2)
        numpy.savetxt(similaritiesFileName, C, fmt='%.5f')
        
        #Write config file 
        configFile = open(configFileName, 'w')
        
        configStr = "graph_1=" + graph1FileName + " s\n"
        configStr +="graph_2=" + graph2FileName + " s\n"
        configStr +="C_matrix=" + similaritiesFileName + " s\n"
        configStr +="algo=" + self.algorithm + " s\n"
        configStr +="algo_init_sol=unif s\n"
        configStr +="alpha_ldh=" + str(self.alpha) + " d\n"
        configStr +="cdesc_matrix=A c\n"
        configStr +="cscore_matrix=A c\n"
        configStr +="hungarian_max=10000 d\n"
        configStr +="algo_fw_xeps=0.01 d\n"
        configStr +="algo_fw_feps=0.01 d\n"
        configStr +="dummy_nodes=0 i\n"
        configStr +="dummy_nodes_fill=" + str(self.rho) + " d\n"
        configStr +="dummy_nodes_c_coef=" + str(self.gamma) + " d\n"
        configStr +="qcvqcc_lambda_M=10 d\n"
        configStr +="qcvqcc_lambda_min=1e-5 d\n"
        configStr +="blast_match=0 i\n"
        configStr +="blast_match_proj=0 i\n"
        configStr +="exp_out_file=" + outputFileName + " s\n"
        configStr +="exp_out_format=Compact Permutation s\n"
        configStr +="verbose_mode=0 i\n"
        configStr +="verbose_file=cout s\n"
        
        configFile.write(configStr)
        configFile.close()
        
        fnull = open(os.devnull, 'w')
        #This is a bit hacky 
        try: 
            argList = ["/home/charanpal/.local/bin/graphm", configFileName] 
            subprocess.call(argList, stdout = fnull, stderr = fnull)    
        except OSError: 
            argList = ["/home/dhanjalc/.local/bin/graphm", configFileName] 
{'fraction_non_alphanumeric': 0.09710305844352478, 'fraction_numerical': 0.01756333905319471, 'mean_word_length': 2.146395681168625, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3187613', 'n_tokens_mistral': 3077, 'n_tokens_neox': 2918, 'n_words': 750}