Skip to content

Commit 17d7149

Browse files
committed
Use Rust to improve performance of string methods, use HTML templating
1 parent 34634e1 commit 17d7149

16 files changed

+464
-251
lines changed

prolog/Makefile

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
FASTFUNC_SERVER_PORT = 4999
22
.PHONY: build
33
build:
4-
swipl main.pl --quit setup
4+
mkdir -p bin
5+
cd util-rs && cargo +nightly build --release && cp ./target/release/libutils_rs.so ../bin/libutils_rs.so
6+
# swipl main.pl --quit setup
57
.PHONY: test
68
test:
79
make build

prolog/constraints.pl

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@
3737
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838
%% Meta Constraints: These apply operations to other constraints
3939

40-
%% and_constraint(+Lhs, +Rhs, -Func, -CostOut, -NewConstraints)
40+
%! and_constraint(+Lhs, +Rhs, -Func, -CostOut, -NewConstraints)
4141
% Tests if Func satisfies all constraints, producing a cost for this function,
4242
% CostOut, and a set of constraints which follow Constraints, NewConstraints.
4343
and_constraint(Lhs, Rhs, Fn, Cost, and_constraint(NewConstraint0, NewConstraint1)) :-
4444
call(Lhs, Fn, Cost0, NewConstraint0),
4545
call(Rhs, Fn, Cost1, NewConstraint1),
4646
Cost is Cost0 + Cost1.
4747

48-
%% at_most_n_constraint(+N, +Constraint, -Func, -Cost, -NewConstraint)
48+
%! at_most_n_constraint(+N, +Constraint, -Func, -Cost, -NewConstraint)
4949
% Evaluates at most N+1 times (if base case is reached, )
5050
at_most_n_constraint(N, Constraint, Func, Cost, at_most_n_constraint(NSub, Constraint)) :-
5151
call(Constraint, Func, Cost, _), !,

prolog/function.pl

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
init_uuid(Uuid) :- \+var(Uuid), !.
9595

9696
init_uuid(Uuid) :-
97-
var(Uuid), uuid(Uuid), !.
97+
var(Uuid), uuid(Uuids), atom_concat('u', Uuids, Uuid), !.
9898

9999
add_function(Uuid, Name, Generics, InputTypes, OutputTypes, Docs) :-
100100
init_uuid(Uuid),

prolog/function/parse.pl

+46-7
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
parse_types/4,
55
parse_trait/2,
66
parse_type/2,
7-
format_func/2,
8-
format_skeleton/6
7+
format_skeleton/6,
8+
format_signature/2
99
]).
1010
:- use_module(function).
1111
:- use_module(library(dcg/basics)).
12+
:- use_module(sequence_ops).
1213

1314
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415
subst_generics_into(
@@ -149,13 +150,51 @@
149150
subst_generics(Generics, UInputs, Inputs),
150151
subst_generics(Generics, UOutputs, Outputs), !.
151152

152-
%% Formats the function with the given name
153-
format_func(String, Uuid) :-
154-
function(Uuid, Name, Generics, Inputs, Outputs, Docs),
155-
format_skeleton(String, Name, Generics, Inputs, Outputs, Docs).
156-
157153
%% Formats the function skeleton.
158154
format_skeleton(String, Name, [], Inputs, Outputs, Docs) :-
159155
format(string(String), '~w :: ~w -> ~w | ~w', [Name, Inputs, Outputs, Docs]).
160156
format_skeleton(String, Name, Generics, Inputs, Outputs, Docs) :-
161157
format(string(String), '~w<~w> :: ~w -> ~w | ~w', [Name, Generics, Inputs, Outputs, Docs]).
158+
159+
format_generic(generic(Name, Bounds), String) :-
160+
\+is_list(Bounds),
161+
format(string(String), "~w", Name), !.
162+
163+
format_generic(generic(Name, Bounds), String) :-
164+
is_list(Bounds),
165+
join(Bounds, " + ", SubStr),
166+
format(string(String), "~w: ~w", [Name, SubStr]), !.
167+
168+
format_generic(G, String) :-
169+
format(string(String), "~w", [G]), !.
170+
171+
format_generics([], "") :- !.
172+
format_generics(Generics, String) :-
173+
maplist(format_generic, Generics, GenericSubs),
174+
join(GenericSubs, ", ", GenericContents),
175+
format(string(String), "<~w>", GenericContents).
176+
177+
format_type(type(Name, SubTypes), String) :-
178+
is_list(SubTypes),
179+
SubTypes = [_|_],
180+
maplist(format_type, SubTypes, SubTys),
181+
join(SubTys, ", ", Tys),
182+
format(string(String), "~w<~w>", [Name, Tys]), !.
183+
184+
format_type(type(Name, _), String) :-
185+
format(string(String), "~w", [Name]).
186+
187+
format_type(gen(Ty), String) :-
188+
format(string(String), "~w", Ty).
189+
190+
191+
format_type(Ty, String) :-
192+
format(string(String), "~w", Ty).
193+
194+
format_signature(function(_, _, Generics, Inputs, Outputs, _), String) :-
195+
format_generics(Generics, GenString),
196+
maplist(format_type, Inputs, Inputsf),
197+
join(Inputsf, ", ", Inputsff),
198+
maplist(format_type, Outputs, Outputsf),
199+
join(Outputsf, ", ", Outputsff),
200+
format(string(String), '~w :: [~w] -> [~w]', [GenString, Inputsff, Outputsff]).

prolog/function/serde.pl

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
write_json_metadata/4,
33
read_json_metadata/4,
44
jsonify_fns/2,
5+
jsonify_fn/2,
56
jsonify_type/2,
67
jsonify_types/2
78
]).

