{"id":14283,"date":"2021-10-01T16:22:36","date_gmt":"2021-10-01T20:22:36","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/?p=14283"},"modified":"2021-10-01T19:36:56","modified_gmt":"2021-10-01T23:36:56","slug":"efficient-object-oriented-kronecker-product-manipulation","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2021\/10\/01\/efficient-object-oriented-kronecker-product-manipulation\/","title":{"rendered":"Efficient Object-Oriented Kronecker Product Manipulation"},"content":{"rendered":"<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\">\r\n<html><body><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><a href = \"http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3208495\"><span>Sean<\/span><\/a><span>'s pick this week is <\/span><a href = \"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/25969\"><span>KronProd<\/span><\/a><span> by <\/span><a href = \"http:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/1440443\"><span>Matt J<\/span><\/a><span>.<\/span><\/div><h2  style = 'margin: 3px 10px 5px 4px; padding: 0px; line-height: 20px; min-height: 0px; white-space: pre-wrap; color: rgb(60, 60, 60); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 20px; font-weight: 700; text-align: left; '><span>Background<\/span><\/h2><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>This one is old and very dear to my heart.  Some time in the 2009 era, as I was starting grad school, I needed help calculating subpixel resolution displacement vectors between two CT image volumes.  The displacement vector calculation was one of the main underlying pieces of most of my grad research.  This was before <\/span><span style=' font-family: monospace;'>imregcorr<\/span><span> existed, though it still does not support 3D which was my requirement.<\/span><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>I'd managed to get a 2D variant working, but needed 3D.  Matt replied to my newsreader post to discuss the algorithm and its extension in 3D, and pointed to this to be more efficient than using <\/span><span style=' font-family: monospace;'>kron<\/span><span> directly.  Performance was important as I'd have to compute over four billion displacement vectors over the next year.  <\/span><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Matt has provided many algorithms and overloaded a bunch of operators to work with the <\/span><span style=' font-family: monospace;'>KronProd<\/span><span> class and configured it with custom indexing and size.  In 2009, I didn't understand how custom indexing with <\/span><span style=' font-family: monospace;'>subsref<\/span><span>\/<\/span><span style=' font-family: monospace;'>subsasgn\/size<\/span><span> overloading worked, so it seemed like magic.  With the knowledge of how those work now, and the performance implications in that era, I probably would've pulled the core algorithm into a function for speed since my use was stateless, i.e. a new <\/span><span style=' font-family: monospace;'>KronProd<\/span><span> each time.<\/span><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Here are a few simple operations with a <\/span><span style=' font-family: monospace;'>KronProd<\/span><span>.  We'll create one from a three arrays.<\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 4px 4px 0px 0px; padding: 6px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >kp = KronProd({magic(3), [randi(10,[3 4]), zeros(3,1)], randn(9, 15)})<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableStringElement\" uid=\"E1E132CB\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-testid=\"output_0\" style=\"width: 1146px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"textElement eoOutputContent\" data-width=\"1116\" data-height=\"211\" data-hashorizontaloverflow=\"false\" style=\"max-height: 261px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span class=\"variableNameElement\" style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">kp = <\/span><\/div><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">  81\u00d7225 KronProd array with properties:\r\n\r\n             opset: {[3\u00d73 double]  [3\u00d75 double]  [9\u00d715 double]}\r\n            opinds: [1 2 3]\r\n            numops: 3\r\n           eyemask: [0 0 0]\r\n         domainset: [3 5 15]\r\n            maxdim: 3\r\n       scalarcoeff: 1\r\n    scalarcumprods: [1 1 1]\r\n        scalarmask: [0 0 0]\r\n       domainsizes: [3 5 15]\r\n        rangesizes: [3 3 9]<\/div><\/div><\/div><\/div><\/div><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Now we can work with this as if the full expansion you'd get from the <\/span><span style=' font-family: monospace;'>kron<\/span><span> function.<\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 4px 4px 0px 0px; padding: 6px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >nzeros = nnz(kp)<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class='variableElement' style='font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 12px; '>nzeros = 14580<\/div><\/div><\/div><\/div><div  style = 'margin: 10px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Or a matrix operation where I get back KronProds.<\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 4px 4px 0px 0px; padding: 6px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >[u, s, v] = svd(kp)<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableStringElement\" uid=\"75AC6154\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-testid=\"output_2\" style=\"width: 1146px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"textElement eoOutputContent\" data-width=\"1116\" data-height=\"211\" data-hashorizontaloverflow=\"false\" style=\"max-height: 261px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span class=\"variableNameElement\" style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">u = <\/span><\/div><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">  81\u00d781 KronProd array with properties:\r\n\r\n             opset: {3\u00d71 cell}\r\n            opinds: [1 2 3]\r\n            numops: 3\r\n           eyemask: [0 0 0]\r\n         domainset: [3\u00d71 double]\r\n            maxdim: 3\r\n       scalarcoeff: 1\r\n    scalarcumprods: [1 1 1]\r\n        scalarmask: [0 0 0]\r\n       domainsizes: [3 3 9]\r\n        rangesizes: [3 3 9]<\/div><\/div><\/div><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableStringElement\" uid=\"8BA56F6B\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-testid=\"output_3\" style=\"width: 1146px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"textElement eoOutputContent\" data-width=\"1116\" data-height=\"211\" data-hashorizontaloverflow=\"false\" style=\"max-height: 261px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span class=\"variableNameElement\" style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">s = <\/span><\/div><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">  81\u00d7225 KronProd array with properties:\r\n\r\n             opset: {3\u00d71 cell}\r\n            opinds: [1 2 3]\r\n            numops: 3\r\n           eyemask: [0 0 0]\r\n         domainset: [3\u00d71 double]\r\n            maxdim: 3\r\n       scalarcoeff: 1\r\n    scalarcumprods: [1 1 1]\r\n        scalarmask: [0 0 0]\r\n       domainsizes: [3 5 15]\r\n        rangesizes: [3 3 9]<\/div><\/div><\/div><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableStringElement\" uid=\"DBEAABBE\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-testid=\"output_4\" style=\"width: 1146px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"textElement eoOutputContent\" data-width=\"1116\" data-height=\"211\" data-hashorizontaloverflow=\"false\" style=\"max-height: 261px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span class=\"variableNameElement\" style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">v = <\/span><\/div><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">  225\u00d7225 KronProd array with properties:\r\n\r\n             opset: {3\u00d71 cell}\r\n            opinds: [1 2 3]\r\n            numops: 3\r\n           eyemask: [0 0 0]\r\n         domainset: [3\u00d71 double]\r\n            maxdim: 3\r\n       scalarcoeff: 1\r\n    scalarcumprods: [1 1 1]\r\n        scalarmask: [0 0 0]\r\n       domainsizes: [3 5 15]\r\n        rangesizes: [3 5 15]<\/div><\/div><\/div><\/div><\/div><\/div><div  style = 'margin: 10px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Matt has overloaded <\/span><span style=' font-family: monospace;'>subsref<\/span><span> so when you index into the KronProd, you get back a KronProd or just matrix.<\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 4px 4px 0px 0px; padding: 6px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >kkp = kp(1)<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableStringElement\" uid=\"657F7D26\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-testid=\"output_5\" style=\"width: 1146px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"textElement eoOutputContent\" data-width=\"1116\" data-height=\"211\" data-hashorizontaloverflow=\"false\" style=\"max-height: 261px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span class=\"variableNameElement\" style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">kkp = <\/span><\/div><div style=\"white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">  3\u00d73 KronProd array with properties:\r\n\r\n             opset: {[3\u00d73 double]}\r\n            opinds: 1\r\n            numops: 1\r\n           eyemask: 0\r\n         domainset: 3\r\n            maxdim: 1\r\n       scalarcoeff: 1\r\n    scalarcumprods: 1\r\n        scalarmask: 0\r\n       domainsizes: 3\r\n        rangesizes: 3<\/div><\/div><\/div><\/div><\/div><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 0px; padding: 6px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >km = kp{1}<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableMatrixElement\" uid=\"E8A5F1F5\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-width=\"1116\" data-testid=\"output_6\" style=\"width: 1146px; white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"matrixElement veSpecifier saveLoad eoOutputContent\" style=\"white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"veVariableName variableNameElement double\" style=\"width: 1116px; white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"headerElementClickToInteract\" style=\"white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span style=\"white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">km = <\/span><span class=\"veVariableValueSummary veMetaSummary\" style=\"white-space: normal; font-style: normal; color: rgb(179, 179, 179); font-size: 12px;\">3\u00d73<\/span><\/div><\/div><div class=\"valueContainer\" data-layout=\"{&quot;columnWidth&quot;:40,&quot;totalColumns&quot;:&quot;3&quot;,&quot;totalRows&quot;:&quot;3&quot;,&quot;charsPerColumn&quot;:6}\" style=\"white-space: nowrap; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"variableValue\" style=\"width: 122px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">     8     1     6\r\n     3     5     7\r\n     4     9     2\r\n<\/div><div class=\"horizontalEllipsis hide\" style=\"white-space: nowrap; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><\/div><div class=\"verticalEllipsis hide\" style=\"white-space: nowrap; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><\/div><\/div><\/div><\/div><\/div><\/div><\/div><div  style = 'margin: 10px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>He did not overload <\/span><span style=' font-family: monospace;'>subsasgn<\/span><span> though, so we can't do the opposite.<\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 0px none rgb(0, 0, 0); border-radius: 4px 4px 0px 0px; padding: 6px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span style=\"color: rgb(0, 0, 255);\">try<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >    kp{1} = rand(3)<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span style=\"color: rgb(0, 0, 255);\">catch <\/span><span >ME<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >    fprintf(2, ME.message)<\/span><\/span><\/div><\/div><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 0px; padding: 0px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span style=\"color: rgb(0, 0, 255);\">end<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class=\"inlineElement eoOutputWrapper embeddedOutputsTextElement\" uid=\"F3719EBA\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-testid=\"output_7\" style=\"width: 1146px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"textElement eoOutputContent\" data-width=\"1116\" data-height=\"18\" data-hashorizontaloverflow=\"false\" style=\"max-height: 261px; white-space: pre; font-style: normal; color: rgb(256, 0, 0); font-size: 12px;\">Unable to perform assignment because brace indexing is not supported for variables of this type.<\/div><\/div><\/div><\/div><\/div><div  style = 'margin: 10px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>He's also overloaded <\/span><span style=' font-family: monospace;'>size<\/span><span> so the appearance of size is that of the full Kronecker product.  Under the hood, however, the <\/span><span style=' font-family: monospace;'>KronProd<\/span><span> is actually a scalar, it just <\/span><span style=' font-style: italic;'>appears<\/span><span> to be the expanded size.  <\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper outputs\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 4px 4px 0px 0px; padding: 6px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >sz = size(s)<\/span><\/span><\/div><div  style = 'color: rgb(64, 64, 64); padding: 10px 0px 6px 17px; background: rgb(255, 255, 255) none repeat scroll 0% 0% \/ auto padding-box border-box; font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; overflow-x: hidden; line-height: 17.234px; '><div class=\"inlineElement eoOutputWrapper embeddedOutputsVariableMatrixElement\" uid=\"E25EE4A2\" data-scroll-top=\"null\" data-scroll-left=\"null\" data-width=\"1116\" data-testid=\"output_8\" style=\"width: 1146px; white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"matrixElement veSpecifier saveLoad eoOutputContent\" style=\"white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"veVariableName variableNameElement double\" style=\"width: 1116px; white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"headerElementClickToInteract\" style=\"white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><span style=\"white-space: normal; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">sz = <\/span><span class=\"veVariableValueSummary veMetaSummary\" style=\"white-space: normal; font-style: normal; color: rgb(179, 179, 179); font-size: 12px;\">1\u00d72<\/span><\/div><\/div><div class=\"valueContainer\" data-layout=\"{&quot;columnWidth&quot;:40,&quot;totalColumns&quot;:&quot;2&quot;,&quot;totalRows&quot;:&quot;1&quot;,&quot;charsPerColumn&quot;:6}\" style=\"white-space: nowrap; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><div class=\"variableValue\" style=\"width: 82px; white-space: pre; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\">    81   225\r\n<\/div><div class=\"horizontalEllipsis hide\" style=\"white-space: nowrap; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><\/div><div class=\"verticalEllipsis hide\" style=\"white-space: nowrap; font-style: normal; color: rgb(64, 64, 64); font-size: 12px;\"><\/div><\/div><\/div><\/div><\/div><\/div><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Starting in MATLAB R2021b, we now have an easier and more formal means for controlling indexing and creating scalar objects using <\/span><a href = \"https:\/\/www.mathworks.com\/help\/matlab\/matlab_oop\/indexed-reference-and-assignment.html\"><span>modular indexing<\/span><\/a><span>.  <\/span><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Right now <\/span><span style=' font-family: monospace;'>subsref<\/span><span> overloads (), {}, and dot(.).  It overloads dot, just because it has to with the old approach, so we don't need to do that with the newer indexing.  So the class definition line would need to be:<\/span><\/div><div class = 'preformatted-matlab' style = 'margin: 10px 3px 10px 55px; padding: 10px 10px 10px 5px; '><div  style = 'border-left: 0px none rgb(0, 0, 0); border-right: 0px none rgb(0, 0, 0); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px; line-height: 15.6px; min-height: 16px; white-space: pre; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 12px; '><span style=\"white-space: pre\"><span style=\"color: rgb(0, 0, 255);\">classdef <\/span><span >KronProd &lt; matlab.mixin.indexing.RedefinesParen &amp; matlab.mixin.indexing.RedefinesBrace<\/span><\/span><\/div><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Now, we'd need to implement the abstract methods for <\/span><span style=' font-family: monospace;'>parenAssign, parenReference, braceAssign, braceReference<\/span><span>.  These methods would then use similar logic to what's used today, in a protected methods block, something along these lines:<\/span><\/div><div style=\"background-color: #F7F7F7; margin: 10px 0 10px 0;\"><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 1px solid rgb(233, 233, 233); border-bottom: 0px none rgb(0, 0, 0); border-radius: 4px 4px 0px 0px; padding: 6px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span style=\"color: rgb(0, 0, 255);\">function <\/span><span >B = braceReference(obj, indexOp)<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >    inds = M.opinds(indexOp(1).Indices{1});<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >    B=M.opset(inds);<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >    <\/span><span style=\"color: rgb(0, 0, 255);\">if <\/span><span >isnum(inds)<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >        B=B{:};<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 0px none rgb(0, 0, 0); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span >    <\/span><span style=\"color: rgb(0, 0, 255);\">end<\/span><\/span><\/div><\/div><div class=\"inlineWrapper\"><div  style = 'border-left: 1px solid rgb(233, 233, 233); border-right: 1px solid rgb(233, 233, 233); border-top: 0px none rgb(0, 0, 0); border-bottom: 1px solid rgb(233, 233, 233); border-radius: 0px 0px 4px 4px; padding: 0px 45px 4px 13px; line-height: 17.234px; min-height: 18px; white-space: nowrap; color: rgb(0, 0, 0); font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace; font-size: 14px; '><span style=\"white-space: pre\"><span style=\"color: rgb(0, 0, 255);\">end<\/span><\/span><\/div><\/div><\/div><h2  style = 'margin: 20px 10px 5px 4px; padding: 0px; line-height: 20px; min-height: 0px; white-space: pre-wrap; color: rgb(60, 60, 60); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 20px; font-weight: 700; text-align: left; '><span>Comments<\/span><\/h2><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Matt, if we ever meet in real life, I owe you a beer!<\/span><\/div><div  style = 'margin: 2px 10px 9px 4px; padding: 0px; line-height: 21px; min-height: 0px; white-space: pre-wrap; color: rgb(0, 0, 0); font-family: Helvetica, Arial, sans-serif; font-style: normal; font-size: 14px; font-weight: 400; text-align: left; '><span>Give it a try and let us know what you think <\/span><a href = \"about:blank&lt;#respond&gt;\"><span>here<\/span><\/a><span> or leave a<\/span><span> <\/span><a href = \"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/25969\"><span>comment<\/span><\/a><span> for Matt.<\/span><\/div>\r\n<\/div><\/body><\/html><script type=\"text\/javascript\">var css = '.variableValue { width: 100% !important; } .embeddedOutputsMatrixElement,.eoOutputWrapper .matrixElement {    min-height: 18px;    box-sizing: border-box;} .embeddedOutputsMatrixElement .matrixElement,.eoOutputWrapper  .matrixElement,.rtcDataTipElement .matrixElement {    position: relative;} .matrixElement .variableValue,.rtcDataTipElement .matrixElement .variableValue {    white-space: pre;    display: inline-block;    vertical-align: top;    overflow: hidden;} .embeddedOutputsMatrixElement.inlineElement {} .embeddedOutputsMatrixElement.inlineElement .topHeaderWrapper {    display: none;} .embeddedOutputsMatrixElement.inlineElement .veTable .body {    padding-top: 0 !important;    max-height: 100px;} .inlineElement .matrixElement {    max-height: 300px;} .embeddedOutputsMatrixElement.rightPaneElement {} .rightPaneElement .matrixElement,.rtcDataTipElement .matrixElement {    overflow: hidden;    padding-left: 9px;} .rightPaneElement .matrixElement {    margin-bottom: -1px;} .embeddedOutputsMatrixElement .matrixElement .valueContainer,.eoOutputWrapper .matrixElement .valueContainer,.rtcDataTipElement .matrixElement .valueContainer {    white-space: nowrap;    margin-bottom: 3px;} .embeddedOutputsMatrixElement .matrixElement .valueContainer .horizontalEllipsis.hide,.embeddedOutputsMatrixElement .matrixElement .verticalEllipsis.hide,.eoOutputWrapper .matrixElement .valueContainer .horizontalEllipsis.hide,.eoOutputWrapper .matrixElement .verticalEllipsis.hide,.rtcDataTipElement .matrixElement .valueContainer .horizontalEllipsis.hide,.rtcDataTipElement .matrixElement .verticalEllipsis.hide {    display: none;} .embeddedOutputsVariableMatrixElement .matrixElement .valueContainer.hideEllipses .verticalEllipsis, .embeddedOutputsVariableMatrixElement .matrixElement .valueContainer.hideEllipses .horizontalEllipsis {    display:none;} .embeddedOutputsMatrixElement .matrixElement .valueContainer .horizontalEllipsis,.eoOutputWrapper .matrixElement .valueContainer .horizontalEllipsis {    margin-bottom: -3px;} .eoOutputWrapper .embeddedOutputsVariableMatrixElement .matrixElement .valueContainer {    cursor: default !important;} .embeddedOutputsVariableElement {    white-space: pre-wrap;    word-wrap: break-word;    min-height: 18px;    max-height: 250px;    overflow: auto;} .variableElement {} .embeddedOutputsVariableElement.inlineElement {} .inlineElement .variableElement {} .embeddedOutputsVariableElement.rightPaneElement {    min-height: 16px;} .rightPaneElement .variableElement {    padding-top: 2px;    padding-left: 9px;} .variableNameElement {    margin-bottom: 3px;    display: inline-block;} \/* * Ellipses as base64 for HTML export. *\/.matrixElement .horizontalEllipsis,.rtcDataTipElement .matrixElement .horizontalEllipsis {    display: inline-block;    margin-top: 3px;    \/* base64 encoded version of images-liveeditor\/HEllipsis.png *\/    width: 30px;    height: 12px;    background-repeat: no-repeat;    background-image: url(\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAJCAYAAADO1CeCAAAAJUlEQVR42mP4\/\/8\/A70xw0i29BUDFPxnAEtTW37wWDqakIa4pQDvOOG89lHX2gAAAABJRU5ErkJggg==\");} .matrixElement .verticalEllipsis,.textElement .verticalEllipsis,.rtcDataTipElement .matrixElement .verticalEllipsis,.rtcDataTipElement .textElement .verticalEllipsis {    margin-left: 35px;    \/* base64 encoded version of images-liveeditor\/VEllipsis.png *\/    width: 12px;    height: 30px;    background-repeat: no-repeat;    background-image: url(\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAZCAYAAAAIcL+IAAAALklEQVR42mP4\/\/8\/AzGYgWyFMECMwv8QddRS+P\/\/KyimlmcGUOFoOI6GI\/UVAgDnd8Dd4+NCwgAAAABJRU5ErkJggg==\");} \/* Styling that is common to warnings and errors is in diagnosticOutput.css *\/.embeddedOutputsErrorElement {    min-height: 18px;    max-height: 250px;    overflow: auto;} .embeddedOutputsErrorElement.inlineElement {} .embeddedOutputsErrorElement.rightPaneElement {} \/* Styling that is common to warnings and errors is in diagnosticOutput.css *\/.embeddedOutputsWarningElement{    min-height: 18px;    max-height: 250px;    overflow: auto;} .embeddedOutputsWarningElement.inlineElement {} .embeddedOutputsWarningElement.rightPaneElement {} \/* Copyright 2015-2019 The MathWorks, Inc. *\/\/* In this file, styles are not scoped to rtcContainer since they could be in the Dojo Tooltip *\/.diagnosticMessage-wrapper {    font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;    font-size: 12px;} .diagnosticMessage-wrapper.diagnosticMessage-warningType {    color: rgb(255,100,0);} .diagnosticMessage-wrapper.diagnosticMessage-warningType a {    color: rgb(255,100,0);    text-decoration: underline;} .diagnosticMessage-wrapper.diagnosticMessage-errorType {    color: rgb(230,0,0);} .diagnosticMessage-wrapper.diagnosticMessage-errorType a {    color: rgb(230,0,0);    text-decoration: underline;} .diagnosticMessage-wrapper .diagnosticMessage-messagePart,.diagnosticMessage-wrapper .diagnosticMessage-causePart {    white-space: pre-wrap;} .diagnosticMessage-wrapper .diagnosticMessage-stackPart {    white-space: pre;} .embeddedOutputsTextElement,.embeddedOutputsVariableStringElement {    white-space: pre;    word-wrap:  initial;    min-height: 18px;    max-height: 250px;    overflow: auto;} .textElement,.rtcDataTipElement .textElement {    padding-top: 3px;} .embeddedOutputsTextElement.inlineElement,.embeddedOutputsVariableStringElement.inlineElement {} .inlineElement .textElement {} .embeddedOutputsTextElement.rightPaneElement,.embeddedOutputsVariableStringElement.rightPaneElement {    min-height: 16px;} .rightPaneElement .textElement {    padding-top: 2px;    padding-left: 9px;} .embeddedOutputsVariableTableElement .ClientViewDiv  table tr {  height: 22px;  white-space: nowrap;} .embeddedOutputsVariableTableElement .ClientViewDiv  table tr td,.embeddedOutputsVariableTableElement .ClientViewDiv  table tr th {  background-color:white;  text-overflow: ellipsis;  font-family: Arial, sans-serif;  font-size: 12px;  overflow : hidden;} .embeddedOutputsVariableTableElement .ClientViewDiv  table tr span {  text-overflow: ellipsis;  padding: 3px;} .embeddedOutputsVariableTableElement .ClientViewDiv  table tr th {    color: rgba(0,0,0,0.5);  padding: 3px;  font-size: 9px;}'; var head = document.head || document.getElementsByTagName('head')[0], style = document.createElement('style'); head.appendChild(style); style.type = 'text\/css'; if (style.styleSheet){ style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); }<\/script><a href=\"https:\/\/blogs.mathworks.com\/pick\/files\/mainKronProd-1.mlx\"><button class=\"btn btn-sm btn_color_blue pull-right add_margin_10\">Download Live Script<\/button><\/a>","protected":false},"excerpt":{"rendered":"<p>\r\nSean's pick this week is KronProd by Matt J.BackgroundThis one is old and very dear to my heart.  Some time in the 2009 era, as I was starting grad school, I needed help calculating subpixel... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2021\/10\/01\/efficient-object-oriented-kronecker-product-manipulation\/\">read more >><\/a><\/p>","protected":false},"author":87,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/14283"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=14283"}],"version-history":[{"count":4,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/14283\/revisions"}],"predecessor-version":[{"id":15301,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/14283\/revisions\/15301"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=14283"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=14283"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=14283"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}