Skip to content

Commit

Permalink
Merge pull request #5 from psrenergy/px/interface
Browse files Browse the repository at this point in the history
Bump Version `-> v0.2`
  • Loading branch information
pedromxavier authored Oct 18, 2023
2 parents f6b09fb + 88ed038 commit d70a5b6
Show file tree
Hide file tree
Showing 16 changed files with 312 additions and 113 deletions.
10 changes: 6 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ jobs:
arch: ${{ matrix.arch }}
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
# - uses: julia-actions/julia-processcoverage@v1
# - uses: codecov/codecov-action@v2
# with:
# file: lcov.info
env:
PBO_INTEGRATION_TESTS: ${{ vars.PBO_INTEGRATION_TESTS }}
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v2
with:
file: lcov.info
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PseudoBooleanOptimization"
uuid = "c8fa9a04-bc42-452d-8558-dc51757be744"
authors = ["pedromxavier <[email protected]>"]
version = "0.1.1"
version = "0.2.0"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
36 changes: 36 additions & 0 deletions src/library/function/abstract.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,39 @@ function Base.convert(::Type{U}, f::AbstractPBF{V,T}) where {V,T,U<:Number}
error("Can't convert non-scalar pseudo-Boolean function to scalar type '$U'")
end
end

function Base.show(io::IO, ::MIME"text/plain", f::AbstractPBF{V,T}) where {V,T}
if isconstant(f)
print(io, f[nothing])

return nothing
end

terms = sort!(map(((ω, c)::Pair) -> (sort!(collect(ω)) => c), pairs(f)); by=first, lt=varlt)

for (i, (ω, c)) in enumerate(terms)
if i > 1
if c < zero(T)
print(io, " - ")
else
print(io, " + ")
end
else # i == 1
if c < zero(T)
print(io, "-")
end
end

c_ = abs(c)

if isempty(ω)
print(io, c_)
elseif isone(c_)
join(io, varshow.(ω), " ")
else
join(io, [string(c_); varshow.(ω)], " ")
end
end

