From 1208f56d41df3c96e07a45c4d924ea5568f4fe74 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Wed, 18 Dec 2024 09:07:29 -0500 Subject: [PATCH 1/9] Add pairs(Thing), which returns an Iterator --- M2/Macaulay2/d/actors2.dd | 2 +- M2/Macaulay2/d/evaluate.d | 1 + M2/Macaulay2/m2/iterators.m2 | 8 +++++ .../packages/Macaulay2Doc/doc_tables.m2 | 33 ++++++++++++++----- M2/Macaulay2/tests/normal/iterators.m2 | 2 ++ 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/M2/Macaulay2/d/actors2.dd b/M2/Macaulay2/d/actors2.dd index 1f8b7de3d3d..9e160422775 100644 --- a/M2/Macaulay2/d/actors2.dd +++ b/M2/Macaulay2/d/actors2.dd @@ -143,7 +143,7 @@ pairs(e:Expr):Expr := ( provide Expr(Sequence(toExpr(i),o.i)); i = i+1;))) is o:List do pairs(Expr(o.v)) -- # typical value: pairs, BasicList, List - else WrongArg("a hash table, a sequence, a list, or a raw polynomial")); + else applyEE(getGlobalVariable(pairsIteratorS), e)); -- # typical value: pairs, Thing, Iterator setupfun("pairs",pairs); -- operators diff --git a/M2/Macaulay2/d/evaluate.d b/M2/Macaulay2/d/evaluate.d index 29bb86293f3..e5a13261d9a 100644 --- a/M2/Macaulay2/d/evaluate.d +++ b/M2/Macaulay2/d/evaluate.d @@ -28,6 +28,7 @@ export iteratorS := setupvar("iterator", nullE); export nextS := setupvar("next", nullE); export applyIteratorS := setupvar("applyIterator", nullE); export joinIteratorsS := setupvar("joinIterators", nullE); +export pairsIteratorS := setupvar("pairsIterator", nullE); eval(c:Code):Expr; applyEE(f:Expr,e:Expr):Expr; diff --git a/M2/Macaulay2/m2/iterators.m2 b/M2/Macaulay2/m2/iterators.m2 index ded8da8eff3..fc5b6353f42 100644 --- a/M2/Macaulay2/m2/iterators.m2 +++ b/M2/Macaulay2/m2/iterators.m2 @@ -65,3 +65,11 @@ joinIterators = a -> ( r)))) Iterator | Iterator := (x, y) -> joinIterators(x, y) + +pairsIterator = x -> Iterator ( + iter := iterator x; + i := 0; + () -> ( + y := next iter; + if y === StopIteration then StopIteration + else (i, (i += 1; y)))) diff --git a/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 b/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 index d199b436d42..8ddb4a3541f 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 @@ -233,16 +233,23 @@ doc /// (pairs, HashTable) (pairs, Dictionary) (pairs, BasicList) + (pairs, Thing) Headline list the pairs in a hash table, dictionary, or basic list - Usage - pairs x - Inputs - x:HashTable - or @TO Dictionary@ or @TO BasicList@ - Outputs - L:List - of all pairs {\tt (k, x#k)} + Synopsis + Usage + pairs x + Inputs + x:{HashTable, Dictionary, BasicList} + Outputs + L:List -- of all pairs @CODE "(k, x#k)"@ + Synopsis + Usage + pairs x + Inputs + x:Thing -- an instance of a class with an @TO iterator@ method installed + Outputs + :Iterator Description Text If {\tt x} is a hash table or dictionary, the pairs consist of @@ -267,6 +274,16 @@ doc /// L = {3, 5, 7}; pairs L pairs {apple, banana, carrot} + Text + If @CODE "x"@ belongs to any other class, then @TO iterator@ is called + on it, and if successful, an @TO Iterator@ object is returned. + Example + pairs "foo" + toList oo + i = pairs Iterator(() -> 5) + next i + next i + next i Caveat As the first example illustrates, pairs are not necessarily listed in any particular order. diff --git a/M2/Macaulay2/tests/normal/iterators.m2 b/M2/Macaulay2/tests/normal/iterators.m2 index fe741f7f793..d35a4c30c7f 100644 --- a/M2/Macaulay2/tests/normal/iterators.m2 +++ b/M2/Macaulay2/tests/normal/iterators.m2 @@ -52,3 +52,5 @@ assert Equation(toList(iterator {1, 2, 3} | iterator {4, 5, 6}), assert Equation(join({1, 2, 3}, iterator {4, 5, 6}), {1, 2, 3, 4, 5, 6}) assert Equation(join((1, 2, 3), iterator {4, 5, 6}), (1, 2, 3, 4, 5, 6)) assert Equation(join([1, 2, 3], iterator {4, 5, 6}), [1, 2, 3, 4, 5, 6]) + +assert Equation(toList pairs "foo", {(0, "f"), (1, "o"), (2, "o")}) From 67f2ab55212a3c90334f2a0f1398e3f5e025fe17 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Wed, 18 Dec 2024 09:37:08 -0500 Subject: [PATCH 2/9] Add WrongArgImmutableHashTable helper function in d directory It's a pretty common error message --- M2/Macaulay2/d/actors3.d | 2 +- M2/Macaulay2/d/actors4.d | 6 +++--- M2/Macaulay2/d/evaluate.d | 14 +++++++------- M2/Macaulay2/d/expr.d | 2 ++ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/M2/Macaulay2/d/actors3.d b/M2/Macaulay2/d/actors3.d index 65902ee3d08..35bc4768867 100644 --- a/M2/Macaulay2/d/actors3.d +++ b/M2/Macaulay2/d/actors3.d @@ -82,7 +82,7 @@ override(e:Expr):Expr := ( if length(args) == 2 then ( when args.0 is h:HashTable do ( - if h.Mutable then WrongArg("an immutable hash table") + if h.Mutable then WrongArgImmutableHashTable() else when args.1 is v:Sequence do override(h,v,numOptions(v)) else override(h,Sequence(args.1),if isOption(args.1) then 1 else 0) ) diff --git a/M2/Macaulay2/d/actors4.d b/M2/Macaulay2/d/actors4.d index 9185872f813..71e3aff195e 100644 --- a/M2/Macaulay2/d/actors4.d +++ b/M2/Macaulay2/d/actors4.d @@ -236,7 +236,7 @@ selectPairs(e:Expr):Expr := ( when a.0 is obj:HashTable do ( if obj.Mutable - then WrongArg(1, "an immutable hash table") + then WrongArgImmutableHashTable(1) else selectPairs(obj.numEntries, obj, a.1)) else WrongArgHashTable(1)) -- # typical value: selectPairs, ZZ, HashTable, Function, HashTable @@ -248,7 +248,7 @@ selectPairs(e:Expr):Expr := ( when a.1 is obj:HashTable do ( if obj.Mutable - then WrongArg(2, "an immutable hash table") + then WrongArgImmutableHashTable(2) else selectPairs(toInt(n), obj, a.2)) else WrongArgHashTable(2))) else WrongArgZZ(1)) @@ -298,7 +298,7 @@ any(f:Expr,e:Expr):Expr := ( is b:List do Expr(any(f,b.v)) is i:ZZcell do if isInt(i) then Expr(any(f,toInt(i))) else WrongArgSmallInteger(1) is c:HashTable do - if c.Mutable then WrongArg(1,"an immutable hash table") else + if c.Mutable then WrongArgImmutableHashTable(1) else Expr(any(f,c)) else WrongArg("a list or a hash table")); any(f:Expr,a:Sequence,b:Sequence):Expr := ( diff --git a/M2/Macaulay2/d/evaluate.d b/M2/Macaulay2/d/evaluate.d index e5a13261d9a..7419446134b 100644 --- a/M2/Macaulay2/d/evaluate.d +++ b/M2/Macaulay2/d/evaluate.d @@ -1726,7 +1726,7 @@ scanpairsfun(e:Expr):Expr := ( then when a.0 is o:HashTable do if o.Mutable - then WrongArg("an immutable hash table") + then WrongArgImmutableHashTable() else scanpairs(a.1,o) else WrongArgHashTable(1) else WrongNumArgs(2) @@ -1825,7 +1825,7 @@ mapkeysfun(e:Expr):Expr := ( then when a.0 is o:HashTable do if o.Mutable - then WrongArg("an immutable hash table") + then WrongArgImmutableHashTable() else if length(a) == 2 then mapkeys(a.1,o) else mapkeysmerge(a.1,o,a.2) else WrongArgHashTable(1) else WrongNumArgs(2,3) @@ -1865,7 +1865,7 @@ mapvaluesfun(e:Expr):Expr := ( then when a.0 is o:HashTable do if o.Mutable - then WrongArg("an immutable hash table") + then WrongArgImmutableHashTable() else mapvalues(a.1,o) else WrongArgHashTable(1) else WrongNumArgs(2) @@ -2067,18 +2067,18 @@ combine(e:Expr):Expr := ( is v:Sequence do if length(v) == 5 then ( when v.0 is x:HashTable do - if x.Mutable then WrongArg(1,"an immutable hash table") else + if x.Mutable then WrongArgImmutableHashTable(1) else when v.1 is y:HashTable do - if y.Mutable then WrongArg(2,"an immutable hash table") else + if y.Mutable then WrongArgImmutableHashTable(2) else combine(v.2,v.3,v.4,x,y) else WrongArgHashTable(2) else WrongArgHashTable(1) ) else if length(v) == 6 then ( when v.0 is x:HashTable do - if x.Mutable then WrongArg(1,"an immutable hash table") else + if x.Mutable then WrongArgImmutableHashTable(1) else when v.1 is y:HashTable do - if y.Mutable then WrongArg(2,"an immutable hash table") else + if y.Mutable then WrongArgImmutableHashTable(2) else twistCombine(v.2,v.3,v.4,v.5,x,y) else WrongArgHashTable(2) else WrongArgHashTable(1) diff --git a/M2/Macaulay2/d/expr.d b/M2/Macaulay2/d/expr.d index ab258c77ac5..7958fd5a315 100644 --- a/M2/Macaulay2/d/expr.d +++ b/M2/Macaulay2/d/expr.d @@ -389,6 +389,8 @@ export WrongArgMatrix(n:int):Expr := WrongArg(n,"a raw matrix"); export WrongArgMatrix():Expr := WrongArg("a raw matrix"); export WrongArgHashTable():Expr := WrongArg("a hash table"); export WrongArgHashTable(n:int):Expr := WrongArg(n, "a hash table"); +export WrongArgImmutableHashTable():Expr := WrongArg("an immutable hash table"); +export WrongArgImmutableHashTable(n:int):Expr := WrongArg(n, "an immutable hash table"); export ArgChanged(name:string,n:int):Expr := ( buildErrorPacket(quoteit(name) + " expected argument " + tostring(n) + " not to change its type during execution")); From 6348b0cf5e59af30d8b8c5a546c149308104d183 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Wed, 18 Dec 2024 09:57:47 -0500 Subject: [PATCH 3/9] Add applyPairs for non-hash tables applyPairs(x, f) is the same as apply(pairs x, f) --- M2/Macaulay2/d/actors2.dd | 2 +- M2/Macaulay2/d/actors3.d | 17 +++++++++++++++++ M2/Macaulay2/d/evaluate.d | 14 +------------- .../Macaulay2Doc/functions/applyPairs-doc.m2 | 11 ++++++++++- M2/Macaulay2/tests/normal/iterators.m2 | 2 ++ 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/M2/Macaulay2/d/actors2.dd b/M2/Macaulay2/d/actors2.dd index 9e160422775..c61e9918f88 100644 --- a/M2/Macaulay2/d/actors2.dd +++ b/M2/Macaulay2/d/actors2.dd @@ -104,7 +104,7 @@ values(e:Expr):Expr := ( else WrongArg("a hash table or dictionary")); setupfun("values",values); -pairs(e:Expr):Expr := ( +export pairs(e:Expr):Expr := ( when e is oc:DictionaryClosure do ( -- # typical value: pairs, Dictionary, List o := oc.dictionary.symboltable; diff --git a/M2/Macaulay2/d/actors3.d b/M2/Macaulay2/d/actors3.d index 35bc4768867..0f3256c947a 100644 --- a/M2/Macaulay2/d/actors3.d +++ b/M2/Macaulay2/d/actors3.d @@ -2,6 +2,7 @@ use evaluate; use actors; +use actors2; use ballarith; isOption(e:Expr):bool := ( @@ -1895,6 +1896,22 @@ map(e:Expr):Expr := ( else WrongNumArgs(2,3)); setupfun("apply",map); +applyPairs(e:Expr):Expr := ( + when e + is a:Sequence do ( + if length(a) == 2 then ( + when a.0 + is o:HashTable do ( + if o.Mutable then WrongArgImmutableHashTable(1) + else mappairs(a.1, o)) + -- # typical value: applyPairs, BasicList, Function, List + -- # typical value: applyPairs, Dictionary, Function, List + -- # typical value: applyPairs, Thing, Function, Iterator + else map(pairs(a.0), a.1)) + else WrongNumArgs(2)) + else WrongNumArgs(2)); +setupfun("applyPairs", applyPairs); + -- # typical value: scan, ZZ, Function, Thing scan(n:int,f:Expr):Expr := ( if n <= 0 then return nullE; diff --git a/M2/Macaulay2/d/evaluate.d b/M2/Macaulay2/d/evaluate.d index 7419446134b..c2d5667566c 100644 --- a/M2/Macaulay2/d/evaluate.d +++ b/M2/Macaulay2/d/evaluate.d @@ -1735,7 +1735,7 @@ setupfun("scanPairs",scanpairsfun); mpre():Expr := buildErrorPacket("applyPairs: expected function to return null, a sequence of length 2, or an option x=>y"); -- # typical value: applyPairs, HashTable, Function, HashTable -mappairs(f:Expr,o:HashTable):Expr := ( -- o is not Mutable +export mappairs(f:Expr,o:HashTable):Expr := ( -- o is not Mutable x := newHashTable(o.Class,o.parent); x.beingInitialized = true; foreach bucket in o.table do ( @@ -1763,18 +1763,6 @@ mappairs(f:Expr,o:HashTable):Expr := ( -- o is not Mutable p = p.next; )); Expr(sethash(x,o.Mutable))); -mappairsfun(e:Expr):Expr := ( - when e is a:Sequence do - if length(a) == 2 - then when a.0 is o:HashTable - do - if o.Mutable - then WrongArg("an immutable hash table") - else mappairs(a.1,o) - else WrongArgHashTable(1) - else WrongNumArgs(2) - else WrongNumArgs(2)); -setupfun("applyPairs",mappairsfun); -- # typical value: applyKeys, HashTable, Function, HashTable export mapkeys(f:Expr,o:HashTable):Expr := ( -- o is not Mutable diff --git a/M2/Macaulay2/packages/Macaulay2Doc/functions/applyPairs-doc.m2 b/M2/Macaulay2/packages/Macaulay2Doc/functions/applyPairs-doc.m2 index c49d89ee5b5..1c283823b5b 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/functions/applyPairs-doc.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/functions/applyPairs-doc.m2 @@ -6,12 +6,16 @@ doc /// Key applyPairs (applyPairs,HashTable,Function) + (applyPairs,BasicList,Function) + (applyPairs,Dictionary,Function) + (applyPairs,Thing,Function) Headline apply a function to each pair in a hash table Usage applyPairs(H, f) Inputs - H:HashTable + H:{HashTable, BasicList, Dictionary} + or any instance of a class with an @TO iterator@ method installed f:Function of two arguments, returning a pair or @TO null@ Outputs @@ -22,6 +26,11 @@ doc /// H = new HashTable from {1 => 10, 2 => 15, 3 => 20} applyPairs(H, (k,v) -> (k+1, v+10)) applyPairs(H, (k,v) -> (v,k)) + Text + If @CODE "H"@ is not a hash table, then @M2CODE "apply(pairs H, f)"@ is + called. + Example + applyPairs({4, 5, 6}, (i, x) -> i * x) Caveat It is an error for the function {\tt f} to return two pairs with the same key. SeeAlso diff --git a/M2/Macaulay2/tests/normal/iterators.m2 b/M2/Macaulay2/tests/normal/iterators.m2 index d35a4c30c7f..bede022ef65 100644 --- a/M2/Macaulay2/tests/normal/iterators.m2 +++ b/M2/Macaulay2/tests/normal/iterators.m2 @@ -54,3 +54,5 @@ assert Equation(join((1, 2, 3), iterator {4, 5, 6}), (1, 2, 3, 4, 5, 6)) assert Equation(join([1, 2, 3], iterator {4, 5, 6}), [1, 2, 3, 4, 5, 6]) assert Equation(toList pairs "foo", {(0, "f"), (1, "o"), (2, "o")}) +assert Equation(toList applyPairs("foo", (i, c) -> (c, i + 1)), + {("f", 1), ("o", 2), ("o", 3)}) From 5a6a333e8d86e9bce9662d1ee4612640e2eb0be0 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Wed, 18 Dec 2024 10:11:59 -0500 Subject: [PATCH 4/9] Add scanPairs for non-hash tables scanPairs(x, f) is the same as scan(pairs x, f) --- M2/Macaulay2/d/actors3.d | 14 ++++++++++++++ M2/Macaulay2/d/evaluate.d | 14 +------------- M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 | 11 +++++++++-- M2/Macaulay2/tests/normal/iterators.m2 | 3 +++ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/M2/Macaulay2/d/actors3.d b/M2/Macaulay2/d/actors3.d index 0f3256c947a..227055e4556 100644 --- a/M2/Macaulay2/d/actors3.d +++ b/M2/Macaulay2/d/actors3.d @@ -2363,6 +2363,20 @@ scan(e:Expr):Expr := ( else WrongNumArgs(2)); setupfun("scan",scan); +-- # typical value: scanPairs, Thing, Function, Nothing +scanPairs(e:Expr):Expr := ( + when e + is a:Sequence do ( + if length(a) == 2 then ( + when a.0 + is o:HashTable do ( + if o.Mutable then WrongArgImmutableHashTable(1) + else scanpairs(a.1, o)) + else scan(pairs(a.0), a.1)) + else WrongNumArgs(2)) + else WrongNumArgs(2)); +setupfun("scanPairs", scanPairs); + nextPrime(e:Expr):Expr := ( when e is x:ZZcell do toExpr(nextPrime(x.v - oneZZ)) diff --git a/M2/Macaulay2/d/evaluate.d b/M2/Macaulay2/d/evaluate.d index c2d5667566c..4ea4de36d90 100644 --- a/M2/Macaulay2/d/evaluate.d +++ b/M2/Macaulay2/d/evaluate.d @@ -1710,7 +1710,7 @@ setup(LeftArrowS,assigntofun); idfun(e:Expr):Expr := e; setupfun("identity",idfun); -- # typical value: scanPairs, HashTable, Function, Nothing -scanpairs(f:Expr,obj:HashTable):Expr := ( -- obj is not Mutable +export scanpairs(f:Expr,obj:HashTable):Expr := ( -- obj is not Mutable foreach bucket in obj.table do ( p := bucket; while true do ( @@ -1720,18 +1720,6 @@ scanpairs(f:Expr,obj:HashTable):Expr := ( -- obj is not Mutable p = p.next; )); nullE); -scanpairsfun(e:Expr):Expr := ( - when e is a:Sequence do - if length(a) == 2 - then when a.0 is o:HashTable - do - if o.Mutable - then WrongArgImmutableHashTable() - else scanpairs(a.1,o) - else WrongArgHashTable(1) - else WrongNumArgs(2) - else WrongNumArgs(2)); -setupfun("scanPairs",scanpairsfun); mpre():Expr := buildErrorPacket("applyPairs: expected function to return null, a sequence of length 2, or an option x=>y"); -- # typical value: applyPairs, HashTable, Function, HashTable diff --git a/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 b/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 index 8ddb4a3541f..80a074c480f 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/doc_tables.m2 @@ -394,12 +394,14 @@ doc /// Key scanPairs (scanPairs, HashTable, Function) + (scanPairs, Thing, Function) Headline apply a function to the pairs in a hash table Usage scanPairs(t, f) Inputs - t:HashTable + t:{HashTable, BasicList, Dictionary} + or any instance of a class with an @TO iterator@ method installed f:Function Description Text @@ -410,7 +412,12 @@ doc /// Example t = hashTable {{1,8},{2,20},{3,4},{4,20}} scanPairs(t, (k,v) -> print (k+v)) - scanPairs(t, (k,v) -> if v==20 then print k) + scanPairs(t, (k,v) -> if v==20 then print k) + Text + If @CODE "t"@ is not a hash table, then @M2CODE "scan(pairs t, f)"@ is + called. + Example + scanPairs({4, 5, 6}, print) Caveat This function requires an immutable hash table. To scan the pairs in a mutable hash table, use {\tt scan(pairs t, f)}. diff --git a/M2/Macaulay2/tests/normal/iterators.m2 b/M2/Macaulay2/tests/normal/iterators.m2 index bede022ef65..f9d4ad5afa4 100644 --- a/M2/Macaulay2/tests/normal/iterators.m2 +++ b/M2/Macaulay2/tests/normal/iterators.m2 @@ -56,3 +56,6 @@ assert Equation(join([1, 2, 3], iterator {4, 5, 6}), [1, 2, 3, 4, 5, 6]) assert Equation(toList pairs "foo", {(0, "f"), (1, "o"), (2, "o")}) assert Equation(toList applyPairs("foo", (i, c) -> (c, i + 1)), {("f", 1), ("o", 2), ("o", 3)}) +x = 0 +scanPairs("foo", (i, c) -> x += i + first ascii c) +assert Equation(x, 0 + 102 + 1 + 111 + 2 + 111) From 2e43c71a0c2b49f8d3f0348f1c42cab49f8c6e7b Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Wed, 18 Dec 2024 10:39:37 -0500 Subject: [PATCH 5/9] Add selectPairs for non-hash table selectPairs(x, f) is the same as select(pairs x, f) Doesn't support iterators (yet) since select is defined for them at top-level. --- M2/Macaulay2/d/actors4.d | 11 +++++++---- .../packages/Macaulay2Doc/functions/select-doc.m2 | 14 ++++++++++++-- M2/Macaulay2/tests/normal/iterators.m2 | 3 +++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/M2/Macaulay2/d/actors4.d b/M2/Macaulay2/d/actors4.d index 71e3aff195e..0928926e9ee 100644 --- a/M2/Macaulay2/d/actors4.d +++ b/M2/Macaulay2/d/actors4.d @@ -200,6 +200,8 @@ select(e:Expr):Expr := ( else WrongNumArgs(2,5)); setupfun("select", select).Protected = false; -- will be overloaded in m2/lists.m2 and m2/regex.m2 +-- # typical value: selectPairs, HashTable, Function, HashTable +-- # typical value: selectPairs, ZZ, HashTable, Function, HashTable selectPairs(nval:int, obj:HashTable, f:Expr):Expr := ( u := newHashTable(obj.Class,obj.parent); u.beingInitialized = true; @@ -228,18 +230,18 @@ selectPairs(nval:int, obj:HashTable, f:Expr):Expr := ( "expected predicate to yield true or false")); p = p.next)); Expr(sethash(u,obj.Mutable))); +-- TODO: support iterators selectPairs(e:Expr):Expr := ( when e is a:Sequence do ( - -- # typical value: selectPairs, HashTable, Function, HashTable if length(a) == 2 then ( when a.0 is obj:HashTable do ( if obj.Mutable then WrongArgImmutableHashTable(1) else selectPairs(obj.numEntries, obj, a.1)) - else WrongArgHashTable(1)) - -- # typical value: selectPairs, ZZ, HashTable, Function, HashTable + -- # typical value: selectPairs, BasicList, Function, List + else select(pairs(a.0), a.1)) else if length(a) == 3 then ( when a.0 is n:ZZcell do ( @@ -250,7 +252,8 @@ selectPairs(e:Expr):Expr := ( if obj.Mutable then WrongArgImmutableHashTable(2) else selectPairs(toInt(n), obj, a.2)) - else WrongArgHashTable(2))) + -- # typical value: selectPairs, ZZ, BasicList, Function, List + else select(a.0, pairs(a.1), a.2, nullE, nullE))) else WrongArgZZ(1)) else WrongNumArgs(2, 3)) else WrongNumArgs(2, 3)); diff --git a/M2/Macaulay2/packages/Macaulay2Doc/functions/select-doc.m2 b/M2/Macaulay2/packages/Macaulay2Doc/functions/select-doc.m2 index 6f4ea9b5cce..595370671b5 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/functions/select-doc.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/functions/select-doc.m2 @@ -265,7 +265,9 @@ doc /// doc /// Key selectPairs + (selectPairs, BasicList, Function) (selectPairs, HashTable, Function) + (selectPairs, ZZ, BasicList, Function) (selectPairs, ZZ, HashTable, Function) Headline select a part of a hash table by pairs @@ -274,10 +276,10 @@ doc /// selectPairs(n, x, f) Inputs n:ZZ - x:HashTable -- must be immutable + x:{HashTable, BasicList} f:Function Outputs - :HashTable + :{HashTable, BasicList} containing all (or @VAR "n"@, if it is given) key-value pairs (@VAR "k"@,@VAR "v"@) from @VAR "x"@ for which @CODE "f(k,v)"@ evaluates to true. @@ -286,6 +288,14 @@ doc /// x = hashTable{(1, 2), (2, 4), (3, 6), (4, 8), (5, 10)} selectPairs(x, (k,v) -> odd(k + v)) selectPairs(2, x, (k, v) -> odd(k + v)) + Text + If @CODE "x"@ is not a hash table, then @M2CODE "select(pairs x, f)"@ + (or @M2CODE "select(n, pairs x, f)"@) is called. + Example + selectPairs(toList(1..10), (i, x) -> even x) + selectPairs(3, toList(1..10), (i, x) -> even x) + Caveat + If @CODE "x"@ is a hash table, then it must be immutable. SeeAlso selectValues selectKeys diff --git a/M2/Macaulay2/tests/normal/iterators.m2 b/M2/Macaulay2/tests/normal/iterators.m2 index f9d4ad5afa4..340e14c4aa4 100644 --- a/M2/Macaulay2/tests/normal/iterators.m2 +++ b/M2/Macaulay2/tests/normal/iterators.m2 @@ -59,3 +59,6 @@ assert Equation(toList applyPairs("foo", (i, c) -> (c, i + 1)), x = 0 scanPairs("foo", (i, c) -> x += i + first ascii c) assert Equation(x, 0 + 102 + 1 + 111 + 2 + 111) +assert Equation(selectPairs(1..10, (i, x) -> even x), + ((1, 2), (3, 4), (5, 6), (7, 8), (9, 10))) +assert Equation(selectPairs(2, 1..10, (i, x) -> even x), ((1, 2), (3, 4))) From a05d192e55c0091a13b68763348a15f23af378eb Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Thu, 19 Dec 2024 21:51:09 -0500 Subject: [PATCH 6/9] Make pairs(BasicList) return list of same class --- M2/Macaulay2/d/actors2.dd | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/M2/Macaulay2/d/actors2.dd b/M2/Macaulay2/d/actors2.dd index c61e9918f88..d9b19fc98cd 100644 --- a/M2/Macaulay2/d/actors2.dd +++ b/M2/Macaulay2/d/actors2.dd @@ -142,7 +142,12 @@ export pairs(e:Expr):Expr := ( while i < length(o) do ( provide Expr(Sequence(toExpr(i),o.i)); i = i+1;))) - is o:List do pairs(Expr(o.v)) -- # typical value: pairs, BasicList, List + -- # typical value: pairs, BasicList, List + is o:List do ( + r := pairs(Expr(o.v)); + when r + is s:Sequence do list(o.Class, s, o.Mutable) + else buildErrorPacket("internal error; expected a sequence")) else applyEE(getGlobalVariable(pairsIteratorS), e)); -- # typical value: pairs, Thing, Iterator setupfun("pairs",pairs); From 977dcd92b3727d5f9acaf6a5888636c544f7256f Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Thu, 19 Dec 2024 21:30:35 -0500 Subject: [PATCH 7/9] Move isFunction to util.d w/ similar functions and export --- M2/Macaulay2/d/pthread.d | 8 -------- M2/Macaulay2/d/util.d | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/M2/Macaulay2/d/pthread.d b/M2/Macaulay2/d/pthread.d index f396bba20fe..acd635f8e95 100644 --- a/M2/Macaulay2/d/pthread.d +++ b/M2/Macaulay2/d/pthread.d @@ -42,14 +42,6 @@ startup(tb:TaskCellBody):null := ( compilerBarrier(); null()); -isFunction(e:Expr):bool := ( - when e - is CompiledFunction do true - is CompiledFunctionClosure do true - is FunctionClosure do true - is s:SpecialExpr do isFunction(s.e) - else false); - taskDone(tb:TaskCellBody):bool := tb.resultRetrieved || taskDone(tb.task); cancelTask(tb:TaskCellBody):Expr := ( diff --git a/M2/Macaulay2/d/util.d b/M2/Macaulay2/d/util.d index c920c889679..0403063f2b0 100644 --- a/M2/Macaulay2/d/util.d +++ b/M2/Macaulay2/d/util.d @@ -187,6 +187,14 @@ export getSequenceOfMutableMatrices(e:Expr) : RawMutableMatrixArray := ( is a:RawMutableMatrixCell do RawMutableMatrixArray(a.p) else RawMutableMatrixArray()); +export isFunction(e:Expr):bool := ( + when e + is CompiledFunction do true + is CompiledFunctionClosure do true + is FunctionClosure do true + is s:SpecialExpr do isFunction(s.e) + else false); + ----------------------------------------------------------------------------- -- helper routines for checking and converting return values From 1c7499655d3df684024c34a411e39082c0fa8427 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Thu, 19 Dec 2024 21:31:15 -0500 Subject: [PATCH 8/9] Add support for sequence arguments to hashTable --- M2/Macaulay2/d/hashtables.dd | 18 +++++++++--------- M2/Macaulay2/tests/normal/hashtables.m2 | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/M2/Macaulay2/d/hashtables.dd b/M2/Macaulay2/d/hashtables.dd index ca3018f8beb..0628e53e099 100644 --- a/M2/Macaulay2/d/hashtables.dd +++ b/M2/Macaulay2/d/hashtables.dd @@ -257,15 +257,15 @@ toHashTable(e:Expr):Expr := ( when e is w:List do toHashTable(w.v) is s:Sequence do ( - if length(s) != 2 then return WrongNumArgs(1,2); - when s.0 - is FunctionClosure do nothing - is CompiledFunction do nothing - is CompiledFunctionClosure do nothing - else return WrongArg(1,"a function"); - when s.1 is w:List do toHashTableWithCollisionHandler(w.v,s.0) - else WrongArg(2,"a list")) - else WrongArg("a list")); + if length(s) == 2 then ( + if isFunction(s.0) then ( + when s.1 + is w:Sequence do toHashTableWithCollisionHandler(w, s.0) + is w:List do toHashTableWithCollisionHandler(w.v, s.0) + else WrongArg(2, "a list or sequence")) + else toHashTable(s)) + else toHashTable(s)) + else WrongArg("a list or sequence")); setupfun("hashTable",toHashTable); copy(table:array(KeyValuePair)):array(KeyValuePair) := ( diff --git a/M2/Macaulay2/tests/normal/hashtables.m2 b/M2/Macaulay2/tests/normal/hashtables.m2 index b194be50b4e..d3e29d3b98e 100644 --- a/M2/Macaulay2/tests/normal/hashtables.m2 +++ b/M2/Macaulay2/tests/normal/hashtables.m2 @@ -40,6 +40,8 @@ x = set(1..10) assert(select(x, odd) === set {1, 3, 5, 7, 9}) assert(select(2, x, odd) == set {1, 3}) +assert(hashTable ((0, 1), (1, 2)) === hashTable {(0, 1), (1, 2)}) + -- Local Variables: -- compile-command: "make -C $M2BUILDDIR/Macaulay2/packages/Macaulay2Doc/test hashtables.out" -- End: From 7f4070b411d8f01e5244d34109ce3fa79ab35041 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Thu, 19 Dec 2024 21:34:06 -0500 Subject: [PATCH 9/9] Update hashTable methods Now specify that they take BasicList arguments and move from typicalvalues.m2. Also document missing function variant. --- M2/Macaulay2/d/hashtables.dd | 2 ++ M2/Macaulay2/m2/typicalvalues.m2 | 2 -- M2/Macaulay2/packages/Macaulay2Doc/types.m2 | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/M2/Macaulay2/d/hashtables.dd b/M2/Macaulay2/d/hashtables.dd index 0628e53e099..316b9df4b91 100644 --- a/M2/Macaulay2/d/hashtables.dd +++ b/M2/Macaulay2/d/hashtables.dd @@ -255,11 +255,13 @@ export toHashTable(v:Sequence):Expr := ( Expr(sethash(o,false))); toHashTable(e:Expr):Expr := ( when e + -- # typical value: hashTable, BasicList, HashTable is w:List do toHashTable(w.v) is s:Sequence do ( if length(s) == 2 then ( if isFunction(s.0) then ( when s.1 + -- # typical value: hashTable, Function, BasicList, HashTable is w:Sequence do toHashTableWithCollisionHandler(w, s.0) is w:List do toHashTableWithCollisionHandler(w.v, s.0) else WrongArg(2, "a list or sequence")) diff --git a/M2/Macaulay2/m2/typicalvalues.m2 b/M2/Macaulay2/m2/typicalvalues.m2 index c353e341f3f..7b393266b45 100644 --- a/M2/Macaulay2/m2/typicalvalues.m2 +++ b/M2/Macaulay2/m2/typicalvalues.m2 @@ -51,8 +51,6 @@ take(BasicList,ZZ) := take(BasicList,List) := BasicList => take take(Thing,ZZ) := take(Thing,List) := List => take isMutable(Thing) := Boolean => isMutable -hashTable List := HashTable => hashTable -hashTable(Function,List) := HashTable => hashTable remove(MutableList,ZZ) := Nothing => remove remove(Database,String) := Nothing => remove remove(HashTable,Thing) := Nothing => remove diff --git a/M2/Macaulay2/packages/Macaulay2Doc/types.m2 b/M2/Macaulay2/packages/Macaulay2Doc/types.m2 index 002f7847883..da6c6c40ce9 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/types.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/types.m2 @@ -544,7 +544,10 @@ document { } document { - Key => {hashTable,(hashTable, List)}, + Key => { + hashTable, + (hashTable, BasicList), + (hashTable, Function, BasicList)}, Headline => "make a hash table", TT "hashTable(h,v)", " -- produce a hash table from a list ", TT "v", " of key-value pairs, with an optional collision handler function ", TT "h", ".", PARA{},