Skip to content

Commit

Permalink
Merge pull request #440 from jinyus/inko
Browse files Browse the repository at this point in the history
Add Inko
  • Loading branch information
jinyus authored Nov 17, 2023
2 parents 8a8700b + 40e5820 commit de9fe56
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 0 deletions.
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

0 comments on commit de9fe56

Please sign in to comment.