Skip to content
This repository was archived by the owner on Apr 21, 2022. It is now read-only.

Conversation

@dourouc05
Copy link
Contributor

@dourouc05 dourouc05 commented Oct 30, 2019

Following jump-dev/JuMP.jl#1982, here is the implementation of two other compression formats (BZIP2 and XZ). While I was at it, I also refactored a bit the common functions (in the hope that adding new compression formats and new export formats will be easier, the changes to be done being centralised).

For now, I did not add tests, as I'm not sure which ones I should add (currently, it seems compression is handled within each file format, but I think just testing one of them should be enough -- e.g., just LP, as nothing is really dependent on the file format).

@codecov-io
Copy link

codecov-io commented Oct 30, 2019

Codecov Report

Merging #90 into master will decrease coverage by 0.03%.
The diff coverage is 97.22%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #90      +/-   ##
==========================================
- Coverage   95.92%   95.88%   -0.04%     
==========================================
  Files           8        9       +1     
  Lines        1275     1289      +14     
==========================================
+ Hits         1223     1236      +13     
- Misses         52       53       +1
Impacted Files Coverage Δ
src/compression.jl 100% <100%> (ø)
src/MOF/MOF.jl 100% <100%> (ø) ⬆️
src/MathOptFormat.jl 95.08% <91.66%> (-2.07%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update cc7e817...2b71875. Read the comment docs.

@odow
Copy link
Owner

odow commented Oct 30, 2019

Instead of the enum's for compression, I wonder if a better approach is to define an abstract type so that people can add different compression schemes without having to depend on a whole lot of different packages.

abstract type AbstractCompressionScheme end

struct NoCompression <: AbstractCompressionScheme end
function compressed_open(
    f::Function, filename::String, mode::String, ::NoCompression
) 
    return open(f, filename, mode)
end

struct Gzip <: AbstractCompressionScheme end
function open(
    f::Function, filename::String, mode::String, ::Gzip
)
    if mode == "w"
        open(f, CodecZlib.GzipCompressorStream, filename, "w")
    else
        ...
    end
end

@dourouc05
Copy link
Contributor Author

I'm trying to implement your approach, with types. However, when looping over the compression formats (detect the format from the extension), I don't see any clean way of implementing it with types. I find that subtypes is not really clean, but I cannot see anything else…

Here is what I did right now: 698b8cc

@odow
Copy link
Owner

odow commented Oct 30, 2019

Just force the user to provide the compression scheme. Define

function read_from_file(filename; compression_scheme = nothing)
    if compression_scheme === nothing
        compression_scheme = endswith(filename, ".gz") ? Gzip() : NoCompression()
    end
    compressed_open(filename, "r", compression_scheme) do
        read_from_file(...)
    end
end

@dourouc05
Copy link
Contributor Author

Better this way? I still define three "default" compression schemes, supported everywhere. The latest commit also includes a little bit of documentation.

Should the new open methods overload Base.open? Right now, if I understood correctly what's happening, it seems like there is a new function in MOF (with one method per compression scheme). I had to do things like return Base.open to make it work.

return _file_formats[_filename_to_format(filename)][2]()
end

function gzip_open(f::Function, filename::String, mode::String; compression::AbstractCompressionScheme=AutomaticCompressionDetection())
Copy link
Owner

Choose a reason for hiding this comment

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

Remove this function.

abstract type AbstractCompressionScheme end

struct AutomaticCompressionDetection <: AbstractCompressionScheme end
# No open() implementation, this would not make sense (flag to indicate that _filename_to_compression should be called).
Copy link
Owner

Choose a reason for hiding this comment

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

function _compressed_open(
    f::Function,
    filename::String,
    mode::String,
    ::AutomaticCompression
)
    compression = _filename_to_compression(filename)
    return _compressed_open(f, filename, mode, compression)
end

# No open() implementation, this would not make sense (flag to indicate that _filename_to_compression should be called).

struct NoCompression <: AbstractCompressionScheme end
function open(
Copy link
Owner

Choose a reason for hiding this comment

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

_compressed_open

end

struct Gzip <: AbstractCompressionScheme end
function open(
Copy link
Owner

Choose a reason for hiding this comment

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

_compressed_open

end

struct Bzip2 <: AbstractCompressionScheme end
function open(
Copy link
Owner

Choose a reason for hiding this comment

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

_compressed_open

end

struct Xz <: AbstractCompressionScheme end
function open(
Copy link
Owner

Choose a reason for hiding this comment

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

_compressed_open

"""
abstract type AbstractCompressionScheme end

struct AutomaticCompressionDetection <: AbstractCompressionScheme end
Copy link
Owner

Choose a reason for hiding this comment

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

Just AutomaticCompression

function MOI.write_to_file(model::MATH_OPT_FORMATS, filename::String)
gzip_open(filename, "w") do io
function MOI.write_to_file(model::MATH_OPT_FORMATS, filename::String; compression::AbstractCompressionScheme=AutomaticCompressionDetection())
gzip_open(filename, "w", compression=compression) do io
Copy link
Owner

Choose a reason for hiding this comment

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

_compressed_open(filename, "w", compression) do io

function MOI.read_from_file(model::MATH_OPT_FORMATS, filename::String)
gzip_open(filename, "r") do io
function MOI.read_from_file(model::MATH_OPT_FORMATS, filename::String; compression::AbstractCompressionScheme=AutomaticCompressionDetection())
gzip_open(filename, "r", compression=compression) do io
Copy link
Owner

Choose a reason for hiding this comment

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

_compressed_open(filename, "r", compression) do io

else
error("File-type of $(filename) not supported by MathOptFormat.jl.")
end
model = _filename_to_model(filename)
Copy link
Owner

Choose a reason for hiding this comment

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

function read_from_file(
    filename::String; 
    compression::AbstractCompressionScheme = AutomaticCompression(),
    file_format::FileFormat = AUTOMATIC_FILE_FORMAT,
)
    if file_format == AUTOMATIC_FILE_FORMAT
        for (format, (ext, _)) in _FILE_FORMATS
            if endswith(filename, ext) || occursin("$(ext).", filename)
                file_format = format
                break
            end
        end
        error(
            "Unable to detect automatically format of $(filename). Use the " *
            "`file_format` keyword to specify the file format."
        )
    end
    model = _FILE_FORMATS[file_format]()
    MOI.read_from_file(model, filename; compression = compression)
    return model
end

You might want to do something similar with AutomaticCompression so that we don't try NoCompression if the user passes in a weird filename.

@dourouc05
Copy link
Contributor Author

Better this way?

@dourouc05
Copy link
Contributor Author

I've added a few tests. One of them fails, I registered an issue for that (JuliaIO/CodecXz.jl#16).

@odow
Copy link
Owner

odow commented Nov 3, 2019

Just remove Xz for now

@dourouc05
Copy link
Contributor Author

dourouc05 commented Nov 3, 2019 via email

@dourouc05
Copy link
Contributor Author

I've commented out this code so it can easily be restored once the package is fixed.

@dourouc05
Copy link
Contributor Author

All tests pass; could this be merged?

@odow odow merged commit a8b6900 into odow:master Nov 26, 2019
@odow
Copy link
Owner

odow commented Nov 26, 2019

Sorry for moving slowly on this. Thanks!

@dourouc05
Copy link
Contributor Author

No problem, thanks for merging :)!

@dourouc05 dourouc05 deleted the dourouc05-compression branch November 26, 2019 16:14
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants