-
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.
- Loading branch information
Showing
14 changed files
with
321 additions
and
187 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
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 |
---|---|---|
@@ -1,103 +1,20 @@ | ||
import logging | ||
from typing import Dict, List | ||
|
||
from concepts.models import Concept, Item, Link | ||
from concepts.models import Item | ||
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): | ||
print("compute singletons") | ||
# 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 | ||
singletons.create_singleton_concepts() | ||
|
||
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( | ||
nonsingletons = 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() | ||
) | ||
nonsingletons.create_concepts() |
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
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,59 @@ | ||
from typing import Any, Dict, List, Tuple | ||
|
||
|
||
class UnionFind: | ||
item_to_element: Dict[Any, int] = {} | ||
components: Dict[int, List[int]] = {} | ||
element_links: List[Tuple[int, int]] = [] | ||
|
||
def __init__(self, items, links): | ||
"""Initialize union-find with a list of items | ||
and a list of links given as pairs of items.""" | ||
self.size = len(items) | ||
self.item_list = list(items) | ||
self.parent = [i for i in range(self.size)] | ||
self.rank = [0] * self.size | ||
for i, item in enumerate(self.item_list): | ||
self.item_to_element[item] = i | ||
for link in links: | ||
elt_link = map(self.item_to_element.get, link) | ||
self.element_links.append(elt_link) | ||
self._compute_components() | ||
|
||
# find the root element for given element | ||
def _find_representative(self, x): | ||
if self.parent[x] != x: | ||
self.parent[x] = self._find_representative(self.parent[x]) | ||
return self.parent[x] | ||
|
||
def _union(self, root_x, root_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 _connect_elements(self): | ||
for link in self.element_links: | ||
roots = map(self._find_representative, link) | ||
self._union(*roots) | ||
|
||
def _compute_components(self): | ||
self._connect_elements() | ||
for i in range(self.size): | ||
root = self._find_representative(i) | ||
if root not in self.components: | ||
self.components[root] = [i] | ||
else: | ||
self.components[root].append(i) | ||
|
||
def get_item_components(self, sort_key): | ||
def elements_to_sorted_items(elements: List[int]): | ||
items = list(map(lambda e: self.item_list[e], elements)) | ||
items.sort(key=sort_key) | ||
return items | ||
|
||
return list(map(elements_to_sorted_items, self.components.values())) |
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,8 @@ | ||
from concepts.models import Item | ||
from django.core.management.base import BaseCommand | ||
|
||
|
||
class Command(BaseCommand): | ||
def handle(self, *args, **options): | ||
print("clearing agda-unimath data") | ||
Item.objects.filter(source=Item.Source.AGDA_UNIMATH).delete() |
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,8 @@ | ||
from django.core.management.base import BaseCommand | ||
from slurper import source_agda_unimath | ||
|
||
|
||
class Command(BaseCommand): | ||
def handle(self, *args, **options): | ||
print("importing agda-unimath data") | ||
source_agda_unimath.AU_SLURPER.save_items() |
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
Oops, something went wrong.