return nothing
end
32 changes: 24 additions & 8 deletions src/library/function/function.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,31 @@ function Base.promote_rule(::Type{PBF{V,Tf,S}}, ::Type{PBF{V,Tg,S}}) where {V,Tf
return PBF{V,T,S}
end

# Constructors
function PBF{V,T,S}(items) where {V,T,S}
@assert Base.haslength(items)
# Constructors - Base case
function PBF{V,T,S}() where {V,T,S}
return zero(PBF{V,T,S})
end

# Constructors - Induction
function PBF{V,T,S}(args...) where {V,T,S}
return PBF{V,T,S}(collect(args))
end

# Constructors - Generator
function PBF{V,T,S}(items::G) where {V,T,S,G<:Iterators.Generator}
return PBF{V,T,S}(collect(items))
end

f = sizehint!(zero(PBF{V,T,S}), length(items))
# Constructors - Dict
# function PBF{V,T,S}(items::AbstractDict) where {V,T,S}
# return PBF{V,T,S}(collect(items))
# end

# Constructors - Item list
function PBF{V,T,S}(items::AbstractVector) where {V,T,S}
f = zero(PBF{V,T,S})

Base.haslength(items) && sizehint!(f, length(items))

for x in items
ω, c = term(PBF{V,T,S}, x)
Expand All @@ -38,7 +58,3 @@ function PBF{V,T,S}(items) where {V,T,S}

return f
end

function PBF{V,T,S}(args...) where {V,T,S}
return PBF{V,T,S}(args)
end
6 changes: 5 additions & 1 deletion src/library/variables/varmap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ function varmap(::Type{V}, i::Integer) where {V}
end

function varmap(::Type{V}, i::Integer) where {V<:Union{AbstractString,Symbol}}
return V("x$(_subscript(i))")
if i >= 0
return V("var_$(i)")
else
return V("aux_$(-i)")
end
end
4 changes: 2 additions & 2 deletions src/library/variables/varmul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ function varmul(u::Set{V}, v::Set{V}) where {V}
end

function varmul(u::V, v::Set{V}) where {V}
return u v
return push!(copy(u), v)
end

function varmul(u::Set{V}, v::V) where {V}
return u v
return push!(copy(u), v)
end

function varmul(u::V, v::V) where {V}
Expand Down
38 changes: 0 additions & 38 deletions src/library/variables/varshow.jl
Original file line number Diff line number Diff line change
@@ -1,41 +1,3 @@
varshow(io::IO, v::V) where {V} = show(io, varshow(v))
varshow(v::Integer, x::AbstractString = "x") = "$(x)$(_subscript(v))"
varshow(v::V) where {V<:Union{Symbol,AbstractString}} = string(v)

function Base.show(io::IO, ::MIME"text/plain", f::AbstractPBF{V,T}) where {V,T}
if isconstant(f)
print(io, f[nothing])

return nothing
end

terms = sort!(map(((ω, c)::Pair) -> (sort(collect(ω)) => c), pairs(f)); by=first, lt=varlt)

for (i, (ω, c)) in enumerate(terms)
if i > 1
if c < zero(T)
print(io, " - ")
else
print(io, " + ")
end
else
if c < zero(T)
print(io, "-")
end
end

c_ = abs(c)

if isone(c_)
join(io, varshow.(ω), " ")
else
join(io, [string(c_); varshow.(ω)], " ")
end
end

return nothing
end

# function Base.show(io::IO, f::VectorFunction{V,T}) where {V,T}
# join(io, f.Ω, " + ")
# end
19 changes: 9 additions & 10 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Tests

## Requirements

- [ ] Constructors
- [ ] Standard Constructor
- [ ] Operators
- [ ] `+`
- [ ] `-`
- [ ] `*`
- [ ] `/`
- [ ] `^`
## Unit Tests

## Integration Tests

To run the integration tests, the `PBO_INTEGRATION_TEST` environment variable must be set to a try value. For example:

```bash
export PBO_INTEGRATION_TEST=1
```
46 changes: 42 additions & 4 deletions test/assets/assets.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
module Assets
# Base.get_bool_env will be available in Julia 1.10 and beyond
# Source:
# https://github.com/JuliaLang/julia/blob/3cc4fdc7a11b99a253fb1d4b1b420bb52ac95b69/base/env.jl#L100C1-L136C4

using PseudoBooleanOptimization
const GET_BOOL_ENV_TRUTHY = (
"t", "T",
"true", "True", "TRUE",
"y", "Y",
"yes", "Yes", "YES",
"1"
)
const GET_BOOL_ENV_FALSY = (
"f", "F",
"false", "False", "FALSE",
"n", "N",
"no", "No", "NO",
"0"
)

const PBO = PseudoBooleanOptimization
"""
get_bool_env(key::String, default::Bool)::Union{Bool,Nothing}
include("function.jl")
Evaluate whether the value of environnment variable `key` is a truthy or falsy string,
and return `nothing` if it is not recognized as either. If the variable is not set, or is set to "",
return `default`.
Recognized values are the following, and their Capitalized and UPPERCASE forms:
truthy: "t", "true", "y", "yes", "1"
falsy: "f", "false", "n", "no", "0"
"""
function get_bool_env(key::String, default::Bool)::Union{Bool,Nothing}
if !haskey(ENV, key)
return default
end

val = ENV[key]

if isempty(val)
return default
elseif val GET_BOOL_ENV_TRUTHY
return true
elseif val GET_BOOL_ENV_FALSY
return false
else
return nothing
end
end
12 changes: 9 additions & 3 deletions test/integration/integration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ function integration_tests()
return nothing
end

function test_dependant(pkg_name::AbstractString, dep_path::AbstractString = PBO.__PROJECT__)
function test_dependant(pkg_name::AbstractString, dep_path::AbstractString = PBO.__PROJECT__; kws...)
@info "Integration Tests: $pkg_name"

Pkg.activate(; temp = true)

Pkg.develop(; path = dep_path)
Expand All @@ -15,9 +17,13 @@ function test_dependant(pkg_name::AbstractString, dep_path::AbstractString = PBO
Pkg.status()

try
Pkg.test(pkg_name)
Pkg.test(pkg_name; kws...)
catch e
return false
if e isa PkgError
return false
else
rethrow(e)
end
end

return true
Expand Down
13 changes: 10 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
using Pkg
using Pkg.Types: PkgError
using Test
using PseudoBooleanOptimization
const PBO = PseudoBooleanOptimization

# Test assets, i.e., test examples and mockups
# include("assets/assets.jl")
# Test assets, i.e., helper functions, test examples and data mockups
include("assets/assets.jl")

# Unit tests
include("unit/unit.jl")

# Integration tests
include("integration/integration.jl")

function main(; run_itegration_tests::Bool = false)
function run_integration_tests()::Bool
return "--run-integration-tests" ARGS || get_bool_env("PBO_INTEGRATION_TESTS", false)
end

function main(; run_itegration_tests::Bool = run_integration_tests())
@testset "♠ PseudoBooleanOptimization.jl $(PBO.__VERSION__) Test Suite ♠" verbose = true begin
unit_tests()

if run_itegration_tests
@info "Running Integration Tests"

integration_tests()
end
end
Expand Down
79 changes: 76 additions & 3 deletions test/unit/calculus.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,80 @@
function test_calculus()
@testset "Calculus" begin
for f in Assets.PBF_LIST
@test PBO.maxgap(f) (PBO.upperbound(f) - PBO.lowerbound(f))
@testset "⊛ Calculus" verbose = true begin
@testset "∴ SetDict" begin
@testset "→ Derivatives" begin
let V = Symbol, T = Float64, F = PBO.SetDictPBF{V,T}
f = F(
-1.0,
:x => 2.0,
:y => -3.0,
:z => 4.0,
:w => -5.0,
[:x, :y] => 6.0,
[:x, :z] => -7.0,
[:x, :w] => 8.0,
[:y, :z] => -9.0,
[:y, :w] => 10.0,
[:z, :w] => -11.0,
[:x, :y, :z] => 12.0,
[:x, :y, :w] => -13.0,
[:x, :z, :w] => 14.0,
[:y, :z, :w] => -15.0,
[:x, :y, :z, :w] => 16.0,
)

fx = F(
2.0,
:y => 6.0,
:z => -7.0,
:w => 8.0,
[:y, :z] => 12.0,
[:y, :w] => -13.0,
[:z, :w] => 14.0,
[:y, :z, :w] => 16.0,
)

fy = F(
-3.0,
:x => 6.0,
:z => -9.0,
:w => 10.0,
[:x, :z] => 12.0,
[:x, :w] => -13.0,
[:z, :w] => -15.0,
[:x, :z, :w] => 16.0,
)

fz = F(
4.0,
:x => -7.0,
:y => -9.0,
:w => -11.0,
[:x, :y] => 12.0,
[:x, :w] => 14.0,
[:y, :w] => -15.0,
[:x, :y, :w] => 16.0,
)

fw = F(
-5.0,
:x => 8.0,
:y => 10.0,
:z => -11.0,
[:x, :y] => -13.0,
[:x, :z] => 14.0,
[:y, :z] => -15.0,
[:x, :y, :z] => 16.0,
)

@test PBO.derivative(f, :x) == fx
@test PBO.derivative(f, :y) == fy
@test PBO.derivative(f, :z) == fz
@test PBO.derivative(f, :w) == fw
@test PBO.derivative(f, :u) == zero(F)

@test PBO.gradient(f, [:x, :y, :z, :w]) == [fx, fy, fz, fw]
end
end
end
end

Expand Down
Loading

0 comments on commit d70a5b6

Please sign in to comment.