juliagraphs / lightgraphsflows.jl Goto Github PK
View Code? Open in Web Editor NEWFlow algorithms on LightGraphs
License: Other
Flow algorithms on LightGraphs
License: Other
Dependencies are not versionned yet, it will be preferable to consider the package as stable
The tag name "v0.1" is not of the appropriate SemVer form (vX.Y.Z).
cc: @mbesancon
Hi,
I got the same kind of floating point error as etienneINSA in a previous issue while solving a min-cut problem with the push-relabel algorithm. Here is the code below to reproduce it with the graph capacity matrix files in attachment.
using LightGraphsFlows
import LightGraphs
const lg = LightGraphs
using NPZ
sg = lg.loadgraph("lsg.lg")
cm = npzread("lcm.npy")
(part1, part2, maxflow) = LightGraphsFlows.mincut(sg, 1, 16, cm, LightGraphsFlows.PushRelabelAlgorithm())
The master branch has the following warnings:
┌ Warning: Deprecated syntax `doc" "` at /home/juliohm/.julia/dev/LightGraphsFlows/src/push_relabel.jl:10.
│ Use `@doc doc" "` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/push_relabel.jl:10
┌ Warning: Deprecated syntax `doc" "` at /home/juliohm/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:43.
│ Use `@doc doc" "` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:43
It would be nice to specialize methods on weighted graphs, with weights representing the capacities. In a lot of situations, people who need flow algorithms work with weighted graphs. It also provide a sparse representation of the flow network. (without the need of an external sparse matrix).
(related : #9)
Doctests are currently not passing, designed with older version of the algorithms it seems (method errors when calling multiroute flows for instance).
I'm not a huge fan of defining tests in strings, they will be redundant with the test folder which has the merit of being checked at each push and having more readable fails.
The solution in LightGraphs.jl was to ignore doctests when building the doc, I would suggest simply removing them.
Hi,
mincut seems to return false result with this graph:
Non-labeled edges have infinite capacity
edges 1-2, 4-7, 5-7 and 6-7 are saturated after the running of the algorithm
Output:
[1, 3, 6, 5] [2, 4, 7] 3.0
Expected Output
[1, 2, 3, 4, 5, 6] [7] 3.0
The algorithm should find every reachable node from the source by a flow, it instead reaches nodes reachable by non saturated direct edges
How to reproduce:
flow_graph = lg.DiGraph(7)
capacity_matrix = zeros(7,7)
flow_edges = [
(1,2,2),(1,3,2),(2,4,4),(2,5,4),
(3,5,4),(3,6,4),(4,7,1),(5,7,1),(6,7,1)
]
for e in flow_edges
u, v, f = e
lg.add_edge!(flow_graph, u, v)
capacity_matrix[u,v] = f
end
a,b,c= LightGraphsFlows.mincut(flow_graph, 1, 7, capacity_matrix, EdmondsKarpAlgorithm())
println(a)
println(b)
println(c)
Hello,
I am running the maximum_flow function (Edmonds Karp Algorithm) but I have noticed that the function does not return the labelling associated with the minimum cut.
Is there a way to return this output?
Thanks!
Hi, got these warnings on the master branch while trying to update a package that depends on LGFlows:
julia> using LightGraphsFlows
[ Info: Recompiling stale cache file /home/juliohm/.julia/compiled/v0.7/LightGraphsFlows/Iwpqk.ji for LightGraphsFlows [2f5eb75a-258c-59e0-affc-f41c55f75335]
┌ Warning: Deprecated syntax `parametric method syntax edmonds_karp_impl{T, ##380}(residual_graph::##380, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T})` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `edmonds_karp_impl(residual_graph::##380, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}) where {T, ##380}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax edmonds_karp_impl{T, ##380}(::Type{lg.IsDirected{##380}}, residual_graph::##380, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `edmonds_karp_impl(#s15::Type{lg.IsDirected{##380}}, residual_graph::##380, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; ) where {T, ##380}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `parametric method syntax dinic_impl{T, ##386}(residual_graph::##386, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T})` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `dinic_impl(residual_graph::##386, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}) where {T, ##386}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax dinic_impl{T, ##386}(::Type{lg.IsDirected{##386}}, residual_graph::##386, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `dinic_impl(#s19::Type{lg.IsDirected{##386}}, residual_graph::##386, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; ) where {T, ##386}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `parametric method syntax blocking_flow!{T, ##388}(residual_graph::##388, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}, flow_matrix::AbstractMatrix, P::AbstractVector{Int})` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `blocking_flow!(residual_graph::##388, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}, flow_matrix::AbstractMatrix, P::AbstractVector{Int}) where {T, ##388}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax blocking_flow!{T, ##388}(::Type{lg.IsDirected{##388}}, residual_graph::##388, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}, flow_matrix::AbstractMatrix, P::AbstractVector{Int}; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `blocking_flow!(#s19::Type{lg.IsDirected{##388}}, residual_graph::##388, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}, flow_matrix::AbstractMatrix, P::AbstractVector{Int}; ) where {T, ##388}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `parametric method syntax boykov_kolmogorov_impl{T, U, AG <: lg.AbstractGraph{U}}(residual_graph::AG, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T})` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `boykov_kolmogorov_impl(residual_graph::AG, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}) where {T, U, AG <: lg.AbstractGraph{U}}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax boykov_kolmogorov_impl{T, U, AG <: lg.AbstractGraph{U}}(::Type{lg.IsDirected{AG}}, residual_graph::AG, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `boykov_kolmogorov_impl(#s19::Type{lg.IsDirected{AG}}, residual_graph::AG, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; ) where {T, U, AG <: lg.AbstractGraph{U}}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `parametric method syntax find_path!{T, AG <: lg.AbstractGraph{T}}(residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector)` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `find_path!(residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector) where {T, AG <: lg.AbstractGraph{T}}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax find_path!{T, AG <: lg.AbstractGraph{T}}(::Type{lg.IsDirected{AG}}, residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `find_path!(#s19::Type{lg.IsDirected{AG}}, residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector; ) where {T, AG <: lg.AbstractGraph{T}}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `parametric method syntax adopt!{T, AG <: lg.AbstractGraph{T}}(residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector, O::Vector)` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `adopt!(residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector, O::Vector) where {T, AG <: lg.AbstractGraph{T}}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax adopt!{T, AG <: lg.AbstractGraph{T}}(::Type{lg.IsDirected{AG}}, residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector, O::Vector; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `adopt!(#s25::Type{lg.IsDirected{AG}}, residual_graph::AG, source::Integer, target::Integer, flow_matrix::AbstractMatrix, capacity_matrix::AbstractMatrix, PARENT::Vector, TREE::Vector, A::Vector, O::Vector; ) where {T, AG <: lg.AbstractGraph{T}}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `doc" "` at /home/juliohm/.julia/dev/LightGraphsFlows/src/push_relabel.jl:10.
│ Use `@doc doc" "` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/push_relabel.jl:10
┌ Warning: Deprecated syntax `multiple line breaks between doc string and object` at /home/juliohm/.julia/dev/LightGraphsFlows/src/push_relabel.jl:59.
│ Use `at most one line break` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/push_relabel.jl:59
WARNING: importing deprecated binding Base.@doc_str into LightGraphsFlows.
WARNING: Base.@doc_str is deprecated, use `Markdown` instead
likely near /home/juliohm/.julia/dev/LightGraphsFlows/src/push_relabel.jl:1
┌ Warning: Deprecated syntax `parametric method syntax push_relabel{T, ##393}(residual_graph::##393, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T})` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `push_relabel(residual_graph::##393, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}) where {T, ##393}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax push_relabel{T, ##393}(::Type{lg.IsDirected{##393}}, residual_graph::##393, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `push_relabel(#s25::Type{lg.IsDirected{##393}}, residual_graph::##393, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; ) where {T, ##393}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
┌ Warning: Deprecated syntax `multiple line breaks between doc string and object` at /home/juliohm/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:17.
│ Use `at most one line break` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:17
┌ Warning: Deprecated syntax `doc" "` at /home/juliohm/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:43.
│ Use `@doc doc" "` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:43
┌ Warning: Deprecated syntax `multiple line breaks between doc string and object` at /home/juliohm/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:143.
│ Use `at most one line break` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:143
┌ Warning: Deprecated syntax `multiple line breaks between doc string and object` at /home/juliohm/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:145.
│ Use `at most one line break` instead.
└ @ ~/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:145
WARNING: Base.@doc_str is deprecated, use `Markdown` instead
likely near /home/juliohm/.julia/dev/LightGraphsFlows/src/ext_multiroute_flow.jl:34
┌ Warning: Deprecated syntax `parametric method syntax breakingPoints{T, ##413}(flow_graph::##413, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T})` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342.
│ Use `breakingPoints(flow_graph::##413, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}) where {T, ##413}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:342
┌ Warning: Deprecated syntax `parametric method syntax breakingPoints{T, ##413}(::Type{lg.IsDirected{##413}}, flow_graph::##413, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; )` around /home/juliohm/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330.
│ Use `breakingPoints(#s38::Type{lg.IsDirected{##413}}, flow_graph::##413, source::Integer, target::Integer, capacity_matrix::AbstractMatrix{T}; ) where {T, ##413}` instead.
└ @ ~/.julia/packages/SimpleTraits/CZOA/src/SimpleTraits.jl:330
Could you please take a look?
It looks like all the flow algorithms only work for directed graphs. Would some of them work if we lift this restriction or would we need a new implementation for that?
When trying to solve a mincost flow on an infeasible network, we get a warning and a NaN matrix:
LightGraphsFlows.mincost_flow(g, cap, demand, cost)
glp_intopt: optimal basis to initial LP relaxation not provided
WARNING: Not solved to optimality, status: Infeasible
WARNING: Infeasibility ray (Farkas proof) not available
WARNING: Variable value not defined for component of x. Check that the model was properly solved.
3×3 Array{Float64,2}:
NaN NaN NaN
NaN NaN NaN
NaN NaN NaN
I find it explicit enough, but we could add a optimal boolean in the response tuple, so that users can check if it was feasible and then handle the flow.
Another option would be to return the JuMP status.
maxflow algorithms can be specialized on matrix types, at least for:
Is it possible to add Ford - Fulkerson algorithm to maximum_flow?
As recommended by the JuliaOpt org, MathProgBase is going to be changed for MathOptInterface, we're going to do it once many solvers have switched
Judging by an old comment
multiroute_flow
depends upon its arguments. Maybe there is a way to do this using multiple dispatch instead?I need to extract the set of paths composing the max-flow returned by Edmond Karp's algorithm (or any augmenting paths method). Do you mind if I add this set of paths to the edmonds_karp_impl
function as a returned value?
If it is OK, I will make a push request soon.
The example in mincost.jl calls ClpSolver()
. Would recommend adding
using Clp
to the example with a note about how you can use any solver. It's easy for a novice like me to install LightGraphsFlows and use the maximum_flow()
code, but the mincost_flow()
example code fails out of the box.
I've implemented this algorithm a long time ago in LightGraphs.jl and it was moved to this separate repository here after some discussion about heavy dependencies. This migration apparently didn't include the tests I had written for this algorithm specifically and now I am using this code in production with a major bug somewhere. Can you please point to the exact commit in LightGraphs.jl where you copied the code and tests?
I appreciate if you can help me fix this quickly, there are people trying to use downstream code as we speak.
Hi,
The default max-flow algorithm is stuck in an endless loop with this graph:
The capacities of the first layer are all 0.1
The capacities of the second layer are all 1
The capacities of the third layer are all 0
Here is how to reproduce it :
using LightGraphsFlows
import LightGraphs
const lg = LightGraphs
flow_graph = lg.DiGraph(8)
capacity_matrix = zeros(8,8)
flow_edges = [
(1,3,0.1),(1,4,0.1),(1,5,0.1),(3,6,1),(3,7,1),(3,8,1),
(4,6,1),(4,7,1),(4,8,1),
(5,6,1),(5,7,1),(5,8,1),(6,2,0),(7,2,0),
(8,2,0)
]
for e in flow_edges
u, v, f = e
lg.add_edge!(flow_graph, u, v)
capacity_matrix[u,v] = f
end
println(collect(lg.edges(flow_graph)))
flow,flow_matrix = maximum_flow(flow_graph, 1, 2, capacity_matrix)
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
If you'd like for me to do this for you, comment TagBot fix
on this issue.
I'll open a PR within a few hours, please be patient!
Hi,
The computation of the vertex set part1
in the mincut
function defined in LightGraphsFlows is incorrect as it may contain multiple copies of a same node. The problem occurs for instance with the following example:
g = CompleteDiGraph(10)
cap1 = [
0.0 10.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0;
10.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0;
0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.0;
0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0;
0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0;
0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0;
1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0;
0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0;
0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0;
1.0 0.0 2.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0
]
(part1, part2, value) = LightGraphsFlows.mincut(g,1,10,cap1,LightGraphsFlows.PushRelabelAlgorithm())
Running the previous code gives a vertex set part1
containing twice node 2.
I think that the problem comes from the computation of dests
when computing the minimum cut.
Instead of
[dst for dst in 1:lg.nv(flow_graph) if residual_matrix[node,dst]>0.0 && dst ∉ part1]
shouldn't we have
[dst for dst in 1:lg.nv(flow_graph) if residual_matrix[node,dst]>0.0 && dst ∉ part1 && dst ∉ queue]
since every node in the queue is then added to part1
?
Best,
Mathieu
Attempting to run the example code at https://juliagraphs.org/LightGraphsFlows.jl/latest/mincost.html give the following error:
ClpSolver
is no longer supported. If you are using JuMP, upgrade to the latest version and useClp.Optimizer
instead. If you are using MathProgBase (e.g., vialingprog
), you will need to upgrade to MathOptInterface (https://github.com/jump-dev/MathOptInterface.jl).
Replacing ClpSolver
with Optimizer
, then gives this error:
MethodError: no method matching mincost_flow(::SimpleDiGraph{Int64}, ::Array{Float64,2}, ::SparseMatrixCSC{Float64,Int64}, ::Array{Float64,2}, ::Optimizer, ::Int64, ::Int64)
Closest candidates are:
mincost_flow(::AG, !Matched::AbstractArray{T,1} where T, ::AbstractArray{T,2} where T, ::AbstractArray{T,2} where T, ::Any; kwargs...) where AG<:AbstractGraph at /home//.julia/packages/SimpleTraits/1wYi7/src/SimpleTraits.jl:338
mincost_flow(!Matched::Type{IsDirected{AG}}, !Matched::AG, !Matched::AbstractArray{T,1} where T, ::AbstractArray{T,2} where T, !Matched::AbstractArray{T,2} where T, ::Any; edge_demand, source_nodes, sink_nodes) where AG<:AbstractGraph at /home//.julia/packages/LightGraphsFlows/X92PO/src/mincost.jl:65
Versions:
Hello, a minor glitch: the src link in the min cost flow documentations points to a wrong source version not using JuMP.
Mathieu
Is there a way to have mincost()
return not just the solution variables, but also the dual variables? In the example posted, mincost()
is passed Clpsolver()
, which produces the dual variables already. For anyone unfamiliar with LP duality, these represent the subgradients of the min cost problem with respect to the arc constraints.
Since I need both the primal and dual variables, I'm currently converting the min cost problem to an LP and calling Clpsolver()
directly. However, I'm not sure if mincost()
, as written, takes advantage of reformatting the problem as a network simplex problem before passing it to Clpsolver()
. I'd be missing out on that boost in speed with my current code.
Wikipedia says that network simplex "works very well in practice, typically 200 to 300 times faster than the simplex method applied to general linear program of same dimensions." (Although it does have a "citation needed" annotation)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.