/* Text processing/Max licenses in use (Rosetta code) in Picat. http://rosettacode.org/wiki/Text_processing/Max_licenses_in_use """ A company currently pays a fixed sum for the use of a particular licensed software package. In determining if it has a good deal it decides to calculate its maximum use of the software from its license management log file. Assume the software's licensing daemon faithfully records a checkout event when a copy of the software starts and a checkin event when the software finishes to its log file. An example of checkout and checkin events are: License OUT @ 2008/10/03_23:51:05 for job 4974 ... License IN @ 2008/10/04_00:18:22 for job 4974 Save the 10,000 line log file from here [http://rosettacode.org/resources/mlijobs.txt] into a local file then write a program to scan the file extracting both the maximum licenses that were out at any time, and the time(s) at which this occurs. """ This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import util. main => go. go => Jobs = read_file_lines("mlijobs.txt"), NumJobs = Jobs.length, Counts = new_array(NumJobs), % faster with an array than a list foreach({J,I} in zip(Jobs,1..NumJobs)) C = cond(slice(J,9,11) == "OUT", 1, -1), Counts[I] := cond(I > 1, Counts[I-1], 0) + C end, Max = max(Counts.to_list()), % max/1 only works on lists, not arrays MaxIxs = [I : I in 1..NumJobs, Counts[I] == Max], printf("Max: %d\n%w\n", Max, [slice(Jobs[J],15,30) : J in MaxIxs].join("\n")), nl. % % This variant is as fast than go/0, % even though we convert between lists and arrays. % go2 => Jobs = read_file_lines("mlijobs.txt"), Counts = asum_c(Jobs).to_array(), % convert to array for speedup (0.052s vs 0.132s) % Max = max(Counts.to_list()), % max/1 only works on lists (not arrays) Max = max_array(Counts), % max/1 only works on lists (not arrays) MaxIxs = [I : I in 1..Counts.length, Counts[I] == Max], printf("Max: %d\n%w\n", Max, [slice(Jobs[J],15,30) : J in MaxIxs].join("\n")), nl. % % Slightly different approach: first weed out [-1,1] and do a accumulated sum % directly. We also to the to_array/to_list conversions. % This is as fast as go/0 and go2/0. % go3 => Jobs = read_file_lines("mlijobs.txt"), Counts = asum2([cond(slice(J,9,11) == "OUT", 1, -1) : J in Jobs].to_array()), Max = max_array(Counts), MaxIxs = [I : I in 1..Counts.length, Counts[I] == Max], printf("Max: %d\n%w\n", Max, [slice(Jobs[J],15,30) : J in MaxIxs].join("\n")), nl. % Inspired by the Python solution. % About as fast as go/0, go2/0, and go3/0. go4 => Out = 0,MaxOut = -1,MaxTimes = [], foreach(Job in read_file_lines("mlijobs.txt")) % Out := Out + cond(once(find(Job,"OUT",_,_)), 1, -1), % slightly slower Out := Out + cond(slice(Job,9,11) == "OUT", 1, -1), % faster than using find/4. if Out > MaxOut then MaxOut := Out, MaxTimes := [] end, if Out = MaxOut then MaxTimes := MaxTimes ++ [slice(Job,15,30)] end end, println(max=MaxOut), println(times=MaxTimes), nl. % % max value for an array % (max/1 don't works for arrays) % max_array(Array) = Max => max_array(Array,Array.length,1,Array[1],Max). max_array(Array,N,I,Max0,Max), I < N => if Array[I] > Max0 then Max0 := Array[I] end, max_array(Array,N,I+1,Max0,Max). max_array(_Array,N,I,Max0,Max), I >= N => Max = Max0. % accumulative sum with plain numbers % using lists asum(List) = Asum => asum(List,[],Asum). asum([],Asum0,Asum) => Asum = Asum0.reverse(). asum([H|T],[],Asum) => asum(T,[H],Asum). asum([H|T],Asum0,Asum) => Asum0 = [Last|_], asum(T,[Last+H|Asum0],Asum). % % using arrays (and indexing) % asum2(Array) = Asum => N = Array.length, Asum = new_array(N), asum2(Array,N,1,Asum). asum2(Array,N,I,Asum), I = 1 => Asum[1] = Array[1], asum2(Array,N,2,Asum). asum2(Array,N,I,Asum), I > 1, I <= N => Asum[I] = Asum[I-1]+Array[I], asum2(Array,N,I+1,Asum). asum2(_Array,N,I,_Asum), I >= N => true. % % accumulative sum with the slice function % asum_c(List) = Asum => asum_c(List,[],Asum). asum_c([],Asum0,Asum) => Asum = Asum0.reverse(). asum_c([H|T],[],Asum) => C = cond(slice(H,9,11) == "OUT", 1, -1), asum_c(T,[C],Asum). asum_c([H|T],Asum0,Asum) => Asum0 = [Last|_], C = cond(slice(H,9,11) == "OUT", 1, -1), asum_c(T,[Last+C|Asum0],Asum).