Message Boards Message Boards

0
|
2059 Views
|
5 Replies
|
6 Total Likes
View groups...
Share
Share this post:

Association Pattern Tests in Function Signatures

Posted 10 months ago

Is it possible to specialize pattern tests for f such that the three VerificationTests (below) succeed? Additionally, is there a performance and tuning guide specifically for data science pipelines that process large sets of Association? For example, is it possible to Compile functions whose arguments include Association?

 f[assoc_ : Asssociation[___Rule[_String, _TemporalData]]] := 
  "String->TemporalData";
f[assoc_ : Asssociation[___Rule[_Symbol, _TemporalData]]] := 
  "Symbol->TemporalData";
f[assoc_ : Asssociation[___Rule]] := "_->_";

With[{ts1 = TimeSeries[{1, 2}], ts2 = TimeSeries[-{1, 2}], 
  v = VerificationTest},
 {VerificationTest[f@<|"a" -> ts1, "b" -> ts2|>, 
   "String->TemporalData"]
  , VerificationTest[f@<|a -> ts1, b -> ts2|>, 
   "Symbol->TemporalData"]
  , VerificationTest[f@<|a -> ts1, "b" -> ts2|>, "_->_"] }] //TableForm
Attachments:
POSTED BY: A. Chase Turner
5 Replies

Fixing the typo Asssociation -> Association the code still fails because the pattern

___Rule[_String, _TemporalData]

does not match a sequence of rules with string keys and temporal data values (it is the same thing as (___Rule)[_String, _TemporalData]). Instead you want Rule[_String, _TemporalData] ... See RepeatedNull versus BlankNullSequence for more information. Any time you use Association in a pattern it is good to use HoldPattern to avoid evaluation, so this is how I would rewrite your definitions:

ClearAll @ f;
f[assoc:HoldPattern[Association[Rule[_String, _TemporalData]...]]] := "String->TemporalData";
f[assoc:HoldPattern[Association[Rule[_Symbol, _TemporalData]...]]] := "Symbol->TemporalData";
f[assoc:HoldPattern[Association[___Rule]]] := "_->_";

Then your tests all pass.

POSTED BY: Jason Biggs
Posted 10 months ago

Nice! I feel stupid, because I actually expected pattern matching on the internals of Association to fail, so didn't even try it. I've gotten into the habit of treating associations as sort of opaque and over-generalized.

POSTED BY: Eric Rimbey
Posted 10 months ago

Thank you!!!

POSTED BY: A. Chase Turner
Posted 10 months ago

Jason -- thank you again for your help earlier! Two more follow on questions relative to the attached notebook with VerificationTests:

  1. Is it possible to re-write keyToString so it is Listable and thereby ready for pipelining into Parallelize?
  2. When Keys are already _Strings, are the pattern tests returning the unaltered argument useful, or a runtime headache to evaluate before jumping over to the non-String case?

    keyToString[rule : Rule[_String, _]] := rule;
    keyToString[rule : Rule[b_, c_]] := Rule[ToString@b, c];
    keyToString[rules : {___Rule }] := keyToString /@ rules;
    keyToString[rulesList : {{___Rule } ...}] := 
      keyToString /@ rulesList;
    keyToString[assoc : HoldPattern[Association[Rule[_String, _] ...]]] :=
       assoc;
    keyToString[assoc : HoldPattern[Association[Rule[_, _] ...]]] := 
      AssociationThread[ToString /@ Keys@assoc, Values@assoc];
    keyToString[
       assocList : {HoldPattern[Association[Rule[_, _] ...]] ...}] := 
      keyToString /@ assocList;
    (*UNKNOWN*)
    keyToString::narg = 
      "Warning: argument is not a Rule, {Rule...}, Association, or \
    {Association...}";
    keyToString[unknown_] := 
      Block[{}, Message[keyToString::narg]; unknown];
    
Attachments:
POSTED BY: A. Chase Turner
Posted 10 months ago

I don't know about the second part of your question regarding Compile. For the first part, Association is a special beast. It's kind of atomic, and so generally you can't really just pattern-match on the internals of an Association expression. You could try something like this:

f2[assoc_Association] := 
  "String->TemporalData" /; MatchQ[Normal[assoc], {(_String -> _TemporalData) ..}];
f2[assoc_Association] := 
  "Symbol->TemporalData" /; MatchQ[Normal[assoc], {(_Symbol -> _TemporalData) ..}];

You could also have a step in your workflow where "raw" data gets transformed by some constructor function into a structure that is known to be valid. You can even create a custom head to wrap around the data for easy pattern matching in subsequent functions.

So, you could use a custom head like StringTemporalAssociation and define a constructor like MakeStringTemporalAssociation that processes the raw data and generates a StringTemporalAssociation expression whose internals are guaranteed to match your pattern (which can still be an Association). You can overload StringTemporalAssociation rather than use MakeStringTemporalAssociation if there is no ambiguity. Similarly with SymbolTemporalAssociation or whatever. Pattern matching then simplifies to just head matching.

POSTED BY: Eric Rimbey
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract