Pattern-based collections shorthand

Hi,

The proposal for pattern-based collections says:

As a convenience, a predicate expression alone (without a Path Matching Pattern), like {isa:Imageable} is shorthand for //*{isa::Imageable} . That is, all prim paths match.

This doesn’t seem to be implemented in 24.05 and such an expression matches nothing. Adding // or //* to the front of the expression will cause it check all prims against the predicate. We’re wondering if this is a bug in the documentation or the implementation.

Thanks,
Jerry

Following up on my own question, we’ve noticed another anomaly which is that the pattern //* matches all prims, but adding a predicate to it causes the root prim not to be matched. For example, with this USD file:

#usda 1.0

def Scope "root" {
    def Scope "child" {
    }
}

// matches /root and /root/child
//* matches just /child
//{isa:Scope} matches /child
//*{isa:Scope} matches /child

This seems to be inconsistent and there seems to be no way to match all prims when using a predicate. It also doesn’t match the way CEL works.

Bug or feature?

Jerry

Hi Jerry – the current implementation differs from the proposal here. The expression {isa:Imageable} is a predicate on a relative prim path. E.g. Sdf.PathExpression('{pred}').MakeAbsolute('/foo/bar').GetText() -> '/foo/bar/{pred}'

The expression //{isa:Imageable} is the right way to match everything that is imageable.

Hi Jerry – I think this is likely a bug that has been fixed. These examples work as expected for me.

Thanks for the reply. With both USD 24.05 and 24.08, I’m getting these results with the above USDA file and this Python code:

from pxr import Usd, Sdf
stage = Usd.Stage.Open('foo.usda')
c = stage.DefinePrim('/c') 
e = Usd.CollectionAPI.Apply(c, 't:collection')
m = e.CreateMembershipExpressionAttr()

def testPBC(expression):
    m.Set(Sdf.PathExpression(expression))
    o = Usd.CollectionAPI.ComputeIncludedObjects(e.ComputeMembershipQuery(), stage)
    print(expression, o)

testPBC('//')
testPBC('//*')
testPBC('//{isa:Scope}')
testPBC('//*{isa:Scope}')
// [Usd.Prim(</c>), Usd.Prim(</root>), Usd.Prim(</root/child>)]
//* [Usd.Prim(</root/child>)]
//{isa:Scope} [Usd.Prim(</root/child>)]
//*{isa:Scope} [Usd.Prim(</root/child>)]

I’d expect to see both prims for the third case, not just the child.

Jerry

Thanks for the lovely repro case, Jerry – this fails for me the same way. I confess I cheated yesterday by translating the repro into (what should be) an equivalent example at the SdfPathExpression-level, outside of the UsdCollectionAPI. That works fine, so there’s something going wrong between the two. I’ll investigate and report back. Sorry for the trouble!

Thanks for the confirmation. The reason we’re interested in this is because Nuke has its own implementation of CEL that was modified to use the same syntax as the Pattern-based Collections proposal. The intention was to throw this away when USD implemented SdfPathExpression so that we don’t confuse users with slightly different syntax or features. We can make workrounds for these bugs if we know they’re actual bugs and are going to be fixed in the future.

Jerry

I have fixed this internally so the changes will appear in the GitHub dev branch the next time we push (roughly weekly).

With the fix your test now produces these results:

// [Usd.Prim(</c>), Usd.Prim(</root>), Usd.Prim(</root/child>)]
//* [Usd.Prim(</c>), Usd.Prim(</root>), Usd.Prim(</root/child>)]
//{isa:Scope} [Usd.Prim(</root>), Usd.Prim(</root/child>)]
//*{isa:Scope} [Usd.Prim(</root>), Usd.Prim(</root/child>)]

This is what’s intended – // and //* match the same here because // means “everything” and //* means “zero or more levels of hierarchy followed by any prim name”.

The bug was a problem in the evaluator where it would erroneously skip the first match in this case. Thanks again!

Hello,
In addition to the above, I also have a question related to Pattern-based Collections and referencing collections in expressions.

For example, considering the following stage and using the testPBC function as above.

def Scope "collections" (
  apiSchemas = ["CollectionAPI:list", "CollectionAPI:expr"]
) {
  uniform token collection:list:expansionRule = "explicitOnly"
  rel collection:list:includes = [
    </scope/scope2>
  ]

  pathExpression collection:expr:membershipExpression = "/scope/scope2"
}

def Scope "scope" {
  def Scope "scope2" {
  }
}

If I run

>>> testPBC("%/collections:list")
%/collections:list []
>>> testPBC("%/collections:expr")
%/collections:expr [Usd.Prim(</scope/scope2>)]

It looks like list based collections are not referenceable in pattern based collections.

My question, in line with Jerry’s, is whether this is by design or if it should be possible to reference list based collections in a path expression and both examples above should result in the same set of prim paths?

Thanks,
Diego

Hi Diego – it is by design that Relationship-Mode and Pattern-Based collections do not mix in this way. There’s a detailed description in the User Guide

There is a helper function, UsdComputePathExpressionFromCollectionMembershipQueryRuleMap() which takes a Relationship-Mode rule map from a UsdCollectionMembershipQuery and computes an equivalent SdfPathExpression. You can use this to help convert a Relationship-Mode collection to a Pattern-Based collection, so that other Pattern-Based collections can refer to it with the % syntax.