improve math solver
This commit is contained in:
		
							parent
							
								
									1f4ded31c7
								
							
						
					
					
						commit
						a63f063a05
					
				
							
								
								
									
										194
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										194
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1,3 +1,11 @@
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "aho-corasick"
 | 
			
		||||
version = "0.6.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "alga"
 | 
			
		||||
version = "0.7.2"
 | 
			
		||||
@ -17,6 +25,16 @@ dependencies = [
 | 
			
		||||
 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "atty"
 | 
			
		||||
version = "0.2.11"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bitflags"
 | 
			
		||||
version = "1.0.4"
 | 
			
		||||
@ -27,9 +45,17 @@ name = "cad_rs"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "nalgebra 0.16.13 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cfg-if"
 | 
			
		||||
version = "0.1.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cloudabi"
 | 
			
		||||
version = "0.0.3"
 | 
			
		||||
@ -38,6 +64,23 @@ dependencies = [
 | 
			
		||||
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "either"
 | 
			
		||||
version = "1.5.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "env_logger"
 | 
			
		||||
version = "0.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "fuchsia-cprng"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
@ -51,6 +94,27 @@ dependencies = [
 | 
			
		||||
 "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "humantime"
 | 
			
		||||
version = "1.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "itertools"
 | 
			
		||||
version = "0.8.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "lazy_static"
 | 
			
		||||
version = "1.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "libc"
 | 
			
		||||
version = "0.2.48"
 | 
			
		||||
@ -61,6 +125,14 @@ name = "libm"
 | 
			
		||||
version = "0.1.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "log"
 | 
			
		||||
version = "0.4.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "matrixmultiply"
 | 
			
		||||
version = "0.1.15"
 | 
			
		||||
@ -69,6 +141,15 @@ dependencies = [
 | 
			
		||||
 "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "memchr"
 | 
			
		||||
version = "2.1.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "nalgebra"
 | 
			
		||||
version = "0.16.13"
 | 
			
		||||
@ -97,6 +178,11 @@ name = "num-traits"
 | 
			
		||||
version = "0.2.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quick-error"
 | 
			
		||||
version = "1.2.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rand"
 | 
			
		||||
version = "0.5.6"
 | 
			
		||||
@ -127,11 +213,80 @@ name = "rawpointer"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "redox_syscall"
 | 
			
		||||
version = "0.1.51"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "redox_termios"
 | 
			
		||||
version = "0.1.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "regex"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "regex-syntax"
 | 
			
		||||
version = "0.6.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "termcolor"
 | 
			
		||||
version = "1.0.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "termion"
 | 
			
		||||
version = "1.5.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "thread_local"
 | 
			
		||||
version = "0.3.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "typenum"
 | 
			
		||||
version = "1.10.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ucd-util"
 | 
			
		||||
version = "0.1.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "utf8-ranges"
 | 
			
		||||
version = "1.0.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi"
 | 
			
		||||
version = "0.3.6"
 | 
			
		||||
@ -146,29 +301,68 @@ name = "winapi-i686-pc-windows-gnu"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-util"
 | 
			
		||||
version = "0.1.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-x86_64-pc-windows-gnu"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wincolor"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[metadata]
 | 
			
		||||
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
 | 
			
		||||
"checksum alga 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24bb00eeca59f2986c747b8c2f271d52310ce446be27428fc34705138b155778"
 | 
			
		||||
"checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee"
 | 
			
		||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
 | 
			
		||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
 | 
			
		||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
 | 
			
		||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
 | 
			
		||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
 | 
			
		||||
"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
 | 
			
		||||
"checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31"
 | 
			
		||||
"checksum generic-array 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8107dafa78c80c848b71b60133954b4a58609a3a1a5f9af037ecc7f67280f369"
 | 
			
		||||
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
 | 
			
		||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
 | 
			
		||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
 | 
			
		||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
 | 
			
		||||
"checksum libm 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "03c0bb6d5ce1b5cc6fd0578ec1cbc18c9d88b5b591a5c7c1d6c6175e266a0819"
 | 
			
		||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
 | 
			
		||||
"checksum matrixmultiply 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "dcad67dcec2d58ff56f6292582377e6921afdf3bfbd533e26fb8900ae575e002"
 | 
			
		||||
"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8"
 | 
			
		||||
"checksum nalgebra 0.16.13 (registry+https://github.com/rust-lang/crates.io-index)" = "8e0799b53947b9c9048a1537f024f22f54701bbb75274f65955d081a87c0b739"
 | 
			
		||||
"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8"
 | 
			
		||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
 | 
			
		||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
 | 
			
		||||
"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
 | 
			
		||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 | 
			
		||||
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
 | 
			
		||||
"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019"
 | 
			
		||||
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
 | 
			
		||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
 | 
			
		||||
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
 | 
			
		||||
"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
 | 
			
		||||
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
 | 
			
		||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
 | 
			
		||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
 | 
			
		||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
 | 
			
		||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
 | 
			
		||||
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
 | 
			
		||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
 | 
			
		||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 | 
			
		||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
 | 
			
		||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 | 
			
		||||
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
 | 
			
		||||
 | 
			
		||||
@ -7,3 +7,6 @@ edition = "2018"
 | 
			
		||||
[dependencies]
 | 
			
		||||
nalgebra = "0.16"
 | 
			
		||||
approx = "0.3"
 | 
			
		||||
itertools = "0.8"
 | 
			
		||||
log = "0.4"
 | 
			
		||||
env_logger = "0.6"
 | 
			
		||||
							
								
								
									
										10
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,8 +1,16 @@
 | 
			
		||||
#![feature(drain_filter)]
 | 
			
		||||
#![feature(box_patterns)]
 | 
			
		||||
#![feature(slice_patterns)]
 | 
			
		||||
#![feature(bind_by_move_pattern_guards)]
 | 
			
		||||
#![feature(vec_remove_item)]
 | 
			
		||||
 | 
			
		||||
extern crate nalgebra;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate approx;
 | 
			
		||||
extern crate itertools;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate log;
 | 
			
		||||
extern crate env_logger;
 | 
			
		||||
 | 
			
		||||
mod entity;
 | 
			
		||||
mod math;
 | 
			
		||||
@ -13,6 +21,8 @@ fn main() {
 | 
			
		||||
    use math::Point2;
 | 
			
		||||
    use relation::{Relation, ResolveResult};
 | 
			
		||||
 | 
			
		||||
    env_logger::init();
 | 
			
		||||
 | 
			
		||||
    println!("Hello, world!");
 | 
			
		||||
    let origin = Point::new_ref(Var::new_single(Point2::new(0., 0.)));
 | 
			
		||||
    let p1 = Point::new_ref(Var::new_full(Point2::new(1., 1.)));
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										530
									
								
								src/math.rs
									
									
									
									
									
								
							
							
						
						
									
										530
									
								
								src/math.rs
									
									
									
									
									
								
							@ -214,9 +214,9 @@ impl Region2 {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod solve {
 | 
			
		||||
pub mod solve {
 | 
			
		||||
 | 
			
		||||
    use std::collections::BTreeSet;
 | 
			
		||||
    use std::collections::{BTreeMap, BTreeSet};
 | 
			
		||||
    use std::fmt;
 | 
			
		||||
    use std::iter::FromIterator;
 | 
			
		||||
 | 
			
		||||
@ -268,10 +268,179 @@ mod solve {
 | 
			
		||||
    enum Expr {
 | 
			
		||||
        Unkn(Unknown),
 | 
			
		||||
        Const(Scalar),
 | 
			
		||||
        Plus(Box<Expr>, Box<Expr>),
 | 
			
		||||
        Sum(Exprs),
 | 
			
		||||
        Neg(Box<Expr>),
 | 
			
		||||
        Times(Box<Expr>, Box<Expr>),
 | 
			
		||||
        Inv(Box<Expr>),
 | 
			
		||||
        Product(Exprs),
 | 
			
		||||
        Div(Box<Expr>, Box<Expr>),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    type Exprs = Vec<Expr>;
 | 
			
		||||
 | 
			
		||||
    impl Unknowns for Exprs {
 | 
			
		||||
        fn unknowns(&self) -> UnknownSet {
 | 
			
		||||
            self.iter().flat_map(|e: &Expr| e.unknowns()).collect()
 | 
			
		||||
        }
 | 
			
		||||
        fn has_unknowns(&self) -> bool {
 | 
			
		||||
            self.iter().any(|e: &Expr| e.has_unknowns())
 | 
			
		||||
        }
 | 
			
		||||
        fn has_unknown(&self, u: Unknown) -> bool {
 | 
			
		||||
            self.iter().any(|e: &Expr| e.has_unknown(u))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn write_separated_exprs(es: &Exprs, f: &mut fmt::Formatter, sep: &str) -> fmt::Result {
 | 
			
		||||
        let mut is_first = true;
 | 
			
		||||
        for e in es {
 | 
			
		||||
            if is_first {
 | 
			
		||||
                is_first = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                write!(f, "{}", sep)?
 | 
			
		||||
            }
 | 
			
		||||
            write!(f, "({})", e)?
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn remove_common_terms(l: &mut Vec<Expr>, r: &mut Vec<Expr>) -> Vec<Expr> {
 | 
			
		||||
        let common: Vec<_> = l.drain_filter(|e| r.contains(e)).collect();
 | 
			
		||||
        common.iter().for_each(|e| {
 | 
			
		||||
            r.remove_item(e);
 | 
			
		||||
        });
 | 
			
		||||
        common
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn remove_term(terms: &mut Vec<Expr>, term: &Expr) -> Option<Expr> {
 | 
			
		||||
        terms.remove_item(term)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn sum_fold(l: Expr, r: Expr) -> Expr {
 | 
			
		||||
        use itertools::Itertools;
 | 
			
		||||
        use Expr::*;
 | 
			
		||||
        match (l, r) {
 | 
			
		||||
            (Const(lc), Const(rc)) => Const(lc + rc),
 | 
			
		||||
            (Const(c), o) | (o, Const(c)) if relative_eq!(c, 0.) => o,
 | 
			
		||||
            (Product(mut l), Product(mut r)) => {
 | 
			
		||||
                let comm = remove_common_terms(&mut l, &mut r);
 | 
			
		||||
                Expr::new_product(Sum(comm), Expr::new_sum(Product(l), Product(r))).simplify()
 | 
			
		||||
            }
 | 
			
		||||
            (Product(mut l), r) | (r, Product(mut l)) => {
 | 
			
		||||
                let comm = remove_term(&mut l, &r);
 | 
			
		||||
                match comm {
 | 
			
		||||
                    Some(_) => {
 | 
			
		||||
                        Expr::new_product(r, Expr::new_sum(Product(l), Const(1.))).simplify()
 | 
			
		||||
                    }
 | 
			
		||||
                    None => Expr::new_sum(Product(l), r),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            (l, r) => Expr::new_sum(l, r),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn group_sum(es: Exprs) -> Exprs {
 | 
			
		||||
        use Expr::*;
 | 
			
		||||
        let mut common: BTreeMap<UnknownSet, Expr> = BTreeMap::new();
 | 
			
		||||
        for e in es {
 | 
			
		||||
            let unkns = e.unknowns();
 | 
			
		||||
            match common.get_mut(&unkns) {
 | 
			
		||||
                None => {
 | 
			
		||||
                    match e {
 | 
			
		||||
                        Const(c) if relative_eq!(c, 0.) => (),
 | 
			
		||||
                        e => {
 | 
			
		||||
                            common.insert(unkns, e);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                Some(existing) => {
 | 
			
		||||
                    match existing {
 | 
			
		||||
                        Sum(ref mut es) => {
 | 
			
		||||
                            // already failed at merging, so just add it to the list
 | 
			
		||||
                            es.push(e);
 | 
			
		||||
                        }
 | 
			
		||||
                        other => {
 | 
			
		||||
                            *other = sum_fold(other.clone(), e);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        common.into_iter().map(|(_, v)| v).collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn product_fold(l: Expr, r: Expr) -> Expr {
 | 
			
		||||
        use itertools::Itertools;
 | 
			
		||||
        use Expr::*;
 | 
			
		||||
        match (l, r) {
 | 
			
		||||
            (Const(lc), Const(rc)) => Const(lc * rc),
 | 
			
		||||
            (Const(c), o) | (o, Const(c)) if relative_eq!(c, 1.) => o,
 | 
			
		||||
            (Div(num, den), mul) | (mul, Div(num, den)) => {
 | 
			
		||||
                if mul == *den {
 | 
			
		||||
                    *num
 | 
			
		||||
                } else {
 | 
			
		||||
                    Expr::Div(Box::new(Expr::Product(vec![*num, mul])), den).simplify()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            (l, r) => Expr::new_product(l, r),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn group_product(es: Exprs) -> Exprs {
 | 
			
		||||
        use Expr::*;
 | 
			
		||||
        let mut common: BTreeMap<UnknownSet, Expr> = BTreeMap::new();
 | 
			
		||||
        for e in es {
 | 
			
		||||
            let unkns = e.unknowns();
 | 
			
		||||
            match common.get_mut(&unkns) {
 | 
			
		||||
                None => {
 | 
			
		||||
                    match e {
 | 
			
		||||
                        Const(c) if relative_eq!(c, 1.) => (),
 | 
			
		||||
                        e => {
 | 
			
		||||
                            common.insert(unkns, e);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                Some(existing) => {
 | 
			
		||||
                    match existing {
 | 
			
		||||
                        Sum(ref mut es) => {
 | 
			
		||||
                            // already failed at merging, so just add it to the list
 | 
			
		||||
                            es.push(e);
 | 
			
		||||
                        }
 | 
			
		||||
                        other => *other = product_fold(other.clone(), e),
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        common.into_iter().map(|(_, v)| v).collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn distribute_product_sums(mut es: Exprs) -> Expr {
 | 
			
		||||
        trace!("distribute_product_sums: {}", Product(es.clone()));
 | 
			
		||||
        use itertools::Itertools;
 | 
			
		||||
        use Expr::*;
 | 
			
		||||
        let sums = es
 | 
			
		||||
            .drain_filter(|e| match e {
 | 
			
		||||
                Sum(_) => true,
 | 
			
		||||
                _ => false,
 | 
			
		||||
            })
 | 
			
		||||
            .map(|e| {
 | 
			
		||||
                trace!("sum in product: {}", e);
 | 
			
		||||
                match e {
 | 
			
		||||
                    Sum(es) => es,
 | 
			
		||||
                    _ => unreachable!(),
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        let products: Vec<_> = sums.multi_cartesian_product().collect();
 | 
			
		||||
        if products.is_empty() {
 | 
			
		||||
            trace!("no sums to distribute");
 | 
			
		||||
            return Product(es);
 | 
			
		||||
        }
 | 
			
		||||
        let sums = products
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(|mut prod| {
 | 
			
		||||
                prod.extend(es.clone());
 | 
			
		||||
                trace!("prod: {}", Product(prod.clone()));
 | 
			
		||||
                Product(prod)
 | 
			
		||||
            })
 | 
			
		||||
            .collect();
 | 
			
		||||
        Sum(sums)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Unknowns for Expr {
 | 
			
		||||
@ -280,8 +449,9 @@ mod solve {
 | 
			
		||||
            match self {
 | 
			
		||||
                Unkn(u) => u.unknowns(),
 | 
			
		||||
                Const(_) => UnknownSet::default(),
 | 
			
		||||
                Plus(l, r) | Times(l, r) => l.unknowns().union(&r.unknowns()).cloned().collect(),
 | 
			
		||||
                Neg(e) | Inv(e) => e.unknowns(),
 | 
			
		||||
                Sum(es) | Product(es) => es.unknowns(),
 | 
			
		||||
                Div(l, r) => l.unknowns().union(&r.unknowns()).cloned().collect(),
 | 
			
		||||
                Neg(e) => e.unknowns(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        fn has_unknowns(&self) -> bool {
 | 
			
		||||
@ -289,8 +459,9 @@ mod solve {
 | 
			
		||||
            match self {
 | 
			
		||||
                Unkn(u) => u.has_unknowns(),
 | 
			
		||||
                Const(_) => false,
 | 
			
		||||
                Plus(l, r) | Times(l, r) => l.has_unknowns() || r.has_unknowns(),
 | 
			
		||||
                Neg(e) | Inv(e) => e.has_unknowns(),
 | 
			
		||||
                Sum(es) | Product(es) => es.has_unknowns(),
 | 
			
		||||
                Div(l, r) => l.has_unknowns() || r.has_unknowns(),
 | 
			
		||||
                Neg(e) => e.has_unknowns(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        fn has_unknown(&self, u: Unknown) -> bool {
 | 
			
		||||
@ -298,30 +469,31 @@ mod solve {
 | 
			
		||||
            match self {
 | 
			
		||||
                Unkn(u1) => u1.has_unknown(u),
 | 
			
		||||
                Const(_) => false,
 | 
			
		||||
                Plus(l, r) | Times(l, r) => l.has_unknown(u) || r.has_unknown(u),
 | 
			
		||||
                Neg(e) | Inv(e) => e.has_unknown(u),
 | 
			
		||||
                Sum(es) | Product(es) => es.has_unknown(u),
 | 
			
		||||
                Div(l, r) => l.has_unknown(u) || r.has_unknown(u),
 | 
			
		||||
                Neg(e) => e.has_unknown(u),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Expr {
 | 
			
		||||
        fn new_plus(e1: Expr, e2: Expr) -> Expr {
 | 
			
		||||
            Expr::Plus(Box::new(e1), Box::new(e2))
 | 
			
		||||
        fn new_sum(e1: Expr, e2: Expr) -> Expr {
 | 
			
		||||
            Expr::Sum(vec![e1, e2])
 | 
			
		||||
        }
 | 
			
		||||
        fn new_times(e1: Expr, e2: Expr) -> Expr {
 | 
			
		||||
            Expr::Times(Box::new(e1), Box::new(e2))
 | 
			
		||||
        fn new_product(e1: Expr, e2: Expr) -> Expr {
 | 
			
		||||
            Expr::Product(vec![e1, e2])
 | 
			
		||||
        }
 | 
			
		||||
        fn new_neg(e1: Expr) -> Expr {
 | 
			
		||||
            Expr::Neg(Box::new(e1))
 | 
			
		||||
        }
 | 
			
		||||
        fn new_inv(e1: Expr) -> Expr {
 | 
			
		||||
            Expr::Inv(Box::new(e1))
 | 
			
		||||
        fn new_div(num: Expr, den: Expr) -> Expr {
 | 
			
		||||
            Expr::Div(Box::new(num), Box::new(den))
 | 
			
		||||
        }
 | 
			
		||||
        fn new_minus(e1: Expr, e2: Expr) -> Expr {
 | 
			
		||||
            Expr::Plus(Box::new(e1), Box::new(Expr::new_neg(e2)))
 | 
			
		||||
            Expr::Sum(vec![e1, Expr::new_neg(e2)])
 | 
			
		||||
        }
 | 
			
		||||
        fn new_div(e1: Expr, e2: Expr) -> Expr {
 | 
			
		||||
            Expr::Times(Box::new(e1), Box::new(Expr::new_inv(e2)))
 | 
			
		||||
        fn new_inv(den: Expr) -> Expr {
 | 
			
		||||
            Expr::new_div(Expr::Const(1.), den)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn is_zero(&self) -> bool {
 | 
			
		||||
@ -343,90 +515,132 @@ mod solve {
 | 
			
		||||
        fn simplify(self) -> Expr {
 | 
			
		||||
            use Expr::*;
 | 
			
		||||
            match self {
 | 
			
		||||
                Plus(l, r) => match (l.simplify(), r.simplify()) {
 | 
			
		||||
                    (Const(lc), Const(rc)) => Const(lc + rc),
 | 
			
		||||
                    (Const(c), ref o) | (ref o, Const(c)) if relative_eq!(c, 0.) => o.clone(),
 | 
			
		||||
                    (Times(l1, l2), Times(r1, r2)) => {
 | 
			
		||||
                        if l2 == r2 {
 | 
			
		||||
                            Expr::new_times(Expr::Plus(l1, r1), *l2).simplify()
 | 
			
		||||
                        } else if l1 == r1 {
 | 
			
		||||
                            Expr::new_times(Expr::Plus(l2, r2), *l1).simplify()
 | 
			
		||||
                        } else if l1 == r2 {
 | 
			
		||||
                            Expr::new_times(Expr::Plus(l2, r1), *l1).simplify()
 | 
			
		||||
                        } else if l2 == r1 {
 | 
			
		||||
                            Expr::new_times(Expr::Plus(l1, r2), *l2).simplify()
 | 
			
		||||
                Sum(es) => {
 | 
			
		||||
                    let mut new_es: Vec<_> = es
 | 
			
		||||
                        .into_iter()
 | 
			
		||||
                        .map(|e| e.simplify())
 | 
			
		||||
                        .flat_map(|e| match e {
 | 
			
		||||
                            Sum(more_es) => more_es,
 | 
			
		||||
                            other => vec![other],
 | 
			
		||||
                        })
 | 
			
		||||
                        .collect();
 | 
			
		||||
                    let pre_new_es = new_es.clone();
 | 
			
		||||
                    new_es = group_sum(new_es);
 | 
			
		||||
                    trace!(
 | 
			
		||||
                        "simplify sum {} => {}",
 | 
			
		||||
                        Sum(pre_new_es),
 | 
			
		||||
                        Sum(new_es.clone())
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    match new_es.len() {
 | 
			
		||||
                        0 => Const(0.),                          // none
 | 
			
		||||
                        1 => new_es.into_iter().next().unwrap(), // one
 | 
			
		||||
                        _ => Sum(new_es),                        // many
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                Product(es) => {
 | 
			
		||||
                    let new_es: Vec<_> = es
 | 
			
		||||
                        .into_iter()
 | 
			
		||||
                        .map(|e| e.simplify())
 | 
			
		||||
                        .flat_map(|e| match e {
 | 
			
		||||
                            Product(more_es) => more_es,
 | 
			
		||||
                            other => vec![other],
 | 
			
		||||
                        })
 | 
			
		||||
                        .collect();
 | 
			
		||||
                    let pre_new_es = new_es.clone();
 | 
			
		||||
                    let new_es = group_product(new_es);
 | 
			
		||||
                    trace!(
 | 
			
		||||
                        "simplify product {} => {}",
 | 
			
		||||
                        Product(pre_new_es),
 | 
			
		||||
                        Product(new_es.clone())
 | 
			
		||||
                    );
 | 
			
		||||
                    match new_es.len() {
 | 
			
		||||
                        0 => Const(1.),                          // none
 | 
			
		||||
                        1 => new_es.into_iter().next().unwrap(), // one
 | 
			
		||||
                        _ => Product(new_es),                    // many
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                Neg(mut v) => {
 | 
			
		||||
                    *v = v.simplify();
 | 
			
		||||
                    trace!("simplify neg {}", Neg(v.clone()));
 | 
			
		||||
                    match v {
 | 
			
		||||
                        box Const(c) => Const(-c),
 | 
			
		||||
                        box Neg(v) => *v,
 | 
			
		||||
                        e => Product(vec![Const(-1.), *e]),
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                Div(mut num, mut den) => {
 | 
			
		||||
                    *num = num.simplify();
 | 
			
		||||
                    *den = den.simplify();
 | 
			
		||||
                    trace!("simplify div {}", Div(num.clone(), den.clone()));
 | 
			
		||||
                    match (num, den) {
 | 
			
		||||
                        (box Const(num), box Const(den)) => Const(num / den),
 | 
			
		||||
                        (num, box Const(den)) => {
 | 
			
		||||
                            if relative_eq!(den, 1.) {
 | 
			
		||||
                                *num
 | 
			
		||||
                            } else {
 | 
			
		||||
                            Expr::new_plus(Times(l1, l2), Times(r1, r2))
 | 
			
		||||
                                Expr::new_product(*num, Const(1. / den))
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    (l, r) => Self::new_plus(l, r),
 | 
			
		||||
                },
 | 
			
		||||
                Times(l, r) => match (l.simplify(), r.simplify()) {
 | 
			
		||||
                    (Const(lc), Const(rc)) => Const(lc * rc),
 | 
			
		||||
                    (Const(c), ref o) | (ref o, Const(c)) if relative_eq!(c, 1.) => o.clone(),
 | 
			
		||||
                    (Inv(ref den), ref num) | (ref num, Inv(ref den)) if *num == **den => Const(1.),
 | 
			
		||||
                    (l, r) => Self::new_times(l, r),
 | 
			
		||||
                },
 | 
			
		||||
                Neg(v) => match v.simplify() {
 | 
			
		||||
                    Const(c) => Const(-c),
 | 
			
		||||
                    Neg(v) => *v,
 | 
			
		||||
                    e => Self::new_times(Const(-1.), e),
 | 
			
		||||
                },
 | 
			
		||||
                Inv(v) => match v.simplify() {
 | 
			
		||||
                    Const(c) => Const(1. / c),
 | 
			
		||||
                    Inv(v) => *v,
 | 
			
		||||
                    e => Self::new_inv(e),
 | 
			
		||||
                        (num, box Div(dennum, denden)) => {
 | 
			
		||||
                            Div(Box::new(Product(vec![*num, *denden])), dennum).simplify()
 | 
			
		||||
                        }
 | 
			
		||||
                        (box Product(mut es), box den) => match es.remove_item(&den) {
 | 
			
		||||
                            Some(_) => Product(es),
 | 
			
		||||
                            None => Expr::new_div(Product(es), den),
 | 
			
		||||
                        },
 | 
			
		||||
                        (num, den) => {
 | 
			
		||||
                            if num == den {
 | 
			
		||||
                                Expr::Const(1.)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                Div(num, den)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                e => e,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn distrubute(self) -> Expr {
 | 
			
		||||
        fn distribute(self) -> Expr {
 | 
			
		||||
            use Expr::*;
 | 
			
		||||
            trace!("distribute {}", self);
 | 
			
		||||
            match self {
 | 
			
		||||
                Plus(l, r) => Expr::new_plus(l.distrubute(), r.distrubute()),
 | 
			
		||||
                Times(l, r) => match (*l, *r) {
 | 
			
		||||
                    (Plus(l, r), o) | (o, Plus(l, r)) => Expr::new_plus(
 | 
			
		||||
                        Expr::Times(Box::new(o.clone()), l),
 | 
			
		||||
                        Expr::Times(Box::new(o), r),
 | 
			
		||||
                    )
 | 
			
		||||
                    .distrubute(),
 | 
			
		||||
                    (l, r) => Expr::new_times(l, r),
 | 
			
		||||
                },
 | 
			
		||||
                Neg(v) => match *v {
 | 
			
		||||
                    Plus(l, r) => Expr::new_plus(Neg(l).distrubute(), Neg(r).distrubute()),
 | 
			
		||||
                    Times(l, r) => Expr::new_times(Neg(l).distrubute(), *r),
 | 
			
		||||
                    Neg(v) => v.distrubute(),
 | 
			
		||||
                    Inv(v) => Expr::new_inv(Neg(v).distrubute()),
 | 
			
		||||
                    e => Expr::new_neg(e),
 | 
			
		||||
                },
 | 
			
		||||
                Inv(v) => match *v {
 | 
			
		||||
                    Plus(l, r) => Expr::new_plus(Inv(l).distrubute(), Inv(r).distrubute()),
 | 
			
		||||
                    Times(l, r) => Expr::new_times(Inv(l).distrubute(), Inv(r).distrubute()),
 | 
			
		||||
                    Inv(v) => v.distrubute(),
 | 
			
		||||
                    e => Expr::new_inv(e),
 | 
			
		||||
                },
 | 
			
		||||
                e => e,
 | 
			
		||||
                Sum(mut es) => {
 | 
			
		||||
                    for e in &mut es {
 | 
			
		||||
                        *e = e.clone().distribute();
 | 
			
		||||
                    }
 | 
			
		||||
                    Sum(es)
 | 
			
		||||
                }
 | 
			
		||||
                Product(es) => distribute_product_sums(es),
 | 
			
		||||
                Div(mut num, mut den) => {
 | 
			
		||||
                    *num = num.distribute();
 | 
			
		||||
                    *den = den.distribute();
 | 
			
		||||
                    match (num, den) {
 | 
			
		||||
                        (box Sum(es), box den) => Sum(es
 | 
			
		||||
                            .into_iter()
 | 
			
		||||
                            .map(|e| Expr::new_div(e, den.clone()))
 | 
			
		||||
                            .collect()),
 | 
			
		||||
                        (mut num, mut den) => Div(num, den),
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
        fn reduce(self, for_u: Unknown) -> Expr {
 | 
			
		||||
            use Expr::*;
 | 
			
		||||
            match self {
 | 
			
		||||
                Plus(l, r) => match (l.reduce(for_u), r.reduce(for_u)) {
 | 
			
		||||
                    (Const(lc), Const(rc)) => Const(lc + rc),
 | 
			
		||||
                    (l, r) => Self::new_plus(l, r),
 | 
			
		||||
                },
 | 
			
		||||
                Times(l, r) => match (l.reduce(for_u), r.reduce(for_u)) {
 | 
			
		||||
                    (Const(lc), Const(rc)) => Const(lc * rc),
 | 
			
		||||
                    (l, r) => Self::new_times(l, r),
 | 
			
		||||
                },
 | 
			
		||||
                Neg(v) => match v.reduce(for_u) {
 | 
			
		||||
                    Unkn(u) if u == for_u => Expr::new_times(Const(-1.), Unkn(u)),
 | 
			
		||||
                    e => Self::new_neg(e),
 | 
			
		||||
                },
 | 
			
		||||
                Inv(v) => match v.reduce(for_u) {
 | 
			
		||||
                    e => Self::new_inv(e),
 | 
			
		||||
                Neg(v) => match v {
 | 
			
		||||
                    // box Sum(mut l, mut r) => {
 | 
			
		||||
                    //     *l = Neg(l.clone()).distribute();
 | 
			
		||||
                    //     *r = Neg(r.clone()).distribute();
 | 
			
		||||
                    //     Sum(l, r)
 | 
			
		||||
                    // }
 | 
			
		||||
                    // box Product(mut l, r) => {
 | 
			
		||||
                    //     *l = Neg(l.clone()).distribute();
 | 
			
		||||
                    //     Product(l, r)
 | 
			
		||||
                    // }
 | 
			
		||||
                    box Neg(v) => v.distribute(),
 | 
			
		||||
                    box Div(mut num, mut den) => {
 | 
			
		||||
                        *num = Neg(num.clone()).distribute();
 | 
			
		||||
                        *den = Neg(den.clone()).distribute();
 | 
			
		||||
                        Div(num, den)
 | 
			
		||||
                    }
 | 
			
		||||
                    e => Neg(e),
 | 
			
		||||
                },
 | 
			
		||||
                e => e,
 | 
			
		||||
            }
 | 
			
		||||
@ -439,10 +653,10 @@ mod solve {
 | 
			
		||||
            match self {
 | 
			
		||||
                Unkn(u) => write!(f, "{}", u),
 | 
			
		||||
                Const(c) => write!(f, "{}", c),
 | 
			
		||||
                Plus(l, r) => write!(f, "({}) + ({})", l, r),
 | 
			
		||||
                Times(l, r) => write!(f, "({}) * ({})", l, r),
 | 
			
		||||
                Sum(es) => write_separated_exprs(es, f, " + "),
 | 
			
		||||
                Product(es) => write_separated_exprs(es, f, " * "),
 | 
			
		||||
                Div(num, den) => write!(f, "({}) / ({})", num, den),
 | 
			
		||||
                Neg(e) => write!(f, "-({})", e),
 | 
			
		||||
                Inv(e) => write!(f, "1 / ({})", e),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -477,27 +691,62 @@ mod solve {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Eqn {
 | 
			
		||||
        fn simplify(self) -> Eqn {
 | 
			
		||||
            Eqn(self.0.simplify(), self.1.simplify())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn solve(&self, for_u: Unknown) -> Option<Expr> {
 | 
			
		||||
            use Expr::*;
 | 
			
		||||
            if !self.has_unknown(for_u) {
 | 
			
		||||
                return None;
 | 
			
		||||
            }
 | 
			
		||||
            let (l, r) = (self.0.clone().simplify(), self.1.clone().simplify());
 | 
			
		||||
            let (l, r) = (
 | 
			
		||||
                self.0
 | 
			
		||||
                    .clone() /*.distribute()*/
 | 
			
		||||
                    .simplify(),
 | 
			
		||||
                self.1
 | 
			
		||||
                    .clone() /*.distribute()*/
 | 
			
		||||
                    .simplify(),
 | 
			
		||||
            );
 | 
			
		||||
            let (mut l, mut r) = ord_by_unkn(l, r, for_u)?;
 | 
			
		||||
            loop {
 | 
			
		||||
                trace!("solve: {} == {}", l, r);
 | 
			
		||||
                let (new_l, new_r): (Expr, Expr) = match l {
 | 
			
		||||
                    Unkn(u) => return if u == for_u { Some(r.simplify()) } else { None },
 | 
			
		||||
                    Plus(a, b) => {
 | 
			
		||||
                        let (a, b) = ord_by_unkn(*a, *b, for_u)?;
 | 
			
		||||
                        (a, Expr::new_minus(r, b))
 | 
			
		||||
                    Sum(es) => {
 | 
			
		||||
                        let (us, not_us): (Vec<_>, Vec<_>) =
 | 
			
		||||
                            es.into_iter().partition(|e| e.has_unknown(for_u));
 | 
			
		||||
                        if us.len() != 1 {
 | 
			
		||||
                            return None;
 | 
			
		||||
                        }
 | 
			
		||||
                    Times(a, b) => {
 | 
			
		||||
                        let (a, b) = ord_by_unkn(*a, *b, for_u)?;
 | 
			
		||||
                        (a, Expr::new_div(r, b))
 | 
			
		||||
                        (
 | 
			
		||||
                            Sum(us).simplify(),
 | 
			
		||||
                            Expr::new_minus(r, Sum(not_us)).simplify(),
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    Product(es) => {
 | 
			
		||||
                        let (us, not_us): (Vec<_>, Vec<_>) =
 | 
			
		||||
                            es.into_iter().partition(|e| e.has_unknown(for_u));
 | 
			
		||||
                        if us.len() != 1 {
 | 
			
		||||
                            return None;
 | 
			
		||||
                        }
 | 
			
		||||
                        (
 | 
			
		||||
                            Product(us).simplify(),
 | 
			
		||||
                            Expr::new_div(r, Product(not_us)).simplify(),
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    Neg(v) => (*v, Expr::new_neg(r)),
 | 
			
		||||
                    Inv(v) => (*v, Expr::new_inv(r)),
 | 
			
		||||
                    Div(num, den) => {
 | 
			
		||||
                        let (nu, du) = (num.has_unknown(for_u), den.has_unknown(for_u));
 | 
			
		||||
                        match (nu, du) {
 | 
			
		||||
                            (true, false) => (*num, Expr::new_product(r, *den)),
 | 
			
		||||
                            (false, true) => (Expr::new_product(r, *den), *num),
 | 
			
		||||
                            (true, true) => return None, // TODO: simplify
 | 
			
		||||
                            (false, false) => return None,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Const(_) => return None,
 | 
			
		||||
                    _ => return None,
 | 
			
		||||
                };
 | 
			
		||||
                l = new_l;
 | 
			
		||||
                r = new_r;
 | 
			
		||||
@ -505,6 +754,12 @@ mod solve {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl fmt::Display for Eqn {
 | 
			
		||||
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
			
		||||
            write!(f, "{} == {}", self.0, self.1)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Clone, Debug, PartialEq)]
 | 
			
		||||
    struct Eqns(Vec<Eqn>);
 | 
			
		||||
 | 
			
		||||
@ -554,6 +809,7 @@ mod solve {
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_solve() {
 | 
			
		||||
            use Expr::*;
 | 
			
		||||
            let _ = env_logger::try_init();
 | 
			
		||||
            let u1 = Unknown(1);
 | 
			
		||||
            let e1 = Unkn(u1);
 | 
			
		||||
            let e2 = Const(1.);
 | 
			
		||||
@ -563,9 +819,9 @@ mod solve {
 | 
			
		||||
            let eqn = Eqn(e2.clone(), e1.clone());
 | 
			
		||||
            assert_eq!(eqn.solve(u1), Some(Const(1.)));
 | 
			
		||||
 | 
			
		||||
            let e3 = Expr::new_plus(Const(1.), Const(1.));
 | 
			
		||||
            let e3 = Expr::new_sum(Const(1.), Expr::new_sum(Const(1.), Const(2.)));
 | 
			
		||||
            let eqn = Eqn(e1.clone(), e3.clone());
 | 
			
		||||
            assert_eq!(eqn.solve(u1), Some(Const(2.)));
 | 
			
		||||
            assert_eq!(eqn.solve(u1), Some(Const(4.)));
 | 
			
		||||
            let e3 = Expr::new_minus(Const(1.), Const(1.));
 | 
			
		||||
            let eqn = Eqn(e1.clone(), e3.clone());
 | 
			
		||||
            assert_eq!(eqn.solve(u1), Some(Const(0.)));
 | 
			
		||||
@ -573,30 +829,74 @@ mod solve {
 | 
			
		||||
            let e1 = Expr::new_div(Const(2.), Expr::new_minus(Const(1.), Const(4.)));
 | 
			
		||||
            let e2 = Expr::new_minus(Const(1.), Unkn(u1));
 | 
			
		||||
            let eqn = Eqn(e1, e2);
 | 
			
		||||
            info!("eqn: {} => {}", eqn, eqn.clone().simplify());
 | 
			
		||||
            let e = eqn.solve(u1).unwrap();
 | 
			
		||||
            assert!(const_expr(e.clone()).is_some());
 | 
			
		||||
            assert!(relative_eq!(const_expr(e.clone()).unwrap(), 5. / 3.));
 | 
			
		||||
 | 
			
		||||
            let e1 = Expr::new_times(Const(2.), Expr::new_minus(Const(1.), Const(4.)));
 | 
			
		||||
            let e2 = Expr::new_minus(Expr::new_times(Unkn(u1), Const(2.)), Unkn(u1));
 | 
			
		||||
            println!(
 | 
			
		||||
            let e1 = Expr::new_product(Const(2.), Expr::new_minus(Const(1.), Const(4.)));
 | 
			
		||||
            let e2 = Expr::new_minus(Expr::new_product(Unkn(u1), Const(2.)), Unkn(u1));
 | 
			
		||||
            info!(
 | 
			
		||||
                "e1==e2: {}=={} => {}=={}",
 | 
			
		||||
                e1,
 | 
			
		||||
                e2,
 | 
			
		||||
                e1.clone().simplify(),
 | 
			
		||||
                e2.clone().simplify()
 | 
			
		||||
            );
 | 
			
		||||
            println!(
 | 
			
		||||
                "e1==e2: {}=={} => {}=={}",
 | 
			
		||||
                e1,
 | 
			
		||||
                e2,
 | 
			
		||||
                e1.clone().distrubute(),
 | 
			
		||||
                e2.clone().distrubute()
 | 
			
		||||
            );
 | 
			
		||||
            let eqn = Eqn(e1, e2);
 | 
			
		||||
            let e = eqn.solve(u1).unwrap();
 | 
			
		||||
            assert!(const_expr(e.clone()).is_some());
 | 
			
		||||
            assert!(relative_eq!(const_expr(e.clone()).unwrap(), -6.));
 | 
			
		||||
 | 
			
		||||
            let e1 = Expr::new_product(Const(2.), Expr::new_minus(Const(1.), Const(4.)));
 | 
			
		||||
            let e2 = Expr::new_div(
 | 
			
		||||
                Expr::new_sum(
 | 
			
		||||
                    Expr::new_product(Unkn(u1), Const(2.)),
 | 
			
		||||
                    Expr::new_product(Unkn(u1), Unkn(u1)),
 | 
			
		||||
                ),
 | 
			
		||||
                Unkn(u1),
 | 
			
		||||
            );
 | 
			
		||||
            info!(
 | 
			
		||||
                "{}=={} distrib=> {}=={}",
 | 
			
		||||
                e1,
 | 
			
		||||
                e2,
 | 
			
		||||
                e1.clone().distribute(),
 | 
			
		||||
                e2.clone().distribute()
 | 
			
		||||
            );
 | 
			
		||||
            info!(
 | 
			
		||||
                "{}=={} simplify=> {}=={}",
 | 
			
		||||
                e1,
 | 
			
		||||
                e2,
 | 
			
		||||
                e1.clone().distribute().simplify(),
 | 
			
		||||
                e2.clone().distribute().simplify()
 | 
			
		||||
            );
 | 
			
		||||
            let eqn = Eqn(e1, e2);
 | 
			
		||||
            let e = eqn.solve(u1).unwrap();
 | 
			
		||||
            assert!(const_expr(e.clone()).is_some());
 | 
			
		||||
            assert!(relative_eq!(const_expr(e.clone()).unwrap(), -8.));
 | 
			
		||||
 | 
			
		||||
            let e1 = Expr::new_product(Const(2.), Expr::new_minus(Const(1.), Const(4.)));
 | 
			
		||||
            let e2 = Expr::new_div(
 | 
			
		||||
                Expr::new_sum(
 | 
			
		||||
                    Expr::new_product(Unkn(u1), Const(2.)),
 | 
			
		||||
                    Expr::new_sum(
 | 
			
		||||
                        Expr::new_sum(Expr::new_product(Unkn(u1), Unkn(u1)), Unkn(u1)),
 | 
			
		||||
                        Expr::new_minus(Const(2.), Const(1. + 1.)),
 | 
			
		||||
                    ),
 | 
			
		||||
                ),
 | 
			
		||||
                Unkn(u1),
 | 
			
		||||
            );
 | 
			
		||||
            info!(
 | 
			
		||||
                "e1==e2: {}=={} => {}=={}",
 | 
			
		||||
                e1,
 | 
			
		||||
                e2,
 | 
			
		||||
                e1.clone().distribute().simplify(),
 | 
			
		||||
                e2.clone().distribute().simplify().simplify()
 | 
			
		||||
            );
 | 
			
		||||
            let eqn = Eqn(e1, e2);
 | 
			
		||||
            let e = eqn.solve(u1).unwrap();
 | 
			
		||||
            assert!(const_expr(e.clone()).is_some());
 | 
			
		||||
            assert!(relative_eq!(const_expr(e.clone()).unwrap(), -9.));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user