leafref require-instance allows to carry non existing values - ietf-netmod-yang

want to get clarity on the following:
say, (omitting key for brevity)
list l1 {
leaf lx {
leafref /x/y;
require-instance false;
mandatory false;
}
}
because mandatory is false,
I can have a l1 instance without the leaf lx.
because require-instance is false, i can have a list instance with lx of any value (of valid type) whether a corresponding /x/y exists or not.
And, suppose the leaf is mandatory;
list l1 {
leaf lx {
leafref /x/y;
require-instance false;
mandatory true;
}
}
now,
list instance must carry the leaf lx. And any value (of correct type) is valid because require-instance is false.
correct ?
when should I use this facility ?

If require-instance is set to false then the value space of the leafref node is the same as the value space of the referred node. This may be useful if the value space of the referred node is particulary complex, has lots of restrictions etc. So, basically, module creators can reuse what they have defined earlier.
If require-instance is set to true (or omitted) then when there are no leaf instances that specify the value-space of a leafref node then it's value space is empty. Thus, you cannot create a valid instance of a leafref node because there are no possible values for it.
Below is the relevant part of the YANG 1.1 RFC 7950:
9.9. The leafref Built-In Type
The leafref built-in type is restricted to the value space of some leaf or leaf-list node in the schema tree and optionally further restricted by corresponding instance nodes in the data tree. The "path" substatement (Section 9.9.2) is used to identify the referred leaf or leaf-list node in the schema tree. The value space of the referring node is the value space of the referred node.
and a fragment about the require-instance statement:
9.9.3. The "require-instance" Statement
[...] If this statement is not present, it defaults to "true".
If "require-instance" is "true", it means that the instance being referred to MUST exist for the data to be valid. This constraint is enforced according to the rules in Section 8.
If "require-instance" is "false", it means that the instance being referred to MAY exist in valid data.
IMHO this part of the YANG 1.1 RFC 7950 is a bit misleading. First, it says that the value space of the referring node is the value space of the referred node but later on it says that there is an instance existence restriction by default. This means that, by default, the value space od the referring node is a set of leaf instance values of the referred node and not the complete value space of that node.

Related

How does instance-identifier looks like in yang model?

AS far as I understand, instance-identifier type has an XPath statement which points to some node is a tree. And what's next? How does instance-identifier identify this node? How do I apply instance-identifier to the node it points to? Or do I get it totally wrong...
I also don't have any example of this except those found in google like
leaf instance-identifier-leaf {
type instance-identifier;
}
An instance-identifier can be a reference to any data node in the system.
Think of it as a pointer; it doesn't contain the data itself, just a reference to it (e.g. an address)
It is useful for example to represent a reference to an object that is modeled as a YANG container or list instance..
Given that YANG data can be expressed as an XML document, the way you 'point' to a specific element within that is therefore similar to 'pointing' to a specific XML element. The way you do that in XML is by using XPath, which allows to use a
Here's an example:
container a {
list b {
key x;
leaf x { type int8; }
list c {
key y;
leaf y { type int8; }
}
}
}
leaf ref {
type instance-identifier;
}
So imagine that a real system has its datastore containing this data (for simplification, I'm using XML format, and ignoring namespaces; a real system doesn't need to keep its datastore in XML format):
<a>
<b>
<x>1</x>
</b>
<b>
<x>5</x>
<c>
<y>1</y>
</c>
<c>
<y>2</y>
</c>
</b>
<b>
<x>10</x>
<c>
<y>5</y>
</c>
</b>
</a>
So basically we have a bunch of list entries, some of them cascaded.
If you'd represent all these nodes in xpath, you'd get a list with:
/a
/a/b[x=1]
/a/b[x=5]
/a/b[x=5]/c[y=1]
/a/b[x=5]/c[y=2]
/a/b[x=10]
/a/b[x=10]/c[y=5]
If you had an instance identifier outside this hierarchy called ref, it could take any of these xpaths as possible values, as a string value. So it contain a reference to one of those nodes; it would not contain the node itself, just a reference to it.
One final note is that it is not mandatory that the node referenced by the instance-identifier actually exists in the datastore; you can have an instance-identifier that is pointing to a non-existent node. There is a yang statement (requires-instance) that can be added as a substatement of the type statement, that allows to control whether only existing instances can be referenced, or whether non-existing ones can also be accepted.
Regarding the format of the value, note that the way the instance-identifier is represented depends on the protocol you are using. An instance identifier in NETCONF is different from one in RESTCONF (although they are very similar).
You could imagine a CLI to have a custom way to represent YANG objects, for example:
A data node is defined with the xpath /a/b[x=5]/c[y=1]
In CLI, that node address is viewed as c-5-1 (just an example)
If you had an instance-identifier pointing to that object, its value would be the string 'c-5-1' in CLI, but in NETCONF it would still be the xpath.
In short, the format depends on the protocol you are using.

Drools RETE algorithm confusion

I am having an issue understanding RETE algorithm Beta node JoinNode and notNode?
Documentation says :
There are two two-input nodes, JoinNode and NotNode, and both are
types of BetaNodes. BetaNodes are used to compare 2 objects, and their
fields, to each other. The objects may be the same or different types.
By convention, we refer to the two inputs as left and right. The left
input for a BetaNode is generally a list of objects; in Drools this is
a Tuple. The right input is a single object. Two Nodes can be used to
implement 'exists' checks. BetaNodes also have memory. The left input
is called the Beta Memory and remembers all incoming tuples. The right
input is called the Alpha Memory and remembers all incoming objects.
I understood, Alpha Node: Various literal conditions for drl rules but above documentation for BetaNodes is confusing me a bit.
say below is drl condition for above diagram:
$person : Person( favouriteCheese == $cheddar )
Query: 1) what are these left and right inputs to two-input Beta Nodes exactly as explained in above documentation? I believe it's referring to facts and rules where I believe tuples would be facts?
2) notNode would be basically drl condition matching literal condition with not?
Updated question on 6Sep17:
3) I believe above diagram represent joinNode, how would notNode be represented , if above workflow is altered to suit notNode?
The condition corresponding to the diagram would be
Cheese( $name: name == "Cheddar" )
Person( favouriteCheese == $name )
Once there is a match, a new tuple consisting of the matching Cheese and Person is composed and can act as a new tuple for further matches if there is a third pattern in the condition.
A not-node would be one that asserts the non-existence of some fact. It would fire only once.
You might find a much better description of "rete" on the web.

Enable explicit Type indices in coqtop?

In Coq there is a hierarchy of types each one denoting the type of the previous i.e. Type_0 : Type_1, Type_1 : Type_2 and so on. In coqtop however when I type Check Type. I get Type : Type which looks like a contradiction but is not since Type is implicitly indexed.
Question: How to enable explicit indexing of the Type universes?
The short answer as #ejgallego mentioned above is to enable the printing of universe levels:
Coq < Set Printing Universes.
Coq < Check Type.
Type#{Top.1}
: Type#{Top.1+1}
(* Top.1 |= *)
Conceptually there is indeed a hierarchy of types which might be called Type#{1}, Type#{2}, etc. However, Coq actually maintains symbols for universe indices and relationships among them (universe constraints) rather than explicit numbers. The constraints are kept consistent so that it's always possible to assign some explicit number to every symbol in a consistent manner.
In the output above you can see that Coq has created a universe level Top.1 for the Type inside the Check Type. command. Its type is always one level higher, which Coq does without another symbol with the expression Top.1+1. With Set Printing Universes a list of constraints is also output as a comment; in this case it gives the one symbol in the context Top.1 and no constraints on the right hand side.
Coq maintains a global list of universe levels and constraints it has created so far. You can read a more thorough explanation of universe levels and constraints in CPDT: http://adam.chlipala.net/cpdt/html/Universes.html.

deleting a leaf with default value (yang)

say I have this
container c {
leaf l1;
leaf l2 (default 'abcd');
}
and I do this (restconf):
DELETE /c/l2
what is the expected behavior in the server ?
is it
'delete the leaf data' or
'do not delete but preserve the leaf with
default value'
after issuing the delete , what is the expected result for a GET
GET /c
c {
l1 : 100 // for ex
l2 : 'abcd'
}
This is described in RFC7950, Section 7.6.1:
The default value of a leaf is the value that the server uses if the
leaf does not exist in the data tree. The usage of the default value
depends on the leaf's closest ancestor node in the schema tree that
is not a non-presence container (see Section 7.5.1):
o If no such ancestor exists in the schema tree, the default value
MUST be used.
o Otherwise, if this ancestor is a case node, the default value MUST
be used if any node from the case exists in the data tree or the
case node is the choice's default case, and if no nodes from any
other case exist in the data tree.
o Otherwise, the default value MUST be used if the ancestor node
exists in the data tree.
In these cases, the default value is said to be in use.
Note that if the leaf or any of its ancestors has a "when" condition
or "if-feature" expression that evaluates to "false", then the
default value is not in use.
When the default value is in use, the server MUST operationally
behave as if the leaf was present in the data tree with the default
value as its value.
If a leaf has a "default" statement, the leaf's default value is the
value of the "default" statement. Otherwise, if the leaf's type has
a default value and the leaf is not mandatory, then the leaf's
default value is the type's default value. In all other cases, the
leaf does not have a default value.
In your case c is a non-presence container, therefore the first bullet above kicks in. This means your default will be in use if you delete the corresponding leaf from the data tree (yes, you can delete it). The server MUST therefore operationally behave as if the leaf was present, and this leaf must have the specified default value.
It does not matter which protocol is used to do the operations.
For RESTCONF and GET, the behavior is described in Section 3.5.4:
RESTCONF requires that a server report its default handling mode (see
Section 9.1.2 for details). If the optional "with-defaults" query
parameter is supported by the server, a client may use it to control
retrieval of default values (see Section 4.8.9 for details).
If a leaf or leaf-list is missing from the configuration and there is
a YANG-defined default for that data resource, then the server MUST
use the YANG-defined default as the configured value.
If the target of a GET method is a data node that represents a leaf
or leaf-list that has a default value, and the leaf or leaf-list has
not been instantiated yet, the server MUST return the default
value(s) that are in use by the server. In this case, the server
MUST ignore its basic-mode, described in Section 4.8.9, and return
the default value.
If the target of a GET method is a data node that represents a
container or list that has any child resources with default values,
for the child resources that have not been given value yet, the
server MAY return the default values that are in use by the server,
in accordance with its reported default handing mode and query
parameters passed by the client.
So your GET example may or may not be correct, depending on which defaults handling mode is in effect, as the last paragraph above suggests.

