Skip to content

feat: Add PATH-Algorithm feature for graph matching - #39

Open
ken-berkpinar wants to merge 9 commits into
JuliaGraphs:mainfrom
ken-berkpinar:feature/path-graph-matching
Open

feat: Add PATH-Algorithm feature for graph matching#39
ken-berkpinar wants to merge 9 commits into
JuliaGraphs:mainfrom
ken-berkpinar:feature/path-graph-matching

Conversation

@ken-berkpinar

Copy link
Copy Markdown

In this PR a graph matching algorithm is implemented based on M. Zaslavskiy, F. Bach and J. -P. Vert, "A Path Following Algorithm for the Graph Matching Problem," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 31, no. 12, pp. 2227-2242, Dec. 2009, doi: 10.1109/TPAMI.2008.245.

On the examples of the QAP that are mentioned in the paper this implementation yields feasible results. On Chr15a and Chr15c from https://qaplib.mgi.polymtl.ca/ it yields worse values then are listed in the paper, but on all others (Tai10a can not be found) this implementation finds a much better approximation in a feasible runtime when run with precision values of 1/10.

As I don't have much experience with writing pulishable code I'm hoping to get helpful feedback. Thank you in advance.

@ken-berkpinar
ken-berkpinar force-pushed the feature/path-graph-matching branch from bc5fc57 to 0532c10 Compare August 3, 2026 12:28
@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.61682% with 80 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.18%. Comparing base (f2cf29d) to head (e0c3e46).
⚠️ Report is 15 commits behind head on main.

Files with missing lines Patch % Lines
src/pathGraphMatching.jl 62.61% 80 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (f2cf29d) and HEAD (e0c3e46). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (f2cf29d) HEAD (e0c3e46)
2 1
Additional details and impacted files
@@             Coverage Diff             @@
##             main      #39       +/-   ##
===========================================
- Coverage   98.33%   80.18%   -18.15%     
===========================================
  Files           8       11        +3     
  Lines         180      434      +254     
===========================================
+ Hits          177      348      +171     
- Misses          3       86       +83     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/pathGraphMatching.jl
Comment on lines +305 to +307
function isPerm(P)
return all(x -> x == 0.0 || x == 1.0, P)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function already exits in utils.jl see:

function is_permutation_matrix(P::AbstractMatrix)

Comment thread src/pathGraphMatching.jl
Comment on lines +310 to +318
function permMtV(P)
return [argmax(row) for row in eachrow(P)]
end

# returns the permutation matrix of a permutation vector P
function permVtM(P)
return Matrix{Float64}(I(length(P))[P, :])
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to utils.jl

Comment thread src/pathGraphMatching.jl
Comment on lines +320 to +323
function sqd_frob(A)
val = norm(A, 2)
return val^2
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this: sum(abs2, A)

Comment thread src/pathGraphMatching.jl
Comment on lines +327 to +337
function diagonal_degree(G)
D = zeros(size(G))
for j in 1:size(D, 1)
sum = 0.0
for i in 1:size(D, 1)
sum += G[i, j]
end
D[j, j] = sum
end
return D
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move utils.jl

Comment thread src/pathGraphMatching.jl
Comment on lines +354 to +356
function laplacian(G)
return diagonal_degree(G) .- G
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the one of Graphs.jl

Comment thread test/pathGraphMatching.jl
0.1,
)
@test P == [1, 2]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tesst also for smaller functions

Comment thread src/GraphsOptim.jl
using MathOptInterface: OPTIMAL
using SparseArrays: sparse
using OptimalTransport: sinkhorn
using FrankWolfe

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import just the function you are using

Comment thread src/pathGraphMatching.jl
- `log_string::Union{String, Nothing}`: Formatted summary string if `return_log=true`, otherwise `nothing`.
- `dataPoints::Union{NamedTuple, Nothing}`: `NamedTuple` containing `λ_list`, `f0_list`, `f1_list`, and `fλ_list` if `return_dataPoints=true`, otherwise `nothing`.
"""
function pathAlgorithm(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Break this function in little blocks

Comment thread src/pathGraphMatching.jl
Comment on lines +263 to +296
log_stream = IOBuffer()
if return_log
function write_log(msg)
return println(log_stream, msg) # Schreibt in den Buffer
end

write_log("="^60)
write_log("Results for Graph Matching/QAP")
write_log("="^60)
write_log("")
write_log("ϵ_λ_f: $(ϵ_λ_f)")
write_log("ϵ_λ_p: $(ϵ_λ_p)")
write_log("solveQAP: $(solveQAP)")
write_log("")
write_log("Runtime: $(elapsed_time) seconds")
write_log("λ Iterations: $(count_iter)")
write_log("")
write_log("Cost:")
if !solveQAP
write_log("F0: $(f0(p_opt, G, H))")
write_log("F1: $(f1(p_opt, G, H))")
else
write_log("$(qapVal(p_opt, G, H))")
end
write_log("")
write_log("-"^60)
write_log("Resulting Matrix P")
write_log("-"^60)
write_log(p_vec)
end
log_string = return_log ? String(take!(log_stream)) : nothing

dataPoints = if return_dataPoints
(; λ_list=λ_list, f0_list=f0_list, f1_list=f1_list, fλ_list=fλ_list)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider to remove this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants