rslt ← {larg} (land ##.cf rand) rarg ⍝ Ratio of operand timings. (cf. compare, abbrv. confer(arch.) [Lat: conferre:com-:together + ferre:bring]) Phil Last supplies this operator, which reports the ratio of the times taken to apply its left and right operand functions to (or between) its argument(s). ⍺ f ∇∇ g ⍵ ←→ (⍺ f time ⍵) ÷ ⍺ g time ⍵ f ∇∇ g ⍵ ←→ ( f time ⍵) ÷ g time ⍵ Technical notes: Phil points out that we could do some interesting code transformations: cf←{⍺←⊢ ⍝ Compare operand timings. a←⍺ ⋄ f←⍺⍺ ⋄ g←⍵⍵ ⋄ w←⍵ ⋄ t←{⍬⍴2↓⎕AI-(⍺⍺/⍳1+⍵)⊢⎕AI} ÷/1{⊃∇/⍺{(1000<+/⍵)↓(2×⍺)⍵}({a f w}t ⍺)({a g w}t ⍺)}1 } Spreading the code over a number of lines, we see: cf←{⍺←⊢ ⍝ Compare operand timings. a←⍺ ⍝ naming of ⍺ f←⍺⍺ ⍝ ⍺⍺ g←⍵⍵ ⍝ ⍵⍵ w←⍵ ⍝ ⍵ t←{ ⍝ ⍺⍺-timing operator ⍬⍴2↓⎕AI-(⍺⍺/⍳1+⍵)⊢⎕AI ⍝ time ⍺⍺ ⍺⍺ .. ⍺⍺ applications. [1] } ⍝ └────⍵────┘ ÷/1{ ⍝ ratio of (initially 1) applications. ⊃∇/⍺{ ⍝ repetition while 2-item vector from: (1000<+/⍵)↓(2×⍺)⍵ ⍝ doubling apps while time < 1 sec. }({a f w}t ⍺)({a g w}t ⍺) ⍝ timing each function f and g. [2] }1 } cf keeps doubling the number of function applications in line[1] until the total time spent is at least one second. Notice that the operands of the timing operator t: {a f w} & {a g w} in line[2] are constant functions in that they ignore any arguments. Phil notes that we can derive such constant function without having to name their arguments. So instead of: a←⍺ ┐ f←⍺⍺ ├─── {a f w} g←⍵⍵ ├─── {a g w} w←⍵ ┘ we can say: ┐ ff←⊢∘(⍺∘⍺⍺)∘⍵ ├─── ff ¯¯ │ gg←⊢∘(⍺∘⍵⍵)∘⍵ ├─── gg ¯¯ ┘ You can try this in the session with a constant-function-making operator: mkff←{ ff∘←⊢∘(⍺∘⍺⍺)∘⍵ } ⍝ make constant function: ff←{⍺ ⍺⍺ ⍵}. 2 + mkff 3 ⍝ ff←{2+3} ff 99 5 Although not necessary in this case, we could extend mkff to generate a function that ignores both its right and _left_ arguments by binding a further ⊢∘: mkff←{ ff∘←⊢∘(⊢∘(⍺∘⍺⍺)∘⍵) } ⍝ make constant function ff←{⍺ ⍺⍺ ⍵}. ¯¯ ¯ 20 + mkff 30 ⍝ ff←{20+30} ff 4 ⍝ right and 50 2 ff 3 ⍝ left arg ignored. 50 (muse: If Dyalog were extended to allow functions (and operators) to return funct- ions as results, the above might look a little neater: mk∆ ← {⍺←⊢ ⋄ ⊢∘(⊢∘(⍺∘⍺⍺)∘⍵) } ⍝ constant function: {⍺ ⍺⍺ ⍵}. gg ← 3 × mk∆ 4 ⍝ gg←{3×4} 'do' gg 'zen' 12 This is explored further in the experimental "Function Results Edition" of Dyalog, See: http://dfns.dyalog.com/downloads/fre.pdf ) Incorporating this technique into our cf operator yields: cf←{⍺←⊢ ⍝ Compare operand timings. ff←⊢∘(⍺∘⍺⍺)∘⍵ ⍝ naming of {⍺ ⍺⍺ ⍵} gg←⊢∘(⍺∘⍵⍵)∘⍵ ⍝ {⍺ ⍵⍵ ⍵} t←{ ⍝ ⍺⍺-timing operator ⍬⍴2↓⎕AI-(⊢∘⍺⍺/⍳1+⍵)⊢⎕AI ⍝ time ⍺⍺ ⍺⍺ .. ⍺⍺ applications. [1] } ⍝ └────⍵────┘ ÷/1{ ⍝ ratio of (initially 1) applications. ⊃∇/⍺{ ⍝ repetition while 2-item vector from: (1000<+/⍵)↓(2×⍺)⍵ ⍝ doubling apps while time < 1 sec. }(ff t ⍺)(gg t ⍺) ⍝ timing each function ff and gg. [2] }1 ⍝ ¯¯ ¯¯ } Next, we can avoid naming ff and gg by binding them with the timing operator and passing the resulting derived functions as operands to line[2]: cf←{⍺←⊢ ⍝ Compare operand timings. t←{ ⍝ ⍺⍺-timing operator ⍬⍴2↓⎕AI-(⊢∘⍺⍺/⍳1+⍵)⊢⎕AI ⍝ time ⍺⍺ ⍺⍺ .. ⍺⍺ applications. [1] } ⍝ └────⍵────┘ ÷/1 ⊢∘(⍺∘⍺⍺)∘⍵ t{ ⍝ ratio of (initially 1) applications. ⊃∇/⍺{ ⍝ repetition while 2-item vector from: (1000<+/⍵)↓(2×⍺)⍵ ⍝ doubling apps while time < 1 sec. }(⍺⍺ ⍺)(⍵⍵ ⍺) ⍝ timing each function ⍺⍺ and ⍵⍵. [2] }(⊢∘(⍺∘⍵⍵)∘⍵ t)1 ⍝ ⍵⍵ timing function. } Unfortunately, in the absence of a higher level "hyperator" that takes operator t as operand, this is as far as we can go, unless we are prepared to repeat the definition of t for left and right operands. Either way, we wind up with a cf operator that has no local assignment and no guards; it is a simple expression: cf←{⍺←⊢ ⍝ Compare operand timings. ÷/1⊢∘(⊢∘(⍺∘⍺⍺)∘⍵){⍬⍴2↓⎕AI-(⍺⍺/⍳1+⍵)⊢⎕AI}{ ⊃∇/⍺{ (1000<+/⍵)↓(2×⍺)⍵ }(⍺⍺ ⍺)(⍵⍵ ⍺) }(⊢∘(⊢∘(⍺∘⍵⍵)∘⍵){⍬⍴2↓⎕AI-(⍺⍺/⍳1+⍵)⊢⎕AI})1 } Examples: {(+/⍵)÷⍴⍵} cf {+/⍵÷⍴⍵} ⍳1000 ⍝ compare codings of mean. 0.164 ⎕av (,⍨¨) cf (,¨⍨) ⎕av ⍝ commute-each vs. each-commute. 1.35 See also: cmpx time profile Back to: contents Back to: Workspaces