         for (f, comparators, name) in functions {
             let results = groups.map { (results) -> [TermResult] in
                 var newResults = [TermResult]()
-                for (n, result) in _sortResults(results, comparators: comparators).enumerated() {
-                    var r = result
-                    switch f {
-                    case .rowNumber:
+                
+                if case .rowNumber = f {
+                    for (n, result) in _sortResults(results, comparators: comparators).enumerated() {
+                        var r = result
                         try? r.extend(variable: name, value: Term(integer: n))
-                    case .rank:
-                        // TODO: assign the same rank to rows with equal comparator values
-                        try? r.extend(variable: name, value: Term(integer: n))
-                    }
-                    newResults.append(r)
-                }
+                        newResults.append(r)
+                    }
+                } else if case .rank = f {
+                    let sorted = _sortResults(results, comparators: comparators)
+                    if sorted.count > 0 {
+                        var last = sorted.first!
+                        var n = 0
+                        
+                        try? last.extend(variable: name, value: Term(integer: n))
+                        newResults.append(last)
+                        
+                        for result in sorted.dropFirst() {
+                            var r = result
+                            if !_resultsEqual(r, last, comparators: comparators) {
+                                n += 1
+                            }
+                            try? r.extend(variable: name, value: Term(integer: n))
+                            newResults.append(r)
+                        }
+                    }
+                }
+                
                 return newResults
             }
             groups = results

        }
    }

    private func _sortResults(_ results: [TermResult], comparators: [Algebra.SortComparator]) -> [TermResult] {
        let s = results.sorted { (a, b) -> Bool in
            for (ascending, expr) in comparators {

        let predicate = self.freshVariable()
        let quad = QuadPattern(subject: subject, predicate: predicate, object: object, graph: graph)
        let i = try store.results(matching: quad)
        // OPTIMIZE: this can be made more efficient by adding an NPS function to the store,
        //           and allowing it to do the filtering based on a IDResult objects before
        //           materializing the terms
        let set = Set(iris)
        var keys = [String]()
        for node in [subject, object] {
