-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement naive concepts, basic autocomplete
- Loading branch information
1 parent
0fc46c5
commit 85490df
Showing
15 changed files
with
401 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import logging | ||
from typing import Dict, List | ||
|
||
from concepts.models import Concept, Item, Link | ||
from django.core.management.base import BaseCommand | ||
from django.db.models import Q | ||
from django.db.utils import IntegrityError | ||
|
||
|
||
class UnionFind: | ||
def __init__(self, size): | ||
self.parent = [i for i in range(size)] | ||
self.rank = [0] * size | ||
|
||
def find(self, x): | ||
if self.parent[x] != x: | ||
self.parent[x] = self.find(self.parent[x]) | ||
return self.parent[x] | ||
|
||
def union(self, x, y): | ||
root_x = self.find(x) | ||
root_y = self.find(y) | ||
|
||
if root_x != root_y: | ||
if self.rank[root_x] < self.rank[root_y]: | ||
self.parent[root_x] = root_y | ||
elif self.rank[root_x] > self.rank[root_y]: | ||
self.parent[root_y] = root_x | ||
else: | ||
self.parent[root_y] = root_x | ||
self.rank[root_x] += 1 | ||
|
||
def get_components(self): | ||
components = {} | ||
for i in range(len(self.parent)): | ||
root = self.find(i) | ||
if root not in components: | ||
components[root] = [i] | ||
else: | ||
components[root].append(i) | ||
return components | ||
|
||
|
||
class Command(BaseCommand): | ||
num_to_id: List[str] = [] | ||
id_to_num: Dict[str, int] = {} | ||
id_to_item: Dict[str, Item] = {} | ||
|
||
def union(self, uf, link: Link): | ||
uf.union(self.id_to_num[link.source.id], self.id_to_num[link.destination.id]) | ||
|
||
def handle(self, *args, **options): | ||
# all items that do not appear in an edge are components | ||
singletons = Item.objects.filter( | ||
incoming_items__isnull=True, outgoing_items__isnull=True | ||
) | ||
count_duplicates = 0 | ||
for i in singletons: | ||
new_concept = Concept(name=i.name, description=i.description) | ||
try: | ||
new_concept.save() | ||
except IntegrityError: | ||
count_duplicates += 1 | ||
logging.log( | ||
logging.WARNING, | ||
f" A concept named '{new_concept.name}' already exists.", | ||
) | ||
i.concept = new_concept | ||
|
||
print("compute non-singletons") | ||
# now deal with those that do not have a concept yet | ||
print( | ||
Item.objects.filter( | ||
Q(incoming_items__isnull=False) | Q(outgoing_items__isnull=False) | ||
).query | ||
) | ||
for i in Item.objects.filter( | ||
Q(incoming_items__isnull=False) | Q(outgoing_items__isnull=False) | ||
): | ||
self.num_to_id.append(i.id) | ||
self.id_to_item[i.id] = i | ||
for i, id in enumerate(self.num_to_id): | ||
self.id_to_num[id] = i | ||
uf = UnionFind(len(self.num_to_id)) | ||
for link in Link.objects.all(): | ||
self.union(uf, link) | ||
for v in uf.get_components().values(): | ||
# first check if WD is one of the items | ||
items = list(map(lambda i: self.id_to_item[self.num_to_id[i]], v)) | ||
items.sort(key=Item.source_key()) | ||
new_concept = Concept(name=items[0].name, description=items[0].description) | ||
try: | ||
new_concept.save() | ||
except IntegrityError: | ||
logging.log( | ||
logging.WARNING, | ||
f" A concept named '{new_concept.name}' already exists.", | ||
) | ||
new_concept = Concept.objects.get(name=items[0].name) | ||
print(f"linking {new_concept.id}") | ||
for item in items: | ||
item.concept = new_concept | ||
item.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from concepts.models import Item, Link | ||
from django.core.management.base import BaseCommand | ||
from django.db.models import Count | ||
|
||
|
||
class Command(BaseCommand): | ||
def handle(self, *args, **options): | ||
print("link same") | ||
for name_count in ( | ||
Item.objects.all() | ||
.values("name") | ||
.annotate(total=Count("name")) | ||
.filter(total__gte=2) | ||
): | ||
items = Item.objects.filter(name=name_count["name"]) | ||
for i in range(len(items) - 1): | ||
for j in range(i + 1, len(items)): | ||
Link.save_new(items[i], items[j], Link.Label.NAME_EQ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Generated by Django 4.2.6 on 2023-11-17 18:33 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("concepts", "0005_alter_item_options_alter_item_source"), | ||
] | ||
|
||
operations = [ | ||
migrations.RemoveField( | ||
model_name="item", | ||
name="links", | ||
), | ||
migrations.CreateModel( | ||
name="Link", | ||
fields=[ | ||
( | ||
"id", | ||
models.BigAutoField( | ||
auto_created=True, | ||
primary_key=True, | ||
serialize=False, | ||
verbose_name="ID", | ||
), | ||
), | ||
( | ||
"label", | ||
models.CharField( | ||
choices=[ | ||
("Wd", "Wikidata"), | ||
("AUm", "Agda Unimath"), | ||
("eq", "same name"), | ||
], | ||
max_length=4, | ||
), | ||
), | ||
( | ||
"destination", | ||
models.ForeignKey( | ||
on_delete=django.db.models.deletion.CASCADE, | ||
related_name="incoming_items", | ||
to="concepts.item", | ||
), | ||
), | ||
( | ||
"source", | ||
models.ForeignKey( | ||
on_delete=django.db.models.deletion.CASCADE, | ||
related_name="outgoing_items", | ||
to="concepts.item", | ||
), | ||
), | ||
], | ||
options={ | ||
"ordering": ["source", "destination", "label"], | ||
"unique_together": {("source", "destination", "label")}, | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Generated by Django 4.2.6 on 2023-11-18 11:48 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("concepts", "0006_remove_item_links_link"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Concept", | ||
fields=[ | ||
( | ||
"id", | ||
models.BigAutoField( | ||
auto_created=True, | ||
primary_key=True, | ||
serialize=False, | ||
verbose_name="ID", | ||
), | ||
), | ||
("name", models.CharField(max_length=200, null=True, unique=True)), | ||
("description", models.TextField(null=True)), | ||
], | ||
options={ | ||
"ordering": ["name", "description"], | ||
}, | ||
), | ||
migrations.AddField( | ||
model_name="item", | ||
name="concept", | ||
field=models.ForeignKey( | ||
blank=True, | ||
null=True, | ||
on_delete=django.db.models.deletion.SET_NULL, | ||
to="concepts.concept", | ||
), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<!doctype html> | ||
{% load static %} | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css"> | ||
<link rel="stylesheet" href="{% static 'concepts/mathswitch.css' %}"> | ||
<title>mathswitch</title> | ||
<meta | ||
name="description" | ||
content="Infrastructure for relaying and exchanging mathematical concepts." | ||
/> | ||
</head> | ||
<body> | ||
<header class="container"> | ||
<hgroup> | ||
<h1>mathswitch</h1> | ||
<p>Infrastructure for relaying and exchanging mathematical concepts.</p> | ||
</hgroup> | ||
</header> | ||
<main class="container"> | ||
{% block content %} | ||
{% endblock %} | ||
</main> | ||
<footer class="container"> | ||
<img class="powered-by-wikidata" alt="Powered by Wikidata" /> | ||
</footer> | ||
</body> | ||
</html> |
Oops, something went wrong.