prolog/main.pl

+3
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@
198198
:- if(prolog_version_eight).
199199
execute_command(String) :-
200200
split_left(String, " ", 1, ["launch", PortStr]),
201+
split_left(String, " ", 1, Splits),
202+
format("~w~n", [String]),
203+
format("!!~w~n", [Splits]),
201204
number_string(Port, PortStr),
202205
catch(
203206
server(Port),

prolog/search.pl

+1-12
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
func_path_no_cycles/4,
55
find_item/3,
66
find_items/2,
7-
func_search/7,
8-
fn_member_constraint/1
7+
func_search/7
98
]).
109
:- use_module(function).
1110
:- use_module(constraints, [
@@ -107,16 +106,6 @@
107106
append(Candidates, NewPaths, NewCand),
108107
func_path_bfs(NewCand, PathConstraint, NextPath).
109108

110-
%% cmp_constraint_list(?Order, @L1, @L2)
111-
% Determine Cmp between L1 and L2 cost/constraint/list triples.
112-
cmp_candidate(Cmp, (CostA, _, _), (CostB, _, _)) :-
113-
compare(Cmp, CostA, CostB).
114-
115-
cmp_or_continue(=, Cmp, L1, L2) :-
116-
compare(Cmp, L1, L2).
117-
cmp_or_continue(>, >, _, _).
118-
cmp_or_continue(<, <, _, _).
119-
120109
func_path_best_fs([(_, FnConstraint, Visited)|_], PathConstraint, Path) :-
121110
% If no constraints left, add path to paths
122111
test_path(Visited, FnConstraint, PathConstraint, Path).

prolog/sequence_ops.pl

+13-106
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@
1313
:- table(fuzzy_substr/3).
1414
:- endif.
1515

16+
:- use_foreign_library('./bin/libutils_rs.so').
17+
1618
:- meta_predicate run_levenshtein(+, +, 2, -).
1719

18-
%% list_subset(?List1, ?List2)
20+
%! list_subset(?List1, ?List2)
1921
% Returns true if List1 is a subset of List2.
2022
list_subset([], _).
2123
list_subset([First|Rest], B) :-
2224
member(First, B),
2325
list_subset(Rest, B), !.
2426

25-
%% join(+Items, +Sep, -Output)
27+
%! join(+Items, +Sep, -Output)
2628
% Joins the string with the provided separator string
2729
join([], _Sep, "") :- !.
2830
join([Item], _Sep, Item) :- !.
@@ -31,7 +33,7 @@
3133
string_concat(Head, Sep, HeadSep),
3234
string_concat(HeadSep, TailOutput, Output), !.
3335

34-
%% sequence_match/2(+Sequence, +String)
36+
%! sequence_match/2(+Sequence, +String)
3537
% sequence_match is true if the all elements in Sequence appear in
3638
% String, in sequential order.
3739
sequence_match(Sequence, String) :-
@@ -48,114 +50,19 @@
4850
sequence_match(Sequence, [_|Tail1]) :-
4951
sequence_match(Sequence, Tail1).
5052

51-
%% split_left/4(String, Sep, N, -Substrings)
52-
% split_left splits the provided string on the characters in Sep,
53-
% up to a maximum of N times into Substrings. Multiple seperator characters
54-
% will be treated as one.
55-
split_left(String, Sep, N, Substrings) :-
56-
string_chars(String, Chars),
57-
string_chars(Sep, Sep_),
58-
split_left(Chars, Sep_, N, [], CharSubstrings),
59-
maplist(
60-
string_chars,
61-
Substrings,
62-
CharSubstrings
63-
), !.
64-
65-
%% Splits the string from left to right, on the provided separator,
66-
% up to a maximum of n times, and stores intermediate state in Accumulator
67-
split_left([], _Sep, _, Accumulator, [Reversed]) :-
68-
reverse(Accumulator, Reversed), !.
69-
split_left([Head|Tail], Sep, 0, Accumulator, [Whole]) :-
70-
member(Head, Sep),
71-
split_left(Tail, Sep, 0, Accumulator, [Whole]), !.
72-
split_left(String, _Sep, 0, Accumulator, [Whole]) :-
73-
reverse(Accumulator, Reversed),
74-
append(Reversed, String, Whole), !.
75-
split_left([Head|Tail], Sep, N, [], Strings) :-
76-
member(Head, Sep),
77-
split_left(Tail, Sep, N, [], Strings), !.
78-
split_left([Head|Tail], Sep, N, Accumulator, [Reversed|Strings]) :-
79-
member(Head, Sep),
80-
reverse(Accumulator, Reversed),
81-
% Force early evaluation
82-
NSub is N - 1,
83-
split_left(Tail, Sep, NSub, [], Strings), !.
84-
split_left([Head|Tail], Sep, N, Accumulator, Strings) :-
85-
split_left(Tail, Sep, N, [Head|Accumulator], Strings), !.
8653

8754
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88-
%% Development notes:
89-
% Haskell impl is ~3x faster (with the backtracking functionality)
90-
% BUT:
91-
% - +1.2GB of disk usage in Docker
92-
% - Requires reading/writing to streams (annoying)
93-
% - Requires compilation and extra steps in Makefiles
94-
95-
%% Basic implementation of substitution cost.
96-
lev_cost(C, C, 0.0) :- !.
97-
lev_cost(A, B, 0.4) :- downcase_atom(A, C), downcase_atom(B, C), !.
98-
lev_cost(_, _, 1.0) :- !.
99-
100-
%% Fills the current row with the cheapest action
101-
fill_row(_, Row, _, [], Row).
102-
fill_row(PrevRow, Row, Ca, [Cb|StrB], Out) :-
103-
PrevRow = [Subst,Delete|PRest],
104-
Row = [Insert|Rest],
105-
lev_cost(Ca, Cb, SubstCost),
106-
Substx is Subst + SubstCost,
107-
Deletex is Delete + 1.0,
108-
Insertx is Insert + 1.0,
109-
min_list([Substx, Deletex, Insertx], MinC),
110-
fill_row([Delete|PRest], [MinC,Insert|Rest], Ca, StrB, Out).
111-
112-
%% Rearranges arguments as needed for initial fill_row call.
113-
% can do [Head|Tail], [HRow, Head|Tail] to keep the full table
114-
% for backtracking purposes
115-
fill_row_helper(StrA, Num, Char, [Head|_], [HRow, Head]) :-
116-
Numf is float(Num),
117-
fill_row(Head, [Numf], Char, StrA, RRow),
118-
reverse(RRow, HRow).
119-
120-
%% Helper which builds the levenshtein distance table (or in this case, a single row).
121-
run_levenshtein(A, "", RowFn, [FirstRow]) :-
122-
string(A),
123-
string_chars(A, AChars),
124-
length(AChars, LA),
125-
call(RowFn, LA, FirstRow), !.
126-
127-
run_levenshtein(A, B, RowFn, Table) :-
128-
string(A),
129-
string(B),
130-
string_chars(A, AChars),
131-
string_chars(B, BChars),
132-
length(AChars, LA),
133-
length(BChars, LB),
134-
call(RowFn, LA, FirstRow),
135-
numlist(1, LB, Nums),
136-
foldl(fill_row_helper(AChars), Nums, BChars, [FirstRow], Table), !.
137-
138-
to_float(X, Y) :- Y is float(X).
139-
140-
numlist_helper(LA, List) :-
141-
numlist(0, LA, NList), maplist(to_float, NList, List).
55+
%% Documentation for foreign library
56+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14257

143-
%% levenshtein_distance(+A:str, +B:str, -Distance:float)
58+
%! levenshtein_distance(+A:str, +B:str, -Distance:float) is semidet
14459
% Returns the Levenshtein distance between A and B
14560
% https://en.wikipedia.org/wiki/Levenshtein_distance
146-
% Uses the two-row table solution to optimize for memory and runtime characteristics
147-
levenshtein_distance(A, B, Distance) :-
148-
run_levenshtein(A, B, numlist_helper, [Row|_]),
149-
last(Row, Distance).
15061

151-
zeros_helper(LA, List) :-
152-
LAPlus is LA + 1,
153-
length(List, LAPlus), maplist(=(0.0), List).
154-
155-
%% levenshtein_distance_fuzzy(+A:str, +B:str, -Distance:float)
62+
%! levenshtein_distance_fuzzy(+A:str, +B:str, -Distance:float) is semidet
15663
% https://en.wikipedia.org/wiki/Approximate_string_matching#Problem_formulation_and_algorithms
157-
% Use min_list for minimum distance. Ignore first item in row.
158-
fuzzy_substr(A, B, Distance) :-
159-
run_levenshtein(A, B, zeros_helper, [[_|Out]|_]),
160-
min_list(Out, Distance).
16164

65+
%! split_left/4(String, Sep, N, -Substrings)
66+
% split_left splits the provided string on the characters in Sep,
67+
% up to a maximum of N times into Substrings. Multiple seperator characters
68+
% will be treated as one.

0 commit comments

Comments
 (0)