1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
4  *   info_at_agrum_dot_org
5  *
6  *  This library is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License
17  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief the structural constraint imposing a partial order over nodes
24  *
25  * In DBNs, it is forbidden to add arcs from nodes at time slice t to nodes at
26  * time slice s, where s < t. This class allows for taking this kind of
27  *constraint
28  * into account by imposing a partial order over the nodes: arcs (X,Y) can then
29  * only be added if X <= Y in the partial order.
30  * @warning: there may exist free variables, that is variables whose order
31  * w.r.t. the other variables is unspecified. In this case, arcs adjacent
32  * to them can be constructed. The partial order is specified by assigning
33  * numbers to nodes (through a NodeProperty). Nodes without number (i.e., that
34  * do not belong to the property) are free.
35  *
36  * @author Christophe GONZALES(_at_AMU) and Pierre-Henri WUILLEMIN(_at_LIP6)
37  */
38 
39 #ifndef DOXYGEN_SHOULD_SKIP_THIS
40 
41 namespace gum {
42 
43   namespace learning {
44 
45     /// sets a new graph from which we will perform checkings
setGraphAlone(const DiGraph & graph)46     INLINE void StructuralConstraintSliceOrder::setGraphAlone(const DiGraph& graph) {}
47 
48     /// checks whether the constraints enable to add arc (x,y)
checkArcAdditionAlone(NodeId x,NodeId y)49     INLINE bool StructuralConstraintSliceOrder::checkArcAdditionAlone(NodeId x, NodeId y) const {
50       try {
51         return _SliceOrder_order_[x] <= _SliceOrder_order_[y];
52       } catch (const Exception&) { return true; }
53     }
54 
55     /// checks whether the constraints enable to remove arc (x,y)
checkArcDeletionAlone(NodeId x,NodeId y)56     INLINE bool StructuralConstraintSliceOrder::checkArcDeletionAlone(NodeId x, NodeId y) const {
57       return true;
58     }
59 
60     /// checks whether the constraints enable to reverse arc (x,y)
checkArcReversalAlone(NodeId x,NodeId y)61     INLINE bool StructuralConstraintSliceOrder::checkArcReversalAlone(NodeId x, NodeId y) const {
62       try {
63         return _SliceOrder_order_[x] == _SliceOrder_order_[y];
64       } catch (const Exception&) { return true; }
65     }
66 
67     /// notify the constraint of a modification of the graph
modifyGraphAlone(const ArcAddition & change)68     INLINE void StructuralConstraintSliceOrder::modifyGraphAlone(const ArcAddition& change) {}
69 
70     /// notify the constraint of a modification of the graph
modifyGraphAlone(const ArcDeletion & change)71     INLINE void StructuralConstraintSliceOrder::modifyGraphAlone(const ArcDeletion& change) {}
72 
73     /// notify the constraint of a modification of the graph
modifyGraphAlone(const ArcReversal & change)74     INLINE void StructuralConstraintSliceOrder::modifyGraphAlone(const ArcReversal& change) {}
75 
76     /// notify the constraint of a modification of the graph
modifyGraphAlone(const GraphChange & change)77     INLINE void StructuralConstraintSliceOrder::modifyGraphAlone(const GraphChange& change) {}
78 
79     /// indicates whether a change will always violate the constraint
80     INLINE bool
isAlwaysInvalidAlone(const GraphChange & change)81        StructuralConstraintSliceOrder::isAlwaysInvalidAlone(const GraphChange& change) const {
82       switch (change.type()) {
83         case GraphChangeType::ARC_ADDITION:
84           try {
85             return (_SliceOrder_order_[change.node1()] > _SliceOrder_order_[change.node2()]);
86           } catch (const Exception&) { return false; }
87 
88         case GraphChangeType::ARC_DELETION:
89           return false;
90 
91         case GraphChangeType::ARC_REVERSAL:
92           try {
93             return (_SliceOrder_order_[change.node1()] != _SliceOrder_order_[change.node2()]);
94           } catch (const Exception&) { return false; }
95 
96         default:
97           GUM_ERROR(OperationNotAllowed,
98                     "edge modifications are not "
99                     "supported by SliceOrder constraints");
100       }
101     }
102 
103     /// checks whether the constraints enable to add an arc
104     INLINE bool
checkModificationAlone(const ArcAddition & change)105        StructuralConstraintSliceOrder::checkModificationAlone(const ArcAddition& change) const {
106       return checkArcAdditionAlone(change.node1(), change.node2());
107     }
108 
109     /// checks whether the constraints enable to remove an arc
110     INLINE bool
checkModificationAlone(const ArcDeletion & change)111        StructuralConstraintSliceOrder::checkModificationAlone(const ArcDeletion& change) const {
112       return checkArcDeletionAlone(change.node1(), change.node2());
113     }
114 
115     /// checks whether the constraints enable to reverse an arc
116     INLINE bool
checkModificationAlone(const ArcReversal & change)117        StructuralConstraintSliceOrder::checkModificationAlone(const ArcReversal& change) const {
118       return checkArcReversalAlone(change.node1(), change.node2());
119     }
120 
121     /// checks whether the constraints enable to perform a graph change
122     INLINE bool
checkModificationAlone(const GraphChange & change)123        StructuralConstraintSliceOrder::checkModificationAlone(const GraphChange& change) const {
124       switch (change.type()) {
125         case GraphChangeType::ARC_ADDITION:
126           return checkArcAdditionAlone(change.node1(), change.node2());
127 
128         case GraphChangeType::ARC_DELETION:
129           return checkArcDeletionAlone(change.node1(), change.node2());
130 
131         case GraphChangeType::ARC_REVERSAL:
132           return checkArcReversalAlone(change.node1(), change.node2());
133 
134         default:
135           GUM_ERROR(OperationNotAllowed,
136                     "edge modifications are not "
137                     "supported by StructuralConstraintSliceOrder");
138       }
139     }
140 
141     /// sets the time slices of all the nodes in the property
setSliceOrder(const NodeProperty<NodeId> & order)142     INLINE void StructuralConstraintSliceOrder::setSliceOrder(const NodeProperty< NodeId >& order) {
143       _SliceOrder_order_ = order;
144     }
145 
146     /// sets the default time slice
setDefaultSlice(NodeId slice)147     INLINE void StructuralConstraintSliceOrder::setDefaultSlice(NodeId slice) {
148       for (auto& node: _SliceOrder_order_) {
149         node.second = slice;
150       }
151     }
152 
153     /// adds a new node in the slice order
addNode(NodeId node,NodeId slice)154     INLINE void StructuralConstraintSliceOrder::addNode(NodeId node, NodeId slice) {
155       _SliceOrder_order_.set(node, slice);
156     }
157 
158     /// returns the current slice order
sliceOrder()159     INLINE const NodeProperty< NodeId >& StructuralConstraintSliceOrder::sliceOrder() const {
160       return _SliceOrder_order_;
161     }
162 
163 // include all the methods applicable to the whole class hierarchy
164 #  define GUM_CONSTRAINT_CLASS_NAME StructuralConstraintSliceOrder
165 #  include <agrum/BN/learning/constraints/structuralConstraintPatternInline.h>
166 #  undef GUM_CONSTRAINT_CLASS_NAME
167 
168   } /* namespace learning */
169 
170 } /* namespace gum */
171 
172 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
173