Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Inko #440

Merged
merged 6 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ RUN wget https://github.com/ldc-developers/ldc/releases/download/v1.34.0-beta1/l
RUN rm -rf /usr/local/ldc2* && tar -C /usr/local -xvf ldc2-1.34.0-beta1-linux-x86_64.tar.xz
ENV PATH="$PATH:/usr/local/ldc2-1.34.0-beta1-linux-x86_64/bin"

# install inko
RUN su -c "git clone https://aur.archlinux.org/inko.git /home/builduser/inko" builduser

RUN su -c "cd /home/builduser/inko && makepkg -si --noconfirm --needed --noprogressbar" builduser

RUN mkdir -p /results

# location to write the raw results
Expand Down
1 change: 1 addition & 0 deletions inko/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
180 changes: 180 additions & 0 deletions inko/src/main.inko
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import std.fs.file.(ReadOnlyFile, WriteOnlyFile)
import std.json.Json
import std.stdio.STDOUT
import std.time.Instant

let TOP_N = 5

class Post {
let @id: String
let @title: String
let @tags: Array[String]
}

class RelatedPost {
let @id: String
let @tags: ref Array[String]
let @related: Array[ref Post]
}

fn read_posts(path: String) -> Array[Post] {
let bytes = ByteArray.new

ReadOnlyFile
.new(path)
.then fn (f) { f.read_all(bytes) }
.expect('the JSON file must exist')

let root = match Json.parse(bytes) {
case Ok(Array(v)) -> v
case _ -> panic('the JSON file must contain a valid array')
}

root
.into_iter
.map fn (val) {
let obj = match val {
case Object(v) -> v
case _ -> panic('each entry in the JSON array must be an object')
}

let id = match obj.remove('_id') {
case Some(String(v)) -> v
case _ -> panic('the "_id" key must be a string')
}

let title = match obj.remove('title') {
case Some(String(v)) -> v
case _ -> panic('the "title" key must be a string')
}

let tags = match obj.remove('tags') {
case Some(Array(array)) -> {
array
.into_iter
.map fn (val) {
match val {
case String(v) -> v
case _ -> panic('each tag must be a string')
}
}
.to_array
}
case _ -> panic('the "tags" key must be an array of strings')
}

Post { @id = id, @title = title, @tags = tags }
}
.to_array
}

fn write_posts(path: String, posts: Array[RelatedPost]) {
let values = posts
.into_iter
.map fn (post) {
let related = post
.related
.iter
.map fn (related) {
let map = Map.new
let tags = related.tags.iter.map fn (t) { Json.String(t) }.to_array

map.set('_id', Json.String(related.id))
map.set('title', Json.String(related.title))
map.set('tags', Json.Array(tags))
Json.Object(map)
}
.to_array

let map = Map.new
let tags = post.tags.iter.map fn (t) { Json.String(t) }.to_array

map.set('_id', Json.String(post.id))
map.set('tags', Json.Array(tags))
map.set('related', Json.Array(related))
Json.Object(map)
}
.to_array

let out = Json.Array(values).to_string

WriteOnlyFile
.new(path)
.then fn (f) { f.write_string(out) }
.expect('failed to write to the output JSON file')
}

class async Main {
fn async main {
let posts = read_posts('../posts.json')
let start = Instant.new
let posts_len = posts.size
let tag_map: Map[String, Array[Int]] = Map.with_capacity(100)

posts.iter.each_with_index fn (idx, post) {
post.tags.iter.each fn (tag) {
match tag_map.opt_mut(tag) {
case Some(v) -> v.push(idx)
case _ -> tag_map.set(tag, [idx])
}
}
}

let all_related_posts = Array.with_capacity(posts_len)
let tagged_post_count = Array.filled(with: 0, times: posts_len)

posts.iter.each_with_index fn (i, post) {
posts_len.times fn (i) { tagged_post_count.set(i, 0) }
post.tags.iter.each fn (tag) {
tag_map.get(tag).iter.each fn (i) {
tagged_post_count.set(i, tagged_post_count.get(i) + 1)
}
}

tagged_post_count.set(i, 0)

let top_idx = Array.filled(0, TOP_N * 2)
let mut min_tags = 0
let mut idx = 0

while idx < posts_len {
let count = tagged_post_count.get(idx)

if count > min_tags {
let mut upper_bound = (TOP_N - 2) * 2

while upper_bound >= 0 and count > top_idx.get(upper_bound) {
top_idx.set(upper_bound + 2, top_idx.get(upper_bound))
top_idx.set(upper_bound + 3, top_idx.get(upper_bound + 1))
upper_bound -= 2
}

let insert_pos = upper_bound + 2

top_idx.set(insert_pos, count)
top_idx.set(insert_pos + 1, idx)
min_tags = top_idx.get(TOP_N * 2 - 2 )
}

idx += 1
}

let top_posts = Array.with_capacity(TOP_N)

TOP_N.times fn (j) {
top_posts.push(posts.get(top_idx.get(j * 2 + 1)))
}

all_related_posts.push(RelatedPost {
@id = post.id,
@tags = post.tags,
@related = top_posts,
})
}

let took = start.elapsed

STDOUT.new.print("Processing time (w/o IO): {took.to_millis} ms")
write_posts('../related_posts_inko.json', all_related_posts)
}
}
19 changes: 19 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,21 @@ run_scala_native() {
check_output "related_posts_scala.json"
}

run_inko() {
echo "Running Inko" &&
cd ./inko &&
if [ -z "$appendToFile" ]; then # only build on 5k run
inko build --opt aggressive
fi &&
if [ $HYPER == 11 ]; then
capture "Inko" hyperfine -r $slow_lang_runs -w $warmup --show-output "./build/aggressive/main"
else
command ${time} -f '%es %Mk' ./build/aggressive/main
fi

check_output "related_posts_inko.json"
}

check_output() {
cd ..

Expand Down Expand Up @@ -1132,6 +1147,10 @@ elif [ "$first_arg" = "scala_native" ]; then

run_scala_native

elif [ "$first_arg" = "inko" ]; then

run_inko

elif [ "$first_arg" = "all" ]; then

echo -e "Running all\n" &&
Expand Down