Skip to content

Commit

Permalink
Merge pull request #63 from COBREXA/mk-broadcastable
Browse files Browse the repository at this point in the history
use `broadcastable()` as the broadcasting interface for Values and Bounds
  • Loading branch information
exaexa authored Jan 8, 2025
2 parents 2902921 + 5c1ae3e commit 7fb70fc
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 33 deletions.
4 changes: 2 additions & 2 deletions docs/src/1-metabolic-modeling.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Copyright (c) 2023-2024, University of Luxembourg #src
# Copyright (c) 2023-2025, University of Luxembourg #src
# #src
# Licensed under the Apache License, Version 2.0 (the "License"); #src
# you may not use this file except in compliance with the License. #src
Expand Down Expand Up @@ -394,7 +394,7 @@ result.exchanges
# ### Alternative: Using Accessors.jl
#
# Accessors.jl implement a "lensy" way to update immutable data structures.
# That comes with a nice outcome of doing the right amount of shallow copyies
# That comes with a nice outcome of doing the right amount of shallow copies
# for you automatically, thus avoiding much of the technical danger of in-place
# modifications. (You still lose the equational reasoning on your code, but that
# may not be an issue at all in usual codebases.)
Expand Down
7 changes: 2 additions & 5 deletions docs/src/2-quadratic-optimization.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Copyright (c) 2023-2024, University of Luxembourg #src
# Copyright (c) 2023-2025, University of Luxembourg #src
# #src
# Licensed under the Apache License, Version 2.0 (the "License"); #src
# you may not use this file except in compliance with the License. #src
Expand Down Expand Up @@ -84,10 +84,7 @@ ellipse_system = C.ConstraintTree(
# single-variable-parametrized line equation.
line_param = C.variable().value
line_system =
:point^C.ConstraintTree(
:x => C.Constraint(0 + 2 * line_param),
:y => C.Constraint(0 + 1 * line_param),
)
:point^C.ConstraintTree([:x, :y] .=> C.Constraint.([0, 0] .+ [2, 1] .* line_param))

# Finally, let's connect the systems using `+` operator and add the objective
# that would minimize the distance of the points:
Expand Down
21 changes: 17 additions & 4 deletions src/bound.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Copyright (c) 2023-2024, University of Luxembourg
# Copyright (c) 2023-2025, University of Luxembourg
# Copyright (c) 2023, Heinrich-Heine University Duesseldorf
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -20,12 +20,25 @@ $(TYPEDEF)
Abstract type of all bounds usable in constraints, including [`Between`](@ref)
and [`EqualTo`](@ref).
`length` of any `Bound` defaults to 1 in order to make broadcasting easier (in
turn, one can write e.g. `Constraint.(some_values, EqualTo(0.0))`).
All [`Bound`](@ref)s are broadcastable as scalars by default.
"""
abstract type Bound end

Base.length(x::Bound) = return 1
Base.Broadcast.broadcastable(x::Bound) = return Ref(x)

"""
$(TYPEDSIGNATURES)
**Deprecation warning:** This is kept for backwards compatibility only, and
will be removed in a future release.
"""
function Base.length(x::Bound)
Base.depwarn(
"length(::Bound) is deprecated and will be removed in future release.",
:length,
)
return 1
end

"""
$(TYPEDEF)
Expand Down
29 changes: 9 additions & 20 deletions src/constraint_tree.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Copyright (c) 2023-2024, University of Luxembourg
# Copyright (c) 2023-2025, University of Luxembourg
# Copyright (c) 2023, Heinrich-Heine University Duesseldorf
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -291,25 +291,14 @@ $(TYPEDSIGNATURES)
Make a trivial constraint system that creates variables with indexes in range
`1:length(keys)` named in order as given by `keys`.
Parameter `bounds` is either `nothing` for creating variables without bounds
assigned to them, a single bound for creating variables with the same constraint
assigned to them all, or an iterable object of same length as `keys` with
individual bounds for each variable in the same order as `keys`.
The individual bounds should be subtypes of [`Bound`](@ref), or nothing. To pass
a single bound for all variables, use e.g. `bounds = EqualTo(0)`.
"""
function variables(weight = 1.0; keys::AbstractVector{Symbol}, bounds = nothing)
bs =
isnothing(bounds) ? Base.Iterators.cycle(tuple(nothing)) :
length(bounds) == 1 ? Base.Iterators.cycle(tuple(bounds)) :
length(bounds) == length(keys) ? bounds :
error("lengths of bounds and keys differ for allocated variables")
ConstraintTree(
k => variable(weight; idx = i, bound = b) for
((i, k), b) in Base.zip(enumerate(keys), bs)
)
end
The individual bounds should be subtypes of [`Bound`](@ref), or nothing (which
is the default). The bounds are broadcasted; to pass a single bound for all
variables, one can use e.g. `bounds = EqualTo(0)`.
"""
variables(weight = 1.0; keys::AbstractVector{Symbol}, bounds = Ref(nothing)) =
let go((i, k), b) = k => variable(weight, idx = i, bound = b)
ConstraintTree(go.(enumerate(keys), bounds)...)
end

"""
$(TYPEDSIGNATURES)
Expand Down
6 changes: 5 additions & 1 deletion src/value.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Copyright (c) 2023-2024, University of Luxembourg
# Copyright (c) 2023-2025, University of Luxembourg
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -18,9 +18,13 @@ $(TYPEDEF)
Abstract type of all values usable in constraints, including
[`LinearValue`](@ref) and [`QuadraticValue`](@ref).
All [`Value`](@ref)s are broadcastable as scalars by default.
"""
abstract type Value end

Base.Broadcast.broadcastable(x::Value) = return Ref(x)

"""
$(TYPEDSIGNATURES)
Expand Down
7 changes: 6 additions & 1 deletion test/misc.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Copyright (c) 2023-2024, University of Luxembourg
# Copyright (c) 2023-2025, University of Luxembourg
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,11 @@
import ConstraintTrees as C
import SparseArrays as SP

@testset "Bounds" begin
b = C.EqualTo(0)
@test (@test_deprecated length(b)) == 1
end

@testset "Values" begin
x =
C.LinearValue(SP.sparse([5.0, 0, 6.0, 0])) +
Expand Down

2 comments on commit 7fb70fc

@exaexa
Copy link
Member Author

@exaexa exaexa commented on 7fb70fc Jan 8, 2025

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request updated: JuliaRegistries/General/122313

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.8.1 -m "<description of version>" 7fb70fc43e0644dcfa59d1a2bce9618a9225c138
git push origin v1.8.1

Please sign in to comment.