-
I am struggling with reified predicates in the In the following simulation of a "log rate limiter" which admits duplicate log messages at most once every 10 units (seconds?).
In case that was confusing, here is the full problem text: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
https://leetcode.com/problems/logger-rate-limiter/description/
https://leetcode.ca/2016-11-23-359-Logger-Rate-Limiter/
359. Logger Rate Limiter
Design a logger system that receives a stream of messages along with their timestamps.
Each unique message should only be printed at most every 10 seconds
( i.e. a message printed at timestamp t will prevent other identical messages from being printed until timestamp t + 10).
All messages will come in chronological order. Several messages may arrive at the same timestamp.
Implement the Logger class:
Logger() Initializes the logger object.
bool shouldPrintMessage(int timestamp, string message) Returns true if the message should be printed in the given timestamp,
otherwise returns false.
Example 1:
Input
["Logger", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage"]
[[], [1, "foo"], [2, "bar"], [3, "foo"], [8, "bar"], [10, "foo"], [11, "foo"]]
Output
[null, true, true, false, false, false, true]
Explanation
Logger logger = new Logger();
logger.shouldPrintMessage(1, "foo"); // return true, next allowed timestamp for "foo" is 1 + 10 = 11
logger.shouldPrintMessage(2, "bar"); // return true, next allowed timestamp for "bar" is 2 + 10 = 12
logger.shouldPrintMessage(3, "foo"); // 3 < 11, return false
logger.shouldPrintMessage(8, "bar"); // 8 < 12, return false
logger.shouldPrintMessage(10, "foo"); // 10 < 11, return false
logger.shouldPrintMessage(11, "foo"); // 11 >= 11, return true, next allowed timestamp for "foo" is 11 + 10 = 21
Constraints:
0 <= timestamp <= 109
Every timestamp will be passed in non-decreasing order (chronological order).
1 <= message.length <= 30
At most 104 calls will be made to shouldPrintMessage.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ I noticed in the I could not figure out how to do this without resorting to using :- use_module(library(assoc)).
:- use_module(library(clpz)).
:- use_module(library(reif)).
data_time_message_t(Assoc0, Time, Message, Truth, Assoc) :-
assoc:get_assoc(Message, Assoc0, Time0),
#MustBeGreaterThan #= #Time0 + 10,
if_( #MustBeGreaterThan #< #Time,
( Truth=true,
assoc:put_assoc(Message, Assoc0, Time, Assoc)
),
( Truth=false,
Assoc=Assoc0
)
).
data_time_message_t(Assoc0, Time, Message, Truth, Assoc) :-
\+ assoc:get_assoc(Message, Assoc0, _),
Truth=true,
assoc:put_assoc(Message, Assoc0, Time, Assoc).
?- data_time_message_t(t("foo",2,-,t,t), 3, "foo", Truth, Assoc).
%@ Truth = false, Assoc = t("foo",2,-,t,t)
%@ ; false. To be fair, I couldn't solve this with :- use_module(library(assoc)).
:- use_module(library(clpz)).
:- use_module(library(dif)).
:- use_module(library(reif)).
:- use_module(library(lists)).
data_time_message_t(Data0, Time, Message, Truth, Data) :-
memberd_t([Message, Time0], Data0, true),
if_( #Time0 + 10 #< #Time,
( Truth=true,
select([Message, Time0], Data0, Data1),
append([[Message, Time]], Data1, Data)
),
( Truth=false,
Data=Data0
)
).
data_time_message_t(Data0, Time, Message, true, Data) :-
\+ member([Message, _Time0], Data0),
append([[Message, Time]], Data0, Data).
%% works as expected
?- data_time_message_t([["foo",2]], 13, "foo", Truth, Data).
%@ Truth = true, Data = [["foo",13]]
%@ ; false. but with data_time_message_t(Data0, Time, Message, true, Data) :-
memberd_t([Message, _Time0], Data0, false),
append([[Message, Time]], Data0, Data).
% doesn't work as expected :(
?- data_time_message_t([["foo",2]], 13, "foo", Truth, Data).
%@ Truth = true, Data = [["foo",13]]
%@ ; Truth = true, Data = [["foo",13],["foo",2]], dif:dif(["foo",2],["foo",_A]). so, maybe the problem is the user, not Edit: The answer selected is just the information organized into one place. Credit goes to @haijinSk for asking the right questions, @triska for the BIG clue, and @bakaq spelling it out for me. 😅 Any remaining mistakes are mine. |
Beta Was this translation helpful? Give feedback.
Replies: 8 comments 28 replies
-
I'm a very naive beginner, I apologize. I have myself a question in context of this question. Is bad using negation, if my predicate is not intended to be a true relation, meaning working in bi-directional mode? If membership is the question and everything is grounded (no free variables), isn't it a classical (whatever it means) negation? Like: if I know that something is not here, then |
Beta Was this translation helpful? Give feedback.
-
Now, if I use the Markus @triska's "maplist+dif not-member":
then again:
So, as I (mis)understand it, it simply shows that (with the actual "code/query configuration") there is yet another solution... Or, what exactly is the expected result; only one/the first answer? |
Beta Was this translation helpful? Give feedback.
-
I really appreciate you asking these questions because I have the same questions. Ok, as I read it, this second answer is not valid. It's saying So I'm not sure why that answer is reported because of the logical contradiction, but it leads me to think at least there's a way to rewrite this so that it does not report the contradiction answer. |
Beta Was this translation helpful? Give feedback.
-
I was able to cobble this together, which works as expected: :- use_module(library(assoc)).
:- use_module(library(clpz)).
:- use_module(library(dif)).
:- use_module(library(reif)).
:- use_module(library(lists)).
first([X|_], X).
data_time_message_t(Data0, Time, Message, Truth, Data) :-
memberd_t([Message, Time0], Data0, true),
if_( #Time0 + 10 #< #Time,
( Truth=true,
select([Message, Time0], Data0, Data1),
append([[Message, Time]], Data1, Data)
),
( Truth=false,
Data=Data0
)
).
data_time_message_t(Data0, Time, Message, true, Data) :-
maplist(first, Data0, Keys),
maplist(dif(Message), Keys),
append([[Message, Time]], Data0, Data).
?- data_time_message_t([], 13, "foo", Truth, Data).
%@ Truth = true, Data = [["foo",13]].
?- data_time_message_t([["foo",2]], 13, "foo", Truth, Data).
%@ Truth = true, Data = [["foo",13]]
%@ ; false. But I feel like I am missing a significant concept from @triska 's comment:
My original formulation was data_time_message_t(Data0, Time, Message, true, Data) :-
memberd_t([Message, _], Data0, false),
append([[Message, Time]], Data0, Data). because I really didn't care what the "value" was, I was only trying to check for the existence of the "key" data_time_message_t(Data0, Time, Message, true, Data) :-
maplist(dif([Message, _Time0]), Data0),
% ... snip ... was " I am happy that I found a solution that works for lists, which can probably be adapted to an |
Beta Was this translation helpful? Give feedback.
-
So based on the prior conversations, with some heavy clues, that would indicate that this would be a possible way to test for "contains keys" in a :- use_module(library(assoc)).
:- use_module(library(clpz)).
:- use_module(library(dif)).
:- use_module(library(reif)).
:- use_module(library(lists)).
first([X|_], X).
data_time_message_t(Assoc0, Time, Message, Truth, Assoc) :-
assoc:get_assoc(Message, Assoc0, Time0),
#MustBeGreaterThan #= #Time0 + 10,
if_( #MustBeGreaterThan #< #Time,
( Truth=true,
assoc:put_assoc(Message, Assoc0, Time, Assoc)
),
( Truth=false,
Assoc=Assoc0
)
).
data_time_message_t(Assoc0, Time, Message, true, Assoc) :-
findall(Key, assoc:gen_assoc(Key, Assoc0, _), Keys),
maplist(dif(Message), Keys),
assoc:put_assoc(Message, Assoc0, Time, Assoc).
?- data_time_message_t(t, 2, "foo", Truth, Data).
%@ Truth = true, Data = t("foo",2,-,t,t).
?- Data0 = t("foo",2,-,t,t), data_time_message_t(Data0, 13, "foo", Truth, Data).
%@ Data0 = t("foo",2,-,t,t), Truth = true, Data = t("foo",13,-,t,t)
%@ ; false.
However, I'm not super thrilled to use Does anyone have any better ideas? |
Beta Was this translation helpful? Give feedback.
-
So while working out the contains_t(_, t, _, false).
contains_t(Key, Assoc, Value, true) :-
get_assoc(Key0, Assoc, Value0),
( dif(Key0, Key)
; dif(Value0, Value)
).
?- contains_t(1, t, 2, Truth).
%@ Truth = false
%@ ; false. |
Beta Was this translation helpful? Give feedback.
-
Ok, this is as close as I've gotten. contains_key_assoc_t(Key, t, false).
contains_key_assoc_t(Key, t(K,V,Rel,L,R), true) :-
get_assoc(Key, t(K,V,Rel,L,R), _).
contains_key_assoc_t(Key, t(K,V,Rel,L,R), Found) :-
contains_key_assoc_t_(Key, t(K,V,Rel,L,R), Found).
contains_key_assoc_t_(Key, t(K,V,_,L,R), Found) :-
Assoc=t(K,V,_,L,R),
min_assoc(Assoc, Kmin, _),
max_assoc(Assoc, Kmax, _),
compare(Minrel, Kmin, Key), % Key should be @< Kmin if exists
compare(Maxrel, Kmax, Key), % Key should be @> Kmax if exists
if_(( Minrel=(<)
; Maxrel=(>)
),
Found=false,
( compare(Rel, Key, K),
contains_key_assoc_t(Rel, Key, V, L, R, Found)
)
).
contains_key_assoc_t(<, Key, _, Tree, _, Found) :-
contains_key_assoc_t(Key, Tree, Found).
contains_key_assoc_t(>, Key, _, _, Tree, Found) :-
contains_key_assoc_t(Key, Tree, Found).
?- contains_key_assoc_t(a, t, T).
%@ T = false.
?- contains_key_assoc_t(b, t(a,1,-,t,t), T).
%@ T = false.
?- contains_key_assoc_t(a, t(a,1,-,t,t), T).
%@ T = true
%@ ; false.
?- Assoc+\( put_assoc(a, t, 1, Assoc0),
put_assoc(b, Assoc0, 2, Assoc1),
put_assoc(c, Assoc1, 3, Assoc)
).
%@ Assoc = t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)).
?- contains_key_assoc_t(a, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = true
%@ ; T = false.
?- contains_key_assoc_t(b, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = true
%@ ; T = false.
?- contains_key_assoc_t(c, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = true
%@ ; T = false.
?- contains_key_assoc_t(d, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = false. There's a defaulty issue somewhere that I'm returning a |
Beta Was this translation helpful? Give feedback.
-
I'm about ready to call QED on this. @triska regarding ..., this was the configuration I could achieve with the minimum number of introspections that admitted no redundant choicepoints. :- use_module(library(assoc)).
:- use_module(library(clpz)).
:- use_module(library(dif)).
:- use_module(library(reif)).
:- use_module(library(lists)).
:- use_module(library(lambda)).
contains_key_assoc_t(Key, t, false).
contains_key_assoc_t(Key, t(K,V,Rel,L,R), Found) :-
Assoc= t(K,V,Rel,L,R),
( ground(Key) ->
contains_key_assoc_t_(Key, Assoc, Found)
; gen_assoc(Key, Assoc, _), Found=true
).
contains_key_assoc_t_(Key, t(K,V,_,L,R), Found) :-
Assoc=t(K,V,_,L,R),
min_assoc(Assoc, Kmin, _),
max_assoc(Assoc, Kmax, _),
compare(Minrel, Kmin, Key), % Key should be (@<) Kmin if exists
compare(Maxrel, Kmax, Key), % Key should be (@>) Kmax if exists
if_((Minrel=(>);Maxrel=(<)),
Found=false,
( compare(Rel, Key, K), % could be (<) or (>),
contains_key_assoc_t(Rel, Key, V, L, R, Found)
)
).
contains_key_assoc_t(<, Key, _, Tree, _, Found) :-
contains_key_assoc_t(Key, Tree, Found).
contains_key_assoc_t(>, Key, _, _, Tree, Found) :-
contains_key_assoc_t(Key, Tree, Found).
contains_key_assoc_t(=, Key, _, _, _, true).
?- contains_key_assoc_t(a, t, T).
%@ T = false.
?- contains_key_assoc_t(b, t(a,1,-,t,t), T).
%@ T = false.
?- contains_key_assoc_t(a, t(a,1,-,t,t), T).
%@ T = true.
?- Assoc+\( put_assoc(a, t, 1, Assoc0),
put_assoc(b, Assoc0, 2, Assoc1),
put_assoc(c, Assoc1, 3, Assoc)
).
%@ Assoc = t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)).
?- contains_key_assoc_t(a, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = true.
?- contains_key_assoc_t(b, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = true.
?- contains_key_assoc_t(c, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = true.
?- contains_key_assoc_t(d, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ T = false.
?- contains_key_assoc_t(Key, t(b,2,-,t(a,1,-,t,t),t(c,3,-,t,t)), T).
%@ Key = a, T = true
%@ ; Key = b, T = true
%@ ; Key = c, T = true
%@ ; false.
?- contains_key_assoc_t(x, Assoc, false).
%@ Assoc = t
%@ ; Assoc = t(_A,_B,_C,t,t)
%@ ; Assoc = t(_A,_B,_C,t,t(_D,_E,_F,_G,t))
%@ ; Assoc = t(_A,_B,_C,t,t(_D,_E,_F,_G,t(_H,_I,_J,_K,t)))
%@ ; ... .
?- contains_key_assoc_t(x, Assoc, true).
%@ error('$interrupt_thrown',repl/0).
?- contains_key_assoc_t(Key, Assoc, true).
%@ error('$interrupt_thrown',repl/0).
?- contains_key_assoc_t(x, Assoc, false).
%@ Assoc = t
%@ ; Assoc = t(_A,_B,_C,t,t)
%@ ; Assoc = t(_A,_B,_C,t,t(_D,_E,_F,_G,t))
%@ ; Assoc = t(_A,_B,_C,t,t(_D,_E,_F,_G,t(_H,_I,_J,_K,t)))
%@ ; ... .
?- contains_key_assoc_t(x, Assoc, true).
%@ error('$interrupt_thrown',repl/0).
?- Assoc+\( put_assoc(d, t, 1, Assoc0),
put_assoc(b, Assoc0, 2, Assoc1),
put_assoc(x, Assoc1, 3, Assoc2),
put_assoc(c, Assoc2, 3, Assoc3),
put_assoc(9, Assoc3, 3, Assoc)
).
%@ Assoc = t(d,1,<,t(b,2,-,t(9,3,-,t,t),t(c,3,-,t,t)),t(x,3,-,t,t)).
?- T^Shouldbefalse+\(
( put_assoc(d, t, 1, Assoc0),
put_assoc(b, Assoc0, 2, Assoc1),
put_assoc(x, Assoc1, 3, Assoc2),
put_assoc(c, Assoc2, 3, Assoc3),
put_assoc(9, Assoc3, 3, Assoc),
contains_key_assoc_t_(d, Assoc, T),
contains_key_assoc_t_(b, Assoc, T),
contains_key_assoc_t_(x, Assoc, T),
contains_key_assoc_t_(c, Assoc, T),
contains_key_assoc_t_(9, Assoc, T),
contains_key_assoc_t(notfound, Assoc, Shouldbefalse)
)
).
%@ T = true, Shouldbefalse = false.
contains_key_assoc(Key, Assoc) :-
contains_key_assoc_t(Key, Assoc, true).
% edited with suggestions from @triska
% https://github.com/mthom/scryer-prolog/discussions/2577#discussioncomment-10786041
data_time_message_t(Assoc0, Time, Message, Assoc, Truth) :-
if_(contains_key_assoc_t(Message, Assoc0),
( get_assoc(Message, Assoc0, Time0),
if_( clpz_t(#Time0 + 10 #< #Time),
( Truth=true,
assoc:put_assoc(Message, Assoc0, Time, Assoc)
),
( Truth=false,
Assoc=Assoc0
)
)
),
( Truth=true,
put_assoc(Message, Assoc0, Time, Assoc)
)
).
?- data_time_message_t(t, 2, "foo", Assoc, Truth).
%@ Assoc = t("foo",2,-,t,t), Truth = true.
?- data_time_message_t(t("foo",2,-,t,t), 3, "foo", Assoc, Truth).
%@ Assoc = t("foo",2,-,t,t), Truth = false.
?- data_time_message_t(t("foo",2,-,t,t), 13, "foo", Assoc, Truth).
%@ Assoc = t("foo",13,-,t,t), Truth = true.
?- A2+\( (data_time_message_t(t, 2, "foo", A0, true),
data_time_message_t(A0, 3, "foo", A0, false),
data_time_message_t(A0, 1, "bar", A1, true),
data_time_message_t(A1, 14, "foo", A2, true),
data_time_message_t(A2, 2, "bar", A2, false))
).
%@ A2 = t("foo",14,<,t("bar",1,-,t,t),t). |
Beta Was this translation helpful? Give feedback.
I'm about ready to call QED on this. @triska regarding ..., this was the configuration I could achieve with the minimum number of introspections that admitted no redundant choicepoints.