Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oximo-core/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl fmt::Display for Model {
}
}

if self.is_feasibility() || self.semantic_objective.borrow().is_some() {
if self.is_feasibility() || self.objective.borrow().is_some() {
writeln!(f, "{}", self.display_objective())?;
}
#[cfg(feature = "gdp")]
Expand Down
74 changes: 50 additions & 24 deletions crates/oximo-core/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::indicator::{IndicatorConstraint, IndicatorConstraintId};
use crate::objective::{Objective, ObjectiveSense};
use crate::param::Parameter;
use crate::reformulation::{IndicatorReformulationArtifacts, SosReformulationArtifacts};
use crate::shared::SharedCell;
use crate::shared::{LazySharedCell, SharedCell};
use crate::soc::{SocConstraint, SocConstraintId};
use crate::sos::{SosConstraint, SosConstraintId};
use crate::var::Variable;
Expand Down Expand Up @@ -114,24 +114,26 @@ pub struct Model {
pub(crate) var_names: SharedCell<FxHashMap<SmolStr, VarId>>,
pub(crate) parameters: SharedCell<Vec<Parameter>>,
pub(crate) param_names: SharedCell<FxHashMap<SmolStr, ParamId>>,
pub(crate) semantics: SharedCell<semantic::SemanticRegistry>,
pub(crate) semantics: LazySharedCell<semantic::SemanticRegistry>,
implicit_scalars: Cell<bool>,
scalar_declarations: Cell<usize>,
pub(crate) alternative_scalar_views:
SharedCell<FxHashMap<crate::SemanticConstraintId, crate::semantic::ScalarConstraintView>>,
pub(crate) alternative_scalar_views: LazySharedCell<
FxHashMap<crate::SemanticConstraintId, crate::semantic::ScalarConstraintView>,
>,
pub(crate) inactive_scalar_views:
SharedCell<FxHashMap<ConstraintId, crate::semantic::ScalarConstraintView>>,
LazySharedCell<FxHashMap<ConstraintId, crate::semantic::ScalarConstraintView>>,
pub(crate) constraints: SharedCell<Vec<AlgebraicConstraint>>,
pub(crate) semantic_names: SharedCell<semantic::ConstraintNames>,
pub(crate) soc_constraints: SharedCell<Vec<SocConstraint>>,
pub(crate) psd_constraints: SharedCell<Vec<PsdConstraint>>,
pub(crate) sos_constraints: SharedCell<Vec<SosConstraint>>,
pub(crate) indicator_constraints: SharedCell<Vec<IndicatorConstraint>>,
pub(crate) sos_reformulations: SharedCell<Vec<SosReformulationArtifacts>>,
pub(crate) indicator_reformulations: SharedCell<Vec<IndicatorReformulationArtifacts>>,
pub(crate) semantic_objective: SharedCell<Option<crate::objective::SemanticObjective>>,
pub(crate) sos_reformulations: LazySharedCell<Vec<SosReformulationArtifacts>>,
pub(crate) indicator_reformulations: LazySharedCell<Vec<IndicatorReformulationArtifacts>>,
pub(crate) semantic_objective: LazySharedCell<Option<crate::objective::SemanticObjective>>,
pub(crate) objective: SharedCell<Option<Objective>>,
objective_declared: Cell<bool>,
objective_signature: Cell<Option<semantic::storage::ScalarKind>>,
cached_kind: Cell<Option<ModelKind>>,
cached_kind_parameter_revision: Cell<u64>,
/// Monotonic counter for auto-naming anonymous constraints registered via
Expand Down Expand Up @@ -280,19 +282,25 @@ impl Model {
indicator_constraints: self.indicator_constraints.clone(),
sos_reformulations: self.sos_reformulations.clone(),
indicator_reformulations: self.indicator_reformulations.clone(),
semantic_objective: SharedCell::new(self.semantic_objective.borrow().clone()),
semantic_objective: LazySharedCell::default(),
objective: SharedCell::new(self.objective.borrow().clone()),
objective_declared: Cell::new(self.objective_declared.get()),
objective_signature: Cell::new(self.objective_signature.get()),
cached_kind: Cell::new(self.cached_kind.get()),
cached_kind_parameter_revision: Cell::new(self.cached_kind_parameter_revision.get()),
auto_seq: Cell::new(self.auto_seq.get()),
};

if let Some(objective) = cloned.semantic_objective.borrow_mut().as_mut() {
if self.objective_signature.get().is_none()
&& let Some(source) =
self.semantic_objective.borrow().as_deref().and_then(Option::as_ref)
{
let mut objective = source.clone();
objective.function.rebind_model(cloned.id());
*cloned.semantic_objective.borrow_mut() = Some(objective);
}

if !cloned.semantics.borrow().extensions.is_empty() {
if cloned.semantics.borrow().as_deref().is_some_and(|s| !s.extensions.is_empty()) {
cloned.semantics.borrow_mut().rebind_extensions(cloned.id());
}

Expand Down Expand Up @@ -321,22 +329,23 @@ impl Model {
var_names: SharedCell::new(FxHashMap::default()),
parameters: SharedCell::new(Vec::new()),
param_names: SharedCell::new(FxHashMap::default()),
semantics: SharedCell::new(semantic::SemanticRegistry::default()),
semantics: LazySharedCell::default(),
implicit_scalars: Cell::new(true),
scalar_declarations: Cell::new(0),
alternative_scalar_views: SharedCell::new(FxHashMap::default()),
inactive_scalar_views: SharedCell::new(FxHashMap::default()),
alternative_scalar_views: LazySharedCell::default(),
inactive_scalar_views: LazySharedCell::default(),
constraints: SharedCell::new(Vec::new()),
semantic_names: SharedCell::new(semantic::ConstraintNames::default()),
soc_constraints: SharedCell::new(Vec::new()),
psd_constraints: SharedCell::new(Vec::new()),
sos_constraints: SharedCell::new(Vec::new()),
indicator_constraints: SharedCell::new(Vec::new()),
sos_reformulations: SharedCell::new(Vec::new()),
indicator_reformulations: SharedCell::new(Vec::new()),
semantic_objective: SharedCell::new(None),
sos_reformulations: LazySharedCell::default(),
indicator_reformulations: LazySharedCell::default(),
semantic_objective: LazySharedCell::default(),
objective: SharedCell::new(None),
objective_declared: Cell::new(false),
objective_signature: Cell::new(None),
cached_kind: Cell::new(None),
cached_kind_parameter_revision: Cell::new(0),
auto_seq: Cell::new(0),
Expand Down Expand Up @@ -426,7 +435,9 @@ impl Model {
/// previously set objective. Not part of the stable public API.
#[doc(hidden)]
pub fn __feasibility(&self) {
*self.semantic_objective.borrow_mut() = None;
self.objective.assert_mutable();
self.semantic_objective.clear();
self.objective_signature.set(None);
*self.objective.borrow_mut() = None;
self.objective_declared.set(true);
self.cached_kind.set(None);
Expand All @@ -443,8 +454,9 @@ impl Model {
let function =
crate::FunctionValue::new(crate::Function::semantic_data(&semantic_function));
self.assert_expr_belongs(expr);
*self.semantic_objective.borrow_mut() =
Some(crate::objective::SemanticObjective { function, sense });
self.objective.assert_mutable();
self.semantic_objective.clear();
self.objective_signature.set(semantic::storage::ScalarKind::of(&function));
*self.objective.borrow_mut() = Some(Objective { expr: expr.id, sense });
self.objective_declared.set(true);
self.cached_kind.set(None);
Expand All @@ -453,7 +465,7 @@ impl Model {
/// Whether feasibility was declared explicitly via `objective!(m, Feasibility)`,
/// as opposed to a model that simply has no objective set.
pub fn is_feasibility(&self) -> bool {
self.objective_declared.get() && self.semantic_objective.borrow().is_none()
self.objective_declared.get() && self.objective.borrow().is_none()
}

/// Ensure the model has a solve direction declared: either an objective
Expand Down Expand Up @@ -482,8 +494,15 @@ impl Model {
}

impl Model {
/// Inspect the original objective function and direction.
pub fn semantic_objective(&self) -> Ref<'_, Option<crate::objective::SemanticObjective>> {
self.semantic_objective.borrow()
self.semantic_objective.borrow_or_init(|| {
let kind = self.objective_signature.get()?;
self.objective.borrow().as_ref().map(|objective| crate::objective::SemanticObjective {
function: kind.function(self.id(), objective.expr),
sense: objective.sense,
})
})
}

pub fn minimize<F: crate::objective::ObjectiveFunction>(&self, function: F) {
Expand Down Expand Up @@ -514,9 +533,16 @@ impl Model {
"objective requires a scalar expression representation; opaque registration is deferred"
),
};
self.objective.assert_mutable();
let kind = semantic::storage::ScalarKind::of(&function);
if kind.is_some() {
self.semantic_objective.clear();
} else {
*self.semantic_objective.borrow_mut() =
Some(crate::objective::SemanticObjective { function, sense });
}
self.objective_signature.set(kind);
*self.objective.borrow_mut() = Some(view);
*self.semantic_objective.borrow_mut() =
Some(crate::objective::SemanticObjective { function, sense });
self.objective_declared.set(true);
self.invalidate_kind();
}
Expand Down
34 changes: 21 additions & 13 deletions crates/oximo-core/src/model/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,10 +511,8 @@ impl Model {
}
constraints.reserve(count);
names.reserve(count);
self.reserve_semantics(ConstraintId(0).into(), count);
let mut ids = Vec::with_capacity(count);
let mut semantics = self.semantic_writer();
let mut alternatives = self.alternative_scalar_views.borrow_mut();
let mut semantics = None;

for item in items {
let id =
Expand All @@ -529,7 +527,7 @@ impl Model {
});

if item.alternative {
alternatives.insert(
self.alternative_scalar_views.borrow_mut().insert(
id.into(),
crate::semantic::ScalarConstraintView {
lhs: item.lhs,
Expand All @@ -538,7 +536,21 @@ impl Model {
},
);
}
item.semantic.record(&mut semantics, id, &item.name, item.origin, item.alternative);
if semantics.is_none()
&& self.implicit_scalars.get()
&& matches!(item.semantic, PendingSemantic::Direct(_))
&& matches!(item.origin, PendingOrigin::Declared)
{
self.record_declared_scalar(id);
} else {
item.semantic.record(
semantics.get_or_insert_with(|| self.semantic_writer()),
id,
&item.name,
item.origin,
item.alternative,
);
}
names.insert(item.name, id);
ids.push(id);
}
Expand Down Expand Up @@ -771,7 +783,7 @@ impl Model {
if self.implicit_scalars.get() {
self.scalar_declarations.get()
} else {
self.semantics.borrow().len()
self.semantics.borrow().as_deref().map_or(0, super::semantic::SemanticRegistry::len)
}
}

Expand Down Expand Up @@ -968,7 +980,6 @@ impl Model {
}
constraints.reserve(count);
names.reserve(count);
self.reserve_semantics(SocConstraintId(0).into(), count);
let mut semantics = self.semantic_writer();

for item in items {
Expand Down Expand Up @@ -1117,7 +1128,6 @@ impl Model {
}
constraints.reserve(count);
names.reserve(count);
self.reserve_semantics(SosConstraintId(0).into(), count);
let mut semantics = self.semantic_writer();

for item in items {
Expand Down Expand Up @@ -1401,18 +1411,16 @@ impl Model {

constraints.reserve(items.len());
names.reserve(items.len());
self.reserve_semantics(IndicatorConstraintId(0).into(), items.len());
let mut ids = Vec::with_capacity(items.len());
let mut semantics = self.semantic_writer();
let mut alternatives = self.alternative_scalar_views.borrow_mut();
let mut semantics = None;

for item in items {
let id = IndicatorConstraintId(
u32::try_from(constraints.len()).expect("indicator constraint count overflow"),
);

if item.alternative {
alternatives.insert(
self.alternative_scalar_views.borrow_mut().insert(
id.into(),
crate::semantic::ScalarConstraintView {
lhs: item.lhs,
Expand All @@ -1421,7 +1429,7 @@ impl Model {
},
);
}
semantics.record_indicator(
semantics.get_or_insert_with(|| self.semantic_writer()).record_indicator(
id,
item.name.clone(),
self.id(),
Expand Down
7 changes: 5 additions & 2 deletions crates/oximo-core/src/model/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ impl Model {
}

let semantic = self.semantic_objective.borrow();
if let Some(objective) = semantic.as_ref() {
if let Some(objective) = semantic.as_deref().and_then(Option::as_ref) {
objective.function.visit_expressions(&mut |root| objective_roots.push(root));
}
}
Expand Down Expand Up @@ -319,7 +319,10 @@ impl Model {

for (index, constraint) in constraints.algebraic().iter().enumerate() {
let id = ConstraintId(u32::try_from(index).expect("constraint count fits u32"));
let root = inactive.get(&id).map_or(constraint.lhs, |view| view.lhs);
let root = inactive
.as_deref()
.and_then(|views| views.get(&id))
.map_or(constraint.lhs, |view| view.lhs);
let parameters = builder.parameters_for_roots([root]);
builder.add_target(ParameterTarget::Algebraic(id), parameters);
}
Expand Down
3 changes: 0 additions & 3 deletions crates/oximo-core/src/model/indexed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,6 @@ impl Model {
if !indexed_parallel(keys.len(), forced_parallel, PAR_INDEXED_SOC_THRESHOLD) {
self.soc_constraints.borrow_mut().reserve(keys.len());
self.soc_names_mut().reserve(keys.len());
self.reserve_semantics(crate::SocConstraintId(0).into(), keys.len());

for key in &keys {
let name: SmolStr = format_index_name_small(name_prefix, key);
Expand Down Expand Up @@ -690,7 +689,6 @@ impl Model {
if !indexed_parallel(keys.len(), forced_parallel, PAR_INDEXED_SOS_THRESHOLD) {
self.sos_constraints.borrow_mut().reserve(keys.len());
self.sos_names_mut().reserve(keys.len());
self.reserve_semantics(crate::SosConstraintId(0).into(), keys.len());

for key in &keys {
self.register_sos_one(sos_type, prepare(key));
Expand Down Expand Up @@ -1159,6 +1157,5 @@ impl Model {
fn reserve_scalar_family(&self, count: usize) {
self.constraints.borrow_mut().reserve(count);
self.constraint_names_mut().reserve(count);
self.reserve_semantics(crate::ConstraintId(0).into(), count);
}
}
Loading
Loading