{"action":"created","issue":{"url":"https://api.github.com/repos/chapel-lang/chapel/issues/9879","repository_url":"https://api.github.com/repos/chapel-lang/chapel","labels_url":"https://api.github.com/repos/chapel-lang/chapel/issues/9879/labels{/name}","comments_url":"https://api.github.com/repos/chapel-lang/chapel/issues/9879/comments","events_url":"https://api.github.com/repos/chapel-lang/chapel/issues/9879/events","html_url":"https://github.com/chapel-lang/chapel/issues/9879","id":332588291,"node_id":"MDU6SXNzdWUzMzI1ODgyOTE=","number":9879,"title":"simple UDRI with examples","user":{"login":"vasslitvinov","id":8039635,"node_id":"MDQ6VXNlcjgwMzk2MzU=","avatar_url":"https://avatars0.githubusercontent.com/u/8039635?v=4","gravatar_id":"","url":"https://api.github.com/users/vasslitvinov","html_url":"https://github.com/vasslitvinov","followers_url":"https://api.github.com/users/vasslitvinov/followers","following_url":"https://api.github.com/users/vasslitvinov/following{/other_user}","gists_url":"https://api.github.com/users/vasslitvinov/gists{/gist_id}","starred_url":"https://api.github.com/users/vasslitvinov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vasslitvinov/subscriptions","organizations_url":"https://api.github.com/users/vasslitvinov/orgs","repos_url":"https://api.github.com/users/vasslitvinov/repos","events_url":"https://api.github.com/users/vasslitvinov/events{/privacy}","received_events_url":"https://api.github.com/users/vasslitvinov/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"vasslitvinov","id":8039635,"node_id":"MDQ6VXNlcjgwMzk2MzU=","avatar_url":"https://avatars0.githubusercontent.com/u/8039635?v=4","gravatar_id":"","url":"https://api.github.com/users/vasslitvinov","html_url":"https://github.com/vasslitvinov","followers_url":"https://api.github.com/users/vasslitvinov/followers","following_url":"https://api.github.com/users/vasslitvinov/following{/other_user}","gists_url":"https://api.github.com/users/vasslitvinov/gists{/gist_id}","starred_url":"https://api.github.com/users/vasslitvinov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vasslitvinov/subscriptions","organizations_url":"https://api.github.com/users/vasslitvinov/orgs","repos_url":"https://api.github.com/users/vasslitvinov/repos","events_url":"https://api.github.com/users/vasslitvinov/events{/privacy}","received_events_url":"https://api.github.com/users/vasslitvinov/received_events","type":"User","site_admin":false},"assignees":[{"login":"vasslitvinov","id":8039635,"node_id":"MDQ6VXNlcjgwMzk2MzU=","avatar_url":"https://avatars0.githubusercontent.com/u/8039635?v=4","gravatar_id":"","url":"https://api.github.com/users/vasslitvinov","html_url":"https://github.com/vasslitvinov","followers_url":"https://api.github.com/users/vasslitvinov/followers","following_url":"https://api.github.com/users/vasslitvinov/following{/other_user}","gists_url":"https://api.github.com/users/vasslitvinov/gists{/gist_id}","starred_url":"https://api.github.com/users/vasslitvinov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vasslitvinov/subscriptions","organizations_url":"https://api.github.com/users/vasslitvinov/orgs","repos_url":"https://api.github.com/users/vasslitvinov/repos","events_url":"https://api.github.com/users/vasslitvinov/events{/privacy}","received_events_url":"https://api.github.com/users/vasslitvinov/received_events","type":"User","site_admin":false}],"milestone":null,"comments":13,"created_at":"2018-06-14T22:36:50Z","updated_at":"2018-06-22T14:18:58Z","closed_at":null,"author_association":"MEMBER","body":"This is a simplification of #9542 .\r\n\r\n## Interface\r\n\r\n```chpl\r\nrecord ReduceOp {\r\n\r\n  // Create the global op record for reducing values of 'inputType'.\r\n  // Not used when the user provides their own instance.\r\n  // This could be the compiler-generated default constructor,\r\n  // if applicable.\r\n  proc init(type inputType)\r\n\r\n  // Create a per-task op given 'parentOp' in the parent task.\r\n  // This could be the compiler-generated copy initializer.\r\n  proc init(parentOp :ReduceOp)\r\n\r\n  // Create a per-task accumulation state.\r\n  proc newAccumState() :accumType\r\n\r\n  // Accumulate an input value onto the current task's\r\n  // accumulation state 'AS'.\r\n  proc accumulate(ref AS :accumType, input :inputType) :void\r\n\r\n  // Combine the parent task's accumulation state 'parentAS'\r\n  // with the child task's accumulation state 'childAS',\r\n  // storing the result back into 'parentAS'.\r\n  // Optional. If not defined, accumulate(parentAS, childAS) is used.\r\n  proc combine(ref parentAS :accumType, childAS :accumType) :void\r\n\r\n/* The remaining requirements depend on whether globalAS (the global\r\n   accumulation state) needs to be post-processed into the reduction\r\n   result after all values to be reduced have been processed.\r\n\r\n Case \"no generate\" : when the final globalAS already IS\r\n      the result of the reduction.\r\n\r\n     If so, generate(globalAS) must NOT be defined.\r\n     The requirements below do NOT apply.\r\n     In the case of a reduce intent, the outer variable is used\r\n     for globalAS.\r\n\r\n Case \"with generate\" : when globalAS needs to be post-processed\r\n      to generate the reduction result.\r\n\r\n     If so, generate(globalAS) must be defined.\r\n     The requirements below apply.\r\n*/\r\n\r\n  // Generate the reduction result a.k.a output given the global\r\n  // accumulation state 'globalAS', after all values to be reduced\r\n  // have been processed.\r\n  proc generate(globalAS :accumType) :outputType\r\n\r\n  // Generate the reduction result in the case of a reduce intent\r\n  // into the outer variable 'outerVar'.\r\n  // Note that semantics of the reduce intent requires\r\n  // that the initial value of the outer variable\r\n  // be reflected in the result of the reduction.\r\n  // Optional when outputType == inputType. If not defined,\r\n  // the following is used:\r\n  //   acumulate(globalAS, output); output = generate(globalAS);\r\n  proc generate(ref output :outputType, globalAS :accumType) :void\r\n\r\n}\r\n```\r\n\r\n* `inputType` - values being reduced\r\n* `accumType` - per-task accumulation state\r\n* `outputType` - result of the reduction\r\n\r\n* \"global\" - at the outer level - at the same scope as the forall loop or the reduce expression\r\n* \"parent\", \"child\" - when a \"parent\" task creates a \"child\" sub-task\r\n\r\n## Sum reduction\r\n\r\n```chpl\r\nrecord SumReduceOp {\r\n  type inputType;\r\n  proc newAccumState()         { var x: inputType; return x; }\r\n  proc accumulate(ref AS, val) { AS += val; }\r\n}\r\n```\r\n\r\n## MaxLoc reduction, no uninit\r\n\r\n```chpl\r\nrecord maxloc {\r\n  type inputType;\r\n  proc newAccumState() return (min(inputType(1)), max(inputType(2)));\r\n\r\n  proc accumulate(ref AS, (val,loc)) {\r\n    if AS(1) > val || (AS(1) == val && AS(2) < loc) then\r\n      AS = (val,loc);\r\n  }\r\n}\r\n```\r\n\r\n## MaxLoc reduction, with uninit\r\n\r\n```chpl\r\n// This is the accumulation state.\r\nrecord ValIdxRec {\r\n  var value;\r\n  var idx;\r\n  var uninit: bool;\r\n\r\n  proc init(type inputType) {\r\n    value  = min(inputType(1));\r\n    idx    = min(inputType(2));\r\n    uninit = true;\r\n  }\r\n\r\n  proc init(type inputType, (val,loc)) {\r\n    value  = val;\r\n    idx    = loc;\r\n    uninit = false;\r\n  }\r\n\r\n  proc add((val,loc)) {\r\n    if uninit || val > value ||\r\n      (val == value && idx < loc)\r\n    {\r\n      value = val;\r\n      idx = loc;\r\n    }\r\n    uninit = false;\r\n  }\r\n}\r\n\r\nrecord maxloc {\r\n  type inputType;\r\n\r\n  proc newAccumState() {\r\n    return new ValIdxRec(inputType);\r\n  }\r\n\r\n  proc accumulate(ref AS, (val,loc)) {\r\n    AS.add((val,loc));\r\n  }\r\n\r\n  proc combine(ref parentAS, childAS) {\r\n    // Nothing to do if child is uninitialized.\r\n    if !childAS.uninit then\r\n      parentAS.add((childAS.value, childAS.idx));\r\n  }\r\n\r\n  proc generate(ref globalAS) {\r\n    // Do this even if it is uninitialized.\r\n    return (globalAS.value, globalAS.idx);\r\n  }\r\n}\r\n```\r\n\r\n## SlowSum reduction\r\n\r\n```chpl\r\n// This is the accumulation state.\r\nrecord ArrRec {\r\n  var exps: domain(int);\r\n  var vals: [exps] real;\r\n  proc add(exp: c_int, val: real) {\r\n    // \"on this\" ?\r\n    if !exps.member(exp) then\r\n      exps += exp;\r\n    vals[exp] += val;\r\n  }\r\n}\r\n\r\n// Helper.\r\nproc val2exp(val: real) {\r\n  extern proc frexp(value: real, ref exp: c_int): real;\r\n  var exp: c_int;\r\n  frexp(val, exp);\r\n  return exp;\r\n}\r\n\r\n// The reduce op type.\r\nrecord SlowSumOp {\r\n\r\n  proc init(type inputType) { compilerAssert(inputType == real); }\r\n\r\n  proc newAccumState()  return new ArrRec();\r\n\r\n  proc accumulate(ref AS: ArrRec, val: real) {\r\n    AS.add(val2exp(val), val);\r\n  }\r\n\r\n  proc combine(ref parentAS: ArrRec, childAS: ArrRec) {\r\n    for (exp, val) in zip(childAS.exps, childAS.vals) do\r\n      parentAS.add(exp, val);\r\n  }\r\n\r\n  proc generate(globalAS: ArrRec) {\r\n    var sum = 0.0;\r\n    for val in globalAS.vals do\r\n      sum += val;\r\n    return sum;\r\n  }\r\n}\r\n```\r\n"},"comment":{"url":"https://api.github.com/repos/chapel-lang/chapel/issues/comments/399458281","html_url":"https://github.com/chapel-lang/chapel/issues/9879#issuecomment-399458281","issue_url":"https://api.github.com/repos/chapel-lang/chapel/issues/9879","id":399458281,"node_id":"MDEyOklzc3VlQ29tbWVudDM5OTQ1ODI4MQ==","user":{"login":"vasslitvinov","id":8039635,"node_id":"MDQ6VXNlcjgwMzk2MzU=","avatar_url":"https://avatars0.githubusercontent.com/u/8039635?v=4","gravatar_id":"","url":"https://api.github.com/users/vasslitvinov","html_url":"https://github.com/vasslitvinov","followers_url":"https://api.github.com/users/vasslitvinov/followers","following_url":"https://api.github.com/users/vasslitvinov/following{/other_user}","gists_url":"https://api.github.com/users/vasslitvinov/gists{/gist_id}","starred_url":"https://api.github.com/users/vasslitvinov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vasslitvinov/subscriptions","organizations_url":"https://api.github.com/users/vasslitvinov/orgs","repos_url":"https://api.github.com/users/vasslitvinov/repos","events_url":"https://api.github.com/users/vasslitvinov/events{/privacy}","received_events_url":"https://api.github.com/users/vasslitvinov/received_events","type":"User","site_admin":false},"created_at":"2018-06-22T14:18:58Z","updated_at":"2018-06-22T14:18:58Z","author_association":"MEMBER","body":"> In other words accumulate and generate will have generic arguments instead of using accumType?\r\n\r\nIt is up to the ReduceOp author. Here are some scenarios:\r\n\r\n* Yes, generic arguments. For example: `proc accumulate(AS, input) { AS += input; }`\r\n* No, concrete arguments. In the \"SlowSum reduction\" example above: `proc accumulate(ref AS: ArrRec, val: real)`\r\n* Have an `inputType` type field in the ReduceOp and require that the arugments be of that type: `proc accumulate(AS: inputType, input: inputType) { AS += input; }`\r\n\r\nIn other words, the interface does not require specific types on the method declarations. (Or specific intents, for that matter.) Instead it requires that the corresponding calls be resolvable. For example, given `op:ReduceOp`, `AS:accumType`, `input:inputType`, when those are created for a reduction with the given `inputType`, the call `op.accumulate(AS, input)` must be resolvable.\r\n"}}
{"actor":{"display_login":"vasslitvinov"}}