{"action":"created","comment":{"url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/comments/83604696","pull_request_review_id":4436539,"id":83604696,"diff_hunk":"@@ -0,0 +1,221 @@\n+use matrix::BaseMatrix;\n+\n+use libnum::{Num};\n+\n+use std::fmt;\n+\n+#[doc(hidden)]\n+#[derive(Debug, Copy, Clone)]\n+pub struct ElementComparisonError<T> {\n+    pub x: T,\n+    pub y: T,\n+    pub error: T,\n+    pub row: usize,\n+    pub col: usize\n+}\n+\n+impl<T> fmt::Display for ElementComparisonError<T> where T: fmt::Display {\n+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n+        write!(f,\n+            \"({i}, {j}): x = {x}, y = {y}. Error: {error}\",\n+            i = self.row,\n+            j = self.col,\n+            x = self.x,\n+            y = self.y,\n+            error = self.error)\n+    }\n+}\n+\n+#[doc(hidden)]\n+#[derive(Debug)]\n+pub enum MatrixComparisonResult<T, C> where T: Copy, C: ElementwiseComparator<T> {\n+    Match,\n+    MismatchedDimensions { dim_x: (usize, usize), dim_y: (usize, usize) },\n+    MismatchedElements { comparator: C, mismatches: Vec<ElementComparisonError<T>> }\n+}\n+\n+#[doc(hidden)]\n+pub trait ElementwiseComparator<T> where T: Copy {\n+    fn compare(&self, x: T, y: T) -> Option<T>;\n+    fn description(&self) -> String;\n+    fn definition(&self) -> String;\n+}\n+\n+#[doc(hidden)]\n+#[derive(Copy, Clone, Debug)]\n+pub struct AbsoluteElementwiseComparator<T> {\n+    pub tol: T\n+}\n+\n+impl<T, C> MatrixComparisonResult<T, C> where T: Copy + fmt::Display, C: ElementwiseComparator<T> {\n+    pub fn panic_message(&self) -> Option<String> {\n+        match self {\n+            &MatrixComparisonResult::MismatchedElements { ref comparator, ref mismatches } => {\n+                // TODO: Aligned output\n+                let mut formatted_mismatches = String::new();\n+                for mismatch in mismatches {\n+                    formatted_mismatches.push_str(\" \");\n+                    formatted_mismatches.push_str(&mismatch.to_string());\n+                    formatted_mismatches.push_str(\"\\n\");\n+                }\n+                Some(format!(\"\\n\n+Matrices X and Y have {num} mismatched element pairs. The mismatched elements are listed below, in the format\n+(row, col): x = x[[row, col]], y = y[[row, col]].\n+\n+{mismatches}\n+Comparison criterion: {description}, defined by\n+    {definition}.\n+\\n\",\n+                    num = mismatches.len(),\n+                    description = comparator.description(),\n+                    definition = comparator.definition(),\n+                    mismatches = formatted_mismatches))\n+            },\n+            &MatrixComparisonResult::MismatchedDimensions { dim_x, dim_y } => {\n+                Some(format!(\"\\n\n+Dimensions of matrices X and Y do not match.\n+ dim(X) = {x_rows} x {x_cols}\n+ dim(Y) = {y_rows} x {y_cols}\n+\\n\",\n+                    x_rows = dim_x.0, x_cols = dim_x.1,\n+                    y_rows = dim_y.0, y_cols = dim_y.1))\n+            },\n+            _ => None\n+        }\n+    }\n+}\n+\n+#[doc(hidden)]\n+pub fn elementwise_matrix_comparison<T, M, C>(x: &M, y: &M, comparator: C) -> MatrixComparisonResult<T, C>\n+    where M: BaseMatrix<T>, T: Copy, C: ElementwiseComparator<T> {\n+    if x.rows() == y.rows() && x.cols() == y.cols() {\n+        let mismatches = {\n+            let mut mismatches = Vec::new();\n+            let x = x.as_slice();\n+            let y = y.as_slice();\n+            for i in 0 .. x.rows() {\n+                for j in 0 .. x.cols() {\n+                    let a = x[[i, j]].to_owned();\n+                    let b = y[[i, j]].to_owned();\n+                    if let Some(error) = comparator.compare(a, b) {\n+                        mismatches.push(ElementComparisonError {\n+                            x: a,\n+                            y: b,\n+                            error: error,\n+                            row: i,\n+                            col: j\n+                        });\n+                    }\n+                }\n+            }\n+            mismatches\n+        };\n+        \n+        if mismatches.is_empty() {\n+            MatrixComparisonResult::Match\n+        } else {\n+            MatrixComparisonResult::MismatchedElements { comparator: comparator, mismatches: mismatches }\n+        }\n+    } else {\n+        MatrixComparisonResult::MismatchedDimensions { dim_x: (x.rows(), x.cols()), dim_y: (y.rows(), y.cols()) }\n+    }\n+}\n+\n+impl<T> ElementwiseComparator<T> for AbsoluteElementwiseComparator<T>\n+    where T: Copy + fmt::Display + Num + PartialOrd<T> {\n+\n+    fn compare(&self, a: T, b: T) -> Option<T> {\n+        // Note: Cannot use num::abs because we do not want to restrict\n+        // ourselves to Signed types (i.e. we still want to be able to\n+        // handle unsigned types).\n+        if a == b {\n+            None\n+        } else {\n+            let distance = if a > b { a - b } else { b - a };\n+            if distance <= self.tol {\n+                None\n+            } else {\n+                Some(distance)\n+            }\n+        }\n+    }\n+\n+    fn description(&self) -> String {\n+        format!(\"absolute difference\")\n+    }\n+\n+    fn definition(&self) -> String {\n+        format!(\"|x - y| <= {tol}\", tol = self.tol)\n+    }\n+}\n+\n+/// Compare matrices for approximate equality.\n+/// # Examples\n+///\n+/// ```\n+/// #[macro_use]\n+/// extern crate rulinalg;\n+///\n+/// # fn main() {\n+/// let a = matrix![1.000, 2.000,\n+///                 3.000, 4.000];\n+/// let b = matrix![0.999, 2.001,\n+///                 2.998, 4.000 ];\n+/// assert_matrix_eq!(a, b, comp = abs, tol = 0.01);\n+/// # }\n+/// ```\n+#[macro_export]\n+macro_rules! assert_matrix_eq {\n+    ($x:expr, $y:expr, comp = abs, tol = $tol:expr) => {","path":"src/macros/matrix_eq.rs","position":169,"original_position":169,"commit_id":"daa8526c3437444b0a604f260a3dce4f3a7686e7","original_commit_id":"daa8526c3437444b0a604f260a3dce4f3a7686e7","user":{"login":"Andlon","id":578309,"avatar_url":"https://avatars.githubusercontent.com/u/578309?v=3","gravatar_id":"","url":"https://api.github.com/users/Andlon","html_url":"https://github.com/Andlon","followers_url":"https://api.github.com/users/Andlon/followers","following_url":"https://api.github.com/users/Andlon/following{/other_user}","gists_url":"https://api.github.com/users/Andlon/gists{/gist_id}","starred_url":"https://api.github.com/users/Andlon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Andlon/subscriptions","organizations_url":"https://api.github.com/users/Andlon/orgs","repos_url":"https://api.github.com/users/Andlon/repos","events_url":"https://api.github.com/users/Andlon/events{/privacy}","received_events_url":"https://api.github.com/users/Andlon/received_events","type":"User","site_admin":false},"body":"Yes, the intention is to allow specifying different criterion. I'm not so sure of the syntax yet, but if we keep the current one, I can imagine something like\r\n\r\n```rust\r\nassert_matrix_eq!(x, y, comp = ulp, tol = 4)\r\n```\r\n\r\nto assert within 4 ULP. However, I'm not so sure if we even need to expose an ULP based comparison to the user, or if we just want to use it internally for the default comparison. In any case, I strongly think that some form of \"comp = abs\" (possibly using a very different syntax) should be present in the macro invocation, so that it's completely clear what sort of comparison is being used (implicit assumptions about floating point comparison can lead to all kinds of subtle and hard-to-track-down bugs).\r\n\r\nIt might also be useful later if we want to add comparators that are not elementwise, such as based on matrix norms, for example. This might be useful if you know that an algorithm has an error measured by some norm, i.e. ||A-expected|| <= tol.","created_at":"2016-10-17T09:18:56Z","updated_at":"2016-10-17T09:18:57Z","html_url":"https://github.com/AtheMathmo/rulinalg/pull/71#discussion_r83604696","pull_request_url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71","_links":{"self":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/comments/83604696"},"html":{"href":"https://github.com/AtheMathmo/rulinalg/pull/71#discussion_r83604696"},"pull_request":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71"}}},"pull_request":{"url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71","id":89532787,"html_url":"https://github.com/AtheMathmo/rulinalg/pull/71","diff_url":"https://github.com/AtheMathmo/rulinalg/pull/71.diff","patch_url":"https://github.com/AtheMathmo/rulinalg/pull/71.patch","issue_url":"https://api.github.com/repos/AtheMathmo/rulinalg/issues/71","number":71,"state":"open","locked":false,"title":"Matrix equality assertion","user":{"login":"Andlon","id":578309,"avatar_url":"https://avatars.githubusercontent.com/u/578309?v=3","gravatar_id":"","url":"https://api.github.com/users/Andlon","html_url":"https://github.com/Andlon","followers_url":"https://api.github.com/users/Andlon/followers","following_url":"https://api.github.com/users/Andlon/following{/other_user}","gists_url":"https://api.github.com/users/Andlon/gists{/gist_id}","starred_url":"https://api.github.com/users/Andlon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Andlon/subscriptions","organizations_url":"https://api.github.com/users/Andlon/orgs","repos_url":"https://api.github.com/users/Andlon/repos","events_url":"https://api.github.com/users/Andlon/events{/privacy}","received_events_url":"https://api.github.com/users/Andlon/received_events","type":"User","site_admin":false},"body":"This pull request is not intended as a candidate for merge (yet).\r\n\r\nI'm working on the matrix equality macro mentioned in #67. I added an example in the `examples/` subfolder, which one can run with `cargo run --example mismatched_f64_elements`. See also the small number of tests currently included as well. The example looks like this:\r\n\r\n```rust\r\n#[macro_use]\r\nextern crate rulinalg;\r\n\r\nfn main() {\r\n    // The purpose of this example is to demonstrate the type of errors generated\r\n    // by `assert_matrix_eq!` when the comparison fails (which the below call will).\r\n    let a = matrix![1.00, 2.00;\r\n                    3.00, 4.00];\r\n    let b = matrix![1.01, 2.00;\r\n                    3.40, 4.00];\r\n    assert_matrix_eq!(a, b, comp = abs, tol = 1e-8);\r\n}\r\n```\r\n\r\nand it gives the following output:\r\n\r\n```\r\n     Running `target/debug/examples/mismatched_f64_elements`\r\nthread 'main' panicked at '\r\n\r\nMatrices X and Y have 2 mismatched element pairs. The mismatched elements are listed below, in the format\r\n(row, col): x = x[[row, col]], y = y[[row, col]].\r\n\r\n (0, 0): x = 1, y = 1.01. Error: 0.010000000000000009\r\n (1, 0): x = 3, y = 3.4. Error: 0.3999999999999999\r\n\r\nComparison criterion: absolute difference, defined by\r\n    |x - y| <= 0.00000001.\r\n\r\n', examples/mismatched_f64_elements.rs:11\r\nnote: Run with `RUST_BACKTRACE=1` for a backtrace.\r\n```\r\n\r\nNow, I'd like to give people the chance to give some input on how the macro should work. Comparing floating numbers is _seriously hard_. See for example [this famous article](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). A preliminary conclusion is that there is no one-size-fits-all solution for comparing floating point numbers. Hence, it's impossible for us to have a default `assert_matrix_eq!(a, b)` macro that works in all cases. This is why I've opted for explicitly making the user choose which criterion to assert with (the `comp = abs` and `tol = 1e-8` parameters).\r\n\r\nHowever, I think we can provide a very conservative default `assert_matrix_eq!(a, b)` macro. I need to think a bit more on exactly how it's going to work, but I have the following in mind:\r\n\r\n1. The default invocation is very strict and conservative.\r\n2. The user simply writes `assert_matrix_eq!(a, b)` for his/her tests, and this might be fine if the numbers are very close to exactly equal.\r\n3. However, in the case when the numbers are near but not sufficiently near, the macro will fail.\r\n4. When the macro fails, the error message should explain the next steps the user should take (ideally by referring to a fleshed out part in the documentation on this) to ensure that he/she is using the correct comparison criteria.\r\n\r\nThe reasoning in step 4 again comes back to the fact that a _one-size-fits-all comparison does not exist_. I'm a bit inspired by how `rustc` guides users around compilation failures, by giving error messages that are truly helpful. Hopefully we can do the same for our users (and for our contributors).\r\n\r\nCurrently, the macro only supports absolute difference as a comparison criterion, but I want to at least support [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)-based comparison too (probably basing the default criterion on something involving ULP). I also need to write a **lot** more tests, as I hope this could form the cornerstone of future test assertions in rulinalg as a whole, as well as flesh out the documentation much more. Also, there should perhaps be an analogous `assert_vector_eq` macro?\r\n\r\nWould really appreciate any opinions, questions, reservations or advice anyone might have!","created_at":"2016-10-16T17:40:35Z","updated_at":"2016-10-17T09:18:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8a606dd3b75e0f16d78216c5b7343a5cc312f51b","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71/commits","review_comments_url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71/comments","review_comment_url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AtheMathmo/rulinalg/issues/71/comments","statuses_url":"https://api.github.com/repos/AtheMathmo/rulinalg/statuses/daa8526c3437444b0a604f260a3dce4f3a7686e7","head":{"label":"Andlon:assert_matrix_eq","ref":"assert_matrix_eq","sha":"daa8526c3437444b0a604f260a3dce4f3a7686e7","user":{"login":"Andlon","id":578309,"avatar_url":"https://avatars.githubusercontent.com/u/578309?v=3","gravatar_id":"","url":"https://api.github.com/users/Andlon","html_url":"https://github.com/Andlon","followers_url":"https://api.github.com/users/Andlon/followers","following_url":"https://api.github.com/users/Andlon/following{/other_user}","gists_url":"https://api.github.com/users/Andlon/gists{/gist_id}","starred_url":"https://api.github.com/users/Andlon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Andlon/subscriptions","organizations_url":"https://api.github.com/users/Andlon/orgs","repos_url":"https://api.github.com/users/Andlon/repos","events_url":"https://api.github.com/users/Andlon/events{/privacy}","received_events_url":"https://api.github.com/users/Andlon/received_events","type":"User","site_admin":false},"repo":{"id":68537005,"name":"rulinalg","full_name":"Andlon/rulinalg","owner":{"login":"Andlon","id":578309,"avatar_url":"https://avatars.githubusercontent.com/u/578309?v=3","gravatar_id":"","url":"https://api.github.com/users/Andlon","html_url":"https://github.com/Andlon","followers_url":"https://api.github.com/users/Andlon/followers","following_url":"https://api.github.com/users/Andlon/following{/other_user}","gists_url":"https://api.github.com/users/Andlon/gists{/gist_id}","starred_url":"https://api.github.com/users/Andlon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Andlon/subscriptions","organizations_url":"https://api.github.com/users/Andlon/orgs","repos_url":"https://api.github.com/users/Andlon/repos","events_url":"https://api.github.com/users/Andlon/events{/privacy}","received_events_url":"https://api.github.com/users/Andlon/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Andlon/rulinalg","description":"A linear algebra library in Rust designed for machine learning","fork":true,"url":"https://api.github.com/repos/Andlon/rulinalg","forks_url":"https://api.github.com/repos/Andlon/rulinalg/forks","keys_url":"https://api.github.com/repos/Andlon/rulinalg/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Andlon/rulinalg/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Andlon/rulinalg/teams","hooks_url":"https://api.github.com/repos/Andlon/rulinalg/hooks","issue_events_url":"https://api.github.com/repos/Andlon/rulinalg/issues/events{/number}","events_url":"https://api.github.com/repos/Andlon/rulinalg/events","assignees_url":"https://api.github.com/repos/Andlon/rulinalg/assignees{/user}","branches_url":"https://api.github.com/repos/Andlon/rulinalg/branches{/branch}","tags_url":"https://api.github.com/repos/Andlon/rulinalg/tags","blobs_url":"https://api.github.com/repos/Andlon/rulinalg/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Andlon/rulinalg/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Andlon/rulinalg/git/refs{/sha}","trees_url":"https://api.github.com/repos/Andlon/rulinalg/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Andlon/rulinalg/statuses/{sha}","languages_url":"https://api.github.com/repos/Andlon/rulinalg/languages","stargazers_url":"https://api.github.com/repos/Andlon/rulinalg/stargazers","contributors_url":"https://api.github.com/repos/Andlon/rulinalg/contributors","subscribers_url":"https://api.github.com/repos/Andlon/rulinalg/subscribers","subscription_url":"https://api.github.com/repos/Andlon/rulinalg/subscription","commits_url":"https://api.github.com/repos/Andlon/rulinalg/commits{/sha}","git_commits_url":"https://api.github.com/repos/Andlon/rulinalg/git/commits{/sha}","comments_url":"https://api.github.com/repos/Andlon/rulinalg/comments{/number}","issue_comment_url":"https://api.github.com/repos/Andlon/rulinalg/issues/comments{/number}","contents_url":"https://api.github.com/repos/Andlon/rulinalg/contents/{+path}","compare_url":"https://api.github.com/repos/Andlon/rulinalg/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Andlon/rulinalg/merges","archive_url":"https://api.github.com/repos/Andlon/rulinalg/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Andlon/rulinalg/downloads","issues_url":"https://api.github.com/repos/Andlon/rulinalg/issues{/number}","pulls_url":"https://api.github.com/repos/Andlon/rulinalg/pulls{/number}","milestones_url":"https://api.github.com/repos/Andlon/rulinalg/milestones{/number}","notifications_url":"https://api.github.com/repos/Andlon/rulinalg/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Andlon/rulinalg/labels{/name}","releases_url":"https://api.github.com/repos/Andlon/rulinalg/releases{/id}","deployments_url":"https://api.github.com/repos/Andlon/rulinalg/deployments","created_at":"2016-09-18T17:41:10Z","updated_at":"2016-09-18T17:41:11Z","pushed_at":"2016-10-16T17:14:34Z","git_url":"git://github.com/Andlon/rulinalg.git","ssh_url":"git@github.com:Andlon/rulinalg.git","clone_url":"https://github.com/Andlon/rulinalg.git","svn_url":"https://github.com/Andlon/rulinalg","homepage":"https://crates.io/crates/rulinalg","size":1269,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"AtheMathmo:master","ref":"master","sha":"0912827d19b66ff15803fc740c4d850df062e15a","user":{"login":"AtheMathmo","id":10150986,"avatar_url":"https://avatars.githubusercontent.com/u/10150986?v=3","gravatar_id":"","url":"https://api.github.com/users/AtheMathmo","html_url":"https://github.com/AtheMathmo","followers_url":"https://api.github.com/users/AtheMathmo/followers","following_url":"https://api.github.com/users/AtheMathmo/following{/other_user}","gists_url":"https://api.github.com/users/AtheMathmo/gists{/gist_id}","starred_url":"https://api.github.com/users/AtheMathmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AtheMathmo/subscriptions","organizations_url":"https://api.github.com/users/AtheMathmo/orgs","repos_url":"https://api.github.com/users/AtheMathmo/repos","events_url":"https://api.github.com/users/AtheMathmo/events{/privacy}","received_events_url":"https://api.github.com/users/AtheMathmo/received_events","type":"User","site_admin":false},"repo":{"id":62955795,"name":"rulinalg","full_name":"AtheMathmo/rulinalg","owner":{"login":"AtheMathmo","id":10150986,"avatar_url":"https://avatars.githubusercontent.com/u/10150986?v=3","gravatar_id":"","url":"https://api.github.com/users/AtheMathmo","html_url":"https://github.com/AtheMathmo","followers_url":"https://api.github.com/users/AtheMathmo/followers","following_url":"https://api.github.com/users/AtheMathmo/following{/other_user}","gists_url":"https://api.github.com/users/AtheMathmo/gists{/gist_id}","starred_url":"https://api.github.com/users/AtheMathmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AtheMathmo/subscriptions","organizations_url":"https://api.github.com/users/AtheMathmo/orgs","repos_url":"https://api.github.com/users/AtheMathmo/repos","events_url":"https://api.github.com/users/AtheMathmo/events{/privacy}","received_events_url":"https://api.github.com/users/AtheMathmo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AtheMathmo/rulinalg","description":"A linear algebra library in Rust designed for machine learning","fork":false,"url":"https://api.github.com/repos/AtheMathmo/rulinalg","forks_url":"https://api.github.com/repos/AtheMathmo/rulinalg/forks","keys_url":"https://api.github.com/repos/AtheMathmo/rulinalg/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AtheMathmo/rulinalg/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AtheMathmo/rulinalg/teams","hooks_url":"https://api.github.com/repos/AtheMathmo/rulinalg/hooks","issue_events_url":"https://api.github.com/repos/AtheMathmo/rulinalg/issues/events{/number}","events_url":"https://api.github.com/repos/AtheMathmo/rulinalg/events","assignees_url":"https://api.github.com/repos/AtheMathmo/rulinalg/assignees{/user}","branches_url":"https://api.github.com/repos/AtheMathmo/rulinalg/branches{/branch}","tags_url":"https://api.github.com/repos/AtheMathmo/rulinalg/tags","blobs_url":"https://api.github.com/repos/AtheMathmo/rulinalg/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AtheMathmo/rulinalg/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AtheMathmo/rulinalg/git/refs{/sha}","trees_url":"https://api.github.com/repos/AtheMathmo/rulinalg/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AtheMathmo/rulinalg/statuses/{sha}","languages_url":"https://api.github.com/repos/AtheMathmo/rulinalg/languages","stargazers_url":"https://api.github.com/repos/AtheMathmo/rulinalg/stargazers","contributors_url":"https://api.github.com/repos/AtheMathmo/rulinalg/contributors","subscribers_url":"https://api.github.com/repos/AtheMathmo/rulinalg/subscribers","subscription_url":"https://api.github.com/repos/AtheMathmo/rulinalg/subscription","commits_url":"https://api.github.com/repos/AtheMathmo/rulinalg/commits{/sha}","git_commits_url":"https://api.github.com/repos/AtheMathmo/rulinalg/git/commits{/sha}","comments_url":"https://api.github.com/repos/AtheMathmo/rulinalg/comments{/number}","issue_comment_url":"https://api.github.com/repos/AtheMathmo/rulinalg/issues/comments{/number}","contents_url":"https://api.github.com/repos/AtheMathmo/rulinalg/contents/{+path}","compare_url":"https://api.github.com/repos/AtheMathmo/rulinalg/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AtheMathmo/rulinalg/merges","archive_url":"https://api.github.com/repos/AtheMathmo/rulinalg/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AtheMathmo/rulinalg/downloads","issues_url":"https://api.github.com/repos/AtheMathmo/rulinalg/issues{/number}","pulls_url":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls{/number}","milestones_url":"https://api.github.com/repos/AtheMathmo/rulinalg/milestones{/number}","notifications_url":"https://api.github.com/repos/AtheMathmo/rulinalg/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AtheMathmo/rulinalg/labels{/name}","releases_url":"https://api.github.com/repos/AtheMathmo/rulinalg/releases{/id}","deployments_url":"https://api.github.com/repos/AtheMathmo/rulinalg/deployments","created_at":"2016-07-09T15:27:53Z","updated_at":"2016-10-15T05:34:06Z","pushed_at":"2016-10-16T17:40:36Z","git_url":"git://github.com/AtheMathmo/rulinalg.git","ssh_url":"git@github.com:AtheMathmo/rulinalg.git","clone_url":"https://github.com/AtheMathmo/rulinalg.git","svn_url":"https://github.com/AtheMathmo/rulinalg","homepage":"https://crates.io/crates/rulinalg","size":1638,"stargazers_count":75,"watchers_count":75,"language":"Rust","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":16,"mirror_url":null,"open_issues_count":23,"forks":16,"open_issues":23,"watchers":75,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71"},"html":{"href":"https://github.com/AtheMathmo/rulinalg/pull/71"},"issue":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/issues/71"},"comments":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/issues/71/comments"},"review_comments":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71/comments"},"review_comment":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/pulls/71/commits"},"statuses":{"href":"https://api.github.com/repos/AtheMathmo/rulinalg/statuses/daa8526c3437444b0a604f260a3dce4f3a7686e7"}}}}
{"actor":{"display_login":"Andlon"}}