Loops optimization

Loops optimization

antoine_allazHXWTY
Participant Participant
1,306 Views
14 Replies
Message 1 of 15

Loops optimization

antoine_allazHXWTY
Participant
Participant

Hello,

 

I'm looking for a process to automate loops... I'm sure there is a logical way to do it, but I can't find.

 

I want to have the list of all nodes and groups in my selection, sort hierarchically (you can see the result after). So I create some loops to analyze the parent/children structure. It's works, but I need to write all loops manually. Is there a simple way to do it?

 

for i = 1 to sel.count do (
	if (sel[i].parent == undefined) or ((findItem sel sel[i].parent) == 0) then (
		print (" "+sel[i].name)as string
		for j = 1 to sel.count where sel[j].parent == sel[i] do (
			print (" ├ "+sel[j].name) as string
			for k = 1 to sel.count where sel[k].parent == sel[j] do (
				print ("  ├ "+sel[k].name) as string
				for l = 1 to sel.count where sel[l].parent == sel[k] do (
					print ("   ├ "+sel[l].name) as string
					for m = 1 to sel.count where sel[m].parent == sel[l] do (
						print ("    ├ "+sel[m].name) as string
						for n = 1 to sel.count where sel[n].parent == sel[m] do (
							print ("     ├ "+sel[n].name) as string
							for o = 1 to sel.count where sel[o].parent == sel[n] do (
								print ("     ├ "+sel[o].name) as string
))))))))

 

my result :

"level0_Box001"
"level0_Group001"
"├ level1_Box001"
"├ level1_Group002"
" ├ level2_Group002_Box003"
" ├ level2_Group002_Box004"
" ├ level2_Group002_Box002"
"├ level1_Group003"
" ├ level2_Group005"
"  ├ level3_Group005_Box009"
"  ├ level3_Group005_Box010"
"  ├ level3_Group005_Box011"
"  ├ level3_Group005_Box012"
"  ├ level3_Group005_Box013"
"  ├ level3_Group005_Box014"
" ├ level2_Group004"
"  ├ level3_Group004_Box005"
"  ├ level3_Group004_Box008"
"  ├ Level3_Group006"
"   ├ level4_Group006_Box006"
"   ├ level4_Group006_Box007"
"level0_Group007"
"├ level1_Group007_Box007"
"├ level1_Group007_Box006"
"├ level1_Group007_Box005"

 

Thanks for your help,

Best Regards,

Antoine

0 Likes
Accepted solutions (3)
1,307 Views
14 Replies
Replies (14)
Message 2 of 15

denisT.MaxDoctor
Advisor
Advisor
Accepted solution

What do you know about the recursing function? Google it... there are examples of how to use it in MaxScript Help.

If you have any questions, I'm available to answer them.

0 Likes
Message 3 of 15

denisT.MaxDoctor
Advisor
Advisor
Accepted solution

 

fn expand_node node tab:"" = 
(
	print (tab + node.name)
	for child in node.children do expand_node child tab:(tab + "\t")
)

delete objects
bip = biped.createnew 170 0 [0,0,170*0.96]

expand_node bip

 

0 Likes
Message 4 of 15

istan
Advisor
Advisor
Accepted solution

have you heard about recursive calling a function?

e.g.

fn disp sel pre:"" = (
  for s in sel do (
    format ( (if pre!="" then (pre + "|+ ") else "") + s.name + "\n")
    if s.children.count then (
      disp s.children pre:(pre+"  ")
    )
  )
)
disp sel

 

0 Likes
Message 5 of 15

antoine_allazHXWTY
Participant
Participant

Thank you very much for your answers ! No, I never heard about recursive function. So I'll investigate.

0 Likes
Message 6 of 15

antoine_allazHXWTY
Participant
Participant

So it's done, thank you !

sel = #()
sel = getCurrentSelection()
gr_parent = #()
gr_list = #()

for i in sel do (
	if (i.parent == undefined) or ((findItem sel i.parent) == 0) then (
		append gr_parent i
	)
)
for i in gr_parent do (
	expand_node i
	append gr_list ("\n")
)

print gr_list
0 Likes
Message 7 of 15

klvnk
Collaborator
Collaborator

nothing to do with the question per se but I did discover the calling c++ mxs functions  with optional arguments (being used) considerably slower

0 Likes
Message 8 of 15

denisT.MaxDoctor
Advisor
Advisor

@klvnk wrote:

nothing to do with the question per se but I did discover the calling c++ mxs functions  with optional arguments (being used) considerably slower


is it specifically for recursive calls? 

it depends on how the C++ function parses optional arguments... yes it's slower, but not dramatically I hope. 

0 Likes
Message 9 of 15

klvnk
Collaborator
Collaborator

it depends on how the C++ function parses optional arguments

 

there's a set of standard macros/functions for this eg BOOL use_edges = bool_key_arg(use_edges, temp, TRUE);

 

here's the example when I found it, it was testing various get all element routines as I'd added it  to adjedge and wanted to see how it compared...

 

 

 

 

 

(
	count = 1000;
	n = $;
	t = timeStamp()

	for i = 1 to count do meshop.getElements n;
	format "meshop.getElements = % \n" (timeStamp() - t)
	
	t = timeStamp()
	for i = 1 to count do meshop.getAllElements n;
	
	format "meshop.getAllElements = % \n" (timeStamp() - t)
	
	t = timeStamp()
	ae = adjedge.buildEdges n;
	for i = 1 to count do adjedge.getAllElements n ae;
	
	format "adjedge.getAllElements unsupplied = % \n" (timeStamp() - t)
	
	t = timeStamp()
	for i = 1 to count do adjedge.getAllElements n ae use_edges:false;
	
	format "adjedge.getAllElements optional = % \n" (timeStamp() - t)
	
)	

 

 

 

 

 

 

adjedge is a object type I added using my own edge list code the other functions aren't really relevent the results

were

 

 

 

 

 

meshop.getElements = 276 
meshop.getAllElements = 295 
adjedge.getAllElements unsupplied = 58 
adjedge.getAllElements optional = 534 

 

 

 

 

 

when I originally ran it with the optional arg I was wtf why is the adjedge version so  much slowler when it should be miles ahead ! then I added the unsupplied. It's such a hit I won't be using optionals from now on.

 

edit: seems to be an issue when the arg == default  🤔

 

0 Likes
Message 10 of 15

denisT.MaxDoctor
Advisor
Advisor

It is quite clear that there are no miracles. A function with optional arguments must go through the whole list of arguments and find the ones that must be processed... If the function will not handle them, it makes no difference whether they are basic or optional.

 

you can set a mandatory order of keys and their data type, take the key in order, check for its presence, and do not check the data type... then everything will be fast. 😁

0 Likes
Message 11 of 15

denisT.MaxDoctor
Advisor
Advisor

So for functions that require a lot of different parameters, I usually pass one on the "structure" type... and then do all the "parsing" at the c++ type level.

0 Likes
Message 12 of 15

denisT.MaxDoctor
Advisor
Advisor

Actually, the biggest issue with MXS loops is memory leakage. Everything else is manageable. 😁

 

fn measure_heapfree count:1000 = 
(
	t0 = timestamp()
	h0 = heapfree
	n = count
	while n > 1 do
	(
		k = n - 1
		while k > 0 do 
		(
			k -= 1
		)
		n -= 1
	)
	#(count, n, k, timestamp() - t0, h0 - heapfree)
)
measure_heapfree()
0 Likes
Message 13 of 15

A012255
Enthusiast
Enthusiast

@klvnk wrote:

nothing to do with the question per se but I did discover the calling c++ mxs functions  with optional arguments (being used) considerably slower


Not in general, as there is not much code for parsing an optional argument. But of course it depends how often you call it in a loop 😉

But usually this will be the point, where I move the whole loop to C++.

However parsing "Name literals" like #foo1, #foo2 takes longer as string compares will be needed. But even then, there is not much difference if integers are used instead.

There might be a difference between release and debug version?

0 Likes
Message 14 of 15

denisT.MaxDoctor
Advisor
Advisor

@A012255 wrote:

@klvnk wrote:

nothing to do with the question per se but I did discover the calling c++ mxs functions  with optional arguments (being used) considerably slower


 

However parsing "Name literals" like #foo1, #foo2 takes longer as string compares will be needed.


Exactly the opposite... Comparing names is much faster than comparing strings. Key search (name comparison) does nothing with strings.

0 Likes
Message 15 of 15

denisT.MaxDoctor
Advisor
Advisor

Of course, it doesn't make sense to make a c++ function to extend MXS like:

 

deletePolyVertex <node> [index:<int>]


we need to convert the node to a reference,  check the class, get MNMesh, find the key, get the vert index... And we must understand that the system in general has to evaluate the values (arguments) that are passed to c++. But it makes sense if we pass one or multiple vertices where <index key> is optional and can be an integer (float, double, int64, any number), or as well #selection. #all, bits, array. etc...

0 Likes