-
Notifications
You must be signed in to change notification settings - Fork 353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal : Provide a Functionally equivalent operator #1987
Comments
@kwokcb This definitely sounds like it's a design choice, since the order in which |
This makes sense for |
A couple of additional thoughts:
|
The MaterialX document serves multiple purposes.
In the first case I would certainly hope we're not dependent on any ordering of child elements of attributes, but certainly as @jstone-lucasfilm points out the second case has some places in the document where the order is important. I can very much imagine a world where I want to compare two MaterialX documents to know if they will render the same image, and thus don't care if inputs are defined in a different order. As well as also wanting to know the documents are actually identical. Perhaps this suggest we need more than one document comparison function? |
That's a good note, @ld-kerley, and I can certainly imagine a future method that aims to determine whether two MaterialX documents generate identical renders, independent of whether they would behave identically in an artist UI. |
That is basically what I need.
This issue can be rejigged from an issue to a be a proposal for a new interface if that's agreeable. |
@kwokcb Got it, and that's definitely a fundamentally different task than comparing whether two documents are identical. Just to suggest an approach, what if you were to sort all of the nodegraphs topologically before comparing the documents in your framework? |
The existing topological sort method cannot be used as it's just connection order sort. ( def getSortedChildren(graphElement, useTopologicalSort=True):
sortedNames = []
if useTopologicalSort:
sorted = graphElement.topologicalSort()
else:
sorted = graphElement.getChildren()
for node in sorted:
sortedNames.append(node.getNamePath())
# sort the names
if not useTopologicalSort:
sortedNames.sort()
return sortedNames
def printSorted(doc, topologicalSort=True):
sorted = getSortedChildren(doc, topologicalSort)
sorted2 = []
sortedPaths = []
for (i, nodeName) in enumerate(sorted):
print(str(i) + ": " + nodeName)
sortedPaths.append(nodeName)
node = doc.getChild(nodeName)
if node.getCategory() == "nodegraph":
sorted2 = getSortedChildren(node, topologicalSort)
for j, nodeName2 in enumerate(sorted2):
print(" " + str(j) + ": " + nodeName2)
sortedPaths.append(nodeName)
return sortedPaths
print('----------------------')
print('Use topological sort. Is not name sorted')
print('----------------------')
sorted1 = printSorted(doc)
print('- vs -')
sorted2 = printSorted(doc2)
print('Is equivalent:', sorted1 == sorted2)
print('----------------------')
print('Use getChild + sort. Is name sorted')
print('----------------------')
sorted1 = printSorted(doc, False)
print('- vs -')
sorted2 = printSorted(doc2, False)
print('Is equivalent:', sorted1 == sorted2) with test files: <?xml version="1.0"?>
<materialx version="1.39" colorspace="lin_rec709">
<nodegraph name="unlit_graph">
<output name="output_color4" type="color3" nodename="ramplr_color4" />
<ramplr name="ramplr_color4" type="color3">
<input name="valuel" type="color3" value="1,0.8,0" />
<input name="valuer" type="color3" value="0,0.5,1" />
<input name="texcoord" type="vector2" value="0,0" />
</ramplr>
</nodegraph>
<surface_unlit name="unlitshader" type="surfaceshader">
<input name="emission_color" type="color3" nodegraph="unlit_graph" />
</surface_unlit>
<surfacematerial name="MAT_unlitshader" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="unlitshader" />
</surfacematerial>
</materialx> <?xml version="1.0"?>
<materialx version="1.39" colorspace="lin_rec709">
<surface_unlit name="unlitshader" type="surfaceshader">
<input name="emission_color" type="color3" nodegraph="unlit_graph" />
</surface_unlit>
<nodegraph name="unlit_graph">
<ramplr name="ramplr_color4" type="color3">
<input name="valuel" type="color3" value="1,0.8,0" />
<input name="valuer" type="color3" value="0,0.5,1" />
<input name="texcoord" type="vector2" value="0,0" />
</ramplr>
<output name="output_color4" type="color3" nodename="ramplr_color4" />
</nodegraph>
<surfacematerial name="MAT_unlitshader" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="unlitshader" />
</surfacematerial>
</materialx> gives this result: ----------------------
Use topological sort. Is not name sorted
----------------------
0: unlit_graph
0: unlit_graph/ramplr_color4
1: unlit_graph/output_color4
1: unlitshader
2: MAT_unlitshader
- vs -
0: unlitshader
1: unlit_graph
0: unlit_graph/ramplr_color4
1: unlit_graph/output_color4
2: MAT_unlitshader
Is equivalent: False
----------------------
Use getChild + sort. Is name sorted
----------------------
0: MAT_unlitshader
1: unlit_graph
0: unlit_graph/output_color4
1: unlit_graph/ramplr_color4
2: unlitshader
- vs -
0: MAT_unlitshader
1: unlit_graph
0: unlit_graph/output_color4
1: unlit_graph/ramplr_color4
2: unlitshader
Is equivalent: True
Thus I think I'll refactor the operator== code into a new function to work in-place as it's the fastest way without revisiting the document in multiple passes. Just requires a attribute name sort and a node child name sort and can reuse the string normalization utility in place as well (or as a pre-pass). |
Proposal
The current equivalence operator (operator==) will fail if:
This is the desired logic.
However, if there can easily be a case where the attributes or children can be added in different order -- in which case the logic fails if you want to perform a functionally equivalent comparison.
The proposal is support such a comparison.
Workflows
A simple cut (remove) and paste (add last) could change order.
such as position.
Proposal
Current Logic
Key logic in code commented in code
Example
File 1
File 2:
The text was updated successfully, but these errors were encountered: