juliasmoothoptimizers / qpsreader.jl Goto Github PK
View Code? Open in Web Editor NEWA reader for MPS and QPS files
License: Other
A reader for MPS and QPS files
License: Other
I am reviewing the CITATION usage in the repos and in particular moving to CFF files. The bib can still be generated using Github menu.
Here are a couple of suggestions to adapt this repo:
I'll write a benchmark script before working on performance improvements.
I propose to use 3 benchmark sets:
.SIF
files and fixed MPS format..mps
, some with integer variables, and some in free MPS format.The reason for including a larger testset of instances would be to allow modifications that improve performance on large instances, while allowing a limited degradation on smaller instances.
For information, the readers in C/C++ solvers (commercial and open-source) are ~10-30x faster than the ones we have in Julia.
julia> using QPSReader
julia> netlib_path = fetch_netlib()
julia> blend = readqps(joinpath(netlib_path, "BLEND.SIF"))
[ Info: Using 'BLEND' as NAME (l. 5)
[ Info: Using 'C' as objective (l. 98)
[ Info: Using '65' as RHS (l. 376)
ERROR: Unknown row 23.26.
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] read_rhs_line!(::QPSData, ::QPSReader.MPSCard{QPSReader.FreeMPS}) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:498
[3] readqps(::String; mpsformat::Symbol) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:800
[4] readqps(::String) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:703
[5] top-level scope at REPL[5]:1
[6] eval(::Module, ::Any) at ./boot.jl:331
[7] eval_user_input(::Any, ::REPL.REPLBackend) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:86
[8] run_backend(::REPL.REPLBackend) at /Users/dpo/.julia/packages/Revise/Pcs5V/src/Revise.jl:1073
[9] top-level scope at none:0
julia> prob = readqps(joinpath(netlib_path, "DFL001.SIF"))
[ Info: Using 'DFL001' as NAME (l. 5)
[ Info: Using 'NIL' as objective (l. 6098)
[ Info: Using 'R0006' as RHS (l. 29101)
ERROR: ArgumentError: cannot parse "R0009" as Float64
Stacktrace:
[1] _parse_failure(::Type{T} where T, ::String, ::Int64, ::Int64) at ./parse.jl:370 (repeats 2 times)
[2] #tryparse_internal#347 at ./parse.jl:366 [inlined]
[3] tryparse_internal at ./parse.jl:364 [inlined]
[4] #parse#348 at ./parse.jl:376 [inlined]
[5] parse at ./parse.jl:376 [inlined]
[6] read_rhs_line!(::QPSData, ::QPSReader.MPSCard{QPSReader.FreeMPS}) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:478
[7] readqps(::String; mpsformat::Symbol) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:800
[8] readqps(::String) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:703
[9] top-level scope at REPL[6]:1
[10] eval(::Module, ::Any) at ./boot.jl:331
[11] eval_user_input(::Any, ::REPL.REPLBackend) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:86
[12] run_backend(::REPL.REPLBackend) at /Users/dpo/.julia/packages/Revise/Pcs5V/src/Revise.jl:1073
[13] top-level scope at none:0
julia> prob = readqps(joinpath(netlib_path, "FORPLAN.SIF"))
[ Info: Using 'FORPLAN' as NAME (l. 5)
[ Info: Using 'OB1PNW20' as objective (l. 21)
ERROR: Duplicate row name DEDO3 at line 23
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] read_rows_line!(::QPSData, ::QPSReader.MPSCard{QPSReader.FreeMPS}) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:363
[3] readqps(::String; mpsformat::Symbol) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:796
[4] readqps(::String) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:703
[5] top-level scope at REPL[7]:1
[6] eval(::Module, ::Any) at ./boot.jl:331
[7] eval_user_input(::Any, ::REPL.REPLBackend) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:86
[8] run_backend(::REPL.REPLBackend) at /Users/dpo/.julia/packages/Revise/Pcs5V/src/Revise.jl:1073
[9] top-level scope at none:0
julia> prob = readqps(joinpath(netlib_path, "GFRD-PNC.SIF"))
[ Info: Using 'GFRD-PNC' as NAME (l. 5)
[ Info: Using 'OBJ' as objective (l. 20)
[ Info: Using 'PAF' as RHS (l. 2821)
ERROR: ArgumentError: cannot parse "PEE" as Float64
Stacktrace:
[1] _parse_failure(::Type{T} where T, ::String, ::Int64, ::Int64) at ./parse.jl:370 (repeats 2 times)
[2] #tryparse_internal#347 at ./parse.jl:366 [inlined]
[3] tryparse_internal at ./parse.jl:364 [inlined]
[4] #parse#348 at ./parse.jl:376 [inlined]
[5] parse at ./parse.jl:376 [inlined]
[6] read_rhs_line!(::QPSData, ::QPSReader.MPSCard{QPSReader.FreeMPS}) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:478
[7] readqps(::String; mpsformat::Symbol) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:800
[8] readqps(::String) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:703
[9] top-level scope at REPL[8]:1
[10] eval(::Module, ::Any) at ./boot.jl:331
[11] eval_user_input(::Any, ::REPL.REPLBackend) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:86
[12] run_backend(::REPL.REPLBackend) at /Users/dpo/.julia/packages/Revise/Pcs5V/src/Revise.jl:1073
[13] top-level scope at none:0
julia> prob = readqps(joinpath(netlib_path, "SIERRA.SIF"))
[ Info: Using 'SIERRA' as NAME (l. 5)
[ Info: Using 'OBJ' as objective (l. 1247)
[ Info: Using 'BB1R' as RHS (l. 6566)
ERROR: ArgumentError: cannot parse "BB2R" as Float64
Stacktrace:
[1] _parse_failure(::Type{T} where T, ::String, ::Int64, ::Int64) at ./parse.jl:370 (repeats 2 times)
[2] #tryparse_internal#347 at ./parse.jl:366 [inlined]
[3] tryparse_internal at ./parse.jl:364 [inlined]
[4] #parse#348 at ./parse.jl:376 [inlined]
[5] parse at ./parse.jl:376 [inlined]
[6] read_rhs_line!(::QPSData, ::QPSReader.MPSCard{QPSReader.FreeMPS}) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:478
[7] readqps(::String; mpsformat::Symbol) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:800
[8] readqps(::String) at /Users/dpo/dev/julia/JSO/QPSReader.jl/src/readqps.jl:703
[9] top-level scope at REPL[9]:1
[10] eval(::Module, ::Any) at ./boot.jl:331
[11] eval_user_input(::Any, ::REPL.REPLBackend) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:86
[12] run_backend(::REPL.REPLBackend) at /Users/dpo/.julia/packages/Revise/Pcs5V/src/Revise.jl:1073
[13] top-level scope at none:0
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!
Several Julia packages need to read MPS files, so having a stand-alone Julia reader for MPS files would avoid duplicating code.
For instance:
Couple of questions:
(obviously, I can PR all this, just want the go-ahead before spending time on it)
The neos-5044663-wairoa instance from MIPLIB 2017 fails to read.
julia> QPSReader.readqps(GZip.gzopen("neos-5044663-wairoa.mps.gz"), mpsformat=:fixed)
[ Info: Using 'neos-5044663-wairoa' as NAME (l. 8)
[ Info: Using 'R0000000' as objective (l. 10)
┌ Error: Ignoring marker at line 230060
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 301671
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 301674
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 301707
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 301712
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 302575
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 302578
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 302793
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 302796
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 303257
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 303260
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 303353
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 303358
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304105
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304108
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304155
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304158
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304469
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304472
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304565
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304568
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304601
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304606
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304699
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304704
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304797
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304800
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304881
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 304888
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 305027
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 305030
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 305485
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 305490
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 306351
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 306354
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 306593
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 306596
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 307447
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 307450
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 307635
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 307638
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 308283
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 308286
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 309055
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 309058
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 309275
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 309280
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 310407
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 310410
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 310543
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 310546
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 310731
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 310736
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 311137
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 311140
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 311315
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 311318
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 311365
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 311368
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 312335
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 312338
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 312523
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 312526
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 312849
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 312852
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 313155
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 313158
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 313481
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 313486
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 314337
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 314340
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 314479
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 314482
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 314979
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 314982
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 315477
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 315480
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 315619
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 315764
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
┌ Error: Ignoring marker at line 319405
└ @ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:852
ERROR: ArgumentError: cannot parse "lumn" as Float64
Stacktrace:
[1] _parse_failure(T::Type, s::String, startpos::Int64, endpos::Int64) (repeats 2 times)
@ Base ./parse.jl:373
[2] #tryparse_internal#403
@ ./parse.jl:369 [inlined]
[3] tryparse_internal
@ ./parse.jl:367 [inlined]
[4] #parse#404
@ ./parse.jl:379 [inlined]
[5] parse
@ ./parse.jl:379 [inlined]
[6] read_columns_line!(qps::QPSReader.QPSData, card::QPSReader.MPSCard{QPSReader.FixedMPS}; integer_section::Bool)
@ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:487
[7] readqps(qps::GZip.GZipStream; mpsformat::Symbol)
@ QPSReader ~/.julia/packages/QPSReader/panNr/src/readqps.jl:856
[8] top-level scope
@ REPL[5]:1
The problematic line in the file is likely:
C0063540 LB_full 0 $ empty column
I had never seen "$" in an MPS file before, but apparently it's valid comment in fixed format. IBM docs say:
If the first character in Field 3 or 5 is a dollar sign ($), the remaining characters in the record are treated as a comment. Another method for inserting comments is to place an asterisk (*) in column 1. Everything on such a line is treated as a comment.
MPS files may have multiple objective rows, right-hand sides, etc... which is currently not handled in the code.
N
row is encountered, so only the last such row is recorded.RHS
rhs1 r1 2.0 r2 6.0
rhs2 r1 -2.0 r2 -6.0
would yield right-hand sides of -2
and -6
for rows r1
and r2
, respectively.
Obviously, nobody follows the same convention, so I would propose to do as follows:
N
row is selected as the objective. Other N
rows are ignored.N
rows.RHS
, BOUNDS
, RANGES
is selected; others (if any) are ignoredCOLUMNS
and QUADOBJ
sections are added together. This follows the default behavior of creating a sparse matrix from the coefficients list: duplicate entries are added.RHS
, BOUNDS
, RANGES
sections over-write previous entries.Here's a quick and non-exhaustive overview of what others do:
The RHS section allows one or more right-hand-side vectors to be
defined; most people don't bother having more than one.
The MPS format allows multiple righthand sides (RHSs), multiple bounds, and multiple range vectors. It also allows extra free rows. Together, these features are known as extra rim vectors. By default, the CPLEX MPS reader selects the first RHS, bound, and range definitions that it finds. The first free row (that is, N-type row) becomes the objective function, and the remaining free rows are discarded. The extra rim data are also discarded.
The Gurobi docs says
The name of the RHS is specified in the first field (column 5 in fixed format), but this name is ignored by the Gurobi reader
and when I test with Gurobi 9.0, duplicate rhs entries for a given row are ignored (i.e., only the first occurrence of each row is recorded).
bound name (ignored)
Mosek docs do not mention how multiple entries are handled, however in practice it looks like the first occurrence of RHS is recorded, so in the example above, the line rhs2 ...
would be ignored.
If there are duplicate entries, only the last one is recorded, i.e.,
rhs1 r1 2.0 r1 6.0
would yield a right-hand side value of 6.0
for row r1
.
I think it would be enough to have
# .travis.yml
julia:
- 1.0
- 1
- nightly
and
# .appveyor.yml
environment:
matrix:
- julia_version: 1.0
- julia_version: 1
- julia_version: nightly
since 1
should automatically point to the newest stable 1.Y.Z
release.
While integer variables are not supported, the code claims to at least set their bounds. However, the reader can silently give incorrect bounds.
The CPLEX MPS documentation says:
ILOG CPLEX accepts two commonly used ways of extending
the MPS file format to include integer variables: in the COLUMNS section or in the BOUNDS
section.
In the first way, integer variables are identified within the COLUMNS section of the MPS file
by marker lines.
...
If no bounds are specified for the variables within markers, bounds of 0 (zero) and 1 (one)
are assumed.
GLPK follows the CPLEX behavior.
However, QPSReader ignores markers, so it can't can't enforce this rule to set the correct variable bounds (it sets an upper bound of infinity in this case).
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.