weird object returned by vector_indexing_suite

I have a
std::vector<const T*>
that I return from a c++ function:
getallTs()
I have exposed the T class with:
class_<T,T*>
and the vector like so:
class_<std::vector<const T*> >("TsList")
.def(vector_indexing_suite<std::vector<const T*>,true>())
;
What does the NoProxy argument mean?
I expose the function like so:
def("getallTs", getallTs,
return_value_policy<return_by_value>{});
I observe a weird behaviour.
When I call from python
tlist = getallTs()
I get a TsList object.
len(tlist)
works.
tlist[<anycorrectindex>].<someattribute>
also works.
However, if I just
print(tlist[0])
and
print(tlist[100])
python prints
object T at <address>
This address is the same for all the Ts in tlist.
Also, I cannot iterate over Tlist with a python for loop.
for t in tlist:
doesn't work.
Any ideas what is wrong with the way I am exposing the vector and the function to python?
I understand the python objects that each wrap a c++ T hold a raw pointer to T.
These T instances exist throughout the process in a global table.
The c++ function retunrns a vector of pointers to those instances.
What does indexing_suite do with those?
Thanks,
When accessing elements by index, the indexing suite defaults to providing a proxy to the element, as a means to provide reference semantics for mutable types that Python users will often expect with collections:
val = c[i]
c[i].m() # Mutates state, equivalent to `val.m()`
assert(val == c[i]) # Have same state.
val.m()
assert(val == c[i]) # Have same state.
In the above example, val is a proxy object that is aware of the container element. When NoProxy is true, one gets value semantics when indexing, resulting in a copy on each index access.
val = c[i] # val is a copy.
c[i].m() # Modify a copy of c[i].
assert(val == c[i]) # These have the same state because c[i] returns a new copy.
val.m()
assert(val != c[i]) # These do not have the same state.
When proxies are not used, the mutations to the elements will only persists when invoked on a reference to the element, such as during iteration:
for val in c:
val.m() # modification observed in c[#]
When invoking print(c[i]), a temporary proxy object is created and passed to print, and the lifetime of the proxy object ends upon returning from print(). Hence, the memory and identification used by the temporary proxy object may be re-used. This can result in elements appearing to have the same identification:
id0 = id(c[0]) # id of the temporary proxy
id1 = id(c[1]) # id of another temporary proxy
assert(id0 ?? id1) # Non-deterministic if these will be the same.
assert(c[0] is not c[1]) # Guaranteed to not be the same.
On the other hand, during the lifetime of a proxy, other proxies to the same element will have identical identification, and proxies to different elements will have different identification:
c0 = c[0] # proxy to element 0.
c0_2 = c[0] # another proxy to element 0.
c1 = c[1] # proxy to element 1
assert(c0 is c0_2)
assert(c0 is c[0])
assert(c0 is not c1)
In the situation where T has been exposed as being held by T*, iteration over std::vector<const T*> will fail in Python if there is no to-Python conversion for const T* to a Python object. Exposing class T as being held by T* registers automatic to-Python and from-Python conversions for T*, not const T*. When iterating over the collection in Python, references to elements are returned, resulting in a Python object failing to be constructed from a const T*. On the other hand, when accessing elements via index, the resulting Python object is either a proxy or a copy, which can use the existing converters. To resolve this, consider either:
having std::vector<>'s element type be the same as T's held type
explicitly registering a const T* to-Python converter