Copie figée du cœur de GNU Backgammon (commit 14b6798)
Fichiers repris sans modification dans engine/gnubg/, poids et table d'équité Kazaross-XG2 dans engine/data/, provenance détaillée dans engine/gnubg/PROVENANCE.md. Le lint ne vérifie plus les espaces de ces copies, pour qu'elles restent identiques à l'original. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d0f44b689b
commit
792f6395bf
@@ -0,0 +1,765 @@
|
||||
<?xml version = "1.0"?>
|
||||
<!DOCTYPE met PUBLIC "-//GNU Backgammon//DTD Match Equity Tables//EN"
|
||||
"met.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
Copyright (C) 2011 Neil Kazaross
|
||||
|
||||
Table rolled up to 9 point match by eXtreme Gammon. Then uses
|
||||
R/K MET which was rolled up to 15 and extrapolated to 25 points
|
||||
|
||||
Transcribed for use by GNUbg by Michael Petch <mpetch@capp-sysware.com>
|
||||
|
||||
This file is distributed as a part of the GNU Backgammon program.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without any warranty.
|
||||
|
||||
-->
|
||||
|
||||
<met>
|
||||
<info>
|
||||
<name>Kazaross XG2 25 point MET</name>
|
||||
<description>Generated using XG rollouts to 9pts, GNUbg 0.90 2-ply full rollouts to 15 points. Extended to 25pts by projecting take points.</description>
|
||||
<length>25</length>
|
||||
</info>
|
||||
|
||||
<pre-crawford-table type="explicit">
|
||||
<row>
|
||||
<me>0.50000</me>
|
||||
<me>0.67736</me>
|
||||
<me>0.75076</me>
|
||||
<me>0.81436</me>
|
||||
<me>0.84179</me>
|
||||
<me>0.88731</me>
|
||||
<me>0.90724</me>
|
||||
<me>0.93250</me>
|
||||
<me>0.94402</me>
|
||||
<me>0.959275</me>
|
||||
<me>0.966442</me>
|
||||
<me>0.975534</me>
|
||||
<me>0.979845</me>
|
||||
<me>0.985273</me>
|
||||
<me>0.987893</me>
|
||||
<me>0.99114</me>
|
||||
<me>0.99273</me>
|
||||
<me>0.99467</me>
|
||||
<me>0.99563</me>
|
||||
<me>0.99679</me>
|
||||
<me>0.99737</me>
|
||||
<me>0.99807</me>
|
||||
<me>0.99842</me>
|
||||
<me>0.99884</me>
|
||||
<me>0.99905</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.32264</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.59947</me>
|
||||
<me>0.66870</me>
|
||||
<me>0.74359</me>
|
||||
<me>0.79940</me>
|
||||
<me>0.84225</me>
|
||||
<me>0.87539</me>
|
||||
<me>0.90197</me>
|
||||
<me>0.923034</me>
|
||||
<me>0.939311</me>
|
||||
<me>0.952470</me>
|
||||
<me>0.962495</me>
|
||||
<me>0.970701</me>
|
||||
<me>0.976887</me>
|
||||
<me>0.98196</me>
|
||||
<me>0.98580</me>
|
||||
<me>0.98893</me>
|
||||
<me>0.99129</me>
|
||||
<me>0.99322</me>
|
||||
<me>0.99466</me>
|
||||
<me>0.99585</me>
|
||||
<me>0.99675</me>
|
||||
<me>0.99746</me>
|
||||
<me>0.99802</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.24924</me>
|
||||
<me>0.40053</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.57150</me>
|
||||
<me>0.64795</me>
|
||||
<me>0.71123</me>
|
||||
<me>0.76209</me>
|
||||
<me>0.80468</me>
|
||||
<me>0.84017</me>
|
||||
<me>0.870638</me>
|
||||
<me>0.894417</me>
|
||||
<me>0.914831</me>
|
||||
<me>0.930702</me>
|
||||
<me>0.944426</me>
|
||||
<me>0.954931</me>
|
||||
<me>0.96399</me>
|
||||
<me>0.97093</me>
|
||||
<me>0.97687</me>
|
||||
<me>0.98139</me>
|
||||
<me>0.98522</me>
|
||||
<me>0.98814</me>
|
||||
<me>0.99062</me>
|
||||
<me>0.99248</me>
|
||||
<me>0.99407</me>
|
||||
<me>0.99527</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.18564</me>
|
||||
<me>0.33130</me>
|
||||
<me>0.42850</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.57732</me>
|
||||
<me>0.64285</me>
|
||||
<me>0.69924</me>
|
||||
<me>0.74577</me>
|
||||
<me>0.78799</me>
|
||||
<me>0.824059</me>
|
||||
<me>0.853955</me>
|
||||
<me>0.879141</me>
|
||||
<me>0.900233</me>
|
||||
<me>0.918040</me>
|
||||
<me>0.932657</me>
|
||||
<me>0.94495</me>
|
||||
<me>0.95499</me>
|
||||
<me>0.96341</me>
|
||||
<me>0.97021</me>
|
||||
<me>0.97589</me>
|
||||
<me>0.98044</me>
|
||||
<me>0.98422</me>
|
||||
<me>0.98726</me>
|
||||
<me>0.98975</me>
|
||||
<me>0.99174</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.15821</me>
|
||||
<me>0.25641</me>
|
||||
<me>0.35205</me>
|
||||
<me>0.42268</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.56635</me>
|
||||
<me>0.62638</me>
|
||||
<me>0.67786</me>
|
||||
<me>0.72540</me>
|
||||
<me>0.767055</me>
|
||||
<me>0.802732</me>
|
||||
<me>0.833654</me>
|
||||
<me>0.859934</me>
|
||||
<me>0.882866</me>
|
||||
<me>0.902013</me>
|
||||
<me>0.91847</me>
|
||||
<me>0.93223</me>
|
||||
<me>0.94397</me>
|
||||
<me>0.95367</me>
|
||||
<me>0.96189</me>
|
||||
<me>0.96864</me>
|
||||
<me>0.97432</me>
|
||||
<me>0.97896</me>
|
||||
<me>0.98283</me>
|
||||
<me>0.98600</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.11269</me>
|
||||
<me>0.20060</me>
|
||||
<me>0.28877</me>
|
||||
<me>0.35715</me>
|
||||
<me>0.43365</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.56261</me>
|
||||
<me>0.61636</me>
|
||||
<me>0.66787</me>
|
||||
<me>0.713057</me>
|
||||
<me>0.753427</me>
|
||||
<me>0.788634</me>
|
||||
<me>0.819569</me>
|
||||
<me>0.846648</me>
|
||||
<me>0.869999</me>
|
||||
<me>0.89021</me>
|
||||
<me>0.90756</me>
|
||||
<me>0.92246</me>
|
||||
<me>0.93508</me>
|
||||
<me>0.94583</me>
|
||||
<me>0.95488</me>
|
||||
<me>0.96254</me>
|
||||
<me>0.96894</me>
|
||||
<me>0.97432</me>
|
||||
<me>0.97879</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.09276</me>
|
||||
<me>0.15775</me>
|
||||
<me>0.23791</me>
|
||||
<me>0.30076</me>
|
||||
<me>0.37362</me>
|
||||
<me>0.43739</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.55480</me>
|
||||
<me>0.60854</me>
|
||||
<me>0.656283</me>
|
||||
<me>0.700209</me>
|
||||
<me>0.739054</me>
|
||||
<me>0.774121</me>
|
||||
<me>0.805203</me>
|
||||
<me>0.832566</me>
|
||||
<me>0.85659</me>
|
||||
<me>0.87761</me>
|
||||
<me>0.89591</me>
|
||||
<me>0.91171</me>
|
||||
<me>0.92535</me>
|
||||
<me>0.93702</me>
|
||||
<me>0.94703</me>
|
||||
<me>0.95553</me>
|
||||
<me>0.96276</me>
|
||||
<me>0.96887</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.06750</me>
|
||||
<me>0.12461</me>
|
||||
<me>0.19532</me>
|
||||
<me>0.25423</me>
|
||||
<me>0.32214</me>
|
||||
<me>0.38364</me>
|
||||
<me>0.44520</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.55442</me>
|
||||
<me>0.603718</me>
|
||||
<me>0.649899</me>
|
||||
<me>0.691356</me>
|
||||
<me>0.729447</me>
|
||||
<me>0.763593</me>
|
||||
<me>0.794397</me>
|
||||
<me>0.82158</me>
|
||||
<me>0.84578</me>
|
||||
<me>0.86714</me>
|
||||
<me>0.88589</me>
|
||||
<me>0.90230</me>
|
||||
<me>0.91658</me>
|
||||
<me>0.92898</me>
|
||||
<me>0.93968</me>
|
||||
<me>0.94891</me>
|
||||
<me>0.95682</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.05598</me>
|
||||
<me>0.09803</me>
|
||||
<me>0.15983</me>
|
||||
<me>0.21201</me>
|
||||
<me>0.27460</me>
|
||||
<me>0.33213</me>
|
||||
<me>0.39146</me>
|
||||
<me>0.44558</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.550196</me>
|
||||
<me>0.597926</me>
|
||||
<me>0.641481</me>
|
||||
<me>0.682119</me>
|
||||
<me>0.718927</me>
|
||||
<me>0.752814</me>
|
||||
<me>0.78301</me>
|
||||
<me>0.81037</me>
|
||||
<me>0.83483</me>
|
||||
<me>0.85662</me>
|
||||
<me>0.87591</me>
|
||||
<me>0.89294</me>
|
||||
<me>0.90791</me>
|
||||
<me>0.92098</me>
|
||||
<me>0.93240</me>
|
||||
<me>0.94230</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.040725</me>
|
||||
<me>0.076966</me>
|
||||
<me>0.129362</me>
|
||||
<me>0.175941</me>
|
||||
<me>0.232945</me>
|
||||
<me>0.286943</me>
|
||||
<me>0.343717</me>
|
||||
<me>0.396282</me>
|
||||
<me>0.449804</me>
|
||||
<me>0.500000</me>
|
||||
<me>0.548547</me>
|
||||
<me>0.593459</me>
|
||||
<me>0.635880</me>
|
||||
<me>0.674830</me>
|
||||
<me>0.711113</me>
|
||||
<me>0.74371</me>
|
||||
<me>0.77375</me>
|
||||
<me>0.80093</me>
|
||||
<me>0.82543</me>
|
||||
<me>0.84741</me>
|
||||
<me>0.86703</me>
|
||||
<me>0.88448</me>
|
||||
<me>0.89991</me>
|
||||
<me>0.91353</me>
|
||||
<me>0.92550</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.033558</me>
|
||||
<me>0.060689</me>
|
||||
<me>0.105583</me>
|
||||
<me>0.146045</me>
|
||||
<me>0.197268</me>
|
||||
<me>0.246573</me>
|
||||
<me>0.299791</me>
|
||||
<me>0.350101</me>
|
||||
<me>0.402074</me>
|
||||
<me>0.451453</me>
|
||||
<me>0.500000</me>
|
||||
<me>0.545552</me>
|
||||
<me>0.589242</me>
|
||||
<me>0.629736</me>
|
||||
<me>0.667927</me>
|
||||
<me>0.70303</me>
|
||||
<me>0.73530</me>
|
||||
<me>0.76494</me>
|
||||
<me>0.79198</me>
|
||||
<me>0.81648</me>
|
||||
<me>0.83862</me>
|
||||
<me>0.85849</me>
|
||||
<me>0.87629</me>
|
||||
<me>0.89214</me>
|
||||
<me>0.90622</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.024466</me>
|
||||
<me>0.047530</me>
|
||||
<me>0.085169</me>
|
||||
<me>0.120859</me>
|
||||
<me>0.166346</me>
|
||||
<me>0.211366</me>
|
||||
<me>0.260946</me>
|
||||
<me>0.308644</me>
|
||||
<me>0.358519</me>
|
||||
<me>0.406541</me>
|
||||
<me>0.454448</me>
|
||||
<me>0.500000</me>
|
||||
<me>0.544068</me>
|
||||
<me>0.585701</me>
|
||||
<me>0.625259</me>
|
||||
<me>0.66178</me>
|
||||
<me>0.69610</me>
|
||||
<me>0.72778</me>
|
||||
<me>0.75703</me>
|
||||
<me>0.78381</me>
|
||||
<me>0.80826</me>
|
||||
<me>0.83044</me>
|
||||
<me>0.85051</me>
|
||||
<me>0.86856</me>
|
||||
<me>0.88476</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.020155</me>
|
||||
<me>0.037505</me>
|
||||
<me>0.069298</me>
|
||||
<me>0.099767</me>
|
||||
<me>0.140066</me>
|
||||
<me>0.180431</me>
|
||||
<me>0.225879</me>
|
||||
<me>0.270553</me>
|
||||
<me>0.317881</me>
|
||||
<me>0.364120</me>
|
||||
<me>0.410758</me>
|
||||
<me>0.455932</me>
|
||||
<me>0.500000</me>
|
||||
<me>0.541943</me>
|
||||
<me>0.582545</me>
|
||||
<me>0.62036</me>
|
||||
<me>0.65619</me>
|
||||
<me>0.68966</me>
|
||||
<me>0.72081</me>
|
||||
<me>0.74963</me>
|
||||
<me>0.77619</me>
|
||||
<me>0.80054</me>
|
||||
<me>0.82276</me>
|
||||
<me>0.84295</me>
|
||||
<me>0.86123</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.014727</me>
|
||||
<me>0.029299</me>
|
||||
<me>0.055574</me>
|
||||
<me>0.081960</me>
|
||||
<me>0.117134</me>
|
||||
<me>0.153352</me>
|
||||
<me>0.194797</me>
|
||||
<me>0.236407</me>
|
||||
<me>0.281073</me>
|
||||
<me>0.325170</me>
|
||||
<me>0.370264</me>
|
||||
<me>0.414299</me>
|
||||
<me>0.458057</me>
|
||||
<me>0.500000</me>
|
||||
<me>0.540750</me>
|
||||
<me>0.57942</me>
|
||||
<me>0.61634</me>
|
||||
<me>0.65117</me>
|
||||
<me>0.68391</me>
|
||||
<me>0.71448</me>
|
||||
<me>0.74290</me>
|
||||
<me>0.76917</me>
|
||||
<me>0.79339</me>
|
||||
<me>0.81559</me>
|
||||
<me>0.83586</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.012107</me>
|
||||
<me>0.023113</me>
|
||||
<me>0.045069</me>
|
||||
<me>0.067343</me>
|
||||
<me>0.097987</me>
|
||||
<me>0.130001</me>
|
||||
<me>0.167434</me>
|
||||
<me>0.205603</me>
|
||||
<me>0.247186</me>
|
||||
<me>0.288887</me>
|
||||
<me>0.332073</me>
|
||||
<me>0.374741</me>
|
||||
<me>0.417455</me>
|
||||
<me>0.459250</me>
|
||||
<me>0.500000</me>
|
||||
<me>0.53916</me>
|
||||
<me>0.57679</me>
|
||||
<me>0.61261</me>
|
||||
<me>0.64659</me>
|
||||
<me>0.67859</me>
|
||||
<me>0.70862</me>
|
||||
<me>0.73664</me>
|
||||
<me>0.76265</me>
|
||||
<me>0.78669</me>
|
||||
<me>0.80883</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00886</me>
|
||||
<me>0.01804</me>
|
||||
<me>0.03601</me>
|
||||
<me>0.05505</me>
|
||||
<me>0.08153</me>
|
||||
<me>0.10979</me>
|
||||
<me>0.14341</me>
|
||||
<me>0.17842</me>
|
||||
<me>0.21699</me>
|
||||
<me>0.25629</me>
|
||||
<me>0.29697</me>
|
||||
<me>0.33822</me>
|
||||
<me>0.37964</me>
|
||||
<me>0.42058</me>
|
||||
<me>0.46084</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53796</me>
|
||||
<me>0.57441</me>
|
||||
<me>0.60929</me>
|
||||
<me>0.64241</me>
|
||||
<me>0.67376</me>
|
||||
<me>0.70323</me>
|
||||
<me>0.73084</me>
|
||||
<me>0.75657</me>
|
||||
<me>0.78046</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00727</me>
|
||||
<me>0.01420</me>
|
||||
<me>0.02907</me>
|
||||
<me>0.04501</me>
|
||||
<me>0.06777</me>
|
||||
<me>0.09244</me>
|
||||
<me>0.12239</me>
|
||||
<me>0.15422</me>
|
||||
<me>0.18963</me>
|
||||
<me>0.22625</me>
|
||||
<me>0.26470</me>
|
||||
<me>0.30390</me>
|
||||
<me>0.34381</me>
|
||||
<me>0.38366</me>
|
||||
<me>0.42321</me>
|
||||
<me>0.46204</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53676</me>
|
||||
<me>0.57222</me>
|
||||
<me>0.60618</me>
|
||||
<me>0.63856</me>
|
||||
<me>0.66925</me>
|
||||
<me>0.69822</me>
|
||||
<me>0.72542</me>
|
||||
<me>0.75087</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00533</me>
|
||||
<me>0.01107</me>
|
||||
<me>0.02313</me>
|
||||
<me>0.03659</me>
|
||||
<me>0.05603</me>
|
||||
<me>0.07754</me>
|
||||
<me>0.10409</me>
|
||||
<me>0.13286</me>
|
||||
<me>0.16517</me>
|
||||
<me>0.19907</me>
|
||||
<me>0.23506</me>
|
||||
<me>0.27222</me>
|
||||
<me>0.31034</me>
|
||||
<me>0.34883</me>
|
||||
<me>0.38739</me>
|
||||
<me>0.42559</me>
|
||||
<me>0.46324</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53574</me>
|
||||
<me>0.57023</me>
|
||||
<me>0.60336</me>
|
||||
<me>0.63501</me>
|
||||
<me>0.66510</me>
|
||||
<me>0.69356</me>
|
||||
<me>0.72038</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00437</me>
|
||||
<me>0.00871</me>
|
||||
<me>0.01861</me>
|
||||
<me>0.02979</me>
|
||||
<me>0.04633</me>
|
||||
<me>0.06492</me>
|
||||
<me>0.08829</me>
|
||||
<me>0.11411</me>
|
||||
<me>0.14338</me>
|
||||
<me>0.17457</me>
|
||||
<me>0.20802</me>
|
||||
<me>0.24297</me>
|
||||
<me>0.27919</me>
|
||||
<me>0.31609</me>
|
||||
<me>0.35341</me>
|
||||
<me>0.39071</me>
|
||||
<me>0.42778</me>
|
||||
<me>0.46426</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53475</me>
|
||||
<me>0.56838</me>
|
||||
<me>0.60073</me>
|
||||
<me>0.63171</me>
|
||||
<me>0.66122</me>
|
||||
<me>0.68921</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00321</me>
|
||||
<me>0.00678</me>
|
||||
<me>0.01478</me>
|
||||
<me>0.02411</me>
|
||||
<me>0.03811</me>
|
||||
<me>0.05417</me>
|
||||
<me>0.07465</me>
|
||||
<me>0.09770</me>
|
||||
<me>0.12409</me>
|
||||
<me>0.15259</me>
|
||||
<me>0.18352</me>
|
||||
<me>0.21619</me>
|
||||
<me>0.25037</me>
|
||||
<me>0.28552</me>
|
||||
<me>0.32141</me>
|
||||
<me>0.35759</me>
|
||||
<me>0.39382</me>
|
||||
<me>0.42977</me>
|
||||
<me>0.46525</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53387</me>
|
||||
<me>0.56667</me>
|
||||
<me>0.59830</me>
|
||||
<me>0.62864</me>
|
||||
<me>0.65760</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00263</me>
|
||||
<me>0.00534</me>
|
||||
<me>0.01186</me>
|
||||
<me>0.01956</me>
|
||||
<me>0.03136</me>
|
||||
<me>0.04512</me>
|
||||
<me>0.06298</me>
|
||||
<me>0.08342</me>
|
||||
<me>0.10706</me>
|
||||
<me>0.13297</me>
|
||||
<me>0.16138</me>
|
||||
<me>0.19174</me>
|
||||
<me>0.22381</me>
|
||||
<me>0.25710</me>
|
||||
<me>0.29138</me>
|
||||
<me>0.32624</me>
|
||||
<me>0.36144</me>
|
||||
<me>0.39664</me>
|
||||
<me>0.43162</me>
|
||||
<me>0.46613</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53303</me>
|
||||
<me>0.56508</me>
|
||||
<me>0.59603</me>
|
||||
<me>0.62576</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00193</me>
|
||||
<me>0.00415</me>
|
||||
<me>0.00938</me>
|
||||
<me>0.01578</me>
|
||||
<me>0.02568</me>
|
||||
<me>0.03746</me>
|
||||
<me>0.05297</me>
|
||||
<me>0.07102</me>
|
||||
<me>0.09209</me>
|
||||
<me>0.11552</me>
|
||||
<me>0.14151</me>
|
||||
<me>0.16956</me>
|
||||
<me>0.19946</me>
|
||||
<me>0.23083</me>
|
||||
<me>0.26336</me>
|
||||
<me>0.29677</me>
|
||||
<me>0.33075</me>
|
||||
<me>0.36499</me>
|
||||
<me>0.39927</me>
|
||||
<me>0.43333</me>
|
||||
<me>0.46697</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53226</me>
|
||||
<me>0.56360</me>
|
||||
<me>0.59391</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00158</me>
|
||||
<me>0.00325</me>
|
||||
<me>0.00752</me>
|
||||
<me>0.01274</me>
|
||||
<me>0.02104</me>
|
||||
<me>0.03106</me>
|
||||
<me>0.04447</me>
|
||||
<me>0.06032</me>
|
||||
<me>0.07902</me>
|
||||
<me>0.10009</me>
|
||||
<me>0.12371</me>
|
||||
<me>0.14949</me>
|
||||
<me>0.17724</me>
|
||||
<me>0.20661</me>
|
||||
<me>0.23735</me>
|
||||
<me>0.26916</me>
|
||||
<me>0.30178</me>
|
||||
<me>0.33490</me>
|
||||
<me>0.36829</me>
|
||||
<me>0.40170</me>
|
||||
<me>0.43492</me>
|
||||
<me>0.46774</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53153</me>
|
||||
<me>0.56221</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00116</me>
|
||||
<me>0.00254</me>
|
||||
<me>0.00593</me>
|
||||
<me>0.01025</me>
|
||||
<me>0.01717</me>
|
||||
<me>0.02568</me>
|
||||
<me>0.03724</me>
|
||||
<me>0.05109</me>
|
||||
<me>0.06760</me>
|
||||
<me>0.08647</me>
|
||||
<me>0.10786</me>
|
||||
<me>0.13144</me>
|
||||
<me>0.15705</me>
|
||||
<me>0.18441</me>
|
||||
<me>0.21331</me>
|
||||
<me>0.24343</me>
|
||||
<me>0.27458</me>
|
||||
<me>0.30644</me>
|
||||
<me>0.33878</me>
|
||||
<me>0.37136</me>
|
||||
<me>0.40397</me>
|
||||
<me>0.43640</me>
|
||||
<me>0.46847</me>
|
||||
<me>0.50000</me>
|
||||
<me>0.53086</me>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<me>0.00095</me>
|
||||
<me>0.00198</me>
|
||||
<me>0.00473</me>
|
||||
<me>0.00826</me>
|
||||
<me>0.01400</me>
|
||||
<me>0.02121</me>
|
||||
<me>0.03113</me>
|
||||
<me>0.04318</me>
|
||||
<me>0.05770</me>
|
||||
<me>0.07450</me>
|
||||
<me>0.09378</me>
|
||||
<me>0.11524</me>
|
||||
<me>0.13877</me>
|
||||
<me>0.16414</me>
|
||||
<me>0.19117</me>
|
||||
<me>0.21954</me>
|
||||
<me>0.24913</me>
|
||||
<me>0.27962</me>
|
||||
<me>0.31079</me>
|
||||
<me>0.34240</me>
|
||||
<me>0.37424</me>
|
||||
<me>0.40609</me>
|
||||
<me>0.43779</me>
|
||||
<me>0.46914</me>
|
||||
<me>0.50000</me>
|
||||
</row>
|
||||
|
||||
</pre-crawford-table>
|
||||
|
||||
<post-crawford-table type="explicit" player="both">
|
||||
<row>
|
||||
<me>0.500000</me>
|
||||
<me>0.48803</me>
|
||||
<me>0.32264</me>
|
||||
<me>0.31002</me>
|
||||
<me>0.19012</me>
|
||||
<me>0.18072</me>
|
||||
<me>0.11559</me>
|
||||
<me>0.10906</me>
|
||||
<me>0.06953</me>
|
||||
<me>0.065161</me>
|
||||
<me>0.042069</me>
|
||||
<me>0.039060</me>
|
||||
<me>0.025371</me>
|
||||
<me>0.023428</me>
|
||||
<me>0.015304</me>
|
||||
<me>0.014050</me>
|
||||
<me>0.009240</me>
|
||||
<me>0.008420</me>
|
||||
<me>0.005560</me>
|
||||
<me>0.005050</me>
|
||||
<me>0.003360</me>
|
||||
<me>0.003030</me>
|
||||
<me>0.002030</me>
|
||||
<me>0.001820</me>
|
||||
<me>0.001230</me>
|
||||
</row>
|
||||
|
||||
</post-crawford-table>
|
||||
|
||||
</met>
|
||||
|
||||
+101973
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Provenance de la copie de GNU Backgammon
|
||||
|
||||
Les fichiers de ce dossier sont copiés de GNU Backgammon
|
||||
(https://git.savannah.gnu.org/cgit/gnubg.git), commit
|
||||
`14b67984737ded0f6de43d63dcb789f729d9b06b` (version 1.08.003, 2026-10-23),
|
||||
choisi par l'ADR 0005. Licence : GPLv3 ou ultérieure (`COPYING`). Les
|
||||
en-têtes de copyright sont conservés.
|
||||
|
||||
**Aucun fichier n'est modifié** : chacun est identique octet pour octet à
|
||||
l'original. Vérification, depuis un clone de gnubg à ce commit :
|
||||
|
||||
```sh
|
||||
for f in $(cd engine/gnubg && find . -type f ! -name PROVENANCE.md); do
|
||||
cmp "engine/gnubg/$f" "chemin/du/clone/gnubg/$f" || echo "différent : $f"
|
||||
done
|
||||
```
|
||||
|
||||
Les espaces en fin de ligne de l'original sont gardés ; `tests/lint.sh`
|
||||
exclut donc ce dossier (et `engine/data/`) de cette vérification.
|
||||
|
||||
## Fichiers repris
|
||||
|
||||
Compilés dans le moteur embarqué (`build/libengine.a`) :
|
||||
|
||||
| Fichier | Rôle |
|
||||
| --- | --- |
|
||||
| `eval.c`, `eval.h`, `movefilters.inc` | Évaluation, génération et classement des coups, videau |
|
||||
| `positionid.c`, `positionid.h` | Position ID |
|
||||
| `matchid.c`, `matchid.h` | Match ID |
|
||||
| `matchequity.c`, `matchequity.h`, `mec.c`, `mec.h` | Tables d'équité de match |
|
||||
| `bearoff.c`, `bearoff.h`, `bearoffgammon.c`, `bearoffgammon.h` | Bases de fin de partie |
|
||||
| `drawboard.c`, `drawboard.h` | Notation des coups (`FormatMove`) |
|
||||
| `mtsupport.c` | Données du fil d'exécution unique (branche sans threads) |
|
||||
| `lib/neuralnet.c`, `lib/neuralnet.h`, `lib/neuralnetsse.c`, `lib/inputs.c`, `lib/simd.h`, `lib/sigmoid.h` | Réseaux de neurones |
|
||||
| `lib/cache.c`, `lib/cache.h` | Cache d'évaluations |
|
||||
| `lib/isaac.c`, `lib/isaac.h`, `lib/isaacs.h`, `lib/md5.c`, `lib/md5.h` | Hasards (bruit, désactivé ici) et hachage |
|
||||
| `lib/list.c`, `lib/list.h` | Listes (tables d'équité) |
|
||||
| `lib/gnubg-types.h`, `common.h`, `dice.h` | Types et définitions communes |
|
||||
|
||||
Compilés seulement pour générer les données au build (`build/host/`), avec
|
||||
la vraie GLib, comme dans le build officiel :
|
||||
|
||||
| Fichier | Rôle |
|
||||
| --- | --- |
|
||||
| `makeweights.c` | `gnubg.weights` → `gnubg.wd` (réseaux en binaire) |
|
||||
| `makebearoff.c` | Bases `gnubg_os0.bd` et `gnubg_ts0.bd` |
|
||||
|
||||
Données, dans `engine/data/` (non modifiées non plus) : `gnubg.weights`
|
||||
(racine du dépôt gnubg) et `Kazaross-XG2.xml` (`met/`), la table d'équité
|
||||
de match par défaut de gnubg de bureau.
|
||||
|
||||
## Ce qui remplace le reste de gnubg
|
||||
|
||||
Les fichiers de gnubg non repris sont remplacés par des fichiers propres à
|
||||
Ustagammon, dans `engine/compat/`, trouvés en premier par le compilateur :
|
||||
|
||||
| Fichier | Remplace |
|
||||
| --- | --- |
|
||||
| `config.h` | Le `config.h` produit par `configure` (sans threads, C générique, NEON prévu) |
|
||||
| `glib-shim/glib.h`, `glib-shim/glib/*.h`, `glib-shim.c` | GLib, pour le moteur embarqué seulement |
|
||||
| `backgammon.h`, `output.h`, `util.h`, `format.h`, `multithread.h`, `external.h` | En-têtes réduits aux déclarations utilisées par le cœur |
|
||||
| `gnubg-support.c` | Fonctions et variables de `gnubg.c`, `output.c`, `util.c`, `multithread.c` utilisées par le cœur |
|
||||
| `host-tools-support.c` | `GetTemporaryFile` de `util.c`, pour `makebearoff` |
|
||||
|
||||
La liste des symboles à fournir a été établie à l'édition des liens. Le
|
||||
fichier `jni-bridge/src/stubs.c` de CBG (https://github.com/clavierhaus/gnubg-android,
|
||||
GPLv3) a servi de point de repère, sans reprise de code.
|
||||
|
||||
## Mettre à jour la copie
|
||||
|
||||
Copier les mêmes fichiers depuis le nouveau commit, mettre à jour le commit
|
||||
ci-dessus, puis `make engine` et `make test`. Une erreur de compilation ou
|
||||
d'édition des liens indique un symbole à ajouter dans `engine/compat/`.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Joern Thyssen <jthyssen@dk.ibm.com>
|
||||
* Copyright (C) 2003-2018 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BEAROFF_H
|
||||
#define BEAROFF_H
|
||||
|
||||
#include "gnubg-types.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef enum {
|
||||
BEAROFF_INVALID,
|
||||
BEAROFF_ONESIDED,
|
||||
BEAROFF_TWOSIDED,
|
||||
BEAROFF_HYPERGAMMON
|
||||
} bearofftype;
|
||||
|
||||
typedef struct {
|
||||
bearofftype bt; /* type of bearoff database */
|
||||
unsigned int nPoints; /* number of points covered by database */
|
||||
unsigned int nChequers; /* number of chequers for one-sided database */
|
||||
/* one sided dbs */
|
||||
int fCompressed; /* is database compressed? */
|
||||
int fGammon; /* gammon probs included */
|
||||
int fND; /* normal distribution instead of exact dist? */
|
||||
int fHeuristic; /* heuristic database? */
|
||||
/* two sided dbs */
|
||||
int fCubeful; /* cubeful equities included */
|
||||
FILE *pf; /* file pointer */
|
||||
char *szFilename; /* filename */
|
||||
GMappedFile *map;
|
||||
unsigned char *p; /* pointer to data in memory */
|
||||
} bearoffcontext;
|
||||
|
||||
enum bearoffoptions {
|
||||
BO_NONE = 0,
|
||||
BO_IN_MEMORY = 1,
|
||||
BO_MUST_BE_ONE_SIDED = 2,
|
||||
BO_MUST_BE_TWO_SIDED = 4,
|
||||
BO_HEURISTIC = 8
|
||||
};
|
||||
|
||||
extern bearoffcontext *BearoffInit(const char *szFilename, unsigned int bo, void (*p) (unsigned int));
|
||||
|
||||
extern int
|
||||
BearoffEval(const bearoffcontext * pbc, const TanBoard anBoard, float arOutput[]);
|
||||
|
||||
extern void
|
||||
BearoffStatus(const bearoffcontext * pbc, char *sz);
|
||||
|
||||
extern int
|
||||
BearoffDump(const bearoffcontext * pbc, const TanBoard anBoard, char *sz);
|
||||
|
||||
extern int
|
||||
BearoffDist(const bearoffcontext * pbc, unsigned int nPosID,
|
||||
float arProb[32], float arGammonProb[32],
|
||||
float ar[4], unsigned short int ausProb[32], unsigned short int ausGammonProb[32]);
|
||||
|
||||
extern int
|
||||
BearoffCubeful(const bearoffcontext * pbc, unsigned int iPos, float ar[4], unsigned short int aus[4]);
|
||||
|
||||
extern void BearoffClose(bearoffcontext * pbc);
|
||||
|
||||
extern int
|
||||
isBearoff(const bearoffcontext * pbc, const TanBoard anBoard);
|
||||
|
||||
extern float fnd(float x, float mu, float sigma);
|
||||
|
||||
extern int
|
||||
BearoffHyper(const bearoffcontext * pbc, unsigned int iPos, float arOutput[], float arEquity[]);
|
||||
|
||||
#endif /* BEAROFF_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2000-2002 Joseph Heled <joseph@gnubg.org>
|
||||
* Copyright (C) 2006-2008 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: bearoffgammon.h,v 1.12 2018/06/16 14:54:30 plm Exp $
|
||||
*/
|
||||
|
||||
#if !defined( BEAROFFGAMMON_H )
|
||||
#define BEAROFFGAMMON_H
|
||||
|
||||
/* pack for space */
|
||||
struct GammonProbs {
|
||||
unsigned int p1:16; /* 0 - 36^2 */
|
||||
unsigned int p2:16; /* 0 - 36^3 */
|
||||
unsigned int p3:24; /* 0 - 36^4 */
|
||||
unsigned int p0:8; /* 0 - 36 */
|
||||
};
|
||||
|
||||
extern struct GammonProbs *getBearoffGammonProbs(const unsigned int board[6]);
|
||||
|
||||
extern long *getRaceBGprobs(const unsigned int board[6]);
|
||||
|
||||
#define RBG_NPROBS 5
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2009 Jon Kinsey <jonkinsey@gmail.com>
|
||||
* Copyright (C) 2006-2017 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*! \file common.h
|
||||
* \brief Odd definitions
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
#include <math.h>
|
||||
#include "config.h"
|
||||
|
||||
|
||||
#ifndef HAVE___ATTRIBUTE__
|
||||
#define __attribute__(Spec) /* Empty */
|
||||
#endif /* HAVE___ATTRIBUTE__ */
|
||||
|
||||
#define F_PI (float)G_PI
|
||||
#define F_PI_2 (float)G_PI_2
|
||||
|
||||
/*! \brief Safe error value
|
||||
*/
|
||||
#define ERR_VAL (-FLT_MAX)
|
||||
|
||||
/*! \brief Macro to extract sign
|
||||
*/
|
||||
#ifndef SGN
|
||||
#define SGN(x) ((x) > 0 ? 1 : -1)
|
||||
#endif
|
||||
|
||||
/*! \brief typedef of signal handler function
|
||||
*/
|
||||
#if HAVE_SIGACTION
|
||||
typedef struct sigaction psighandler;
|
||||
#elif HAVE_SIGVEC
|
||||
typedef struct sigvec psighandler;
|
||||
#else
|
||||
typedef void (*psighandler) (int);
|
||||
#endif
|
||||
|
||||
/* abs returns unsigned int by definition */
|
||||
#define Abs(a) ((unsigned int)abs(a))
|
||||
|
||||
/* Do we need to use g_utf8_casefold() for utf8 anywhere? */
|
||||
#define StrCaseCmp(s1, s2) g_ascii_strcasecmp(s1, s2)
|
||||
#define StrNCaseCmp(s1, s2, n) g_ascii_strncasecmp(s1, s2, (gsize)n)
|
||||
/* if the following are defined as macros undefine them */
|
||||
#ifdef strcasecmp
|
||||
#undef strcasecmp
|
||||
#endif
|
||||
#ifdef strncasecmp
|
||||
#undef strncasecmp
|
||||
#endif
|
||||
/* Avoid new code using strcase functions */
|
||||
#define strcasecmp strcasecmp_error_use_StrCaseCmp
|
||||
#define strncasecmp strncasecmp_error_use_StrNCaseCmp
|
||||
|
||||
|
||||
/* Macro to mark parameters that aren't used in the function */
|
||||
#ifdef UNUSED
|
||||
#elif defined(HAVE_FUNC_ATTRIBUTE_UNUSED)
|
||||
#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||
#elif defined(_lint)
|
||||
#define UNUSED(x) /*lint -e{715, 818}*/ _unused_##x
|
||||
#else
|
||||
#define UNUSED(x) _unused_##x
|
||||
#endif
|
||||
|
||||
/* Helper macros for __builtin_expect */
|
||||
#ifdef HAVE___BUILTIN_EXPECT
|
||||
#define likely(expression) __builtin_expect(!!(expression), 1)
|
||||
#define unlikely(expression) __builtin_expect(!!(expression), 0)
|
||||
#else
|
||||
#define likely(expression) (expression)
|
||||
#define unlikely(expression) (expression)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 1999-2016 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DICE_H
|
||||
#define DICE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
RNG_BBS, RNG_ISAAC, RNG_MD5, RNG_MERSENNE,
|
||||
RNG_MANUAL, RNG_RANDOM_DOT_ORG, RNG_FILE,
|
||||
NUM_RNGS
|
||||
} rng;
|
||||
|
||||
typedef struct rngcontext rngcontext;
|
||||
|
||||
extern const char *aszRNG[NUM_RNGS];
|
||||
extern const char *aszRNGTip[NUM_RNGS];
|
||||
extern char szDiceFilename[];
|
||||
extern rng rngCurrent;
|
||||
extern rngcontext *rngctxCurrent;
|
||||
|
||||
rngcontext *CopyRNGContext(rngcontext * rngctx);
|
||||
|
||||
extern void free_rngctx(rngcontext * rngctx);
|
||||
extern void *InitRNG(unsigned long *pnSeed, int *pfInitFrom, int fSet, rng rngx);
|
||||
extern void CloseRNG(rng rngx, rngcontext * rngctx);
|
||||
extern void DestroyRNG(rng rngx, rngcontext ** rngctx);
|
||||
extern void PrintRNGSeed(rng rngx, rngcontext * rngctx);
|
||||
extern void PrintRNGCounter(rng rngx, rngcontext * rngctx);
|
||||
extern void InitRNGSeed(unsigned int n, rng rngx, rngcontext * rngctx);
|
||||
extern int RNGSystemSeed(rng rngx, void *p, unsigned long *pnSeed);
|
||||
|
||||
extern int RollDice(unsigned int anDice[2], rng * prng, rngcontext * rngctx);
|
||||
|
||||
#if defined(HAVE_LIBGMP)
|
||||
extern int InitRNGSeedLong(char *sz, rng rng, rngcontext * rngctx);
|
||||
extern int InitRNGBBSModulus(const char *sz, rngcontext * rngctx);
|
||||
extern int InitRNGBBSFactors(char *sz0, char *sz1, rngcontext * rngctx);
|
||||
#endif
|
||||
|
||||
extern FILE *OpenDiceFile(rngcontext * rngctx, const char *sz);
|
||||
|
||||
extern char *GetDiceFileName(rngcontext * rngctx);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2000-2015 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DRAWBOARD_H
|
||||
#define DRAWBOARD_H
|
||||
|
||||
#include "gnubg-types.h"
|
||||
#include "external.h"
|
||||
|
||||
extern int fClockwise; /* Player 1 moves clockwise */
|
||||
|
||||
extern char *DrawBoard(char *sz, const TanBoard anBoard, int fRoll, char *asz[], char *szMatchID, int nChequers);
|
||||
/* Fill the buffer pch with a representation of the move anMove, assuming
|
||||
* the board looks like anBoard. pch must have room for 28 characters plus
|
||||
* a trailing 0 (consider the move `bar/24* 23/22* 21/20* 19/18*'). */
|
||||
#define FORMATEDMOVESIZE 29
|
||||
extern char *FormatMove(char *sz, const TanBoard anBoard, const int anMove[8]);
|
||||
extern char *FormatMovePlain(char *sz, const TanBoard anBoard, const int anMove[8]);
|
||||
extern int ParseMove(char *pch, int an[8]);
|
||||
extern void CanonicalMoveOrder(int an[]);
|
||||
/* Fill the buffer pch with a FIBS "boardstyle 3" description of the game. */
|
||||
extern char *FIBSBoard(char *pch, TanBoard anBoard, int fRoll,
|
||||
const char *szPlayer, const char *szOpp, int nMatchTo,
|
||||
int nScore, int nOpponent, int nDice0, int nDice1,
|
||||
int nCube, int fCubeOwner, int fDoubled, int fTurn,
|
||||
int fCrawford, int nChequers, int fPostCrawford);
|
||||
|
||||
/* Process a board info structure from external interface */
|
||||
extern int ProcessFIBSBoardInfo(FIBSBoardInfo * brdInfo, ProcessedFIBSBoard * procBrd);
|
||||
|
||||
#endif
|
||||
+6396
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2000-2025 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EVAL_H
|
||||
#define EVAL_H
|
||||
|
||||
#include "dice.h"
|
||||
#include "bearoff.h"
|
||||
#include "neuralnet.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define EXP_LOCK_FUN(ret, name, ...) \
|
||||
typedef ret (*f_##name)( __VA_ARGS__); \
|
||||
extern f_##name name; \
|
||||
extern ret name##NoLocking( __VA_ARGS__); \
|
||||
extern ret name##WithLocking( __VA_ARGS__)
|
||||
|
||||
#define WEIGHTS_VERSION "1.01"
|
||||
#define WEIGHTS_VERSION_BINARY 1.01f
|
||||
#define WEIGHTS_MAGIC_BINARY 472.3782f
|
||||
|
||||
#define NUM_OUTPUTS 5
|
||||
#define NUM_CUBEFUL_OUTPUTS 4
|
||||
#define NUM_ROLLOUT_OUTPUTS 7
|
||||
|
||||
#define BETA_HIDDEN 0.1f
|
||||
#define BETA_OUTPUT 1.0f
|
||||
|
||||
#define OUTPUT_WIN 0
|
||||
#define OUTPUT_WINGAMMON 1
|
||||
#define OUTPUT_WINBACKGAMMON 2
|
||||
#define OUTPUT_LOSEGAMMON 3
|
||||
#define OUTPUT_LOSEBACKGAMMON 4
|
||||
|
||||
#define OUTPUT_EQUITY 5 /* NB: neural nets do not output equity, only
|
||||
* rollouts do. */
|
||||
#define OUTPUT_CUBEFUL_EQUITY 6
|
||||
|
||||
/* Cubeful evaluations */
|
||||
typedef enum {
|
||||
OUTPUT_OPTIMAL = 0,
|
||||
OUTPUT_NODOUBLE,
|
||||
OUTPUT_TAKE,
|
||||
OUTPUT_DROP
|
||||
} CubefulOutputs;
|
||||
|
||||
/* A trivial upper bound on the number of (complete or incomplete)
|
||||
* legal moves of a single roll: if all 15 chequers are spread out,
|
||||
* then there are 18 C 4 + 17 C 3 + 16 C 2 + 15 C 1 = 3875
|
||||
* combinations in which a roll of 11 could be played (up to 4 choices from
|
||||
* 15 chequers, and a chequer may be chosen more than once). The true
|
||||
* bound will be lower than this (because there are only 26 points,
|
||||
* some plays of 15 chequers must "overlap" and map to the same
|
||||
* resulting position), but that would be more difficult to
|
||||
* compute. */
|
||||
#define MAX_INCOMPLETE_MOVES 3875
|
||||
#define MAX_MOVES 3060
|
||||
|
||||
typedef struct {
|
||||
int Accept; /* always allow this many moves.
|
||||
-1 means don't use this level */
|
||||
int Extra; /* and add up to this many more */
|
||||
float Threshold; /* if they are within this equity difference */
|
||||
} movefilter;
|
||||
|
||||
/* we'll have filters for 1..4 ply evaluation */
|
||||
#define MAX_FILTER_PLIES 4
|
||||
extern movefilter defaultFilters[MAX_FILTER_PLIES][MAX_FILTER_PLIES];
|
||||
|
||||
typedef struct {
|
||||
/* FIXME expand this... e.g. different settings for different position
|
||||
* classes */
|
||||
unsigned int fCubeful:1; /* cubeful evaluation */
|
||||
unsigned int nPlies:4;
|
||||
unsigned int fUsePrune:1;
|
||||
unsigned int fDeterministic:1;
|
||||
unsigned int :25; /* padding */
|
||||
float rNoise; /* standard deviation */
|
||||
} evalcontext;
|
||||
|
||||
/* identifies the format of evaluation info in .sgf files
|
||||
* early (pre extending rollouts) had no version numbers
|
||||
* extendable rollouts have a version number of 1
|
||||
* with pruning nets, we have two possibilities - reduction could still
|
||||
* be enabled (version = 2) or, given the speedup and performance
|
||||
* improvements, I assume we will drop reduction entirely. (ver = 3 or more)
|
||||
* When presented with an .sgf file, gnubg will attempt to work out what
|
||||
* data is present in the file based on the version number
|
||||
*/
|
||||
|
||||
#define SGF_FORMAT_VER 3
|
||||
|
||||
typedef struct {
|
||||
evalcontext aecCube[2], aecChequer[2]; /* evaluation parameters */
|
||||
evalcontext aecCubeLate[2], aecChequerLate[2]; /* ... for later moves */
|
||||
evalcontext aecCubeTrunc, aecChequerTrunc; /* ... at truncation point */
|
||||
movefilter aaamfChequer[2][MAX_FILTER_PLIES][MAX_FILTER_PLIES];
|
||||
movefilter aaamfLate[2][MAX_FILTER_PLIES][MAX_FILTER_PLIES];
|
||||
|
||||
unsigned int fCubeful:1; /* Cubeful rollout */
|
||||
unsigned int fVarRedn:1; /* variance reduction */
|
||||
unsigned int fInitial:1; /* roll out as opening position */
|
||||
unsigned int fRotate:1; /* quasi-random dice */
|
||||
unsigned int fTruncBearoff2:1; /* cubeless rollout: trunc at BEAROFF2 */
|
||||
unsigned int fTruncBearoffOS:1; /* cubeless rollout: trunc at BEAROFF_OS */
|
||||
unsigned int fLateEvals:1; /* enable different evals for later moves */
|
||||
unsigned int fDoTruncate:1; /* enable truncated rollouts */
|
||||
unsigned int fStopOnSTD:1; /* stop when std's are small enough */
|
||||
unsigned int fStopOnJsd:1;
|
||||
unsigned int fStopMoveOnJsd:1; /* stop multi-line rollout when jsd
|
||||
* is small enough */
|
||||
unsigned short nTruncate; /* truncation */
|
||||
unsigned int nTrials; /* number of rollouts */
|
||||
unsigned short nLate; /* switch evaluations on move nLate of game */
|
||||
rng rngRollout;
|
||||
unsigned long nSeed;
|
||||
unsigned int nMinimumGames; /* always do at least this many */
|
||||
float rStdLimit; /* stop when std < this */
|
||||
unsigned int nMinimumJsdGames;
|
||||
float rJsdLimit;
|
||||
unsigned int nGamesDone;
|
||||
float rStoppedOnJSD;
|
||||
int nSkip;
|
||||
} rolloutcontext;
|
||||
|
||||
typedef struct {
|
||||
float rEquity;
|
||||
float rJSD;
|
||||
int nOrder;
|
||||
int nRank;
|
||||
} jsdinfo;
|
||||
|
||||
typedef enum {
|
||||
EVAL_NONE, EVAL_EVAL, EVAL_ROLLOUT
|
||||
} evaltype;
|
||||
|
||||
/* enumeration of variations of backgammon
|
||||
* (starting position and/or special rules) */
|
||||
|
||||
extern bgvariation bgvDefault;
|
||||
|
||||
extern int anChequers[NUM_VARIATIONS];
|
||||
extern const char *aszVariations[NUM_VARIATIONS];
|
||||
extern const char *aszVariationCommands[NUM_VARIATIONS];
|
||||
|
||||
/*
|
||||
* Cubeinfo contains the information necessary for evaluation
|
||||
* of a position.
|
||||
* These structs are placed here so that the move struct can be defined
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* nCube: the current value of the cube,
|
||||
* fCubeOwner: the owner of the cube,
|
||||
* fMove: the player for which we are
|
||||
* calculating equity for,
|
||||
* fCrawford, fJacoby, fBeavers: optional rules in effect,
|
||||
* arGammonPrice: the gammon prices;
|
||||
* [ 0 ] = gammon price for player 0,
|
||||
* [ 1 ] = gammon price for player 1,
|
||||
* [ 2 ] = backgammon price for player 0,
|
||||
* [ 3 ] = backgammon price for player 1.
|
||||
*
|
||||
*/
|
||||
int nCube, fCubeOwner, fMove, nMatchTo, anScore[2], fCrawford, fJacoby, fBeavers;
|
||||
float arGammonPrice[4];
|
||||
bgvariation bgv;
|
||||
} cubeinfo;
|
||||
|
||||
typedef struct {
|
||||
evaltype et;
|
||||
evalcontext ec;
|
||||
rolloutcontext rc;
|
||||
} evalsetup;
|
||||
|
||||
typedef enum {
|
||||
DOUBLE_TAKE,
|
||||
DOUBLE_PASS,
|
||||
NODOUBLE_TAKE,
|
||||
TOOGOOD_TAKE,
|
||||
TOOGOOD_PASS,
|
||||
DOUBLE_BEAVER,
|
||||
NODOUBLE_BEAVER,
|
||||
REDOUBLE_TAKE,
|
||||
REDOUBLE_PASS,
|
||||
NO_REDOUBLE_TAKE,
|
||||
TOOGOODRE_TAKE,
|
||||
TOOGOODRE_PASS,
|
||||
NO_REDOUBLE_BEAVER,
|
||||
NODOUBLE_DEADCUBE, /* cube is dead (match play only) */
|
||||
NO_REDOUBLE_DEADCUBE, /* cube is dead (match play only) */
|
||||
NOT_AVAILABLE, /* Cube not available */
|
||||
OPTIONAL_DOUBLE_TAKE,
|
||||
OPTIONAL_REDOUBLE_TAKE,
|
||||
OPTIONAL_DOUBLE_BEAVER,
|
||||
OPTIONAL_DOUBLE_PASS,
|
||||
OPTIONAL_REDOUBLE_PASS
|
||||
} cubedecision;
|
||||
|
||||
typedef enum {
|
||||
DT_NORMAL,
|
||||
DT_BEAVER,
|
||||
DT_RACCOON,
|
||||
NUM_DOUBLE_TYPES
|
||||
} doubletype;
|
||||
|
||||
/*
|
||||
* TT_NA can happen if a single position was loaded from a sgf file.
|
||||
* To check for beavers, use "> TT_NORMAL", not "!= TT_NORMAL".
|
||||
*/
|
||||
typedef enum {
|
||||
TT_NA,
|
||||
TT_NORMAL,
|
||||
TT_BEAVER
|
||||
} taketype;
|
||||
|
||||
extern const char *aszDoubleTypes[NUM_DOUBLE_TYPES];
|
||||
|
||||
/*
|
||||
* prefined settings
|
||||
*/
|
||||
|
||||
#define NUM_SETTINGS 9
|
||||
#define SETTINGS_4PLY 8
|
||||
#define SETTINGS_3PLY 7
|
||||
#define SETTINGS_2PLY 6
|
||||
#define SETTINGS_1PLY 5
|
||||
#define SETTINGS_0PLY 4
|
||||
#define SETTINGS_ADVANCED 3
|
||||
#define SETTINGS_INTERMEDIATE 2
|
||||
#define SETTINGS_NOVICE 1
|
||||
#define SETTINGS_BEGINNER 0
|
||||
|
||||
extern evalcontext aecSettings[NUM_SETTINGS];
|
||||
extern evalcontext ecBasic;
|
||||
extern int aiSettingsMoveFilter[NUM_SETTINGS];
|
||||
extern const char *aszSettings[NUM_SETTINGS];
|
||||
|
||||
#define NUM_MOVEFILTER_SETTINGS 2
|
||||
|
||||
extern const char *aszMoveFilterSettings[NUM_MOVEFILTER_SETTINGS];
|
||||
extern movefilter aaamfMoveFilterSettings[NUM_MOVEFILTER_SETTINGS][MAX_FILTER_PLIES][MAX_FILTER_PLIES];
|
||||
|
||||
typedef enum {
|
||||
CMARK_NONE,
|
||||
CMARK_ROLLOUT
|
||||
} CMark;
|
||||
|
||||
typedef struct {
|
||||
int anMove[8];
|
||||
positionkey key;
|
||||
unsigned int cMoves, cPips;
|
||||
/* scores for this move */
|
||||
float rScore, rScore2;
|
||||
/* evaluation for this move */
|
||||
float arEvalMove[NUM_ROLLOUT_OUTPUTS];
|
||||
float arEvalStdDev[NUM_ROLLOUT_OUTPUTS];
|
||||
evalsetup esMove;
|
||||
CMark cmark;
|
||||
} move;
|
||||
|
||||
extern int fInterrupt;
|
||||
extern cubeinfo ciCubeless;
|
||||
extern const char *aszEvalType[(int) EVAL_ROLLOUT + 1];
|
||||
|
||||
extern bearoffcontext *pbc1;
|
||||
extern bearoffcontext *pbc2;
|
||||
extern bearoffcontext *pbcOS;
|
||||
extern bearoffcontext *pbcTS;
|
||||
extern bearoffcontext *apbcHyper[3];
|
||||
|
||||
typedef struct {
|
||||
unsigned int cMoves; /* and current move when building list */
|
||||
unsigned int cMaxMoves, cMaxPips;
|
||||
int iMoveBest;
|
||||
float rBestScore;
|
||||
move *amMoves;
|
||||
} movelist;
|
||||
|
||||
/* cube efficiencies */
|
||||
|
||||
extern float rOSCubeX;
|
||||
extern float rRaceFactorX[2];
|
||||
extern float rRaceCoefficientX[2];
|
||||
extern float rRaceMax[2];
|
||||
extern float rRaceMin[2];
|
||||
extern float rCrashedX[2];
|
||||
extern float rContactX[2];
|
||||
|
||||
/* position classes */
|
||||
|
||||
typedef enum {
|
||||
CLASS_OVER = 0, /* Game already finished */
|
||||
CLASS_HYPERGAMMON1, /* hypergammon with 1 chequers */
|
||||
CLASS_HYPERGAMMON2, /* hypergammon with 2 chequers */
|
||||
CLASS_HYPERGAMMON3, /* hypergammon with 3 chequers */
|
||||
CLASS_BEAROFF2, /* Two-sided bearoff database (in memory) */
|
||||
CLASS_BEAROFF_TS, /* Two-sided bearoff database (on disk) */
|
||||
CLASS_BEAROFF1, /* One-sided bearoff database (in memory) */
|
||||
CLASS_BEAROFF_OS, /* One-sided bearoff database /on disk) */
|
||||
CLASS_RACE, /* Race neural network */
|
||||
CLASS_CRASHED, /* Contact, one side has less than 7 active checkers */
|
||||
CLASS_CONTACT /* Contact neural network */
|
||||
} positionclass;
|
||||
|
||||
#define N_CLASSES (CLASS_CONTACT + 1)
|
||||
|
||||
#define CLASS_PERFECT CLASS_BEAROFF_TS
|
||||
#define CLASS_GOOD CLASS_BEAROFF_OS /* Good enough to not need SanityCheck */
|
||||
|
||||
typedef int (*classevalfunc) (const TanBoard anBoard, float arOutput[], const bgvariation bgv, NNState * nnStates);
|
||||
|
||||
extern classevalfunc acef[N_CLASSES];
|
||||
|
||||
/* Evaluation cache size is 2^SIZE entries */
|
||||
#define CACHE_SIZE_DEFAULT 19
|
||||
#define CACHE_SIZE_GUIMAX 23
|
||||
|
||||
#define CFMONEY(arEquity,pci) \
|
||||
( ( (pci)->fCubeOwner == -1 ) ? arEquity[ 2 ] : \
|
||||
( ( (pci)->fCubeOwner == (pci)->fMove ) ? arEquity[ 1 ] : arEquity[ 3 ] ) )
|
||||
|
||||
#define CFHYPER(arEquity,pci) \
|
||||
( ( (pci)->fCubeOwner == -1 ) ? \
|
||||
( ( (pci)->fJacoby ) ? arEquity[ 2 ] : arEquity[ 1 ] ) : \
|
||||
( ( (pci)->fCubeOwner == (pci)->fMove ) ? arEquity[ 0 ] : arEquity[ 3 ] ) )
|
||||
|
||||
extern void EvalInitialise(char *szWeights, char *szWeightsBinary, int fNoBearoff, void (*pfProgress) (unsigned int));
|
||||
|
||||
extern int EvalShutdown(void);
|
||||
|
||||
extern void EvalStatus(char *szOutput);
|
||||
|
||||
extern int EvalNewWeights(int nSize);
|
||||
|
||||
extern int EvalSave(const char *szWeights);
|
||||
|
||||
|
||||
EXP_LOCK_FUN(int, EvaluatePosition, NNState * nnStates, const TanBoard anBoard, float arOutput[],
|
||||
cubeinfo * const pci, const evalcontext * pec);
|
||||
|
||||
extern void
|
||||
InvertEvaluationR(float ar[NUM_ROLLOUT_OUTPUTS], const cubeinfo * pci);
|
||||
|
||||
extern void
|
||||
InvertEvaluation(float ar[NUM_OUTPUTS]);
|
||||
|
||||
EXP_LOCK_FUN(int, FindBestMove, int anMove[8], int nDice0, int nDice1,
|
||||
TanBoard anBoard, const cubeinfo * pci, evalcontext * pec, movefilter aamf[MAX_FILTER_PLIES][MAX_FILTER_PLIES]);
|
||||
|
||||
EXP_LOCK_FUN(int, FindnSaveBestMoves, movelist * pml,
|
||||
int nDice0, int nDice1, const TanBoard anBoard,
|
||||
positionkey * keyMove, int fAnalyse, const float rThr,
|
||||
const cubeinfo * pci, const evalcontext * pec, movefilter aamf[MAX_FILTER_PLIES][MAX_FILTER_PLIES]);
|
||||
|
||||
extern void
|
||||
PipCount(const TanBoard anBoard, unsigned int anPips[2]);
|
||||
|
||||
extern int
|
||||
ThorpCount(const TanBoard anBoard, int *pnLeader, float *adjusted, int *pnTrailer);
|
||||
|
||||
extern int
|
||||
KeithCount(const TanBoard anBoard, int pn[2]);
|
||||
|
||||
extern int
|
||||
IsightCount(const TanBoard anBoard, int pn[2]);
|
||||
|
||||
extern int
|
||||
DumpPosition(const TanBoard anBoard, char *szOutput,
|
||||
const evalcontext * pec, cubeinfo * pci, int fOutputMWC,
|
||||
int fOutputWinPC, int fOutputInvert, const char *szMatchID);
|
||||
|
||||
extern void
|
||||
SwapSides(TanBoard anBoard);
|
||||
|
||||
extern int GameStatus(const TanBoard anBoard, bgvariation bgv);
|
||||
|
||||
extern void EvalCacheFlush(void);
|
||||
extern int EvalCacheResize(unsigned int cNew);
|
||||
extern int EvalCacheStats(unsigned int *pcUsed, unsigned int *pcLookup, unsigned int *pcHit);
|
||||
extern double GetEvalCacheSize(void);
|
||||
void SetEvalCacheSize(unsigned int size);
|
||||
extern unsigned int GetEvalCacheEntries(void);
|
||||
extern int GetCacheMB(int size);
|
||||
|
||||
extern evalCache cEval;
|
||||
extern evalCache cpEval;
|
||||
extern unsigned int cCache;
|
||||
|
||||
extern int
|
||||
GenerateMoves(movelist * pml, const TanBoard anBoard, int n0, int n1, int fPartial);
|
||||
|
||||
extern int ApplySubMove(TanBoard anBoard, int iSrc, int nRoll, int fCheckLegal);
|
||||
|
||||
extern int ApplyMove(TanBoard anBoard, const int anMove[8], int fCheckLegal);
|
||||
|
||||
extern positionclass ClassifyPosition(const TanBoard anBoard, bgvariation bgv);
|
||||
|
||||
/* internal use only */
|
||||
extern void EvalRaceBG(const TanBoard anBoard, float arOutput[], bgvariation bgv);
|
||||
|
||||
extern float
|
||||
Utility(float ar[NUM_OUTPUTS], const cubeinfo * pci);
|
||||
|
||||
extern float
|
||||
UtilityME(float ar[NUM_OUTPUTS], const cubeinfo * pci);
|
||||
|
||||
extern int
|
||||
SetCubeInfoMoney(cubeinfo * pci, int nCube, int fCubeOwner,
|
||||
int fMove, int fJacoby, int fBeavers, bgvariation bgv);
|
||||
|
||||
extern int
|
||||
SetCubeInfo(cubeinfo * pci, int nCube, int fCubeOwner,
|
||||
int fMove, int nMatchTo, const int anScore[2],
|
||||
int fCrawford, int fJacoby, int fBeavers, bgvariation bgv);
|
||||
|
||||
extern void
|
||||
swap_us(unsigned int *p0, unsigned int *p1);
|
||||
|
||||
extern void
|
||||
swap(int *p0, int *p1);
|
||||
|
||||
extern void
|
||||
SanityCheck(const TanBoard anBoard, float arOutput[]);
|
||||
|
||||
extern int
|
||||
EvalOver(const TanBoard anBoard, float arOutput[], bgvariation bgv, NNState * nnStates);
|
||||
|
||||
extern float
|
||||
KleinmanCount(int nPipOnRoll, int nPipNotOnRoll);
|
||||
|
||||
extern int
|
||||
GetDPEq(int *pfCube, float *prDPEq, const cubeinfo * pci);
|
||||
|
||||
extern float
|
||||
mwc2eq(float rMwc, const cubeinfo * pci);
|
||||
|
||||
extern float
|
||||
eq2mwc(float rEq, const cubeinfo * pci);
|
||||
|
||||
extern float
|
||||
se_mwc2eq(float rMwc, const cubeinfo * pci);
|
||||
|
||||
extern float
|
||||
se_eq2mwc(float rEq, const cubeinfo * pci);
|
||||
|
||||
extern char
|
||||
*FormatEval(char *sz, evalsetup * pes);
|
||||
|
||||
extern cubedecision FindCubeDecision(float arDouble[], float aarOutput[][NUM_ROLLOUT_OUTPUTS], const cubeinfo * pci);
|
||||
|
||||
EXP_LOCK_FUN(int, GeneralCubeDecisionE, float aarOutput[2][NUM_ROLLOUT_OUTPUTS],
|
||||
const TanBoard anBoard, cubeinfo * const pci, const evalcontext * pec, const evalsetup * pes);
|
||||
|
||||
EXP_LOCK_FUN(int, GeneralEvaluationE, float arOutput[NUM_ROLLOUT_OUTPUTS],
|
||||
const TanBoard anBoard, cubeinfo * const pci, const evalcontext * pec);
|
||||
|
||||
extern int
|
||||
cmp_evalsetup(const evalsetup * pes1, const evalsetup * pes2);
|
||||
|
||||
extern int
|
||||
cmp_evalcontext(const evalcontext * pec1, const evalcontext * pec2);
|
||||
|
||||
extern char
|
||||
*GetCubeRecommendation(cubedecision cd);
|
||||
|
||||
extern cubedecision
|
||||
FindBestCubeDecision(float arDouble[], float aarOutput[2][NUM_ROLLOUT_OUTPUTS], const cubeinfo * pci);
|
||||
|
||||
extern int
|
||||
getCurrentGammonRates(float aarRates[2][2],
|
||||
float arOutput[], const TanBoard anBoard, cubeinfo * pci, const evalcontext * pec);
|
||||
|
||||
extern void
|
||||
getMoneyPoints(float aaarPoints[2][7][2], int fJacoby, int fBeavers, float aarRates[2][2]);
|
||||
|
||||
extern void
|
||||
getMatchPoints(float aaarPoints[2][4][2],
|
||||
int afAutoRedouble[2], int afDead[2], const cubeinfo * pci, float aarRates[2][2]);
|
||||
|
||||
extern void
|
||||
getCubeDecisionOrdering(int aiOrder[3],
|
||||
float arDouble[4], float aarOutput[2][NUM_ROLLOUT_OUTPUTS], const cubeinfo * pci);
|
||||
|
||||
extern float
|
||||
getPercent(cubedecision cd, const float arDouble[]);
|
||||
|
||||
extern void
|
||||
RefreshMoveList(movelist * pml, int *ai);
|
||||
|
||||
EXP_LOCK_FUN(int, ScoreMove, NNState * nnStates, move * pm, const cubeinfo * pci, const evalcontext * pec, int nPlies);
|
||||
|
||||
extern void
|
||||
CopyMoveList(movelist * pmlDest, const movelist * pmlSrc);
|
||||
|
||||
extern int
|
||||
isCloseCubedecision(const float arDouble[]);
|
||||
|
||||
extern int
|
||||
isMissedDouble(float arDouble[], float aarOutput[2][NUM_ROLLOUT_OUTPUTS], int fDouble, const cubeinfo * pci);
|
||||
|
||||
extern unsigned int
|
||||
locateMove(const TanBoard anBoard, const int anMove[8], const movelist * pml);
|
||||
|
||||
extern int
|
||||
equal_movefilter(int i, const movefilter amf1[MAX_FILTER_PLIES], const movefilter amf2[MAX_FILTER_PLIES]);
|
||||
|
||||
extern int
|
||||
equal_movefilters(movefilter aamf1[MAX_FILTER_PLIES][MAX_FILTER_PLIES],
|
||||
movefilter aamf2[MAX_FILTER_PLIES][MAX_FILTER_PLIES]);
|
||||
|
||||
extern doubletype DoubleType(int fDoubled, int fMove, int fTurn);
|
||||
|
||||
extern int
|
||||
PerfectCubeful(bearoffcontext * pbc, const TanBoard anBoard, float arEquity[]);
|
||||
|
||||
extern void
|
||||
baseInputs(const TanBoard anBoard, float arInput[]);
|
||||
|
||||
extern int CompareMoves(const move * pm0, const move * pm1);
|
||||
extern float EvalEfficiency(const TanBoard anBoard, positionclass pc, int ply);
|
||||
extern float Cl2CfMoney(float arOutput[NUM_OUTPUTS], cubeinfo * pci, float rCubeX);
|
||||
extern float Cl2CfMatch(float arOutput[NUM_OUTPUTS], cubeinfo * pci, float rCubeX);
|
||||
extern float Noise(const evalcontext * pec, const TanBoard anBoard, int iOutput);
|
||||
extern int EvalKey(const evalcontext * pec, int nPlies, const cubeinfo * pci, int fCubefulEquity);
|
||||
extern void MakeCubePos(const cubeinfo aciCubePos[], int cci, int fTop, cubeinfo aci[], int fInvert);
|
||||
extern void GetECF3(float arCubeful[], int cci, float arCf[], cubeinfo aci[]);
|
||||
extern int EvaluatePerfectCubeful(const TanBoard anBoard, float arEquity[], bgvariation bgv);
|
||||
|
||||
extern neuralnet nnContact, nnRace, nnCrashed;
|
||||
extern neuralnet nnpContact, nnpRace, nnpCrashed;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2000 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2002-2022 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cache.h"
|
||||
#include "positionid.h"
|
||||
|
||||
#if defined(USE_MULTITHREAD)
|
||||
#include "multithread.h"
|
||||
|
||||
#if defined(__GNUC__) && ( \
|
||||
(( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) \
|
||||
&& (defined (__i486) || defined (__x86_64))) \
|
||||
|| (( __GNUC__ * 100 + __GNUC_MINOR__ >= 404 ) \
|
||||
&& defined (__i386)) \
|
||||
)
|
||||
|
||||
static inline void
|
||||
cache_lock(evalCache * pc, uint32_t k)
|
||||
{
|
||||
while (__sync_lock_test_and_set(&(pc->entries[k].lock), 1))
|
||||
while (__sync_fetch_and_add(&pc->entries[k].lock, 0))
|
||||
__asm__ __volatile__ ("pause":::"memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
cache_unlock(evalCache * pc, uint32_t k)
|
||||
{
|
||||
__sync_lock_release(&(pc->entries[k].lock));
|
||||
}
|
||||
|
||||
#else /* not x86 or older gcc: no suitable intrinsics */
|
||||
|
||||
static inline void
|
||||
WaitForLock(volatile int *lock)
|
||||
{
|
||||
do {
|
||||
MT_SafeDec(lock);
|
||||
} while (MT_SafeIncCheck(lock));
|
||||
}
|
||||
|
||||
static inline void
|
||||
cache_lock(evalCache * pc, uint32_t k)
|
||||
{
|
||||
if (MT_SafeIncCheck(&(pc->entries[k].lock)))
|
||||
WaitForLock(&(pc->entries[k].lock));
|
||||
}
|
||||
|
||||
static inline void
|
||||
cache_unlock(evalCache * pc, uint32_t k)
|
||||
{
|
||||
MT_SafeDec(&(pc->entries[k].lock));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* USE_MULTITHREAD */
|
||||
|
||||
|
||||
static int
|
||||
CacheGetSize(unsigned int s)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
if (s == 0)
|
||||
return 0;
|
||||
|
||||
if (s > 1u << 31)
|
||||
return -1;
|
||||
|
||||
/* A cache size of 1 would allocate zero cache nodes */
|
||||
if (s == 1)
|
||||
s = 2;
|
||||
|
||||
size = s;
|
||||
/* adjust size to smallest power of 2 GE to s */
|
||||
while ((s & (s - 1)) != 0)
|
||||
s &= (s - 1);
|
||||
|
||||
size = (s < size) ? 2 * s : s;
|
||||
|
||||
/* CacheResize() returns the cache size as an int. */
|
||||
if (size > (unsigned int) INT_MAX)
|
||||
return -1;
|
||||
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
int
|
||||
CacheCreate(evalCache * pc, unsigned int s)
|
||||
{
|
||||
int size = CacheGetSize(s);
|
||||
|
||||
if (size < 0)
|
||||
return -1;
|
||||
|
||||
#if CACHE_STATS
|
||||
pc->cLookup = 0;
|
||||
pc->cHit = 0;
|
||||
pc->nAdds = 0;
|
||||
#endif
|
||||
|
||||
pc->size = (unsigned int) size;
|
||||
if (pc->size == 0) {
|
||||
pc->hashMask = 0;
|
||||
pc->entries = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pc->hashMask = (pc->size >> 1) - 1;
|
||||
|
||||
/* Avoid "comparison is always false due to limited range of data type"
|
||||
* warning on 64bits architectures.
|
||||
* Adapt (or remove the condition) if the involved types are changed.
|
||||
*/
|
||||
#if (SIZE_MAX / 64 < UINT_MAX)
|
||||
/* Ensure the allocation size fits in size_t */
|
||||
if ((size_t) (pc->size / 2) > SIZE_MAX / sizeof(*pc->entries))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
pc->entries = (cacheNode *) malloc((pc->size / 2) * sizeof(*pc->entries));
|
||||
if (pc->entries == NULL)
|
||||
return -1;
|
||||
|
||||
CacheFlush(pc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MurmurHash3 https://code.google.com/p/smhasher/wiki/MurmurHash */
|
||||
|
||||
extern uint32_t
|
||||
GetHashKey(uint32_t hashMask, const cacheNodeDetail * restrict e)
|
||||
{
|
||||
uint32_t hash = (uint32_t) e->nEvalContext;
|
||||
int i;
|
||||
|
||||
hash *= 0xcc9e2d51;
|
||||
hash = (hash << 15) | (hash >> (32 - 15));
|
||||
hash *= 0x1b873593;
|
||||
|
||||
hash = (hash << 13) | (hash >> (32 - 13));
|
||||
hash = hash * 5 + 0xe6546b64;
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
uint32_t k = e->key.data[i];
|
||||
|
||||
k *= 0xcc9e2d51;
|
||||
k = (k << 15) | (k >> (32 - 15));
|
||||
k *= 0x1b873593;
|
||||
|
||||
hash ^= k;
|
||||
hash = (hash << 13) | (hash >> (32 - 13));
|
||||
hash = hash * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
/* Real MurmurHash3 has a "hash ^= len" here,
|
||||
* but for us len is constant. Skip it */
|
||||
|
||||
hash ^= hash >> 16;
|
||||
hash *= 0x85ebca6b;
|
||||
hash ^= hash >> 13;
|
||||
hash *= 0xc2b2ae35;
|
||||
hash ^= hash >> 16;
|
||||
|
||||
return (hash & hashMask);
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
CacheLookupWithLocking(evalCache * restrict pc, const cacheNodeDetail * restrict e, float * restrict arOut, float * restrict arCubeful)
|
||||
{
|
||||
uint32_t const l = GetHashKey(pc->hashMask, e);
|
||||
|
||||
#if CACHE_STATS
|
||||
#if defined(USE_MULTITHREAD)
|
||||
MT_SafeInc(&pc->cLookup);
|
||||
#else
|
||||
++pc->cLookup;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_MULTITHREAD)
|
||||
cache_lock(pc, l);
|
||||
#endif
|
||||
|
||||
if (!EqualKeys(pc->entries[l].nd_primary.key, e->key) || pc->entries[l].nd_primary.nEvalContext != e->nEvalContext) { /* Not in primary slot */
|
||||
if (!EqualKeys(pc->entries[l].nd_secondary.key, e->key) || pc->entries[l].nd_secondary.nEvalContext != e->nEvalContext) { /* Cache miss */
|
||||
#if defined(USE_MULTITHREAD)
|
||||
cache_unlock(pc, l);
|
||||
#endif
|
||||
return l;
|
||||
} else { /* Found in second slot, promote "hot" entry */
|
||||
cacheNodeDetail tmp = pc->entries[l].nd_primary;
|
||||
|
||||
pc->entries[l].nd_primary = pc->entries[l].nd_secondary;
|
||||
pc->entries[l].nd_secondary = tmp;
|
||||
}
|
||||
}
|
||||
/* Cache hit */
|
||||
memcpy(arOut, pc->entries[l].nd_primary.ar, sizeof(float) * 5 /*NUM_OUTPUTS */ );
|
||||
if (arCubeful)
|
||||
*arCubeful = pc->entries[l].nd_primary.ar[5]; /* Cubeful equity stored in slot 5 */
|
||||
|
||||
#if defined(USE_MULTITHREAD)
|
||||
cache_unlock(pc, l);
|
||||
#endif
|
||||
|
||||
#if CACHE_STATS
|
||||
#if defined(USE_MULTITHREAD)
|
||||
MT_SafeInc(&pc->cHit);
|
||||
#else
|
||||
++pc->cHit;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return CACHEHIT;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CacheLookupNoLocking(evalCache * restrict pc, const cacheNodeDetail * restrict e, float *restrict arOut, float * restrict arCubeful)
|
||||
{
|
||||
uint32_t const l = GetHashKey(pc->hashMask, e);
|
||||
|
||||
#if CACHE_STATS
|
||||
++pc->cLookup;
|
||||
#endif
|
||||
if (!EqualKeys(pc->entries[l].nd_primary.key, e->key) || pc->entries[l].nd_primary.nEvalContext != e->nEvalContext) { /* Not in primary slot */
|
||||
if (!EqualKeys(pc->entries[l].nd_secondary.key, e->key) || pc->entries[l].nd_secondary.nEvalContext != e->nEvalContext) { /* Cache miss */
|
||||
return l;
|
||||
} else { /* Found in second slot, promote "hot" entry */
|
||||
cacheNodeDetail tmp = pc->entries[l].nd_primary;
|
||||
|
||||
pc->entries[l].nd_primary = pc->entries[l].nd_secondary;
|
||||
pc->entries[l].nd_secondary = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache hit */
|
||||
memcpy(arOut, pc->entries[l].nd_primary.ar, sizeof(float) * 5 /*NUM_OUTPUTS */ );
|
||||
if (arCubeful)
|
||||
*arCubeful = pc->entries[l].nd_primary.ar[5]; /* Cubeful equity stored in slot 5 */
|
||||
|
||||
#if CACHE_STATS
|
||||
++pc->cHit;
|
||||
#endif
|
||||
|
||||
return CACHEHIT;
|
||||
}
|
||||
|
||||
void
|
||||
CacheAddWithLocking(evalCache * restrict pc, const cacheNodeDetail * restrict e, uint32_t l)
|
||||
{
|
||||
#if defined(USE_MULTITHREAD)
|
||||
cache_lock(pc, l);
|
||||
#endif
|
||||
|
||||
pc->entries[l].nd_secondary = pc->entries[l].nd_primary;
|
||||
pc->entries[l].nd_primary = *e;
|
||||
|
||||
#if defined(USE_MULTITHREAD)
|
||||
cache_unlock(pc, l);
|
||||
#endif
|
||||
|
||||
#if CACHE_STATS
|
||||
#if defined(USE_MULTITHREAD)
|
||||
MT_SafeInc(&pc->nAdds);
|
||||
#else
|
||||
++pc->nAdds;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* CacheAddNoLocking() is inlined and in cache.h */
|
||||
|
||||
void
|
||||
CacheDestroy(const evalCache * pc)
|
||||
{
|
||||
free(pc->entries);
|
||||
}
|
||||
|
||||
void
|
||||
CacheFlush(const evalCache * pc)
|
||||
{
|
||||
unsigned int k;
|
||||
for (k = 0; k < pc->size / 2; ++k) {
|
||||
pc->entries[k].nd_primary.key.data[0] = (unsigned int) -1;
|
||||
pc->entries[k].nd_secondary.key.data[0] = (unsigned int) -1;
|
||||
#if defined(USE_MULTITHREAD)
|
||||
pc->entries[k].lock = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CacheResize(evalCache * pc, unsigned int cNew)
|
||||
{
|
||||
evalCache newCache = { 0 };
|
||||
int size = CacheGetSize(cNew);
|
||||
|
||||
if (size < 0)
|
||||
return -1;
|
||||
|
||||
if ((unsigned int) size == pc->size)
|
||||
return size;
|
||||
|
||||
if (CacheCreate(&newCache, cNew) != 0)
|
||||
return -1;
|
||||
|
||||
CacheDestroy(pc);
|
||||
*pc = newCache;
|
||||
|
||||
return (int) pc->size;
|
||||
}
|
||||
|
||||
#if CACHE_STATS
|
||||
void
|
||||
CacheStats(const evalCache * pc, unsigned int *pcLookup, unsigned int *pcHit, unsigned int *pcUsed)
|
||||
{
|
||||
if (pcLookup)
|
||||
*pcLookup = pc->cLookup;
|
||||
|
||||
if (pcHit)
|
||||
*pcHit = pc->cHit;
|
||||
|
||||
if (pcUsed)
|
||||
*pcUsed = pc->nAdds;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2000 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2002-2018 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
typedef unsigned int uint32_t;
|
||||
#endif
|
||||
|
||||
#include "gnubg-types.h"
|
||||
|
||||
/* Set to calculate simple cache stats */
|
||||
#define CACHE_STATS 0
|
||||
|
||||
typedef struct {
|
||||
positionkey key; /* size = 28 */
|
||||
int nEvalContext;
|
||||
float ar[6];
|
||||
} cacheNodeDetail;
|
||||
|
||||
typedef struct {
|
||||
cacheNodeDetail nd_primary;
|
||||
cacheNodeDetail nd_secondary;
|
||||
#if defined(USE_MULTITHREAD)
|
||||
int lock;
|
||||
#endif
|
||||
} cacheNode;
|
||||
|
||||
/* name used in eval.c */
|
||||
typedef cacheNodeDetail evalcache;
|
||||
|
||||
typedef struct {
|
||||
cacheNode *entries;
|
||||
|
||||
unsigned int size;
|
||||
uint32_t hashMask;
|
||||
|
||||
#if CACHE_STATS
|
||||
unsigned int nAdds;
|
||||
unsigned int cLookup;
|
||||
unsigned int cHit;
|
||||
#endif
|
||||
} evalCache;
|
||||
|
||||
/* Cache size will be adjusted to a power of 2 */
|
||||
int CacheCreate(evalCache * pc, unsigned int size);
|
||||
int CacheResize(evalCache * pc, unsigned int cNew);
|
||||
|
||||
#define CACHEHIT ((uint32_t)-1)
|
||||
|
||||
/* returns a value which is passed to CacheAdd (if a miss) */
|
||||
uint32_t CacheLookupWithLocking(evalCache * pc, const cacheNodeDetail * e, float *arOut, float *arCubeful);
|
||||
uint32_t CacheLookupNoLocking(evalCache * pc, const cacheNodeDetail * e, float *arOut, float *arCubeful);
|
||||
|
||||
void CacheAddWithLocking(evalCache * pc, const cacheNodeDetail * e, uint32_t l);
|
||||
|
||||
static inline void
|
||||
CacheAddNoLocking(evalCache * pc, const cacheNodeDetail * e, const uint32_t l)
|
||||
{
|
||||
pc->entries[l].nd_secondary = pc->entries[l].nd_primary;
|
||||
pc->entries[l].nd_primary = *e;
|
||||
#if CACHE_STATS
|
||||
++pc->nAdds;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CacheFlush(const evalCache * pc);
|
||||
void CacheDestroy(const evalCache * pc);
|
||||
|
||||
#if CACHE_STATS
|
||||
void CacheStats(const evalCache * pc, unsigned int *pcLookup, unsigned int *pcHit, unsigned int *pcUsed);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_FUNC_ATTRIBUTE_PURE)
|
||||
uint32_t GetHashKey(uint32_t hashMask, const cacheNodeDetail * e) __attribute((pure));
|
||||
#else
|
||||
uint32_t GetHashKey(uint32_t hashMask, const cacheNodeDetail * e);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 Christian Anthon <anthon@kiku.dk>
|
||||
* Copyright (C) 2007-2011 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: gnubg-types.h,v 1.9 2013/06/16 02:16:23 mdpetch Exp $
|
||||
*/
|
||||
|
||||
#ifndef GNUBG_TYPES_H
|
||||
#define GNUBG_TYPES_H
|
||||
|
||||
typedef unsigned int TanBoard[2][25];
|
||||
typedef const unsigned int (*ConstTanBoard)[25];
|
||||
|
||||
typedef enum {
|
||||
VARIATION_STANDARD, /* standard backgammon */
|
||||
VARIATION_NACKGAMMON, /* standard backgammon with nackgammon starting
|
||||
* position */
|
||||
VARIATION_HYPERGAMMON_1, /* 1-chequer hypergammon */
|
||||
VARIATION_HYPERGAMMON_2, /* 2-chequer hypergammon */
|
||||
VARIATION_HYPERGAMMON_3, /* 3-chequer hypergammon */
|
||||
NUM_VARIATIONS
|
||||
} bgvariation;
|
||||
|
||||
typedef enum {
|
||||
GAME_NONE, GAME_PLAYING, GAME_OVER, GAME_RESIGNED, GAME_DROP
|
||||
} gamestate;
|
||||
|
||||
typedef struct {
|
||||
TanBoard anBoard;
|
||||
unsigned int anDice[2]; /* (0,0) for unrolled dice */
|
||||
int fTurn; /* who makes the next decision */
|
||||
int fResigned;
|
||||
int fResignationDeclined;
|
||||
int fDoubled;
|
||||
int cGames;
|
||||
int fMove; /* player on roll */
|
||||
int fCubeOwner;
|
||||
int fCrawford;
|
||||
int fPostCrawford;
|
||||
int nMatchTo;
|
||||
int anScore[2];
|
||||
int nCube;
|
||||
unsigned int cBeavers;
|
||||
bgvariation bgv;
|
||||
int fCubeUse;
|
||||
int fJacoby;
|
||||
gamestate gs;
|
||||
} matchstate;
|
||||
|
||||
typedef union {
|
||||
unsigned int data[7];
|
||||
} positionkey;
|
||||
|
||||
typedef union {
|
||||
unsigned char auch[10];
|
||||
} oldpositionkey;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Oystein Johansen <oystein@gnubg.org>
|
||||
* Copyright (C) 2011-2018 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: inputs.c,v 1.12 2018/05/12 20:59:35 plm Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "gnubg-types.h"
|
||||
#include "simd.h"
|
||||
#include "eval.h"
|
||||
|
||||
#if defined(USE_SIMD_INSTRUCTIONS)
|
||||
#if defined(USE_NEON)
|
||||
#include <arm_neon.h>
|
||||
#elif defined(USE_AVX)
|
||||
#include <immintrin.h>
|
||||
#elif defined(USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#else
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#else
|
||||
typedef float float_vector[4];
|
||||
#endif /* USE_SIMD_INSTRUCTIONS */
|
||||
|
||||
typedef SSE_ALIGN(float float_vec_aligned[sizeof(float_vector)/sizeof(float)]);
|
||||
|
||||
SSE_ALIGN (static float_vec_aligned inpvec[16]) = {
|
||||
/* 0 */ { 0.0, 0.0, 0.0, 0.0},
|
||||
/* 1 */ { 1.0, 0.0, 0.0, 0.0},
|
||||
/* 2 */ { 0.0, 1.0, 0.0, 0.0},
|
||||
/* 3 */ { 0.0, 0.0, 1.0, 0.0},
|
||||
/* 4 */ { 0.0, 0.0, 1.0, 0.5},
|
||||
/* 5 */ { 0.0, 0.0, 1.0, 1.0},
|
||||
/* 6 */ { 0.0, 0.0, 1.0, 1.5},
|
||||
/* 7 */ { 0.0, 0.0, 1.0, 2.0},
|
||||
/* 8 */ { 0.0, 0.0, 1.0, 2.5},
|
||||
/* 9 */ { 0.0, 0.0, 1.0, 3.0},
|
||||
/* 10 */ { 0.0, 0.0, 1.0, 3.5},
|
||||
/* 11 */ { 0.0, 0.0, 1.0, 4.0},
|
||||
/* 12 */ { 0.0, 0.0, 1.0, 4.5},
|
||||
/* 13 */ { 0.0, 0.0, 1.0, 5.0},
|
||||
/* 14 */ { 0.0, 0.0, 1.0, 5.5},
|
||||
/* 15 */ { 0.0, 0.0, 1.0, 6.0}};
|
||||
|
||||
SSE_ALIGN(static float_vec_aligned inpvecb[16]) = {
|
||||
/* 0 */ { 0.0, 0.0, 0.0, 0.0},
|
||||
/* 1 */ { 1.0, 0.0, 0.0, 0.0},
|
||||
/* 2 */ { 1.0, 1.0, 0.0, 0.0},
|
||||
/* 3 */ { 1.0, 1.0, 1.0, 0.0},
|
||||
/* 4 */ { 1.0, 1.0, 1.0, 0.5},
|
||||
/* 5 */ { 1.0, 1.0, 1.0, 1.0},
|
||||
/* 6 */ { 1.0, 1.0, 1.0, 1.5},
|
||||
/* 7 */ { 1.0, 1.0, 1.0, 2.0},
|
||||
/* 8 */ { 1.0, 1.0, 1.0, 2.5},
|
||||
/* 9 */ { 1.0, 1.0, 1.0, 3.0},
|
||||
/* 10 */ { 1.0, 1.0, 1.0, 3.5},
|
||||
/* 11 */ { 1.0, 1.0, 1.0, 4.0},
|
||||
/* 12 */ { 1.0, 1.0, 1.0, 4.5},
|
||||
/* 13 */ { 1.0, 1.0, 1.0, 5.0},
|
||||
/* 14 */ { 1.0, 1.0, 1.0, 5.5},
|
||||
/* 15 */ { 1.0, 1.0, 1.0, 6.0}};
|
||||
|
||||
#if defined(USE_SIMD_INSTRUCTIONS)
|
||||
extern SIMD_AVX_STACKALIGN void
|
||||
baseInputs(const TanBoard anBoard, float arInput[])
|
||||
{
|
||||
int i = 3;
|
||||
|
||||
const unsigned int *pB = &anBoard[0][0];
|
||||
float *pInput = &arInput[0];
|
||||
|
||||
#if defined(HAVE_SSE)
|
||||
__m128 vec0;
|
||||
__m128 vec1;
|
||||
__m128 vec2;
|
||||
__m128 vec3;
|
||||
__m128 vec4;
|
||||
__m128 vec5;
|
||||
__m128 vec6;
|
||||
__m128 vec7;
|
||||
#elif defined(HAVE_NEON)
|
||||
float32x4_t vec0;
|
||||
float32x4_t vec1;
|
||||
float32x4_t vec2;
|
||||
float32x4_t vec3;
|
||||
float32x4_t vec4;
|
||||
float32x4_t vec5;
|
||||
float32x4_t vec6;
|
||||
float32x4_t vec7;
|
||||
#endif
|
||||
|
||||
while (i--) {
|
||||
#if defined(HAVE_SSE)
|
||||
vec0 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput, vec0);
|
||||
vec1 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec1);
|
||||
vec2 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec2);
|
||||
vec3 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec3);
|
||||
vec4 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec4);
|
||||
vec5 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec5);
|
||||
vec6 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec6);
|
||||
vec7 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec7);
|
||||
#else
|
||||
vec0 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput, vec0);
|
||||
vec1 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec1);
|
||||
vec2 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec2);
|
||||
vec3 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec3);
|
||||
vec4 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec4);
|
||||
vec5 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec5);
|
||||
vec6 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec6);
|
||||
vec7 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec7);
|
||||
#endif
|
||||
pInput += 4;
|
||||
}
|
||||
|
||||
/* bar */
|
||||
#if defined(HAVE_SSE)
|
||||
vec0 = _mm_load_ps(inpvecb[*pB++]);
|
||||
_mm_store_ps(pInput, vec0);
|
||||
#else
|
||||
vec0 = vld1q_f32(inpvecb[*pB++]);
|
||||
vst1q_f32(pInput, vec0);
|
||||
#endif
|
||||
pInput += 4;
|
||||
|
||||
i = 3;
|
||||
while (i--) {
|
||||
#if defined(HAVE_SSE)
|
||||
vec0 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput, vec0);
|
||||
vec1 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec1);
|
||||
vec2 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec2);
|
||||
vec3 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec3);
|
||||
vec4 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec4);
|
||||
vec5 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec5);
|
||||
vec6 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec6);
|
||||
vec7 = _mm_load_ps(inpvec[*pB++]);
|
||||
_mm_store_ps(pInput += 4, vec7);
|
||||
#else
|
||||
vec0 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput, vec0);
|
||||
vec1 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec1);
|
||||
vec2 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec2);
|
||||
vec3 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec3);
|
||||
vec4 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec4);
|
||||
vec5 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec5);
|
||||
vec6 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec6);
|
||||
vec7 = vld1q_f32(inpvec[*pB++]);
|
||||
vst1q_f32(pInput += 4, vec7);
|
||||
#endif
|
||||
pInput += 4;
|
||||
}
|
||||
|
||||
/* bar */
|
||||
#if defined(HAVE_SSE)
|
||||
vec0 = _mm_load_ps(inpvecb[*pB]);
|
||||
_mm_store_ps(pInput, vec0);
|
||||
#else
|
||||
vec0 = vld1q_f32(inpvecb[*pB++]);
|
||||
vst1q_f32(pInput, vec0);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
#else
|
||||
extern void
|
||||
baseInputs(const TanBoard anBoard, float arInput[])
|
||||
{
|
||||
int j, i;
|
||||
|
||||
for (j = 0; j < 2; ++j) {
|
||||
float *afInput = arInput + j * 25 * 4;
|
||||
const unsigned int *board = anBoard[j];
|
||||
|
||||
/* Points */
|
||||
for (i = 0; i < 24; i++) {
|
||||
const unsigned int nc = board[i];
|
||||
|
||||
afInput[i * 4 + 0] = inpvec[nc][0];
|
||||
afInput[i * 4 + 1] = inpvec[nc][1];
|
||||
afInput[i * 4 + 2] = inpvec[nc][2];
|
||||
afInput[i * 4 + 3] = inpvec[nc][3];
|
||||
}
|
||||
|
||||
/* Bar */
|
||||
{
|
||||
const unsigned int nc = board[24];
|
||||
|
||||
afInput[24 * 4 + 0] = inpvecb[nc][0];
|
||||
afInput[24 * 4 + 1] = inpvecb[nc][1];
|
||||
afInput[24 * 4 + 2] = inpvecb[nc][2];
|
||||
afInput[24 * 4 + 3] = inpvecb[nc][3];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* rand.c: By Bob Jenkins. My random number generator, ISAAC. Public Domain.
|
||||
* MODIFIED:
|
||||
* 960327: Creation (addition of randinit, really)
|
||||
* 970719: use context, not global variables, for internal state
|
||||
* 980324: added main (ifdef'ed out), also rearranged randinit()
|
||||
* 010626: Note that this is public domain
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minor modifications for use with GNU Backgammon.
|
||||
* Copyright (C) 1999-2007 the AUTHORS
|
||||
*
|
||||
* $Id: isaac.c,v 1.8 2013/06/16 02:16:24 mdpetch Exp $
|
||||
*/
|
||||
|
||||
/*lint --e{661,662} Ignore warnings of out of bounds array access (as ok) */
|
||||
|
||||
/* No configuration used in this file
|
||||
* #include "config.h" */
|
||||
#include "isaac.h"
|
||||
|
||||
#define ind(mm,x) ((mm)[((x)>>2)&(RANDSIZ-1)])
|
||||
#define rngstep(mix,a,b,mm,m,m2,r,x) \
|
||||
{ \
|
||||
x = *m; \
|
||||
a = ((a^(mix)) + *(m2++)) & 0xffffffff; \
|
||||
*(m++) = y = (ind(mm,x) + a + b) & 0xffffffff; \
|
||||
*(r++) = b = (ind(mm,y>>RANDSIZL) + x) & 0xffffffff; \
|
||||
}
|
||||
|
||||
void
|
||||
isaac(randctx * ctx)
|
||||
{
|
||||
register ub4 a, b, x, y, *m, *mm, *m2, *r, *mend;
|
||||
mm = ctx->randmem;
|
||||
r = ctx->randrsl;
|
||||
a = ctx->randa;
|
||||
b = (ctx->randb + (++ctx->randc)) & 0xffffffff;
|
||||
for (m = mm, mend = m2 = m + (RANDSIZ / 2); m < mend;) {
|
||||
rngstep(a << 13, a, b, mm, m, m2, r, x);
|
||||
rngstep(a >> 6, a, b, mm, m, m2, r, x);
|
||||
rngstep(a << 2, a, b, mm, m, m2, r, x);
|
||||
rngstep(a >> 16, a, b, mm, m, m2, r, x);
|
||||
}
|
||||
for (m2 = mm; m2 < mend;) {
|
||||
rngstep(a << 13, a, b, mm, m, m2, r, x);
|
||||
rngstep(a >> 6, a, b, mm, m, m2, r, x);
|
||||
rngstep(a << 2, a, b, mm, m, m2, r, x);
|
||||
rngstep(a >> 16, a, b, mm, m, m2, r, x);
|
||||
}
|
||||
ctx->randb = b;
|
||||
ctx->randa = a;
|
||||
}
|
||||
|
||||
|
||||
#define mix(a,b,c,d,e,f,g,h) \
|
||||
{ \
|
||||
a^=b<<11; d+=a; b+=c; \
|
||||
b^=c>>2; e+=b; c+=d; \
|
||||
c^=d<<8; f+=c; d+=e; \
|
||||
d^=e>>16; g+=d; e+=f; \
|
||||
e^=f<<10; h+=e; f+=g; \
|
||||
f^=g>>4; a+=f; g+=h; \
|
||||
g^=h<<8; b+=g; h+=a; \
|
||||
h^=a>>9; c+=h; a+=b; \
|
||||
}
|
||||
|
||||
/* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */
|
||||
void
|
||||
irandinit(randctx * ctx, word flag)
|
||||
{
|
||||
word i;
|
||||
ub4 a, b, c, d, e, f, g, h;
|
||||
ub4 *m, *r;
|
||||
ctx->randa = ctx->randb = ctx->randc = 0;
|
||||
m = ctx->randmem;
|
||||
r = ctx->randrsl;
|
||||
a = b = c = d = e = f = g = h = 0x9e3779b9; /* the golden ratio */
|
||||
|
||||
for (i = 0; i < 4; ++i) { /* scramble it */
|
||||
mix(a, b, c, d, e, f, g, h);
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
/* initialize using the contents of r[] as the seed */
|
||||
for (i = 0; i < RANDSIZ; i += 8) {
|
||||
a += r[i];
|
||||
b += r[i + 1];
|
||||
c += r[i + 2];
|
||||
d += r[i + 3];
|
||||
e += r[i + 4];
|
||||
f += r[i + 5];
|
||||
g += r[i + 6];
|
||||
h += r[i + 7];
|
||||
mix(a, b, c, d, e, f, g, h);
|
||||
m[i] = a;
|
||||
m[i + 1] = b;
|
||||
m[i + 2] = c;
|
||||
m[i + 3] = d;
|
||||
m[i + 4] = e;
|
||||
m[i + 5] = f;
|
||||
m[i + 6] = g;
|
||||
m[i + 7] = h;
|
||||
}
|
||||
/* do a second pass to make all of the seed affect all of m */
|
||||
for (i = 0; i < RANDSIZ; i += 8) {
|
||||
a += m[i];
|
||||
b += m[i + 1];
|
||||
c += m[i + 2];
|
||||
d += m[i + 3];
|
||||
e += m[i + 4];
|
||||
f += m[i + 5];
|
||||
g += m[i + 6];
|
||||
h += m[i + 7];
|
||||
mix(a, b, c, d, e, f, g, h);
|
||||
m[i] = a;
|
||||
m[i + 1] = b;
|
||||
m[i + 2] = c;
|
||||
m[i + 3] = d;
|
||||
m[i + 4] = e;
|
||||
m[i + 5] = f;
|
||||
m[i + 6] = g;
|
||||
m[i + 7] = h;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < RANDSIZ; i += 8) {
|
||||
/* fill in mm[] with messy stuff */
|
||||
mix(a, b, c, d, e, f, g, h);
|
||||
m[i] = a;
|
||||
m[i + 1] = b;
|
||||
m[i + 2] = c;
|
||||
m[i + 3] = d;
|
||||
m[i + 4] = e;
|
||||
m[i + 5] = f;
|
||||
m[i + 6] = g;
|
||||
m[i + 7] = h;
|
||||
}
|
||||
}
|
||||
|
||||
isaac(ctx); /* fill in the first set of results */
|
||||
ctx->randcnt = RANDSIZ; /* prepare to use the first set of results */
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* rand.h: definitions for a random number generator
|
||||
* By Bob Jenkins, 1996, Public Domain
|
||||
* MODIFIED:
|
||||
* 960327: Creation (addition of randinit, really)
|
||||
* 970719: use context, not global variables, for internal state
|
||||
* 980324: renamed seed to flag
|
||||
* 980605: recommend RANDSIZL=4 for noncryptography.
|
||||
* 010626: note this is public domain
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minor modifications for use with GNU Backgammon.
|
||||
* Copyright (C) 1999-2006 the AUTHORS
|
||||
*
|
||||
* $Id: isaac.h,v 1.5 2013/06/16 02:16:24 mdpetch Exp $
|
||||
*/
|
||||
|
||||
#include "isaacs.h"
|
||||
|
||||
#ifndef ISAAC_H
|
||||
#define ISAAC_H
|
||||
|
||||
#define RANDSIZL (4) /* I recommend 8 for crypto, 4 for simulations */
|
||||
#define RANDSIZ (1<<RANDSIZL)
|
||||
|
||||
/* context of random number generator */
|
||||
struct randctx {
|
||||
ub4 randcnt;
|
||||
ub4 randrsl[RANDSIZ];
|
||||
ub4 randmem[RANDSIZ];
|
||||
ub4 randa;
|
||||
ub4 randb;
|
||||
ub4 randc;
|
||||
};
|
||||
typedef struct randctx randctx;
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* If (flag==TRUE), then use the contents of randrsl[0..RANDSIZ-1] as the seed.
|
||||
* ------------------------------------------------------------------------------
|
||||
*/
|
||||
void irandinit(randctx * r, word flag);
|
||||
|
||||
void isaac(randctx * r);
|
||||
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Call irand(/o_ randctx *r _o/) to retrieve a single 32-bit random value
|
||||
* ------------------------------------------------------------------------------
|
||||
*/
|
||||
#define irand(r) \
|
||||
(!(r)->randcnt-- ? \
|
||||
(isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \
|
||||
(r)->randrsl[(r)->randcnt])
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* standard.hi: Standard definitions and types, Bob Jenkins
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minor modifications for use with GNU Backgammon.
|
||||
* Copyright (C) 1999-2013 the AUTHORS
|
||||
*
|
||||
* $Id: isaacs.h,v 1.5 2013/09/09 21:06:21 plm Exp $
|
||||
*/
|
||||
|
||||
#ifndef ISAACS_H
|
||||
#define ISAACS_H
|
||||
|
||||
#if 0
|
||||
|
||||
/* Pre-64bits relics. Most of them are not used anyway */
|
||||
|
||||
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
|
||||
#define UB4MAXVAL 0xffffffff
|
||||
typedef signed long int sb4;
|
||||
#define SB4MAXVAL 0x7fffffff
|
||||
typedef unsigned short int ub2;
|
||||
#define UB2MAXVAL 0xffff
|
||||
typedef signed short int sb2;
|
||||
#define SB2MAXVAL 0x7fff
|
||||
typedef unsigned char ub1;
|
||||
#define UB1MAXVAL 0xff
|
||||
typedef signed char sb1; /* signed 1-byte quantities */
|
||||
#define SB1MAXVAL 0x7f
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
typedef unsigned int uint32_t;
|
||||
#endif
|
||||
|
||||
typedef uint32_t ub4; /* unsigned 4-byte quantities */
|
||||
#define UB4MAXVAL 0xffffffff
|
||||
|
||||
typedef int word; /* fastest type available */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2004-2026 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* No configuration used in this file
|
||||
* #include "config.h" */
|
||||
#include "list.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
int
|
||||
ListCreate(listOLD * pl)
|
||||
{
|
||||
pl->plPrev = pl->plNext = pl;
|
||||
pl->p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
listOLD *
|
||||
ListInsert(listOLD * pl, void *p)
|
||||
{
|
||||
listOLD *plNew = g_malloc(sizeof(listOLD));
|
||||
|
||||
plNew->p = p;
|
||||
|
||||
plNew->plNext = pl;
|
||||
plNew->plPrev = pl->plPrev;
|
||||
|
||||
pl->plPrev = plNew;
|
||||
plNew->plPrev->plNext = plNew;
|
||||
|
||||
return plNew;
|
||||
}
|
||||
|
||||
void
|
||||
ListDelete(listOLD * pl)
|
||||
{
|
||||
pl->plPrev->plNext = pl->plNext;
|
||||
pl->plNext->plPrev = pl->plPrev;
|
||||
|
||||
g_free(pl);
|
||||
}
|
||||
|
||||
void
|
||||
ListDeleteAll(const listOLD * pl)
|
||||
{
|
||||
listOLD *pc = pl->plNext;
|
||||
|
||||
while (pc != pl) {
|
||||
listOLD *pn = pc->plNext;
|
||||
|
||||
g_free(pc->p);
|
||||
ListDelete(pc);
|
||||
pc = pn;
|
||||
}
|
||||
|
||||
g_assert(ListEmpty(pl));
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 1996-1999 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2004-2026 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
typedef struct list {
|
||||
struct list *plPrev;
|
||||
struct list *plNext;
|
||||
void *p;
|
||||
} listOLD;
|
||||
/* Renamed to listOLD - use GList instead (hopefullly replace existing usage eventually */
|
||||
|
||||
extern int ListCreate(listOLD * pl);
|
||||
extern listOLD *ListInsert(listOLD * pl, void *p);
|
||||
extern void ListDelete(listOLD * pl);
|
||||
extern void ListDeleteAll(const listOLD * pl);
|
||||
|
||||
static inline int ListEmpty(const listOLD *pl)
|
||||
{
|
||||
return ((pl->plNext == pl) && (pl->plPrev == pl));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Functions to compute MD5 message digest of files or memory blocks.
|
||||
* according to the definition of MD5 in RFC 1321 from April 1992,
|
||||
* by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
||||
* Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
|
||||
*
|
||||
* Minor modifications for use with GNU Backgammon.
|
||||
* Copyright (C) 2000-2019 the AUTHORS
|
||||
*
|
||||
* License changed from the GNU LGPL to the GNU GPL (as permitted under Term 3
|
||||
* of the GNU LGPL) by Gary Wong for distribution with GNU Backgammon.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: md5.c,v 1.15 2019/12/19 09:23:04 Superfly_Jon Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "md5.h"
|
||||
|
||||
/* Be conservative and always perform explicit byte-ordering. This is
|
||||
* redundant on little-endian architectures, but is portable. */
|
||||
#define WRITE( p, n ) \
|
||||
( ( (unsigned char *) (p) )[ 0 ] = (unsigned char)( (n) & 0xFF ), \
|
||||
( (unsigned char *) (p) )[ 1 ] = (unsigned char)(( (n) & 0xFF00 ) >> 8), \
|
||||
( (unsigned char *) (p) )[ 2 ] = (unsigned char)(( (n) & 0xFF0000 ) >> 16), \
|
||||
( (unsigned char *) (p) )[ 3 ] = (unsigned char)(( (n) & 0xFF000000 ) >> 24) )
|
||||
|
||||
#define READ( p ) \
|
||||
( ( (const unsigned char *) (p) )[ 0 ] | \
|
||||
( (unsigned int)((const unsigned char *) (p) )[ 1 ]) << 8 | \
|
||||
( (unsigned int)((const unsigned char *) (p) )[ 2 ]) << 16 | \
|
||||
( (unsigned int)((const unsigned char *) (p) )[ 3 ]) << 24 )
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
* 64-byte boundary. (RFC 1321, 3.1: Step 1) */
|
||||
/* But this isn't used ???? */
|
||||
/*lint -e{785} Ignore not enough initilizer warning */
|
||||
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
|
||||
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
* (RFC 1321, 3.3: Step 3) */
|
||||
void
|
||||
md5_init_ctx(struct md5_ctx *ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xefcdab89;
|
||||
ctx->C = 0x98badcfe;
|
||||
ctx->D = 0x10325476;
|
||||
|
||||
ctx->total[0] = ctx->total[1] = 0;
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result
|
||||
* must be in little endian byte order.
|
||||
*
|
||||
* IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
* aligned for a 32 bits value. */
|
||||
void *
|
||||
md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
|
||||
{
|
||||
char *r = (char *) resbuf;
|
||||
WRITE(r, ctx->A);
|
||||
WRITE(r + 4, ctx->B);
|
||||
WRITE(r + 8, ctx->C);
|
||||
WRITE(r + 12, ctx->D);
|
||||
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
/* Process the remaining bytes in the internal buffer and the usual
|
||||
* prolog according to the standard and write the result to RESBUF.
|
||||
*
|
||||
* IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
* aligned for a 32 bits value. */
|
||||
void *
|
||||
md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
|
||||
{
|
||||
/* Take yet unprocessed bytes into account. */
|
||||
md5_uint32 bytes = ctx->buflen;
|
||||
size_t pad;
|
||||
|
||||
/* Now count remaining bytes. */
|
||||
ctx->total[0] += bytes;
|
||||
if (ctx->total[0] < bytes)
|
||||
++ctx->total[1];
|
||||
|
||||
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
|
||||
memcpy(&ctx->buffer[bytes], fillbuf, pad);
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer. */
|
||||
WRITE(ctx->buffer + bytes + pad, ctx->total[0] << 3);
|
||||
WRITE(ctx->buffer + bytes + pad + 4, ((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
|
||||
|
||||
/* Process last bytes. */
|
||||
md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
|
||||
|
||||
return md5_read_ctx(ctx, resbuf);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Compute MD5 message digest for bytes read from STREAM. The
|
||||
* resulting message digest number will be written into the 16 bytes
|
||||
* beginning at RESBLOCK. */
|
||||
int
|
||||
md5_stream(FILE * stream, void *resblock)
|
||||
{
|
||||
/* Important: BLOCKSIZE must be a multiple of 64. */
|
||||
#define BLOCKSIZE 4096
|
||||
struct md5_ctx ctx;
|
||||
char buffer[BLOCKSIZE + 72];
|
||||
size_t sum;
|
||||
|
||||
/* Initialize the computation context. */
|
||||
md5_init_ctx(&ctx);
|
||||
|
||||
/* Iterate over full file contents. */
|
||||
for (;;) {
|
||||
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
|
||||
* computation function processes the whole buffer so that with the
|
||||
* next round of the loop another block can be read. */
|
||||
size_t n;
|
||||
sum = 0;
|
||||
|
||||
/* Read block. Take care for partial reads. */
|
||||
do {
|
||||
n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
|
||||
|
||||
sum += n;
|
||||
}
|
||||
while (sum < BLOCKSIZE && n != 0);
|
||||
if (n == 0 && ferror(stream))
|
||||
return 1;
|
||||
|
||||
/* If end of file is reached, end the loop. */
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
/* Process buffer with BLOCKSIZE bytes. Note that
|
||||
* BLOCKSIZE % 64 == 0
|
||||
*/
|
||||
md5_process_block(buffer, BLOCKSIZE, &ctx);
|
||||
}
|
||||
|
||||
/* Add the last bytes if necessary. */
|
||||
if (sum > 0)
|
||||
md5_process_bytes(buffer, sum, &ctx);
|
||||
|
||||
/* Construct result in desired memory. */
|
||||
md5_finish_ctx(&ctx, resblock);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
|
||||
* result is always in little endian byte order, so that a byte-wise
|
||||
* output yields to the wanted ASCII representation of the message
|
||||
* digest. */
|
||||
void *
|
||||
md5_buffer(const char *buffer, size_t len, void *resblock)
|
||||
{
|
||||
struct md5_ctx ctx;
|
||||
|
||||
/* Initialize the computation context. */
|
||||
md5_init_ctx(&ctx);
|
||||
|
||||
/* Process whole buffer but last len % 64 bytes. */
|
||||
md5_process_bytes(buffer, len, &ctx);
|
||||
|
||||
/* Put result in desired memory area. */
|
||||
return md5_finish_ctx(&ctx, resblock);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
|
||||
{
|
||||
/* const void aligned_buffer = buffer; */
|
||||
|
||||
/* When we already have some bits in our internal buffer concatenate
|
||||
* both inputs first. */
|
||||
if (ctx->buflen != 0) {
|
||||
size_t left_over = ctx->buflen;
|
||||
size_t add = 128 - left_over > len ? len : 128 - left_over;
|
||||
|
||||
/* Only put full words in the buffer. */
|
||||
add -= add % sizeof(md5_uint32);
|
||||
|
||||
memcpy(&ctx->buffer[left_over], buffer, add);
|
||||
ctx->buflen += (md5_uint32) add;
|
||||
|
||||
if (ctx->buflen > 64) {
|
||||
md5_process_block(ctx->buffer, ctx->buflen & ~63U, ctx);
|
||||
|
||||
ctx->buflen &= 63;
|
||||
/* The regions in the following copy operation cannot overlap. */
|
||||
memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63U], ctx->buflen);
|
||||
}
|
||||
|
||||
buffer = (const char *) buffer + add;
|
||||
len -= add;
|
||||
}
|
||||
|
||||
/* Process available complete blocks. */
|
||||
if (len > 64) {
|
||||
md5_process_block(buffer, len & ~63U, ctx);
|
||||
buffer = (const char *) buffer + (len & ~63U);
|
||||
len &= 63;
|
||||
}
|
||||
|
||||
/* Move remaining bytes in internal buffer. */
|
||||
if (len > 0) {
|
||||
size_t left_over = ctx->buflen;
|
||||
|
||||
memcpy(&ctx->buffer[left_over], buffer, len);
|
||||
left_over += len;
|
||||
if (left_over >= 64) {
|
||||
md5_process_block(ctx->buffer, 64, ctx);
|
||||
left_over -= 64;
|
||||
memcpy(ctx->buffer, &ctx->buffer[64], left_over);
|
||||
}
|
||||
ctx->buflen = (md5_uint32) left_over;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* These are the four functions used in the four steps of the MD5 algorithm
|
||||
* and defined in the RFC 1321. The first function is a little bit optimized
|
||||
* (as found in Colin Plumbs public domain implementation). */
|
||||
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
|
||||
#define FF(b, c, d) (d ^ (b & (c ^ d)))
|
||||
#define FG(b, c, d) FF (d, b, c)
|
||||
#define FH(b, c, d) (b ^ c ^ d)
|
||||
#define FI(b, c, d) (c ^ (b | ~d))
|
||||
|
||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||
* It is assumed that LEN % 64 == 0. */
|
||||
|
||||
void
|
||||
md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
|
||||
{
|
||||
md5_uint32 correct_words[16];
|
||||
const md5_uint32 *words = (const md5_uint32 *) buffer;
|
||||
size_t nwords = len / sizeof(md5_uint32);
|
||||
const md5_uint32 *endp = words + nwords;
|
||||
md5_uint32 A = ctx->A;
|
||||
md5_uint32 B = ctx->B;
|
||||
md5_uint32 C = ctx->C;
|
||||
md5_uint32 D = ctx->D;
|
||||
|
||||
/* First increment the byte count. RFC 1321 specifies the possible
|
||||
* length of the file up to 2^64 bits. Here we only compute the
|
||||
* number of bytes. Do a double word increment. */
|
||||
ctx->total[0] += (md5_uint32) len;
|
||||
if (ctx->total[0] < len)
|
||||
++ctx->total[1];
|
||||
|
||||
/* Process all bytes in the buffer with 64 bytes in each round of
|
||||
* the loop. */
|
||||
while (words < endp) {
|
||||
md5_uint32 *cwp = correct_words;
|
||||
md5_uint32 A_save = A;
|
||||
md5_uint32 B_save = B;
|
||||
md5_uint32 C_save = C;
|
||||
md5_uint32 D_save = D;
|
||||
|
||||
/* First round: using the given function, the context and a constant
|
||||
* the next context is computed. Because the algorithms processing
|
||||
* unit is a 32-bit word and it is determined to work on words in
|
||||
* little endian byte order we perhaps have to change the byte order
|
||||
* before the computation. To reduce the work for the next steps
|
||||
* we store the swapped words in the array CORRECT_WORDS. */
|
||||
|
||||
#define OP(a, b, c, d, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += FF (b, c, d) + (*cwp++ = READ (words)) + T; \
|
||||
++words; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* It is unfortunate that C does not provide an operator for
|
||||
* cyclic rotation. Hope the C compiler is smart enough. */
|
||||
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
|
||||
|
||||
/* Before we start, one word to the strange constants.
|
||||
* They are defined in RFC 1321 as
|
||||
*
|
||||
* T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
|
||||
*/
|
||||
|
||||
/* Round 1. */
|
||||
/*lint --e{123, 717} Ignore macro warning */
|
||||
OP(A, B, C, D, 7, 0xd76aa478);
|
||||
OP(D, A, B, C, 12, 0xe8c7b756);
|
||||
OP(C, D, A, B, 17, 0x242070db);
|
||||
OP(B, C, D, A, 22, 0xc1bdceee);
|
||||
OP(A, B, C, D, 7, 0xf57c0faf);
|
||||
OP(D, A, B, C, 12, 0x4787c62a);
|
||||
OP(C, D, A, B, 17, 0xa8304613);
|
||||
OP(B, C, D, A, 22, 0xfd469501);
|
||||
OP(A, B, C, D, 7, 0x698098d8);
|
||||
OP(D, A, B, C, 12, 0x8b44f7af);
|
||||
OP(C, D, A, B, 17, 0xffff5bb1);
|
||||
OP(B, C, D, A, 22, 0x895cd7be);
|
||||
OP(A, B, C, D, 7, 0x6b901122);
|
||||
OP(D, A, B, C, 12, 0xfd987193);
|
||||
OP(C, D, A, B, 17, 0xa679438e);
|
||||
OP(B, C, D, A, 22, 0x49b40821);
|
||||
|
||||
/* For the second to fourth round we have the possibly swapped words
|
||||
* in CORRECT_WORDS. Redefine the macro to take an additional first
|
||||
* argument specifying the function to use. */
|
||||
#undef OP
|
||||
#define OP(f, a, b, c, d, k, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += f (b, c, d) + correct_words[k] + T; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Round 2. */
|
||||
OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
|
||||
OP(FG, D, A, B, C, 6, 9, 0xc040b340);
|
||||
OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
|
||||
OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
|
||||
OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
|
||||
OP(FG, D, A, B, C, 10, 9, 0x02441453);
|
||||
OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
|
||||
OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
|
||||
OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
|
||||
OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
|
||||
OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
|
||||
OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
|
||||
OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
|
||||
OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
|
||||
OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
|
||||
OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
|
||||
|
||||
/* Round 3. */
|
||||
OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
|
||||
OP(FH, D, A, B, C, 8, 11, 0x8771f681);
|
||||
OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
|
||||
OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
|
||||
OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
|
||||
OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
|
||||
OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
|
||||
OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
|
||||
OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
|
||||
OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
|
||||
OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
|
||||
OP(FH, B, C, D, A, 6, 23, 0x04881d05);
|
||||
OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
|
||||
OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
|
||||
OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
|
||||
OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
|
||||
|
||||
/* Round 4. */
|
||||
OP(FI, A, B, C, D, 0, 6, 0xf4292244);
|
||||
OP(FI, D, A, B, C, 7, 10, 0x432aff97);
|
||||
OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
|
||||
OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
|
||||
OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
|
||||
OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
|
||||
OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
|
||||
OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
|
||||
OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
|
||||
OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
|
||||
OP(FI, C, D, A, B, 6, 15, 0xa3014314);
|
||||
OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
|
||||
OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
|
||||
OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
|
||||
OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
|
||||
OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
|
||||
|
||||
/* Add the starting values of the context. */
|
||||
A += A_save;
|
||||
B += B_save;
|
||||
C += C_save;
|
||||
D += D_save;
|
||||
}
|
||||
|
||||
/* Put checksum in context given as argument. */
|
||||
ctx->A = A;
|
||||
ctx->B = B;
|
||||
ctx->C = C;
|
||||
ctx->D = D;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Declaration of functions and data types used for MD5 sum computing
|
||||
* library functions.
|
||||
* Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
|
||||
*
|
||||
* Minor modifications for use with GNU Backgammon.
|
||||
* Copyright (C) 2009-2021 the AUTHORS
|
||||
*
|
||||
* License changed from the GNU LGPL to the GNU GPL (as permitted under Term 3
|
||||
* of the GNU LGPL) by Gary Wong for distribution with GNU Backgammon.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: md5.h,v 1.8 2014/05/11 15:20:32 plm Exp $
|
||||
*/
|
||||
|
||||
#ifndef MD5_H
|
||||
#define MD5_H 1
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef uint32_t md5_uint32;
|
||||
|
||||
/* Structure to save state of computation between the single steps. */
|
||||
struct md5_ctx {
|
||||
md5_uint32 A;
|
||||
md5_uint32 B;
|
||||
md5_uint32 C;
|
||||
md5_uint32 D;
|
||||
|
||||
md5_uint32 total[2];
|
||||
md5_uint32 buflen;
|
||||
char buffer[128] __attribute__ ((__aligned__(__alignof__(md5_uint32))));
|
||||
};
|
||||
|
||||
/*
|
||||
* The following three functions are build up the low level used in
|
||||
* the functions `md5_stream' and `md5_buffer'.
|
||||
*/
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
* (RFC 1321, 3.3: Step 3) */
|
||||
extern void md5_init_ctx(struct md5_ctx *ctx);
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
* initialization function) update the context for the next LEN bytes
|
||||
* starting at BUFFER.
|
||||
* It is necessary that LEN is a multiple of 64!!! */
|
||||
extern void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx);
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
* initialization function) update the context for the next LEN bytes
|
||||
* starting at BUFFER.
|
||||
* It is NOT required that LEN is a multiple of 64. */
|
||||
extern void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx);
|
||||
|
||||
/* Process the remaining bytes in the buffer and put result from CTX
|
||||
* in first 16 bytes following RESBUF. The result is always in little
|
||||
* endian byte order, so that a byte-wise output yields to the wanted
|
||||
* ASCII representation of the message digest.
|
||||
*
|
||||
* IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
* aligned for a 32 bits value. */
|
||||
extern void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf);
|
||||
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result is
|
||||
* always in little endian byte order, so that a byte-wise output yields
|
||||
* to the wanted ASCII representation of the message digest.
|
||||
*
|
||||
* IMPORTANT: On some systems it is required that RESBUF is correctly
|
||||
* aligned for a 32 bits value. */
|
||||
extern void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf);
|
||||
|
||||
|
||||
#if 0
|
||||
/* Compute MD5 message digest for bytes read from STREAM. The
|
||||
* resulting message digest number will be written into the 16 bytes
|
||||
* beginning at RESBLOCK. */
|
||||
extern int md5_stream(FILE * stream, void *resblock);
|
||||
#endif
|
||||
|
||||
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
|
||||
* result is always in little endian byte order, so that a byte-wise
|
||||
* output yields to the wanted ASCII representation of the message
|
||||
* digest. */
|
||||
extern void *md5_buffer(const char *buffer, size_t len, void *resblock);
|
||||
|
||||
#endif /* md5.h */
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2000-2019 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "backgammon.h"
|
||||
#include "common.h"
|
||||
#include <glib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "neuralnet.h"
|
||||
#include "simd.h"
|
||||
#include "sigmoid.h"
|
||||
|
||||
static int
|
||||
NeuralNetCreate(neuralnet * pnn, unsigned int cInput, unsigned int cHidden,
|
||||
unsigned int cOutput, float rBetaHidden, float rBetaOutput)
|
||||
{
|
||||
pnn->cInput = cInput;
|
||||
pnn->cHidden = cHidden;
|
||||
pnn->cOutput = cOutput;
|
||||
pnn->rBetaHidden = rBetaHidden;
|
||||
pnn->rBetaOutput = rBetaOutput;
|
||||
pnn->nTrained = 0;
|
||||
|
||||
if ((pnn->arHiddenWeight = sse_malloc(cHidden * cInput * sizeof(float))) == NULL)
|
||||
return -1;
|
||||
|
||||
if ((pnn->arOutputWeight = sse_malloc(cOutput * cHidden * sizeof(float))) == NULL) {
|
||||
sse_free(pnn->arHiddenWeight);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pnn->arHiddenThreshold = sse_malloc(cHidden * sizeof(float))) == NULL) {
|
||||
sse_free(pnn->arOutputWeight);
|
||||
sse_free(pnn->arHiddenWeight);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pnn->arOutputThreshold = sse_malloc(cOutput * sizeof(float))) == NULL) {
|
||||
sse_free(pnn->arHiddenThreshold);
|
||||
sse_free(pnn->arOutputWeight);
|
||||
sse_free(pnn->arHiddenWeight);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void
|
||||
NeuralNetDestroy(neuralnet * pnn)
|
||||
{
|
||||
sse_free(pnn->arHiddenWeight);
|
||||
pnn->arHiddenWeight = 0;
|
||||
sse_free(pnn->arOutputWeight);
|
||||
pnn->arOutputWeight = 0;
|
||||
sse_free(pnn->arHiddenThreshold);
|
||||
pnn->arHiddenThreshold = 0;
|
||||
sse_free(pnn->arOutputThreshold);
|
||||
pnn->arOutputThreshold = 0;
|
||||
}
|
||||
|
||||
#if !defined(USE_SIMD_INSTRUCTIONS)
|
||||
|
||||
/* separate context for race, crashed, contact
|
||||
* -1: regular eval
|
||||
* 0: save base
|
||||
* 1: from base
|
||||
*/
|
||||
|
||||
static inline NNEvalType
|
||||
NNevalAction(NNState * pnState)
|
||||
{
|
||||
if (!pnState)
|
||||
return NNEVAL_NONE;
|
||||
|
||||
switch (pnState->state) {
|
||||
case NNSTATE_NONE:
|
||||
{
|
||||
/* incremental evaluation not useful */
|
||||
return NNEVAL_NONE;
|
||||
}
|
||||
case NNSTATE_INCREMENTAL:
|
||||
{
|
||||
/* next call should return FROMBASE */
|
||||
pnState->state = NNSTATE_DONE;
|
||||
|
||||
/* starting a new context; save base in the hope it will be useful */
|
||||
return NNEVAL_SAVE;
|
||||
}
|
||||
case NNSTATE_DONE:
|
||||
{
|
||||
/* context hit! use the previously computed base */
|
||||
return NNEVAL_FROMBASE;
|
||||
}
|
||||
}
|
||||
/* never reached */
|
||||
return NNEVAL_NONE; /* for the picky compiler */
|
||||
}
|
||||
|
||||
static void
|
||||
Evaluate(const neuralnet * pnn, const float arInput[], float ar[], float arOutput[], float *saveAr)
|
||||
{
|
||||
const unsigned int cHidden = pnn->cHidden;
|
||||
unsigned int i, j;
|
||||
float *prWeight;
|
||||
|
||||
/* Calculate activity at hidden nodes */
|
||||
for (i = 0; i < cHidden; i++)
|
||||
ar[i] = pnn->arHiddenThreshold[i];
|
||||
|
||||
prWeight = pnn->arHiddenWeight;
|
||||
|
||||
for (i = 0; i < pnn->cInput; i++) {
|
||||
float const ari = arInput[i];
|
||||
|
||||
if (ari == 0.0f)
|
||||
prWeight += cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
|
||||
if (ari == 1.0f)
|
||||
for (j = cHidden; j; j--)
|
||||
*pr++ += *prWeight++;
|
||||
else
|
||||
for (j = cHidden; j; j--)
|
||||
*pr++ += *prWeight++ * ari;
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAr)
|
||||
memcpy(saveAr, ar, cHidden * sizeof(*saveAr));
|
||||
|
||||
for (i = 0; i < cHidden; i++)
|
||||
ar[i] = sigmoid(-pnn->rBetaHidden * ar[i]);
|
||||
|
||||
/* Calculate activity at output nodes */
|
||||
prWeight = pnn->arOutputWeight;
|
||||
|
||||
for (i = 0; i < pnn->cOutput; i++) {
|
||||
float r = pnn->arOutputThreshold[i];
|
||||
|
||||
for (j = 0; j < cHidden; j++)
|
||||
r += ar[j] * *prWeight++;
|
||||
|
||||
arOutput[i] = sigmoid(-pnn->rBetaOutput * r);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
EvaluateFromBase(const neuralnet * pnn, const float arInputDif[], float ar[], float arOutput[])
|
||||
{
|
||||
unsigned int i, j;
|
||||
float *prWeight;
|
||||
|
||||
/* Calculate activity at hidden nodes */
|
||||
/* for( i = 0; i < pnn->cHidden; i++ )
|
||||
* ar[ i ] = pnn->arHiddenThreshold[ i ]; */
|
||||
|
||||
prWeight = pnn->arHiddenWeight;
|
||||
|
||||
for (i = 0; i < pnn->cInput; ++i) {
|
||||
float const ari = arInputDif[i];
|
||||
|
||||
if (ari == 0.0f)
|
||||
prWeight += pnn->cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
|
||||
if (ari == 1.0f)
|
||||
for (j = pnn->cHidden; j; j--)
|
||||
*pr++ += *prWeight++;
|
||||
else if (ari == -1.0f)
|
||||
for (j = pnn->cHidden; j; j--)
|
||||
*pr++ -= *prWeight++;
|
||||
else
|
||||
for (j = pnn->cHidden; j; j--)
|
||||
*pr++ += *prWeight++ * ari;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < pnn->cHidden; i++)
|
||||
ar[i] = sigmoid(-pnn->rBetaHidden * ar[i]);
|
||||
|
||||
/* Calculate activity at output nodes */
|
||||
prWeight = pnn->arOutputWeight;
|
||||
|
||||
for (i = 0; i < pnn->cOutput; i++) {
|
||||
float r = pnn->arOutputThreshold[i];
|
||||
|
||||
for (j = 0; j < pnn->cHidden; j++)
|
||||
r += ar[j] * *prWeight++;
|
||||
|
||||
arOutput[i] = sigmoid(-pnn->rBetaOutput * r);
|
||||
}
|
||||
}
|
||||
|
||||
extern int
|
||||
NeuralNetEvaluate(const neuralnet * pnn, float arInput[], float arOutput[], NNState * pnState)
|
||||
{
|
||||
float *ar = (float *) g_alloca(pnn->cHidden * sizeof(float));
|
||||
switch (NNevalAction(pnState)) {
|
||||
case NNEVAL_NONE:
|
||||
{
|
||||
Evaluate(pnn, arInput, ar, arOutput, 0);
|
||||
break;
|
||||
}
|
||||
case NNEVAL_SAVE:
|
||||
{
|
||||
pnState->cSavedIBase = pnn->cInput;
|
||||
memcpy(pnState->savedIBase, arInput, pnn->cInput * sizeof(*ar));
|
||||
Evaluate(pnn, arInput, ar, arOutput, pnState->savedBase);
|
||||
break;
|
||||
}
|
||||
case NNEVAL_FROMBASE:
|
||||
{
|
||||
if (pnState->cSavedIBase != pnn->cInput) {
|
||||
Evaluate(pnn, arInput, ar, arOutput, 0);
|
||||
break;
|
||||
}
|
||||
memcpy(ar, pnState->savedBase, pnn->cHidden * sizeof(*ar));
|
||||
|
||||
{
|
||||
float *r = arInput;
|
||||
float *s = pnState->savedIBase;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < pnn->cInput; ++i, ++r, ++s) {
|
||||
if (*r != *s /*lint --e(777) */ ) {
|
||||
*r -= *s;
|
||||
} else {
|
||||
*r = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
EvaluateFromBase(pnn, arInput, ar, arOutput);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int
|
||||
NeuralNetLoad(neuralnet * pnn, FILE * pf)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
float *pr;
|
||||
char dummy[16];
|
||||
|
||||
if (fscanf(pf, "%u %u %u %15s %f %f\n", &pnn->cInput, &pnn->cHidden,
|
||||
&pnn->cOutput, dummy, &pnn->rBetaHidden,
|
||||
&pnn->rBetaOutput) < 5 || pnn->cInput < 1 ||
|
||||
pnn->cHidden < 1 || pnn->cOutput < 1 || pnn->rBetaHidden <= 0.0f || pnn->rBetaOutput <= 0.0f) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NeuralNetCreate(pnn, pnn->cInput, pnn->cHidden, pnn->cOutput, pnn->rBetaHidden, pnn->rBetaOutput))
|
||||
return -1;
|
||||
|
||||
pnn->nTrained = 1;
|
||||
|
||||
for (i = pnn->cInput * pnn->cHidden, pr = pnn->arHiddenWeight; i; i--)
|
||||
if (fscanf(pf, "%f\n", pr++) < 1)
|
||||
return -1;
|
||||
|
||||
for (i = pnn->cHidden * pnn->cOutput, pr = pnn->arOutputWeight; i; i--)
|
||||
if (fscanf(pf, "%f\n", pr++) < 1)
|
||||
return -1;
|
||||
|
||||
for (i = pnn->cHidden, pr = pnn->arHiddenThreshold; i; i--)
|
||||
if (fscanf(pf, "%f\n", pr++) < 1)
|
||||
return -1;
|
||||
|
||||
for (i = pnn->cOutput, pr = pnn->arOutputThreshold; i; i--)
|
||||
if (fscanf(pf, "%f\n", pr++) < 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int
|
||||
NeuralNetLoadBinary(neuralnet * pnn, FILE * pf)
|
||||
{
|
||||
|
||||
int dummy;
|
||||
|
||||
#define FREAD( p, c ) \
|
||||
if ( fread( (p), sizeof( *(p) ), (c), pf ) < (unsigned int)(c) ) return -1
|
||||
|
||||
FREAD(&pnn->cInput, 1);
|
||||
FREAD(&pnn->cHidden, 1);
|
||||
FREAD(&pnn->cOutput, 1);
|
||||
FREAD(&dummy, 1);
|
||||
FREAD(&pnn->rBetaHidden, 1);
|
||||
FREAD(&pnn->rBetaOutput, 1);
|
||||
|
||||
if (pnn->cInput < 1 || pnn->cHidden < 1 || pnn->cOutput < 1 || pnn->rBetaHidden <= 0.0f || pnn->rBetaOutput <= 0.0f) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NeuralNetCreate(pnn, pnn->cInput, pnn->cHidden, pnn->cOutput, pnn->rBetaHidden, pnn->rBetaOutput))
|
||||
return -1;
|
||||
|
||||
pnn->nTrained = 1;
|
||||
|
||||
FREAD(pnn->arHiddenWeight, pnn->cInput * pnn->cHidden);
|
||||
FREAD(pnn->arOutputWeight, pnn->cHidden * pnn->cOutput);
|
||||
FREAD(pnn->arHiddenThreshold, pnn->cHidden);
|
||||
FREAD(pnn->arOutputThreshold, pnn->cOutput);
|
||||
#undef FREAD
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int
|
||||
NeuralNetSaveBinary(const neuralnet * pnn, FILE * pf)
|
||||
{
|
||||
|
||||
#define FWRITE( p, c ) \
|
||||
if ( fwrite( (p), sizeof( *(p) ), (c), pf ) < (unsigned int)(c) ) return -1
|
||||
|
||||
FWRITE(&pnn->cInput, 1);
|
||||
FWRITE(&pnn->cHidden, 1);
|
||||
FWRITE(&pnn->cOutput, 1);
|
||||
FWRITE(&pnn->nTrained, 1);
|
||||
FWRITE(&pnn->rBetaHidden, 1);
|
||||
FWRITE(&pnn->rBetaOutput, 1);
|
||||
|
||||
FWRITE(pnn->arHiddenWeight, pnn->cInput * pnn->cHidden);
|
||||
FWRITE(pnn->arOutputWeight, pnn->cHidden * pnn->cOutput);
|
||||
FWRITE(pnn->arHiddenThreshold, pnn->cHidden);
|
||||
FWRITE(pnn->arOutputThreshold, pnn->cOutput);
|
||||
#undef FWRITE
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(USE_SIMD_INSTRUCTIONS)
|
||||
|
||||
#if defined(DISABLE_SIMD_TEST)
|
||||
|
||||
int
|
||||
SIMD_Supported(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if defined(HAVE_SSE)
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
static int
|
||||
check_for_cpuid(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if defined(ENVIRONMENT32) && defined(__PIC__)
|
||||
/* We have to be careful to not destroy ebx if using PIC on 32bit builds */
|
||||
"pushl %%ebx\n\t"
|
||||
#endif
|
||||
"mov $1, %%eax\n\t"
|
||||
"shl $21, %%eax\n\t"
|
||||
"mov %%eax, %%edx\n\t"
|
||||
#if defined(ENVIRONMENT64)
|
||||
"pushf\n\t"
|
||||
"pop %%rax\n\t"
|
||||
#else
|
||||
"pushfl\n\t"
|
||||
"popl %%eax\n\t"
|
||||
#endif
|
||||
"mov %%eax, %%ecx\n\t"
|
||||
"xor %%edx, %%eax\n\t"
|
||||
#if defined(ENVIRONMENT64)
|
||||
"push %%rax\n\t"
|
||||
"popf\n\t"
|
||||
"pushf\n\t"
|
||||
"pop %%rax\n\t"
|
||||
#else
|
||||
"pushl %%eax\n\t"
|
||||
"popfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %%eax\n\t"
|
||||
#endif
|
||||
"xor %%ecx, %%eax\n\t"
|
||||
"test %%edx, %%eax\n\t"
|
||||
"jnz cpuid_success\n\t"
|
||||
/* Failed (non-pentium compatible machine) */
|
||||
"mov $-1, %%eax\n\t"
|
||||
"jmp cpuid_finished\n\t"
|
||||
|
||||
"cpuid_success:"
|
||||
"xor %%eax, %%eax\n\t"
|
||||
"cpuid\n\t"
|
||||
"cmp $1, %%eax\n\t"
|
||||
/* If 0 returned processor doesn't hav feature test */
|
||||
"jge feature_success\n\t"
|
||||
|
||||
/* Unlucky - somehow cpuid 1 isn't supported */
|
||||
"mov $-2, %%eax\n\t"
|
||||
"jmp cpuid_finished\n\t"
|
||||
|
||||
"feature_success:"
|
||||
"xor %%eax, %%eax\n\t"
|
||||
|
||||
"cpuid_finished:"
|
||||
#if defined(ENVIRONMENT32) && defined(__PIC__)
|
||||
"popl %%ebx\n\t"
|
||||
#endif
|
||||
: "=a"(result)
|
||||
:
|
||||
: "%ecx",
|
||||
#if !defined(ENVIRONMENT32) || !defined(__PIC__)
|
||||
"%ebx",
|
||||
#endif
|
||||
"%edx");
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
CheckSSE(void)
|
||||
{
|
||||
int result;
|
||||
int cpuidchk;
|
||||
|
||||
if ((cpuidchk = check_for_cpuid()) < 0)
|
||||
return cpuidchk;
|
||||
|
||||
#if defined(USE_AVX)
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if defined(ENVIRONMENT32) && defined(__PIC__)
|
||||
/* We have to be careful to not destroy ebx if using PIC on 32bit builds */
|
||||
"pushl %%ebx\n\t"
|
||||
#endif
|
||||
"mov $1, %%eax\n\t"
|
||||
"cpuid\n\t"
|
||||
"and $0x018000000, %%ecx\n\t" /* Check bit 27 (OS uses XSAVE/XRSTOR)*/
|
||||
"cmp $0x018000000, %%ecx\n\t" /* and bit 28 (AVX supported by CPU) */
|
||||
"jne avx_unsupported\n\t"
|
||||
"xor %%ecx, %%ecx\n\t" /* XFEATURE_ENABLED_MASK/XCR0 register number = 0 */
|
||||
"xgetbv\n\t" /* XFEATURE_ENABLED_MASK register is in edx:eax" */
|
||||
"and $0b110, %%eax\n\t"
|
||||
"cmp $0b110, %%eax\n\t" /* check the AVX registers restore at context switch */
|
||||
"jne avx_unsupported\n\t"
|
||||
"mov $1, %%eax\n\t"
|
||||
"jmp avx_end\n\t"
|
||||
|
||||
"avx_unsupported:"
|
||||
"xor %%eax, %%eax\n\t"
|
||||
|
||||
"avx_end:"
|
||||
#if defined(ENVIRONMENT32) && defined(__PIC__)
|
||||
"popl %%ebx\n\t"
|
||||
#endif
|
||||
: "=a"(result) /* Result returned in result variable */
|
||||
:
|
||||
: "%ecx",
|
||||
#if !defined(ENVIRONMENT32) || !defined(__PIC__)
|
||||
"%ebx",
|
||||
#endif
|
||||
"%edx"); /* These are all destroyed by cpuid */
|
||||
|
||||
#else
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
size_t length = sizeof(result);
|
||||
#if defined(__APPLE__)
|
||||
int error = sysctlbyname("hw.optional.sse", &result, &length, NULL, 0);
|
||||
#endif
|
||||
#if defined(__FreeBSD__)
|
||||
int error = sysctlbyname("hw.instruction_sse", &result, &length, NULL, 0);
|
||||
#endif
|
||||
if (error != 0)
|
||||
result = 0;
|
||||
|
||||
#else
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if defined(ENVIRONMENT32) && defined(__PIC__)
|
||||
/* We have to be careful to not destroy ebx if using PIC on I386 */
|
||||
"pushl %%ebx\n\t"
|
||||
#endif
|
||||
/* Check if sse is supported (bit 25/26 in edx from cpuid 1) */
|
||||
"mov $1, %%eax\n\t"
|
||||
"cpuid\n\t"
|
||||
"mov $1, %%eax\n\t"
|
||||
#if defined(USE_SSE2)
|
||||
"shl $26, %%eax\n\t"
|
||||
#else
|
||||
"shl $25, %%eax\n\t"
|
||||
#endif
|
||||
"test %%eax, %%edx\n\t"
|
||||
"jnz sse_success\n\t"
|
||||
/* Not supported */
|
||||
"mov $0, %%eax\n\t"
|
||||
"jmp sse_end\n\t"
|
||||
|
||||
"sse_success:"
|
||||
/* Supported */
|
||||
"mov $1, %%eax\n\t"
|
||||
|
||||
"sse_end:"
|
||||
#if defined(ENVIRONMENT32) && defined(__PIC__)
|
||||
"pop %%ebx\n\t"
|
||||
#endif
|
||||
|
||||
: "=a"(result)
|
||||
:
|
||||
: "%ecx",
|
||||
#if !defined(ENVIRONMENT32) || !defined(__PIC__)
|
||||
"%ebx",
|
||||
#endif
|
||||
"%edx");
|
||||
#endif /* APPLE/BSD */
|
||||
|
||||
#endif /* USE_AVX */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SSE */
|
||||
|
||||
int
|
||||
SIMD_Supported(void)
|
||||
{
|
||||
static int state = -3;
|
||||
|
||||
if (state == -3) {
|
||||
#if defined(HAVE_NEON)
|
||||
state = CheckNEON();
|
||||
#elif defined(HAVE_SSE)
|
||||
state = CheckSSE();
|
||||
#else
|
||||
state = -2;
|
||||
#endif
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2002-2017 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: neuralnet.h,v 1.36 2020/06/05 20:08:31 plm Exp $
|
||||
*/
|
||||
|
||||
#ifndef NEURALNET_H
|
||||
#define NEURALNET_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int cInput;
|
||||
unsigned int cHidden;
|
||||
unsigned int cOutput;
|
||||
int nTrained;
|
||||
float rBetaHidden;
|
||||
float rBetaOutput;
|
||||
float *arHiddenWeight;
|
||||
float *arOutputWeight;
|
||||
float *arHiddenThreshold;
|
||||
float *arOutputThreshold;
|
||||
} neuralnet;
|
||||
|
||||
typedef enum {
|
||||
NNEVAL_NONE,
|
||||
NNEVAL_SAVE,
|
||||
NNEVAL_FROMBASE
|
||||
} NNEvalType;
|
||||
|
||||
typedef enum {
|
||||
NNSTATE_NONE = -1,
|
||||
NNSTATE_INCREMENTAL,
|
||||
NNSTATE_DONE
|
||||
} NNStateType;
|
||||
|
||||
typedef struct {
|
||||
NNStateType state;
|
||||
float *savedBase;
|
||||
float *savedIBase;
|
||||
#if !defined(USE_SIMD_INSTRUCTIONS)
|
||||
unsigned int cSavedIBase;
|
||||
#endif
|
||||
} NNState;
|
||||
|
||||
extern void NeuralNetDestroy(neuralnet * pnn);
|
||||
#if !defined(USE_SIMD_INSTRUCTIONS)
|
||||
extern int NeuralNetEvaluate(const neuralnet * pnn, float arInput[], float arOutput[], NNState * pnState);
|
||||
#else
|
||||
extern int NeuralNetEvaluateSSE(const neuralnet * pnn, float arInput[], float arOutput[], NNState * pnState);
|
||||
#endif
|
||||
extern int NeuralNetLoad(neuralnet * pnn, FILE * pf);
|
||||
extern int NeuralNetLoadBinary(neuralnet * pnn, FILE * pf);
|
||||
extern int NeuralNetSaveBinary(const neuralnet * pnn, FILE * pf);
|
||||
extern int SIMD_Supported(void);
|
||||
|
||||
/* Try to determine whether we are 64-bit or 32-bit */
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
#define ENVIRONMENT64
|
||||
#else
|
||||
#define ENVIRONMENT32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if defined(__x86_64__)
|
||||
#define ENVIRONMENT64
|
||||
#else
|
||||
#define ENVIRONMENT32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2009 Jon Kinsey <jonkinsey@gmail.com>
|
||||
* Copyright (C) 2007-2021 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
|
||||
#if defined(USE_SIMD_INSTRUCTIONS)
|
||||
|
||||
#define DEBUG_SSE 0
|
||||
|
||||
#include "simd.h"
|
||||
#include "neuralnet.h"
|
||||
#include <string.h>
|
||||
|
||||
#if defined(USE_NEON)
|
||||
#include <arm_neon.h>
|
||||
#elif defined(USE_AVX)
|
||||
#include <immintrin.h>
|
||||
#elif defined(USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#else
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include "sigmoid.h"
|
||||
|
||||
#if defined(HAVE_NEON)
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
float *
|
||||
sse_malloc(size_t size)
|
||||
{
|
||||
#if defined(HAVE_POSIX_MEMALIGN)
|
||||
void *ptr = NULL;
|
||||
int ret;
|
||||
|
||||
ret = posix_memalign(&ptr, ALIGN_SIZE, size);
|
||||
|
||||
if (ret == 0)
|
||||
return (float *)ptr;
|
||||
|
||||
/* mimic g_malloc() error message */
|
||||
g_error("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", G_STRLOC, size);
|
||||
|
||||
/* avoid warning: "control reaches end of non-void function" for
|
||||
compilers that don't understand that g_error() never returns. */
|
||||
return NULL;
|
||||
|
||||
#elif defined(HAVE__ALIGNED_MALLOC)
|
||||
return (float *) _aligned_malloc(size, ALIGN_SIZE);
|
||||
#else
|
||||
return (float *) _mm_malloc(size, ALIGN_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sse_free(float *ptr)
|
||||
{
|
||||
#if defined(HAVE_POSIX_MEMALIGN)
|
||||
free(ptr);
|
||||
#elif defined(HAVE__ALIGNED_MALLOC)
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
_mm_free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_NEON)
|
||||
static jmp_buf env;
|
||||
|
||||
static void
|
||||
my_handler(int status)
|
||||
{
|
||||
longjmp(env, status);
|
||||
}
|
||||
|
||||
int
|
||||
CheckNEON(void)
|
||||
{
|
||||
void (*oldsig)(int);
|
||||
|
||||
oldsig = signal(SIGILL, my_handler);
|
||||
if (setjmp(env)) {
|
||||
signal(SIGILL, oldsig);
|
||||
return 0;
|
||||
} else {
|
||||
#if defined(__ARM_FEATURE_SIMD32)
|
||||
/* v7 */
|
||||
__asm__ __volatile__ ("vmin.f32 q0, q0, q0");
|
||||
#elif defined(__ARM_NEON)
|
||||
/* aarch64 */
|
||||
__asm__ __volatile__ ("fmin v0.4s, v0.4s, v0.4s");
|
||||
#else
|
||||
#error "Unexpected ARM architecture"
|
||||
#endif
|
||||
signal(SIGILL, oldsig);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_AVX) || defined(USE_SSE2) || defined(USE_NEON)
|
||||
#include <stdint.h>
|
||||
|
||||
static const union {
|
||||
float f[VEC_SIZE];
|
||||
float_vector ps;
|
||||
#if defined(USE_AVX)
|
||||
} ones = { {
|
||||
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}};
|
||||
#else
|
||||
} ones = { {
|
||||
1.0f, 1.0f, 1.0f, 1.0f}};
|
||||
#endif
|
||||
|
||||
static const union {
|
||||
float f[VEC_SIZE];
|
||||
float_vector ps;
|
||||
#if defined(USE_AVX)
|
||||
} tens = { {
|
||||
10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f}};
|
||||
#else
|
||||
} tens = { {
|
||||
10.0f, 10.0f, 10.0f, 10.0f}};
|
||||
#endif
|
||||
|
||||
static const union {
|
||||
int32_t i32[VEC_SIZE];
|
||||
float_vector ps;
|
||||
#if defined(USE_AVX)
|
||||
} abs_mask = { {
|
||||
0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}};
|
||||
#else
|
||||
} abs_mask = { {
|
||||
0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}};
|
||||
#endif
|
||||
|
||||
static inline float_vector
|
||||
sigmoid_positive_ps(float_vector xin)
|
||||
{
|
||||
union {
|
||||
int_vector i;
|
||||
int32_t i32[VEC_SIZE];
|
||||
} i;
|
||||
float_vector ex;
|
||||
float *ex_elem = (float *) &ex;
|
||||
#if defined(USE_AVX)
|
||||
float_vector x1 = _mm256_min_ps(xin, tens.ps);
|
||||
#elif defined(HAVE_SSE)
|
||||
float_vector x1 = _mm_min_ps(xin, tens.ps);
|
||||
#else
|
||||
float_vector x1 = vminq_f32(xin, tens.ps);
|
||||
float_vector rec;
|
||||
#endif
|
||||
|
||||
#if defined(USE_AVX)
|
||||
x1 = _mm256_mul_ps(x1, tens.ps);
|
||||
i.i = _mm256_cvttps_epi32(x1);
|
||||
#elif defined(HAVE_SSE)
|
||||
x1 = _mm_mul_ps(x1, tens.ps);
|
||||
i.i = _mm_cvttps_epi32(x1);
|
||||
#else
|
||||
x1 = vmulq_f32(x1, tens.ps);
|
||||
i.i = vcvtq_s32_f32(x1);
|
||||
#endif
|
||||
ex_elem[0] = e[i.i32[0]];
|
||||
ex_elem[1] = e[i.i32[1]];
|
||||
ex_elem[2] = e[i.i32[2]];
|
||||
ex_elem[3] = e[i.i32[3]];
|
||||
#if defined(USE_AVX)
|
||||
ex_elem[4] = e[i.i32[4]];
|
||||
ex_elem[5] = e[i.i32[5]];
|
||||
ex_elem[6] = e[i.i32[6]];
|
||||
ex_elem[7] = e[i.i32[7]];
|
||||
#endif
|
||||
|
||||
#if defined(USE_AVX)
|
||||
x1 = _mm256_sub_ps(x1, _mm256_cvtepi32_ps(i.i));
|
||||
x1 = _mm256_add_ps(x1, tens.ps);
|
||||
#if defined(USE_FMA3)
|
||||
x1 = _mm256_fmadd_ps(x1, ex, ones.ps);
|
||||
#else
|
||||
x1 = _mm256_mul_ps(x1, ex);
|
||||
x1 = _mm256_add_ps(x1, ones.ps);
|
||||
#endif
|
||||
#ifdef __FAST_MATH__
|
||||
return _mm256_rcp_ps(x1);
|
||||
#else
|
||||
return _mm256_div_ps(ones.ps, x1);
|
||||
#endif
|
||||
#elif defined(HAVE_SSE)
|
||||
x1 = _mm_sub_ps(x1, _mm_cvtepi32_ps(i.i));
|
||||
x1 = _mm_add_ps(x1, tens.ps);
|
||||
x1 = _mm_mul_ps(x1, ex);
|
||||
x1 = _mm_add_ps(x1, ones.ps);
|
||||
#ifdef __FAST_MATH__
|
||||
return _mm_rcp_ps(x1);
|
||||
#else
|
||||
return _mm_div_ps(ones.ps, x1);
|
||||
#endif
|
||||
#else
|
||||
x1 = vsubq_f32(x1, vcvtq_f32_s32(i.i));
|
||||
x1 = vaddq_f32(x1, tens.ps);
|
||||
x1 = vmulq_f32(x1, ex);
|
||||
x1 = vaddq_f32(x1, ones.ps);
|
||||
|
||||
/* TODO: Check how many Newton-Raphson iterations are needed to match x86 rcp and div accuracy */
|
||||
#ifdef __FAST_MATH__
|
||||
rec = vrecpeq_f32(x1);
|
||||
return vmulq_f32(vrecpsq_f32(x1, rec), rec);
|
||||
#else
|
||||
rec = vrecpeq_f32(x1);
|
||||
rec = vmulq_f32(vrecpsq_f32(x1, rec), rec);
|
||||
return vmulq_f32(vrecpsq_f32(x1, rec), rec);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline float_vector
|
||||
sigmoid_ps(float_vector xin)
|
||||
{
|
||||
#if defined(USE_AVX)
|
||||
float_vector mask = _mm256_cmp_ps(xin, _mm256_setzero_ps(), _CMP_LT_OS);
|
||||
float_vector c;
|
||||
xin = _mm256_and_ps(xin, abs_mask.ps); /* Abs. value by clearing signbit */
|
||||
c = sigmoid_positive_ps(xin);
|
||||
return _mm256_blendv_ps(c, _mm256_sub_ps(ones.ps, c), mask);
|
||||
#elif defined(HAVE_SSE)
|
||||
float_vector mask = _mm_cmplt_ps(xin, _mm_setzero_ps());
|
||||
float_vector c;
|
||||
xin = _mm_and_ps(xin, abs_mask.ps); /* Abs. value by clearing signbit */
|
||||
c = sigmoid_positive_ps(xin);
|
||||
/* _mm_blendv_ps() is only available with SSE4.1 or later */
|
||||
return _mm_or_ps(_mm_andnot_ps(mask, c), _mm_and_ps(mask, _mm_sub_ps(ones.ps, c)));
|
||||
#else
|
||||
int_vector mask = (int_vector)vcltq_f32(xin, vdupq_n_f32(0.0f));
|
||||
float_vector c;
|
||||
xin = (float_vector)vandq_s32((int_vector)xin, (int_vector)abs_mask.ps); /* Abs. value by clearing signbit */
|
||||
c = sigmoid_positive_ps(xin);
|
||||
return vbslq_f32((uint32x4_t)mask, vsubq_f32(ones.ps, c), c);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // USE_SSE2 or USE_AVX
|
||||
|
||||
#if defined(USE_SSE2)
|
||||
#define INPUT_ADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = _mm_load_ps(pr); \
|
||||
vec1 = _mm_load_ps(prWeight); \
|
||||
sum = _mm_add_ps(vec0, vec1); \
|
||||
_mm_store_ps(pr, sum); \
|
||||
}
|
||||
#define INPUT_MULTADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = _mm_load_ps(pr); \
|
||||
vec1 = _mm_load_ps(prWeight); \
|
||||
vec3 = _mm_mul_ps(vec1, scalevec); \
|
||||
sum = _mm_add_ps(vec0, vec3); \
|
||||
_mm_store_ps(pr, sum); \
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_AVX)
|
||||
#define INPUT_ADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = _mm256_load_ps(pr); \
|
||||
vec1 = _mm256_load_ps(prWeight); \
|
||||
sum = _mm256_add_ps(vec0, vec1); \
|
||||
_mm256_store_ps(pr, sum); \
|
||||
}
|
||||
#if defined(USE_FMA3)
|
||||
#define INPUT_MULTADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = _mm256_load_ps(pr); \
|
||||
vec1 = _mm256_load_ps(prWeight); \
|
||||
sum = _mm256_fmadd_ps(vec1, scalevec, vec0); \
|
||||
_mm256_store_ps(pr, sum); \
|
||||
}
|
||||
#else
|
||||
#define INPUT_MULTADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = _mm256_load_ps(pr); \
|
||||
vec1 = _mm256_load_ps(prWeight); \
|
||||
vec3 = _mm256_mul_ps(vec1, scalevec); \
|
||||
sum = _mm256_add_ps(vec0, vec3); \
|
||||
_mm256_store_ps(pr, sum); \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if defined(USE_NEON)
|
||||
#define INPUT_ADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = vld1q_f32(pr); \
|
||||
vec1 = vld1q_f32(prWeight); \
|
||||
sum = vaddq_f32(vec0, vec1); \
|
||||
vst1q_f32(pr, sum); \
|
||||
}
|
||||
#define INPUT_MULTADD() \
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, pr += VEC_SIZE, prWeight += VEC_SIZE) { \
|
||||
vec0 = vld1q_f32(pr); \
|
||||
vec1 = vld1q_f32(prWeight); \
|
||||
vec3 = vmulq_f32(vec1, scalevec); \
|
||||
sum = vaddq_f32(vec0, vec3); \
|
||||
vst1q_f32(pr, sum); \
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
EvaluateSSE(const neuralnet * restrict pnn, const float arInput[], float ar[], float arOutput[])
|
||||
{
|
||||
const unsigned int cHidden = pnn->cHidden;
|
||||
unsigned int i, j;
|
||||
float *prWeight;
|
||||
#if defined(USE_SSE2) || defined(USE_AVX) || defined(USE_NEON)
|
||||
float *par;
|
||||
#if defined(USE_FMA3)
|
||||
float_vector vec0, vec1, scalevec, sum;
|
||||
#else
|
||||
float_vector vec0, vec1, vec3, scalevec, sum;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Calculate activity at hidden nodes */
|
||||
memcpy(ar, pnn->arHiddenThreshold, cHidden * sizeof(float));
|
||||
|
||||
prWeight = pnn->arHiddenWeight;
|
||||
|
||||
if (pnn->cInput != 214) { /* everything but the racing net */
|
||||
for (i = 0; i < 200;) { /* base inputs */
|
||||
float ari = arInput[i++];
|
||||
|
||||
/* 3 binaries, 1 float */
|
||||
|
||||
if (likely(ari == 0.0f))
|
||||
prWeight += cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
INPUT_ADD();
|
||||
}
|
||||
|
||||
ari = arInput[i++];
|
||||
|
||||
if (likely(ari == 0.0f))
|
||||
prWeight += cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
INPUT_ADD();
|
||||
}
|
||||
|
||||
ari = arInput[i++];
|
||||
|
||||
if (likely(ari == 0.0f)) {
|
||||
prWeight += cHidden;
|
||||
/* If 3rd element is 0, so is 4th. Skip it */
|
||||
prWeight += cHidden;
|
||||
i++;
|
||||
continue;
|
||||
} else {
|
||||
float *pr = ar;
|
||||
INPUT_ADD();
|
||||
}
|
||||
|
||||
ari = arInput[i++];
|
||||
|
||||
if (likely(ari == 0.0f))
|
||||
prWeight += cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
|
||||
#if defined(USE_FMA3)
|
||||
scalevec = _mm256_set1_ps(ari);
|
||||
INPUT_MULTADD();
|
||||
#elif defined(USE_NEON)
|
||||
scalevec = vdupq_n_f32(ari);
|
||||
INPUT_MULTADD();
|
||||
#else
|
||||
if (unlikely(ari == 1.0f)) {
|
||||
INPUT_ADD();
|
||||
} else {
|
||||
#if defined(USE_AVX)
|
||||
scalevec = _mm256_set1_ps(ari);
|
||||
#elif defined(HAVE_SSE)
|
||||
scalevec = _mm_set1_ps(ari);
|
||||
#endif
|
||||
INPUT_MULTADD();
|
||||
}
|
||||
#endif
|
||||
} /* base inputs are done */
|
||||
}
|
||||
|
||||
if (pnn->cInput == 250) /* Pruning nets are over, contact/crashed still have 2 * 25 floats */
|
||||
for (i = 200; i < 250; i++) {
|
||||
float const ari = arInput[i];
|
||||
|
||||
if (unlikely(ari == 0.0f))
|
||||
prWeight += cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
|
||||
#if defined(USE_AVX)
|
||||
scalevec = _mm256_set1_ps(ari);
|
||||
#elif defined(HAVE_SSE)
|
||||
scalevec = _mm_set1_ps(ari);
|
||||
#else
|
||||
scalevec = vdupq_n_f32(ari);
|
||||
#endif
|
||||
INPUT_MULTADD();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else /* racing net */
|
||||
for (i = 0; i < pnn->cInput; i++) {
|
||||
float const ari = arInput[i];
|
||||
|
||||
if (likely(ari == 0.0f))
|
||||
prWeight += cHidden;
|
||||
else {
|
||||
float *pr = ar;
|
||||
#if defined(USE_FMA3)
|
||||
scalevec = _mm256_set1_ps(ari);
|
||||
INPUT_MULTADD();
|
||||
#elif defined(USE_NEON)
|
||||
scalevec = vdupq_n_f32(ari);
|
||||
INPUT_MULTADD();
|
||||
#else
|
||||
if (likely(ari == 1.0f)) {
|
||||
INPUT_ADD();
|
||||
} else {
|
||||
#if defined(USE_AVX)
|
||||
scalevec = _mm256_set1_ps(ari);
|
||||
#elif defined(HAVE_SSE)
|
||||
scalevec = _mm_set1_ps(ari);
|
||||
#endif
|
||||
INPUT_MULTADD();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_SSE2) || defined(USE_AVX) || defined(USE_NEON)
|
||||
#if defined(USE_AVX)
|
||||
scalevec = _mm256_set1_ps(-pnn->rBetaHidden);
|
||||
#elif defined(HAVE_SSE)
|
||||
scalevec = _mm_set1_ps(-pnn->rBetaHidden);
|
||||
#else
|
||||
scalevec = vdupq_n_f32(-pnn->rBetaHidden);
|
||||
#endif
|
||||
|
||||
for (par = ar, i = (cHidden >> LOG2VEC_SIZE); i; i--, par += VEC_SIZE) {
|
||||
#if defined(USE_AVX)
|
||||
float_vector vec = _mm256_load_ps(par);
|
||||
vec = _mm256_mul_ps(vec, scalevec);
|
||||
vec = sigmoid_ps(vec);
|
||||
_mm256_store_ps(par, vec);
|
||||
#elif defined(HAVE_SSE)
|
||||
float_vector vec = _mm_load_ps(par);
|
||||
vec = _mm_mul_ps(vec, scalevec);
|
||||
vec = sigmoid_ps(vec);
|
||||
_mm_store_ps(par, vec);
|
||||
#else
|
||||
float_vector vec = vld1q_f32(par);
|
||||
vec = vmulq_f32(vec, scalevec);
|
||||
vec = sigmoid_ps(vec);
|
||||
vst1q_f32(par, vec);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < cHidden; i++)
|
||||
ar[i] = sigmoid(-pnn->rBetaHidden * ar[i]);
|
||||
#endif
|
||||
|
||||
/* Calculate activity at output nodes */
|
||||
prWeight = pnn->arOutputWeight;
|
||||
|
||||
for (i = 0; i < pnn->cOutput; i++) {
|
||||
|
||||
#if defined(USE_AVX)
|
||||
SSE_ALIGN(float r[8]);
|
||||
#else
|
||||
float r;
|
||||
#endif
|
||||
float *pr = ar;
|
||||
#if defined(USE_AVX)
|
||||
sum = _mm256_setzero_ps();
|
||||
#elif defined(HAVE_SSE)
|
||||
sum = _mm_setzero_ps();
|
||||
#else
|
||||
sum = vdupq_n_f32(0.0f);
|
||||
#endif
|
||||
for (j = (cHidden >> LOG2VEC_SIZE); j; j--, prWeight += VEC_SIZE, pr += VEC_SIZE) {
|
||||
#if defined(USE_AVX)
|
||||
vec0 = _mm256_load_ps(pr); /* Eight floats into vec0 */
|
||||
vec1 = _mm256_load_ps(prWeight); /* Eight weights into vec1 */
|
||||
#if defined(USE_FMA3)
|
||||
sum = _mm256_fmadd_ps(vec0, vec1, sum);
|
||||
#else
|
||||
vec3 = _mm256_mul_ps(vec0, vec1); /* Multiply */
|
||||
sum = _mm256_add_ps(sum, vec3); /* Add */
|
||||
#endif
|
||||
#elif defined(HAVE_SSE)
|
||||
vec0 = _mm_load_ps(pr); /* Four floats into vec0 */
|
||||
vec1 = _mm_load_ps(prWeight); /* Four weights into vec1 */
|
||||
vec3 = _mm_mul_ps(vec0, vec1); /* Multiply */
|
||||
sum = _mm_add_ps(sum, vec3); /* Add */
|
||||
#else
|
||||
vec0 = vld1q_f32(pr); /* Four floats into vec0 */
|
||||
vec1 = vld1q_f32(prWeight); /* Four weights into vec1 */
|
||||
vec3 = vmulq_f32(vec0, vec1); /* Multiply */
|
||||
sum = vaddq_f32(sum, vec3); /* Add */
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_AVX)
|
||||
vec0 = _mm256_hadd_ps(sum, sum);
|
||||
vec1 = _mm256_hadd_ps(vec0, vec0);
|
||||
_mm256_store_ps(r, vec1);
|
||||
|
||||
arOutput[i] = sigmoid(-pnn->rBetaOutput * (r[0] + r[4] + pnn->arOutputThreshold[i]));
|
||||
#elif defined(HAVE_SSE)
|
||||
vec0 = _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
vec1 = _mm_add_ps(sum, vec0);
|
||||
vec0 = _mm_shuffle_ps(vec1, vec1, _MM_SHUFFLE(1, 1, 3, 3));
|
||||
sum = _mm_add_ps(vec1, vec0);
|
||||
_mm_store_ss(&r, sum);
|
||||
|
||||
arOutput[i] = sigmoid(-pnn->rBetaOutput * (r + pnn->arOutputThreshold[i]));
|
||||
|
||||
#else
|
||||
{
|
||||
float32x2_t vec0_h, vec0_l, vec1;
|
||||
|
||||
vec0_h = vget_high_f32(sum);
|
||||
vec0_l = vget_low_f32(sum);
|
||||
vec1 = vpadd_f32(vec0_h, vec0_l);
|
||||
vec1 = vpadd_f32(vec1, vec1);
|
||||
vst1_lane_f32(&r, vec1, 0);
|
||||
|
||||
arOutput[i] = sigmoid(-pnn->rBetaOutput * (r + pnn->arOutputThreshold[i]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if defined(USE_AVX)
|
||||
_mm256_zeroupper();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern int
|
||||
NeuralNetEvaluateSSE(const neuralnet * restrict pnn, /*lint -e{818} */ float arInput[],
|
||||
float arOutput[], NNState * UNUSED(pnState))
|
||||
{
|
||||
SSE_ALIGN(float ar[pnn->cHidden]);
|
||||
|
||||
#if DEBUG_SSE
|
||||
g_assert(sse_aligned(arOutput));
|
||||
g_assert(sse_aligned(ar));
|
||||
g_assert(sse_aligned(arInput));
|
||||
#endif
|
||||
|
||||
EvaluateSSE(pnn, arInput, ar, arOutput);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2008-2017 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SIGMOID_H
|
||||
#define SIGMOID_H
|
||||
/* e[k] = exp(k/10) / 10 */
|
||||
static float e[101] = {
|
||||
0.10000000000000001f,
|
||||
0.11051709180756478f,
|
||||
0.12214027581601698f,
|
||||
0.13498588075760032f,
|
||||
0.14918246976412702f,
|
||||
0.16487212707001281f,
|
||||
0.18221188003905089f,
|
||||
0.20137527074704767f,
|
||||
0.22255409284924679f,
|
||||
0.245960311115695f,
|
||||
0.27182818284590454f,
|
||||
0.30041660239464335f,
|
||||
0.33201169227365473f,
|
||||
0.36692966676192446f,
|
||||
0.40551999668446748f,
|
||||
0.44816890703380646f,
|
||||
0.49530324243951152f,
|
||||
0.54739473917271997f,
|
||||
0.60496474644129461f,
|
||||
0.66858944422792688f,
|
||||
0.73890560989306509f,
|
||||
0.81661699125676512f,
|
||||
0.90250134994341225f,
|
||||
0.99741824548147184f,
|
||||
1.1023176380641602f,
|
||||
1.2182493960703473f,
|
||||
1.3463738035001691f,
|
||||
1.4879731724872838f,
|
||||
1.6444646771097049f,
|
||||
1.817414536944306f,
|
||||
2.0085536923187668f,
|
||||
2.2197951281441637f,
|
||||
2.4532530197109352f,
|
||||
2.7112638920657881f,
|
||||
2.9964100047397011f,
|
||||
3.3115451958692312f,
|
||||
3.6598234443677988f,
|
||||
4.0447304360067395f,
|
||||
4.4701184493300818f,
|
||||
4.9402449105530168f,
|
||||
5.4598150033144233f,
|
||||
6.034028759736195f,
|
||||
6.6686331040925158f,
|
||||
7.3699793699595784f,
|
||||
8.1450868664968148f,
|
||||
9.0017131300521811f,
|
||||
9.9484315641933776f,
|
||||
10.994717245212353f,
|
||||
12.151041751873485f,
|
||||
13.428977968493552f,
|
||||
14.841315910257659f,
|
||||
16.402190729990171f,
|
||||
18.127224187515122f,
|
||||
20.033680997479166f,
|
||||
22.140641620418716f,
|
||||
24.469193226422039f,
|
||||
27.042640742615255f,
|
||||
29.886740096706028f,
|
||||
33.029955990964865f,
|
||||
36.503746786532886f,
|
||||
40.34287934927351f,
|
||||
44.585777008251675f,
|
||||
49.274904109325632f,
|
||||
54.457191012592901f,
|
||||
60.184503787208222f,
|
||||
66.514163304436181f,
|
||||
73.509518924197266f,
|
||||
81.24058251675433f,
|
||||
89.784729165041753f,
|
||||
99.227471560502622f,
|
||||
109.66331584284585f,
|
||||
121.19670744925763f,
|
||||
133.9430764394418f,
|
||||
148.02999275845451f,
|
||||
163.59844299959269f,
|
||||
180.80424144560632f,
|
||||
199.81958951041173f,
|
||||
220.83479918872089f,
|
||||
244.06019776244983f,
|
||||
269.72823282685101f,
|
||||
298.09579870417281f,
|
||||
329.44680752838406f,
|
||||
364.09503073323521f,
|
||||
402.38723938223131f,
|
||||
444.7066747699858f,
|
||||
491.47688402991344f,
|
||||
543.16595913629783f,
|
||||
600.29122172610175f,
|
||||
663.42440062778894f,
|
||||
733.19735391559948f,
|
||||
810.3083927575384f,
|
||||
895.52927034825075f,
|
||||
989.71290587439091f,
|
||||
1093.8019208165192f,
|
||||
1208.8380730216988f,
|
||||
1335.9726829661872f,
|
||||
1476.4781565577266f,
|
||||
1631.7607198015421f,
|
||||
1803.3744927828525f,
|
||||
1993.0370438230298f,
|
||||
1993.0370438230298f /* one extra :-) */
|
||||
};
|
||||
|
||||
/* Calculate an approximation to the sigmoid function 1 / ( 1 + e^x ).
|
||||
* This is executed very frequently during neural net evaluation, so
|
||||
* careful optimisation here pays off.
|
||||
*
|
||||
* Statistics on sigmoid(x) calls:
|
||||
* * >99% of the time, x is positive.
|
||||
* * 82% of the time, 3 < abs(x) < 8.
|
||||
*
|
||||
* 02/2017: The numbers above are 10+ years old
|
||||
* (old neural nets, possibly pruning nets not yet in use).
|
||||
* Current stats :
|
||||
* * 85% of the time, x is positive, comprising 80% < 10 and 20% > 10
|
||||
* * 15% of the time, x is negative with 99%+ > -10
|
||||
*/
|
||||
|
||||
static inline float
|
||||
sigmoid(float const xin)
|
||||
{
|
||||
if (likely(xin >= 0.0f)) {
|
||||
/* xin is almost always positive; we place this branch of the `if'
|
||||
* first, in the hope that the compiler/processor will predict the
|
||||
* conditional branch will not be taken. */
|
||||
if (likely(xin < 10.0f)) {
|
||||
/* again, predict the branch not to be taken */
|
||||
const float x1 = 10.0f * xin;
|
||||
const int i = (int) x1;
|
||||
|
||||
return 1.0f / (1.0f + e[i] * ((float)(10 - i) + x1));
|
||||
} else
|
||||
return 1.0f / 19931.370438230298f;
|
||||
} else {
|
||||
if (likely(xin > -10.0f)) {
|
||||
const float x1 = -10.0f * xin;
|
||||
const int i = (int) x1;
|
||||
|
||||
return 1.0f - 1.0f / (1 + e[i] * ((float)(10 - i) + x1));
|
||||
} else
|
||||
return 19930.370438230298f / 19931.370438230298f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Jon Kinsey <jonkinsey@gmail.com>
|
||||
* Copyright (C) 2005-2018 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: simd.h,v 1.9 2018/05/12 21:42:33 plm Exp $
|
||||
*/
|
||||
|
||||
#ifndef SIMD_H
|
||||
#define SIMD_H
|
||||
|
||||
#if defined(USE_SIMD_INSTRUCTIONS)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "common.h"
|
||||
|
||||
#if defined(USE_AVX)
|
||||
#define ALIGN_SIZE 32
|
||||
#define VEC_SIZE 8
|
||||
#define LOG2VEC_SIZE 3
|
||||
#define float_vector __m256
|
||||
#define int_vector __m256i
|
||||
#else
|
||||
#define ALIGN_SIZE 16
|
||||
#define VEC_SIZE 4
|
||||
#define LOG2VEC_SIZE 2
|
||||
#if defined(HAVE_SSE)
|
||||
#define float_vector __m128
|
||||
#define int_vector __m128i
|
||||
#elif defined(HAVE_NEON)
|
||||
#define float_vector float32x4_t
|
||||
#define int_vector int32x4_t
|
||||
/*
|
||||
* Workaround for clang on raspbian 9
|
||||
* It defines __ARM_FEATURE_SIMD32 but its arm_neon.h needs __ARM_NEON
|
||||
*/
|
||||
#define __ARM_NEON 1
|
||||
#else
|
||||
#error "Inconsistent SIMD defines"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define SSE_ALIGN(D) __declspec(align(ALIGN_SIZE)) D
|
||||
#else
|
||||
#define SSE_ALIGN(D) D __attribute__ ((aligned(ALIGN_SIZE)))
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(WIN32)
|
||||
/* Align stack pointer on 16 byte boundary so SSE variables work correctly */
|
||||
#define SIMD_STACKALIGN __attribute__((force_align_arg_pointer))
|
||||
#if defined(USE_AVX)
|
||||
#define SIMD_AVX_STACKALIGN __attribute__((force_align_arg_pointer))
|
||||
#else
|
||||
#define SIMD_AVX_STACKALIGN
|
||||
#endif /* USE_AVX */
|
||||
#else
|
||||
#define SIMD_STACKALIGN
|
||||
#define SIMD_AVX_STACKALIGN
|
||||
#endif /* GNUC/WIN32 */
|
||||
|
||||
#define sse_aligned(ar) (!(((size_t)ar) % ALIGN_SIZE))
|
||||
|
||||
extern float *sse_malloc(size_t size);
|
||||
extern void sse_free(float *ptr);
|
||||
|
||||
#if defined(HAVE_NEON)
|
||||
extern int CheckNEON(void);
|
||||
#endif
|
||||
|
||||
#else /* USE_SIMD_INSTRUCTIONS */
|
||||
|
||||
#define SSE_ALIGN(D) D
|
||||
#define sse_malloc malloc
|
||||
#define sse_free free
|
||||
#define SIMD_STACKALIGN
|
||||
#define SIMD_AVX_STACKALIGN
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SIMD_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2000-2001 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2002-2019 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: makeweights.c,v 1.31 2022/02/02 22:04:12 plm Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "eval.h" /* for WEIGHTS_VERSION */
|
||||
#include "output.h"
|
||||
|
||||
static void
|
||||
usage(char *prog)
|
||||
{
|
||||
g_printerr(_("Usage: %s [[-f] outputfile [inputfile]]\n"
|
||||
" outputfile: Output to file instead of stdout\n"
|
||||
" inputfile: Input from file instead of stdin\n"), prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
extern int
|
||||
main(int argc, /*lint -e{818} */ char *argv[])
|
||||
{
|
||||
neuralnet nn;
|
||||
char szFileVersion[16];
|
||||
static float ar[2] = { WEIGHTS_MAGIC_BINARY, WEIGHTS_VERSION_BINARY };
|
||||
int c;
|
||||
FILE *in = stdin, *out = stdout;
|
||||
|
||||
if (!setlocale(LC_ALL, "C") || !bindtextdomain(PACKAGE, LOCALEDIR) || !textdomain(PACKAGE)) {
|
||||
perror("setting locale failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_set_printerr_handler(print_utf8_to_locale);
|
||||
|
||||
if (argc > 1) {
|
||||
int arg = 1;
|
||||
if (!StrCaseCmp(argv[1], "-f"))
|
||||
arg++; /* Skip */
|
||||
|
||||
if (argc > arg + 2)
|
||||
usage(argv[0]);
|
||||
if ((out = g_fopen(argv[arg], "wb")) == 0) {
|
||||
g_printerr(_("Can't open output file"));
|
||||
exit(1);
|
||||
}
|
||||
if (argc == arg + 2) {
|
||||
if ((in = g_fopen(argv[arg + 1], "r")) == 0) {
|
||||
g_printerr(_("Can't open input file"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generate weights */
|
||||
|
||||
if (fscanf(in, "GNU Backgammon %15s\n", szFileVersion) != 1) {
|
||||
g_printerr(_("%s: invalid weights file\n"), argv[0]);
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (StrCaseCmp(szFileVersion, WEIGHTS_VERSION)) {
|
||||
g_printerr(_("%s: incorrect weights version\n"
|
||||
"(version %s is required, "
|
||||
"but these weights are %s)\n"), argv[0], WEIGHTS_VERSION, szFileVersion);
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (fwrite(ar, sizeof(ar[0]), 2, out) != 2) {
|
||||
g_printerr(_("Failed to write neural net!"));
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (c = 0; !feof(in); c++) {
|
||||
if (NeuralNetLoad(&nn, in) == -1) {
|
||||
g_printerr(_("Failed to load neural net!"));
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (NeuralNetSaveBinary(&nn, out) == -1) {
|
||||
g_printerr(_("Failed to save neural net!"));
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
NeuralNetDestroy(&nn);
|
||||
}
|
||||
|
||||
g_printerr(_("%d nets converted\n"), c);
|
||||
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2003 Joern Thyssen <jth@gnubg.org>
|
||||
* Copyright (C) 2000-2013 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MATCHEQUITY_H
|
||||
#define MATCHEQUITY_H
|
||||
|
||||
#include "eval.h"
|
||||
|
||||
#define MAXSCORE 64
|
||||
#define MAXCUBELEVEL 7
|
||||
|
||||
/* Structure for information about match equity table */
|
||||
|
||||
typedef struct {
|
||||
gchar *szName; /* Name of match equity table */
|
||||
gchar *szFileName; /* File name of MET */
|
||||
gchar *szDescription; /* Description of MET */
|
||||
int nLength; /* Native length of MET or -1 if pure calculated table */
|
||||
} metinfo;
|
||||
|
||||
/* macros for getting match equities */
|
||||
|
||||
#define GET_MET(i,j,aafMET) ( ( (i) < 0 ) ? 1.0f : ( ( (j) < 0 ) ? 0.0f : \
|
||||
(aafMET [ i ][ j ]) ) )
|
||||
#define GET_METPostCrawford(i,afBtilde) ( (i) < 0 ? 1.0f : afBtilde [ i ] )
|
||||
|
||||
/* current match equity table used by gnubg */
|
||||
|
||||
extern float aafMET[MAXSCORE][MAXSCORE];
|
||||
extern float aafMETPostCrawford[2][MAXSCORE];
|
||||
|
||||
/* gammon prices (calculated once for efficiency) */
|
||||
|
||||
extern float aaaafGammonPrices[MAXCUBELEVEL]
|
||||
[MAXSCORE][MAXSCORE][4];
|
||||
extern float aaaafGammonPricesPostCrawford[MAXCUBELEVEL]
|
||||
[MAXSCORE][2][4];
|
||||
|
||||
extern metinfo miCurrent;
|
||||
|
||||
extern float
|
||||
getME(int nScore0, int nScore1, int nMatchTo,
|
||||
int fPlayer,
|
||||
int nPoints, int fWhoWins,
|
||||
int fCrawford, float aafMET[MAXSCORE][MAXSCORE], float aafMETPostCrawford[2][MAXSCORE]);
|
||||
|
||||
extern float
|
||||
getMEAtScore(int nScore0, int nScore1, int nMatchTo,
|
||||
int fPlayer, int fCrawford,
|
||||
float aafMET[MAXSCORE][MAXSCORE], float aafMETPostCrawford[2][MAXSCORE]);
|
||||
|
||||
/* Initialise match equity table */
|
||||
|
||||
void
|
||||
InitMatchEquity(const char *szFileName);
|
||||
|
||||
/* Get double points */
|
||||
|
||||
extern int
|
||||
GetPoints(float arOutput[5], const cubeinfo * pci, float arCP[2]);
|
||||
|
||||
extern float
|
||||
GetDoublePointDeadCube(float arOutput[5], cubeinfo * pci);
|
||||
|
||||
extern void
|
||||
invertMET(void);
|
||||
|
||||
/* enums for the entries in the arrays returned by getMEMultiple
|
||||
* DoublePass, DoubleTakeWin, DoubleTakeWinGammon... for the first 8
|
||||
* then the same values using CubePrimeValues
|
||||
* DP = Double/Pass, DTWG = double/take/wing gammon, etc
|
||||
* DPP = double/Pass with CubePrime values, etc.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
/* player 0 wins, first cube value */
|
||||
DP = 0, NDW = 0, DTW = 1, NDWG = 1, NDWB, DTWG, DTWB,
|
||||
/* player 0 loses, first cube value */
|
||||
NDL, DTL = 6, NDLG = 6, NDLB, DTLG, DTLB,
|
||||
/* player 0 wins, 2nd cube value */
|
||||
DPP0, DTWP0, NDWBP0, DTWGP0, DTWBP0,
|
||||
/* player 0 loses, 2nd cube value */
|
||||
NDLP0, DTLP0, NDLBP0, DTLGP0, DTLBP0,
|
||||
/* player 0 wins, 3rd cube value */
|
||||
DPP1, DTWP1, NDWBP1, DTWGP1, DTWBP1,
|
||||
/* player 0 loses, 3rd cube value */
|
||||
NDLP1, DTLP1, NDLBP1, DTLGP1, DTLBP1
|
||||
} met_indices;
|
||||
|
||||
extern void
|
||||
getMEMultiple(int nScore0, int nScore1, int nMatchTo,
|
||||
int nCube,
|
||||
int nCubePrime0, int nCubePrime1,
|
||||
int fCrawford,
|
||||
float aafMET[MAXSCORE][MAXSCORE], float aafMETPostCrawford[2][MAXSCORE], float *player0, float *player1);
|
||||
|
||||
#endif /* MATCHEQUITY_H */
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2003 Joern Thyssen <jthyssen@dk.ibm.com>
|
||||
* Copyright (C) 2004-2013 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: matchid.c,v 1.30 2021/12/18 22:06:37 plm Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backgammon.h"
|
||||
#include "positionid.h"
|
||||
#include "matchequity.h"
|
||||
#include "matchid.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Calculate log2 of Cube value.
|
||||
*
|
||||
* Input:
|
||||
* n: cube value
|
||||
*
|
||||
* Returns:
|
||||
* log(n)/log(2)
|
||||
*
|
||||
*/
|
||||
|
||||
extern int
|
||||
LogCube(int n)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (n >>= 1)
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SetBit(unsigned char *pc, unsigned int bitPos, int test, unsigned int iBit)
|
||||
{
|
||||
|
||||
const unsigned int k = bitPos / 8;
|
||||
const unsigned char rbit = (unsigned char) (0x1 << (bitPos % 8));
|
||||
|
||||
unsigned char c;
|
||||
|
||||
if (test & (0x1 << iBit))
|
||||
c = rbit;
|
||||
else
|
||||
c = 0;
|
||||
pc[k] = (pc[k] & (0xFF ^ rbit)) | c;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
SetBits(unsigned char *pc, unsigned int bitPos, unsigned int nBits, int iContent)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
|
||||
/* FIXME: rewrite SetBit, SetBits to be faster */
|
||||
|
||||
|
||||
for (i = 0; i < nBits; i++) {
|
||||
|
||||
SetBit(pc, bitPos + i, iContent, i);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
GetBits(const unsigned char *pc, const unsigned int bitPos, const unsigned int nBits, int *piContent)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned char c[2];
|
||||
|
||||
/* FIXME: rewrite GetBits to be faster */
|
||||
|
||||
c[0] = 0;
|
||||
c[1] = 0;
|
||||
|
||||
for (i = 0, j = bitPos; i < nBits; i++, j++) {
|
||||
|
||||
unsigned int k, r;
|
||||
|
||||
k = j / 8;
|
||||
r = j % 8;
|
||||
|
||||
SetBit(c, i, pc[k], r);
|
||||
|
||||
}
|
||||
|
||||
*piContent = c[0] | (c[1] << 8);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
MatchIDFromKey(unsigned char auchKey[9])
|
||||
{
|
||||
unsigned char *puch = auchKey;
|
||||
static char szID[L_MATCHID + 1];
|
||||
char *pch = szID;
|
||||
static const char aszBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
*pch++ = aszBase64[puch[0] >> 2];
|
||||
*pch++ = aszBase64[((puch[0] & 0x03) << 4) | (puch[1] >> 4)];
|
||||
*pch++ = aszBase64[((puch[1] & 0x0F) << 2) | (puch[2] >> 6)];
|
||||
*pch++ = aszBase64[puch[2] & 0x3F];
|
||||
|
||||
puch += 3;
|
||||
}
|
||||
|
||||
*pch = 0;
|
||||
|
||||
return szID;
|
||||
}
|
||||
|
||||
|
||||
extern char *
|
||||
MatchID(const unsigned int anDice[2],
|
||||
const int fTurn,
|
||||
const int fResigned,
|
||||
const int fDoubled,
|
||||
const int fMove,
|
||||
const int fCubeOwner, const int fCrawford, const int nMatchTo, const int anScore[2], const int nCube,
|
||||
const int fJacobyInUse, const gamestate gs)
|
||||
{
|
||||
|
||||
unsigned char auchKey[9];
|
||||
|
||||
memset(auchKey, 0, 9);
|
||||
|
||||
SetBits(auchKey, 0, 4, LogCube(nCube));
|
||||
SetBits(auchKey, 4, 2, fCubeOwner & 0x3);
|
||||
SetBits(auchKey, 6, 1, fMove);
|
||||
SetBits(auchKey, 7, 1, fCrawford);
|
||||
SetBits(auchKey, 8, 3, (int) gs);
|
||||
SetBits(auchKey, 11, 1, fTurn);
|
||||
SetBits(auchKey, 12, 1, fDoubled);
|
||||
SetBits(auchKey, 13, 2, fResigned);
|
||||
if (anDice[0] >= anDice[1]) {
|
||||
SetBits(auchKey, 15, 3, anDice[0] & 0x7);
|
||||
SetBits(auchKey, 18, 3, anDice[1] & 0x7);
|
||||
} else {
|
||||
SetBits(auchKey, 15, 3, anDice[1] & 0x7);
|
||||
SetBits(auchKey, 18, 3, anDice[0] & 0x7);
|
||||
}
|
||||
SetBits(auchKey, 21, 15, nMatchTo & 0x7FFF);
|
||||
SetBits(auchKey, 36, 15, anScore[0] & 0x7FFF);
|
||||
SetBits(auchKey, 51, 15, anScore[1] & 0x7FFF);
|
||||
SetBits(auchKey, 66, 1, (!fJacobyInUse));
|
||||
|
||||
return MatchIDFromKey(auchKey);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
MatchFromKey(int anDice[2],
|
||||
int *pfTurn,
|
||||
int *pfResigned,
|
||||
int *pfDoubled,
|
||||
int *pfMove, int *pfCubeOwner, int *pfCrawford, int *pnMatchTo, int anScore[2], int *pnCube,
|
||||
int *pfJacoby, gamestate * pgs, const unsigned char *auchKey)
|
||||
{
|
||||
int temp;
|
||||
GetBits(auchKey, 0, 4, pnCube);
|
||||
*pnCube = 0x1 << *pnCube;
|
||||
|
||||
GetBits(auchKey, 4, 2, pfCubeOwner);
|
||||
if (*pfCubeOwner && *pfCubeOwner != 1)
|
||||
*pfCubeOwner = -1;
|
||||
|
||||
GetBits(auchKey, 6, 1, pfMove);
|
||||
GetBits(auchKey, 7, 1, pfCrawford);
|
||||
GetBits(auchKey, 8, 3, &temp);
|
||||
*pgs = (gamestate) temp;
|
||||
GetBits(auchKey, 11, 1, pfTurn);
|
||||
GetBits(auchKey, 12, 1, pfDoubled);
|
||||
GetBits(auchKey, 13, 2, pfResigned);
|
||||
GetBits(auchKey, 15, 3, &anDice[0]);
|
||||
GetBits(auchKey, 18, 3, &anDice[1]);
|
||||
GetBits(auchKey, 21, 15, pnMatchTo);
|
||||
GetBits(auchKey, 36, 15, &anScore[0]);
|
||||
GetBits(auchKey, 51, 15, &anScore[1]);
|
||||
GetBits(auchKey, 66, 1, pfJacoby);
|
||||
*pfJacoby = !(*pfJacoby);
|
||||
|
||||
/* FIXME: implement a consistency check */
|
||||
|
||||
if (anDice[0] < 0 || anDice[0] > 6)
|
||||
return -1;
|
||||
if (anDice[1] < 0 || anDice[1] > 6)
|
||||
return -1;
|
||||
if (*pnMatchTo < 0 || *pnMatchTo > MAXSCORE)
|
||||
return -1;
|
||||
|
||||
if (*pnMatchTo) {
|
||||
if (anScore[0] < 0 || anScore[0] > *pnMatchTo)
|
||||
return -1;
|
||||
if (anScore[1] < 0 || anScore[1] > *pnMatchTo)
|
||||
return -1;
|
||||
} else {
|
||||
/* money game */
|
||||
if (*pfCrawford)
|
||||
/* no Crawford game in money play */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern int
|
||||
MatchFromID(unsigned int anDice[2],
|
||||
int *pfTurn,
|
||||
int *pfResigned,
|
||||
int *pfDoubled, int *pfMove, int *pfCubeOwner, int *pfCrawford, int *pnMatchTo, int anScore[2], int *pnCube,
|
||||
int *pfJacoby, gamestate * pgs, const char *szMatchID)
|
||||
{
|
||||
|
||||
unsigned char auchKey[9];
|
||||
unsigned char *puch = auchKey;
|
||||
unsigned char ach[L_MATCHID + 1];
|
||||
unsigned char *pch = ach;
|
||||
int i;
|
||||
|
||||
memset(ach, 0, sizeof(ach));
|
||||
/* decode base64 into key */
|
||||
for (i = 0; i < L_MATCHID && szMatchID[i]; i++)
|
||||
pch[i] = Base64((unsigned char) szMatchID[i]);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
*puch++ = (unsigned char) (pch[0] << 2) | (pch[1] >> 4);
|
||||
*puch++ = (unsigned char) (pch[1] << 4) | (pch[2] >> 2);
|
||||
*puch++ = (unsigned char) (pch[2] << 6) | pch[3];
|
||||
|
||||
pch += 4;
|
||||
}
|
||||
|
||||
/* get matchstate info from the key */
|
||||
|
||||
return MatchFromKey((int *) anDice, pfTurn, pfResigned, pfDoubled, pfMove, pfCubeOwner, pfCrawford, pnMatchTo,
|
||||
(int *) anScore, pnCube, pfJacoby, pgs, auchKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate match ID from matchstate
|
||||
*
|
||||
* Input:
|
||||
* pms: match state
|
||||
*
|
||||
*/
|
||||
|
||||
extern char *
|
||||
MatchIDFromMatchState(const matchstate * pms)
|
||||
{
|
||||
|
||||
return MatchID(pms->anDice,
|
||||
pms->fTurn,
|
||||
pms->fResigned,
|
||||
pms->fDoubled, pms->fMove, pms->fCubeOwner, pms->fCrawford, pms->nMatchTo, pms->anScore, pms->nCube,
|
||||
pms->fJacoby, pms->gs);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Joern Thyssen <jthyssen@dk.ibm.com>
|
||||
* Copyright (C) 2008-2013 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $Id: matchid.h,v 1.18 2021/07/14 19:21:45 plm Exp $
|
||||
*/
|
||||
|
||||
#ifndef MATCHID_H
|
||||
#define MATCHID_H
|
||||
|
||||
#define L_MATCHID 12
|
||||
|
||||
typedef struct {
|
||||
int anDice[2];
|
||||
int fTurn;
|
||||
int fResigned;
|
||||
int fDoubled;
|
||||
gamestate gs;
|
||||
} posinfo;
|
||||
|
||||
extern int LogCube(int n);
|
||||
|
||||
extern char *MatchID(const unsigned int anDice[2],
|
||||
int fTurn,
|
||||
int fResigned,
|
||||
int fDoubled,
|
||||
int fMove,
|
||||
int fCubeOwner,
|
||||
int fCrawford, int nMatchTo, const int anScore[2],
|
||||
int nCube, int fJacoby, gamestate gs);
|
||||
|
||||
extern int MatchFromID(unsigned int anDice[2],
|
||||
int *pfTurn,
|
||||
int *pfResigned,
|
||||
int *pfDoubled, int *pfMove, int *pfCubeOwner, int *pfCrawford, int *pnMatchTo, int anScore[2], int *pnCube,
|
||||
int *pfJacoby, gamestate * pgs, const char *szMatchID);
|
||||
|
||||
extern char *MatchIDFromMatchState(const matchstate * pms);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* mec - match equity calculator for backgammon. calculate equity table
|
||||
* given match length, gammon rate and winning probabilities.
|
||||
*
|
||||
* Copyright (C) 1996 Claes Tornberg <claest@it.kth.se>
|
||||
* Copyright (C) 2004-2013 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Modified for usage with GNUbg by Joern Thyssen <jth@gnubg.org>:
|
||||
*
|
||||
* (1) make external entry for usage in GNUbg
|
||||
* (2) change "double" to "metentry", and typedef metentry to float
|
||||
* or double depending on MEC_STANDALONE
|
||||
* (3) Compile with MEC_STANDALONE to get Tornberg's original program, e.g.,
|
||||
*
|
||||
* gcc -DMEC_STANDALONE mec.c -o mec
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef MEC_STANDALONE
|
||||
#include "mec.h"
|
||||
#endif
|
||||
|
||||
struct dp {
|
||||
double e;
|
||||
double w;
|
||||
};
|
||||
|
||||
typedef struct dp dp;
|
||||
|
||||
static void post_crawford(double gr, double wpf, int ml, double **E, double fd2, double fd4);
|
||||
|
||||
static void crawford(double gr, double wpf, int ml, double **E);
|
||||
|
||||
static void pre_crawford(double gr, double wpf, int ml, double **E);
|
||||
|
||||
static dp dpt(int p, int o, int c, double gr, double wpp, double **E);
|
||||
|
||||
/*
|
||||
* Arguments are (in this order):
|
||||
* match length
|
||||
* gammon rate
|
||||
* winning percentage (favorite)
|
||||
*/
|
||||
|
||||
#ifdef MEC_STANDALONE
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* match length */
|
||||
|
||||
int ml = argc > 1 ? atoi(argv[1]) : 9;
|
||||
|
||||
/* gammon rate, i.e. how many of games won/lost will be gammons */
|
||||
|
||||
double gr = argc > 2 ? atof(argv[2]) : 0;
|
||||
|
||||
/* Here one could argue for different approaches. Does the underdog
|
||||
* in match (current score) have different gammon rate. Or does the
|
||||
* underdog in match (equity at current score) have different gammon
|
||||
* rate. This could be solved, but for now, we assume same rates. */
|
||||
|
||||
/* winning percentage for favorite in one game. NB: when one player
|
||||
* is favorite, there is no symmetry in the equity table! I.e.
|
||||
* E[i][1] = 1 - E[1][i] doesn't necessarily hold. This figure must
|
||||
* be higher than or equal to .5, i.e. 50% */
|
||||
|
||||
double wpf = argc > 3 ? atof(argv[3]) : 0.5;
|
||||
|
||||
/* Equity chart, E[p][o] = equity for p when p is p away, and o is o away.
|
||||
* If there is a game favorite, i.e. wpf > 0.5, p above is considered
|
||||
* to be the favorite in each game. For now we also assume no free drop
|
||||
* vigourish. This will only affect the computation of post-Crawford
|
||||
* equities, and is quite easy to correct. */
|
||||
|
||||
double **E = (double **) malloc((ml + 1) * sizeof(double *));
|
||||
|
||||
double *ec = (double *) calloc((ml + 1) * (ml + 1), sizeof(double));
|
||||
|
||||
if (E == NULL || ec == NULL)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize E to point to correct positions */
|
||||
|
||||
for (i = 0; i <= ml; i++) {
|
||||
E[i] = &ec[i * (ml + 1)];
|
||||
}
|
||||
|
||||
/* Initialize E for 0-away scores */
|
||||
|
||||
for (i = 1; i <= ml; i++) {
|
||||
E[0][i] = 1;
|
||||
E[i][0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute post-Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length. Fill in the equity table. */
|
||||
|
||||
post_crawford(gr, wpf, ml, E, 0.0, 0.0);
|
||||
|
||||
{
|
||||
int i;
|
||||
printf("Post-Crawford:\n");
|
||||
for (i = 1; i < ml; ++i)
|
||||
printf("%6.3f", E[i][1]);
|
||||
printf("\n");
|
||||
for (i = 1; i < ml; ++i)
|
||||
printf("%6.3f", E[1][i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/* Compute Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length, and post-Crawford equities.
|
||||
* Fill in the table. */
|
||||
|
||||
crawford(gr, wpf, ml, E);
|
||||
|
||||
/* Compute pre-Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length, and Crawford equities.
|
||||
* Fill in the table. */
|
||||
|
||||
pre_crawford(gr, wpf, ml, E);
|
||||
|
||||
/* Print the equity table. Nothing fancy. */
|
||||
|
||||
{
|
||||
int i, j;
|
||||
|
||||
printf("Gammon rate %5.4f\n" "Winning %% %5.4f\n\n", gr, wpf);
|
||||
|
||||
|
||||
printf("%3s", "");
|
||||
|
||||
for (i = 1; i <= ml; i++) {
|
||||
printf("%6d", i);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (i = 1; i <= ml; i++) {
|
||||
printf("%3d", i);
|
||||
for (j = 1; j <= ml; j++)
|
||||
printf("%6.3f", E[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
free(ec);
|
||||
free(E);
|
||||
}
|
||||
|
||||
#else /* MEC_STANDALONE */
|
||||
|
||||
extern void
|
||||
mec_pc(const float rGammonRate,
|
||||
const float rFreeDrop2Away, const float rFreeDrop4Away, const float rWinRate, float arMetPC[MAXSCORE])
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
|
||||
/* match length */
|
||||
|
||||
const unsigned int ml = 64;
|
||||
|
||||
/* gammon rate, i.e. how many of games won/lost will be gammons */
|
||||
|
||||
double gr = rGammonRate;
|
||||
|
||||
/* Here one could argue for different approaches. Does the underdog
|
||||
* in match (current score) have different gammon rate. Or does the
|
||||
* underdog in match (equity at current score) have different gammon
|
||||
* rate. This could be solved, but for now, we assume same rates. */
|
||||
|
||||
/* winning percentage for favorite in one game. NB: when one player
|
||||
* is favorite, there is no symmetry in the equity table! I.e.
|
||||
* E[i][1] = 1 - E[1][i] doesn't necessarily hold. This figure must
|
||||
* be higher than or equal to .5, i.e. 50% */
|
||||
|
||||
double wpf = rWinRate;
|
||||
|
||||
/* Equity chart, E[p][o] = equity for p when p is p away, and o is o away.
|
||||
* If there is a game favorite, i.e. wpf > 0.5, p above is considered
|
||||
* to be the favorite in each game. For now we also assume no free drop
|
||||
* vigourish. This will only affect the computation of post-Crawford
|
||||
* equities, and is quite easy to correct. */
|
||||
|
||||
double **E = (double **) malloc((ml + 1) * sizeof(double *));
|
||||
|
||||
double *ec = (double *) calloc((ml + 1) * (ml + 1), sizeof(double));
|
||||
|
||||
if (!E || !ec)
|
||||
exit(-1); /* We're in trouble... */
|
||||
|
||||
{
|
||||
|
||||
/* Initialize E to point to correct positions */
|
||||
|
||||
for (i = 0; i <= ml; i++) {
|
||||
E[i] = &ec[i * (ml + 1)];
|
||||
}
|
||||
|
||||
/* Initialize E for 0-away scores */
|
||||
|
||||
for (i = 1; i <= ml; i++) {
|
||||
E[0][i] = 1;
|
||||
E[i][0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute post-Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length. Fill in the equity table. */
|
||||
|
||||
post_crawford(gr, wpf, ml, E, (double) rFreeDrop2Away, (double) rFreeDrop4Away);
|
||||
|
||||
/* save post Crawford equities */
|
||||
|
||||
for (i = 0; i < ml; ++i)
|
||||
arMetPC[i] = (float) E[i + 1][1];
|
||||
|
||||
/* garbage collect */
|
||||
|
||||
free(ec);
|
||||
free(E);
|
||||
}
|
||||
|
||||
|
||||
extern void
|
||||
mec(const float rGammonRate, const float rWinRate,
|
||||
/* const *//*lint -e{818} */ float aarMetPC[2][MAXSCORE],
|
||||
float aarMet[MAXSCORE][MAXSCORE])
|
||||
{
|
||||
|
||||
unsigned int i, j;
|
||||
|
||||
/* match length */
|
||||
|
||||
const unsigned int ml = 64;
|
||||
|
||||
/* gammon rate, i.e. how many of games won/lost will be gammons */
|
||||
|
||||
double gr = rGammonRate;
|
||||
|
||||
/* Here one could argue for different approaches. Does the underdog
|
||||
* in match (current score) have different gammon rate. Or does the
|
||||
* underdog in match (equity at current score) have different gammon
|
||||
* rate. This could be solved, but for now, we assume same rates. */
|
||||
|
||||
/* winning percentage for favorite in one game. NB: when one player
|
||||
* is favorite, there is no symmetry in the equity table! I.e.
|
||||
* E[i][1] = 1 - E[1][i] doesn't necessarily hold. This figure must
|
||||
* be higher than or equal to .5, i.e. 50% */
|
||||
|
||||
double wpf = rWinRate;
|
||||
|
||||
/* Equity chart, E[p][o] = equity for p when p is p away, and o is o away.
|
||||
* If there is a game favorite, i.e. wpf > 0.5, p above is considered
|
||||
* to be the favorite in each game. For now we also assume no free drop
|
||||
* vigourish. This will only affect the computation of post-Crawford
|
||||
* equities, and is quite easy to correct. */
|
||||
|
||||
double **E = (double **) malloc((ml + 1) * sizeof(double *));
|
||||
|
||||
double *ec = (double *) calloc((ml + 1) * (ml + 1), sizeof(double));
|
||||
|
||||
if (!E || !ec)
|
||||
exit(-1); /* We're in trouble... */
|
||||
|
||||
{
|
||||
|
||||
/* Initialize E to point to correct positions */
|
||||
|
||||
for (i = 0; i <= ml; i++) {
|
||||
E[i] = &ec[i * (ml + 1)];
|
||||
}
|
||||
|
||||
/* Initialize E for 0-away scores */
|
||||
|
||||
for (i = 1; i <= ml; i++) {
|
||||
E[0][i] = 1;
|
||||
E[i][0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute post-Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length. Fill in the equity table. */
|
||||
|
||||
for (i = 0; i < ml; ++i)
|
||||
E[i + 1][1] = aarMetPC[0][i];
|
||||
|
||||
for (i = 0; i < ml; ++i)
|
||||
E[1][i + 1] = 1.0 - (double)aarMetPC[1][i];
|
||||
|
||||
/* Compute Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length, and post-Crawford equities.
|
||||
* Fill in the table. */
|
||||
|
||||
crawford(gr, wpf, ml, E);
|
||||
|
||||
/* Compute pre-Crawford equities, given gammon rate, winning percentage
|
||||
* for favorite (game), match length, and Crawford equities.
|
||||
* Fill in the table. */
|
||||
|
||||
pre_crawford(gr, wpf, ml, E);
|
||||
|
||||
/* save the match equiy table */
|
||||
|
||||
for (i = 0; i < ml; ++i)
|
||||
for (j = 0; j < ml; ++j)
|
||||
aarMet[i][j] = (float) E[i + 1][j + 1];
|
||||
|
||||
/* garbage collect */
|
||||
|
||||
free(ec);
|
||||
free(E);
|
||||
}
|
||||
|
||||
#endif /* ! MEC_STANDALONE */
|
||||
|
||||
/* If last bit is zero, then x is even. */
|
||||
#define even(x) (((x)&0x1)==0)
|
||||
|
||||
/* sq returns x if x is greater than zero, else it returns zero. */
|
||||
#define sq(x) ((x)>0?(x):0)
|
||||
|
||||
static void
|
||||
post_crawford(double gr, double wpf, int ml, /*lint -e{818} */ double **E,
|
||||
double fd2, double fd4)
|
||||
{
|
||||
int i;
|
||||
|
||||
E[1][1] = wpf;
|
||||
|
||||
for (i = 2; i <= ml; i++) {
|
||||
if (even(i)) {
|
||||
/* Free drop condition exists */
|
||||
E[1][i] = E[1][i - 1];
|
||||
E[i][1] = E[i - 1][1];
|
||||
/* jth: add empirical values for free drop */
|
||||
if (i == 2) {
|
||||
/* 2-away */
|
||||
E[1][i] += fd2;
|
||||
E[i][1] -= fd2;
|
||||
} else if (i == 4) {
|
||||
/* 4-away */
|
||||
E[1][i] += fd4;
|
||||
E[i][1] += fd4;
|
||||
}
|
||||
} else {
|
||||
E[1][i] = /* Equity for favorite when 1-away, i-away */
|
||||
E[0][i] * wpf /* Favorite wins */
|
||||
+ E[1][sq(i - 2)] * (1 - wpf) * (1 - gr) /* Favorite loses single */
|
||||
+E[1][sq(i - 4)] * (1 - wpf) * gr; /* Favorite loses gammon */
|
||||
|
||||
E[i][1] = /* Equity for favorite when i-away, 1-away */
|
||||
E[i][0] * (1 - wpf) /* Favorite loses */
|
||||
+E[sq(i - 2)][1] * wpf * (1 - gr) /* Favorite wins single */
|
||||
+E[sq(i - 4)][1] * wpf * gr; /* Favorite wins gammon */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
crawford(double gr, double wpf, int ml, /*lint -e{818} */ double **E)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Compute Crawford equities. Do this backwards, since
|
||||
* we overwrite post-Crawford equities with Crawford equities.
|
||||
* In this way we only overwrite equities no longer needed. */
|
||||
|
||||
for (i = ml; i >= 2; i--) {
|
||||
E[1][i] = /* Equity for favorite when 1-away,i-away */
|
||||
E[0][i] * wpf /* Favorite wins */
|
||||
+ E[1][i - 1] * (1 - wpf) * (1 - gr) /* Favorite loses single */
|
||||
+E[1][i - 2] * (1 - wpf) * gr; /* Favorite loses gammon */
|
||||
|
||||
E[i][1] = /* Equity for favorite when i-away, 1-away */
|
||||
E[i][0] * (1 - wpf) /* Favorite loses */
|
||||
+E[i - 1][1] * wpf * (1 - gr) /* Favorite wins single */
|
||||
+E[i - 2][1] * wpf * gr; /* Favorite wins gammon */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pre_crawford(double gr, double wpf, int ml, double **E)
|
||||
{
|
||||
int i, j;
|
||||
dp dpf, dpu;
|
||||
double eq;
|
||||
|
||||
for (i = 2; i <= ml; i++)
|
||||
for (j = i; j <= ml; j++) {
|
||||
dpf = dpt(i, j, 2, gr, wpf, E);
|
||||
dpu = dpt(j, i, 2, gr, 1 - wpf, E);
|
||||
|
||||
dpu.e = 1 - dpu.e;
|
||||
dpu.w = 1 - dpu.w;
|
||||
|
||||
eq = dpu.e + (dpf.e - dpu.e) * (wpf - dpu.w) / (dpf.w - dpu.w);
|
||||
|
||||
E[i][j] = eq;
|
||||
|
||||
if (i != j) {
|
||||
dpf = dpt(j, i, 2, gr, wpf, E);
|
||||
dpu = dpt(i, j, 2, gr, 1 - wpf, E);
|
||||
|
||||
dpu.e = 1 - dpu.e;
|
||||
dpu.w = 1 - dpu.w;
|
||||
|
||||
eq = dpu.e + (dpf.e - dpu.e) * (wpf - dpu.w) / (dpf.w - dpu.w);
|
||||
|
||||
E[j][i] = eq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute point when p doubles o to c, assuming gammon rate gr,
|
||||
* p wins wpp % of games, and equities E for favorite. At this
|
||||
* point o does equally well passing the double as taking it. */
|
||||
|
||||
static dp
|
||||
dpt(int p, int o, int c, double gr, double wpp, double **E)
|
||||
{
|
||||
dp dpo, dpp;
|
||||
double e0, edp, wdp;
|
||||
|
||||
if (p <= c / 2) {
|
||||
/* No reason for p to double o, since a single win
|
||||
* is enough to win the match. */
|
||||
|
||||
dpp.e = 1;
|
||||
dpp.w = 1;
|
||||
return dpp;
|
||||
}
|
||||
|
||||
/* p might double o to c since he needs more than a single
|
||||
* game to win the match. */
|
||||
|
||||
/* Find out when o (re)doubles p to 2*c */
|
||||
|
||||
dpo = dpt(o, p, 2 * c, gr, 1 - wpp, E);
|
||||
|
||||
/* Find out equity for o if p does well and wins
|
||||
* all games here (assuming no recube from o), i.e.
|
||||
* o loses all games sitting on a c-cube. */
|
||||
|
||||
if (wpp > 0.5) {
|
||||
/* o isn't game favorite, equity for o at o-away x-away is 1 - E[x][o]. */
|
||||
|
||||
e0 = (1 - E[sq(p - c)][o]) * (1 - gr)
|
||||
+ (1 - E[sq(p - 2 * c)][o]) * gr;
|
||||
} else {
|
||||
/* o is game favorite, equity for o at o-away x-away is E[o][x]. */
|
||||
|
||||
e0 = E[o][sq(p - c)] * (1 - gr)
|
||||
+ E[o][sq(p - 2 * c)] * gr;
|
||||
}
|
||||
|
||||
/* Find out o:s equity if o passes the double to c, i.e. loses c / 2 points. */
|
||||
|
||||
if (wpp > 0.5) {
|
||||
/* o isn't game favorite, equity for o at o-away x-away is 1 - E[x][o]. */
|
||||
|
||||
edp = 1 - E[sq(p - c / 2)][o];
|
||||
} else {
|
||||
/* o is game favorite, equity for o at o-away x-away is E[o][x]. */
|
||||
|
||||
edp = E[o][sq(p - c / 2)];
|
||||
}
|
||||
|
||||
/* Find the winning percentage, which on the line from
|
||||
* (w0?,e0) to (dpo.w,dpo.e) gives o an equity equal to O's
|
||||
* equity passing the double to c (i.e. losing c / 2 pts) */
|
||||
|
||||
wdp = (edp - e0) * dpo.w / (dpo.e - e0);
|
||||
|
||||
/* Now we know when p should double o, expressed as
|
||||
* winning percentage and equity for o. Return this
|
||||
* expressed in figures for p */
|
||||
|
||||
dpp.e = 1 - edp;
|
||||
dpp.w = 1 - wdp;
|
||||
return dpp;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2002 Joern Thyssen <jth@gnubg.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MEC_H
|
||||
#define MEC_H
|
||||
|
||||
#include "matchequity.h"
|
||||
|
||||
extern void
|
||||
mec(float rGammonRate, float rWinRate,
|
||||
float aarMetPC[2][MAXSCORE],
|
||||
float aarMet[MAXSCORE][MAXSCORE]);
|
||||
|
||||
extern void
|
||||
mec_pc(float rGammonRate,
|
||||
float rFreeDrop2Away, float rFreeDrop4Away, float rWinRate, float arMetPC[MAXSCORE]);
|
||||
|
||||
#endif /* MEC_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2003 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 1999-2025 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Default movefilters */
|
||||
|
||||
#define MOVEFILTER_NORMAL \
|
||||
{ { { .Accept = 0, .Extra = 12, .Threshold = 0.24f }, { .Accept = 0, .Extra = 0 }, { .Accept = 0, .Extra = 0 }, { .Accept = 0, .Extra = 0 } }, \
|
||||
{ { .Accept = 0, .Extra = 12, .Threshold = 0.24f }, { .Accept = 0, .Extra = 6, .Threshold = 0.12f }, { .Accept = 0, .Extra = 0 }, { .Accept = 0, .Extra = 0 } }, \
|
||||
{ { .Accept = 0, .Extra = 16, .Threshold = 0.32f }, { .Accept = 0, .Extra = 8, .Threshold = 0.16f }, { .Accept = 0, .Extra = 4, .Threshold = 0.06f }, { .Accept = 0, .Extra = 0 } }, \
|
||||
{ { .Accept = 0, .Extra = 16, .Threshold = 0.32f }, { .Accept = 0, .Extra = 12, .Threshold = 0.16f }, { .Accept = 0, .Extra = 6, .Threshold = 0.08f }, { .Accept = 0, .Extra = 4, .Threshold = 0.06f } } }
|
||||
|
||||
#define MOVEFILTER_LARGE \
|
||||
{ { { .Accept = 0, .Extra = 16, .Threshold = 0.32f }, { .Accept = 0, .Extra = 0 }, { .Accept = 0, .Extra = 0 }, { .Accept = 0, .Extra = 0 } }, \
|
||||
{ { .Accept = 0, .Extra = 16, .Threshold = 0.32f }, { .Accept = 0, .Extra = 8, .Threshold = 0.16f }, { .Accept = 0, .Extra = 0 }, { .Accept = 0, .Extra = 0 } }, \
|
||||
{ { .Accept = 0, .Extra = 24, .Threshold = 0.40f }, { .Accept = 0, .Extra = 12, .Threshold = 0.20f }, { .Accept = 0, .Extra = 6, .Threshold = 0.08f }, { .Accept = 0, .Extra = 0 } }, \
|
||||
{ { .Accept = 0, .Extra = 32, .Threshold = 0.40f }, { .Accept = 0, .Extra = 16, .Threshold = 0.20f }, { .Accept = 0, .Extra = 8, .Threshold = 0.10f }, { .Accept = 0, .Extra = 6, .Threshold = 0.08f } } }
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 Jon Kinsey <jonkinsey@gmail.com>
|
||||
* Copyright (C) 2007-2018 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Multithreaded support functions, moved out of multithread.c
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "multithread.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#if defined (DEBUG_MULTITHREADED)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/simd.h"
|
||||
|
||||
SSE_ALIGN(ThreadData td);
|
||||
|
||||
extern ThreadLocalData *
|
||||
MT_CreateThreadLocalData(int id)
|
||||
{
|
||||
ThreadLocalData *tld = (ThreadLocalData *) g_malloc(sizeof(ThreadLocalData));
|
||||
tld->id = id;
|
||||
tld->pnnState = (NNState *) g_malloc(sizeof(NNState) * 3);
|
||||
tld->pnnState[CLASS_RACE - CLASS_RACE].savedBase = g_malloc0(nnRace.cHidden * sizeof(float));
|
||||
tld->pnnState[CLASS_RACE - CLASS_RACE].savedIBase = g_malloc0(nnRace.cInput * sizeof(float));
|
||||
tld->pnnState[CLASS_CRASHED - CLASS_RACE].savedBase = g_malloc0(nnCrashed.cHidden * sizeof(float));
|
||||
tld->pnnState[CLASS_CRASHED - CLASS_RACE].savedIBase = g_malloc0(nnCrashed.cInput * sizeof(float));
|
||||
tld->pnnState[CLASS_CONTACT - CLASS_RACE].savedBase = g_malloc0(nnContact.cHidden * sizeof(float));
|
||||
tld->pnnState[CLASS_CONTACT - CLASS_RACE].savedIBase = g_malloc0(nnContact.cInput * sizeof(float));
|
||||
|
||||
tld->aMoves = (move *) g_malloc0(sizeof(move) * MAX_INCOMPLETE_MOVES);
|
||||
return tld;
|
||||
}
|
||||
|
||||
#if defined(USE_MULTITHREAD)
|
||||
|
||||
#if defined(DEBUG_MULTITHREADED) && defined(WIN32)
|
||||
unsigned int mainThreadID;
|
||||
#endif
|
||||
|
||||
static GMutex condMutex; /* Extra mutex needed for waiting */
|
||||
|
||||
static GPrivate private_item = G_PRIVATE_INIT(free);
|
||||
|
||||
extern void
|
||||
TLSCreate(TLSItem * pItem)
|
||||
{
|
||||
*pItem = &private_item;
|
||||
}
|
||||
|
||||
extern void
|
||||
TLSSetValue(TLSItem pItem, size_t value)
|
||||
{
|
||||
size_t *pNew = (size_t *) g_malloc(sizeof(size_t));
|
||||
*pNew = value;
|
||||
g_private_set(pItem, (gpointer) pNew);
|
||||
}
|
||||
|
||||
extern void
|
||||
InitManualEvent(ManualEvent * pME)
|
||||
{
|
||||
ManualEvent pNewME = g_malloc(sizeof(*pNewME));
|
||||
|
||||
g_cond_init(&pNewME->cond);
|
||||
pNewME->signalled = FALSE;
|
||||
*pME = pNewME;
|
||||
}
|
||||
|
||||
extern void
|
||||
FreeManualEvent(ManualEvent ME)
|
||||
{
|
||||
g_cond_clear(&ME->cond);
|
||||
g_free(ME);
|
||||
}
|
||||
|
||||
extern void
|
||||
WaitForManualEvent(ManualEvent ME)
|
||||
{
|
||||
gint64 end_time;
|
||||
|
||||
multi_debug("wait for manual event asks lock (condMutex)");
|
||||
|
||||
g_mutex_lock(&condMutex);
|
||||
end_time = g_get_monotonic_time() + 10 * G_TIME_SPAN_SECOND;
|
||||
|
||||
multi_debug("wait for manual event gets lock (condMutex)");
|
||||
|
||||
while (!ME->signalled) {
|
||||
multi_debug("waiting for manual event");
|
||||
|
||||
if (!g_cond_wait_until(&ME->cond, &condMutex, end_time))
|
||||
break;
|
||||
else {
|
||||
multi_debug("still waiting for manual event");
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock(&condMutex);
|
||||
multi_debug("wait for manual event unlocks (condMutex)");
|
||||
}
|
||||
|
||||
extern void
|
||||
ResetManualEvent(ManualEvent ME)
|
||||
{
|
||||
multi_debug("reset manual event asks lock (condMutex)");
|
||||
g_mutex_lock(&condMutex);
|
||||
multi_debug("reset manual event gets lock (condMutex)");
|
||||
|
||||
ME->signalled = FALSE;
|
||||
g_mutex_unlock(&condMutex);
|
||||
multi_debug("reset manual event unlocks (condMutex)");
|
||||
}
|
||||
|
||||
extern void
|
||||
SetManualEvent(ManualEvent ME)
|
||||
{
|
||||
multi_debug("set manual event asks lock (condMutex)");
|
||||
g_mutex_lock(&condMutex);
|
||||
multi_debug("set manual event gets lock (condMutex)");
|
||||
|
||||
ME->signalled = TRUE;
|
||||
g_cond_broadcast(&ME->cond);
|
||||
|
||||
g_mutex_unlock(&condMutex);
|
||||
multi_debug("set manual event unlocks (condMutex)");
|
||||
}
|
||||
|
||||
extern void
|
||||
InitMutex(Mutex * pMutex)
|
||||
{
|
||||
g_mutex_init(pMutex);
|
||||
}
|
||||
|
||||
extern void
|
||||
FreeMutex(Mutex * mutex)
|
||||
{
|
||||
g_assert(MT_GetThreadID() == -1);
|
||||
g_mutex_clear(mutex);
|
||||
}
|
||||
|
||||
extern void
|
||||
Mutex_Lock(Mutex * mutex)
|
||||
{
|
||||
g_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
extern void
|
||||
Mutex_Release(Mutex * mutex)
|
||||
{
|
||||
g_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
extern void
|
||||
MT_InitThreads(void)
|
||||
{
|
||||
td.tasks = NULL;
|
||||
MT_SafeSet(&td.doneTasks, 0);
|
||||
td.addedTasks = 0;
|
||||
td.totalTasks = -1;
|
||||
InitManualEvent(&td.activity);
|
||||
TLSCreate(&td.tlsItem);
|
||||
TLSSetValue(td.tlsItem, (size_t) MT_CreateThreadLocalData(-1));
|
||||
|
||||
#if defined(DEBUG_MULTITHREADED) && defined(WIN32)
|
||||
mainThreadID = GetCurrentThreadId();
|
||||
#endif
|
||||
InitMutex(&td.multiLock);
|
||||
InitMutex(&td.queueLock);
|
||||
InitManualEvent(&td.syncStart);
|
||||
InitManualEvent(&td.syncEnd);
|
||||
td.numThreads = 0;
|
||||
}
|
||||
|
||||
extern void
|
||||
CloseThread(void *UNUSED(unused))
|
||||
{
|
||||
ThreadLocalData *pTLD;
|
||||
NNState *pnnState;
|
||||
|
||||
g_assert(MT_SafeCompare(&td.closingThreads, TRUE));
|
||||
|
||||
pTLD = (ThreadLocalData *) TLSGet(td.tlsItem);
|
||||
pnnState = pTLD->pnnState;
|
||||
|
||||
g_free(pTLD->aMoves);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
g_free(pnnState[i].savedBase);
|
||||
g_free(pnnState[i].savedIBase);
|
||||
}
|
||||
|
||||
g_free(pnnState);
|
||||
g_free(pTLD);
|
||||
|
||||
MT_SafeInc(&td.result);
|
||||
}
|
||||
|
||||
extern void
|
||||
MT_Close(void)
|
||||
{
|
||||
MT_CloseThreads();
|
||||
|
||||
FreeManualEvent(td.activity);
|
||||
FreeMutex(&td.multiLock);
|
||||
FreeMutex(&td.queueLock);
|
||||
|
||||
FreeManualEvent(td.syncStart);
|
||||
FreeManualEvent(td.syncEnd);
|
||||
}
|
||||
|
||||
extern void
|
||||
MT_Exclusive(void)
|
||||
{
|
||||
multi_debug("exclusive asks lock (multiLock)");
|
||||
Mutex_Lock(&td.multiLock);
|
||||
multi_debug("exclusive gets lock (multiLock)");
|
||||
}
|
||||
|
||||
extern void
|
||||
MT_Release(void)
|
||||
{
|
||||
Mutex_Release(&td.multiLock);
|
||||
multi_debug("release unlocks (multiLock)");
|
||||
}
|
||||
|
||||
#if defined(DEBUG_MULTITHREADED)
|
||||
extern void
|
||||
multi_debug(const char *str, ...)
|
||||
{
|
||||
int id;
|
||||
va_list vl;
|
||||
char tn[5];
|
||||
char buf[1024];
|
||||
|
||||
/* Sync output so order makes some sense */
|
||||
#if defined(WIN32)
|
||||
WaitForSingleObject(td.multiLock, INFINITE);
|
||||
#endif
|
||||
/* With glib threads, locking here doesn't seem to work :
|
||||
* GLib (gthread-posix.c): Unexpected error from C library during 'pthread_mutex_lock': Resource deadlock avoided. Aborting.
|
||||
* Timestamp the output instead.
|
||||
* Maybe the g_get_*_time() calls will sync output as well anyway... */
|
||||
|
||||
va_start(vl, str);
|
||||
vsprintf(buf, str, vl);
|
||||
|
||||
id = MT_GetThreadID();
|
||||
#if defined(WIN32)
|
||||
if (id == -1 && GetCurrentThreadId() == mainThreadID)
|
||||
#else
|
||||
if (id == -1)
|
||||
#endif
|
||||
strcpy(tn, "MT");
|
||||
else
|
||||
sprintf(tn, "T%d", id);
|
||||
|
||||
printf("%" G_GINT64_FORMAT " %s: %s\n", g_get_monotonic_time(), tn, buf);
|
||||
|
||||
va_end(vl);
|
||||
|
||||
#if defined(WIN32)
|
||||
ReleaseMutex(td.multiLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else /* !defined(USE_MULTITHREAD) */
|
||||
|
||||
extern void
|
||||
MT_InitThreads(void)
|
||||
{
|
||||
td.tld = MT_CreateThreadLocalData(-1);
|
||||
}
|
||||
|
||||
extern void
|
||||
MT_Close(void)
|
||||
{
|
||||
int i;
|
||||
NNState *pnnState;
|
||||
|
||||
if (!td.tld)
|
||||
return;
|
||||
|
||||
g_free(td.tld->aMoves);
|
||||
pnnState = td.tld->pnnState;
|
||||
for (i = 0; i < 3; i++) {
|
||||
g_free(pnnState[i].savedBase);
|
||||
g_free(pnnState[i].savedIBase);
|
||||
}
|
||||
g_free(pnnState);
|
||||
g_free(td.tld);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2000-2014 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* An implementation of the legacy position key/ID described at:
|
||||
* https://www.gnu.org/software/gnubg/manual/gnubg.html#gnubg-tech_postionid
|
||||
*
|
||||
* This encoding creates IDs as compact as possible.
|
||||
*
|
||||
* For internal use in moves generation and evaluation we now use another
|
||||
* key, much faster to encode or decode, that is essentially the raw board
|
||||
* squeezed down to 4 bits/point.
|
||||
*
|
||||
* This library also calculates bearoff IDs, which are enumerations of the
|
||||
*
|
||||
* c+6
|
||||
* C
|
||||
* 6
|
||||
*
|
||||
* combinations of (up to c) chequers among 6 points.
|
||||
*
|
||||
*
|
||||
* $Id: positionid.c,v 1.56 2021/01/26 22:09:24 plm Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <glib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "positionid.h"
|
||||
|
||||
extern void
|
||||
PositionKey(const TanBoard anBoard, positionkey * pkey)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int *anpBoard = pkey->data;
|
||||
|
||||
for (i = 0, j = 0; i < 3; i++, j += 8) {
|
||||
anpBoard[i] = anBoard[1][j] + (anBoard[1][j + 1] << 4)
|
||||
+ (anBoard[1][j + 2] << 8) + (anBoard[1][j + 3] << 12)
|
||||
+ (anBoard[1][j + 4] << 16) + (anBoard[1][j + 5] << 20)
|
||||
+ (anBoard[1][j + 6] << 24) + (anBoard[1][j + 7] << 28);
|
||||
anpBoard[i + 3] = anBoard[0][j] + (anBoard[0][j + 1] << 4)
|
||||
+ (anBoard[0][j + 2] << 8) + (anBoard[0][j + 3] << 12)
|
||||
+ (anBoard[0][j + 4] << 16) + (anBoard[0][j + 5] << 20)
|
||||
+ (anBoard[0][j + 6] << 24) + (anBoard[0][j + 7] << 28);
|
||||
}
|
||||
anpBoard[6] = anBoard[0][24] + (anBoard[1][24] << 4);
|
||||
}
|
||||
|
||||
extern void
|
||||
PositionFromKey(TanBoard anBoard, const positionkey * pkey)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int const *anpBoard = pkey->data;
|
||||
|
||||
for (i = 0, j = 0; i < 3; i++, j += 8) {
|
||||
anBoard[1][j] = anpBoard[i] & 0x0f;
|
||||
anBoard[1][j + 1] = (anpBoard[i] >> 4) & 0x0f;
|
||||
anBoard[1][j + 2] = (anpBoard[i] >> 8) & 0x0f;
|
||||
anBoard[1][j + 3] = (anpBoard[i] >> 12) & 0x0f;
|
||||
anBoard[1][j + 4] = (anpBoard[i] >> 16) & 0x0f;
|
||||
anBoard[1][j + 5] = (anpBoard[i] >> 20) & 0x0f;
|
||||
anBoard[1][j + 6] = (anpBoard[i] >> 24) & 0x0f;
|
||||
anBoard[1][j + 7] = (anpBoard[i] >> 28) & 0x0f;
|
||||
|
||||
anBoard[0][j] = anpBoard[i + 3] & 0x0f;
|
||||
anBoard[0][j + 1] = (anpBoard[i + 3] >> 4) & 0x0f;
|
||||
anBoard[0][j + 2] = (anpBoard[i + 3] >> 8) & 0x0f;
|
||||
anBoard[0][j + 3] = (anpBoard[i + 3] >> 12) & 0x0f;
|
||||
anBoard[0][j + 4] = (anpBoard[i + 3] >> 16) & 0x0f;
|
||||
anBoard[0][j + 5] = (anpBoard[i + 3] >> 20) & 0x0f;
|
||||
anBoard[0][j + 6] = (anpBoard[i + 3] >> 24) & 0x0f;
|
||||
anBoard[0][j + 7] = (anpBoard[i + 3] >> 28) & 0x0f;
|
||||
}
|
||||
anBoard[0][24] = anpBoard[6] & 0x0f;
|
||||
anBoard[1][24] = (anpBoard[6] >> 4) & 0x0f;
|
||||
}
|
||||
|
||||
/* In evaluations, the function above is often followed by swapping
|
||||
* the board. This is expensive (SwapSides is about as costly as
|
||||
* PositionFromKey itself).
|
||||
* Provide one that fills the board already swapped. */
|
||||
|
||||
extern void
|
||||
PositionFromKeySwapped(TanBoard anBoard, const positionkey * pkey)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int const *anpBoard = pkey->data;
|
||||
|
||||
for (i = 0, j = 0; i < 3; i++, j += 8) {
|
||||
anBoard[0][j] = anpBoard[i] & 0x0f;
|
||||
anBoard[0][j + 1] = (anpBoard[i] >> 4) & 0x0f;
|
||||
anBoard[0][j + 2] = (anpBoard[i] >> 8) & 0x0f;
|
||||
anBoard[0][j + 3] = (anpBoard[i] >> 12) & 0x0f;
|
||||
anBoard[0][j + 4] = (anpBoard[i] >> 16) & 0x0f;
|
||||
anBoard[0][j + 5] = (anpBoard[i] >> 20) & 0x0f;
|
||||
anBoard[0][j + 6] = (anpBoard[i] >> 24) & 0x0f;
|
||||
anBoard[0][j + 7] = (anpBoard[i] >> 28) & 0x0f;
|
||||
|
||||
anBoard[1][j] = anpBoard[i + 3] & 0x0f;
|
||||
anBoard[1][j + 1] = (anpBoard[i + 3] >> 4) & 0x0f;
|
||||
anBoard[1][j + 2] = (anpBoard[i + 3] >> 8) & 0x0f;
|
||||
anBoard[1][j + 3] = (anpBoard[i + 3] >> 12) & 0x0f;
|
||||
anBoard[1][j + 4] = (anpBoard[i + 3] >> 16) & 0x0f;
|
||||
anBoard[1][j + 5] = (anpBoard[i + 3] >> 20) & 0x0f;
|
||||
anBoard[1][j + 6] = (anpBoard[i + 3] >> 24) & 0x0f;
|
||||
anBoard[1][j + 7] = (anpBoard[i + 3] >> 28) & 0x0f;
|
||||
}
|
||||
anBoard[1][24] = anpBoard[6] & 0x0f;
|
||||
anBoard[0][24] = (anpBoard[6] >> 4) & 0x0f;
|
||||
}
|
||||
|
||||
static inline void
|
||||
addBits(unsigned char auchKey[10], unsigned int bitPos, unsigned int nBits)
|
||||
{
|
||||
unsigned int k = bitPos / 8;
|
||||
unsigned int r = (bitPos & 0x7);
|
||||
unsigned int b = (((unsigned int) 0x1 << nBits) - 1) << r;
|
||||
|
||||
auchKey[k] |= (unsigned char) b;
|
||||
|
||||
if (k < 8) {
|
||||
auchKey[k + 1] |= (unsigned char) (b >> 8);
|
||||
auchKey[k + 2] |= (unsigned char) (b >> 16);
|
||||
} else if (k == 8) {
|
||||
auchKey[k + 1] |= (unsigned char) (b >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
extern void
|
||||
oldPositionKey(const TanBoard anBoard, oldpositionkey * pkey)
|
||||
{
|
||||
unsigned int i, iBit = 0;
|
||||
const unsigned int *j;
|
||||
|
||||
memset(pkey, 0, sizeof(oldpositionkey));
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
const unsigned int *const b = anBoard[i];
|
||||
for (j = b; j < b + 25; ++j) {
|
||||
const unsigned int nc = *j;
|
||||
|
||||
if (nc) {
|
||||
addBits(pkey->auch, iBit, nc);
|
||||
iBit += nc + 1;
|
||||
} else {
|
||||
++iBit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void
|
||||
oldPositionFromKey(TanBoard anBoard, const oldpositionkey * pkey)
|
||||
{
|
||||
int i = 0, j = 0, k;
|
||||
const unsigned char *a;
|
||||
|
||||
memset(anBoard[0], 0, sizeof(anBoard[0]));
|
||||
memset(anBoard[1], 0, sizeof(anBoard[1]));
|
||||
|
||||
for (a = pkey->auch; a < pkey->auch + 10; ++a) {
|
||||
unsigned char cur = *a;
|
||||
|
||||
for (k = 0; k < 8; ++k) {
|
||||
if ((cur & 0x1)) {
|
||||
if (i >= 2 || j >= 25) { /* Error, so return - will probably show error message */
|
||||
return;
|
||||
}
|
||||
++anBoard[i][j];
|
||||
} else {
|
||||
if (++j == 25) {
|
||||
++i;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
cur >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
oldPositionIDFromKey(const oldpositionkey * pkey)
|
||||
{
|
||||
unsigned char const *puch = pkey->auch;
|
||||
static char szID[L_POSITIONID + 1];
|
||||
char *pch = szID;
|
||||
static const char aszBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
*pch++ = aszBase64[puch[0] >> 2];
|
||||
*pch++ = aszBase64[((puch[0] & 0x03) << 4) | (puch[1] >> 4)];
|
||||
*pch++ = aszBase64[((puch[1] & 0x0F) << 2) | (puch[2] >> 6)];
|
||||
*pch++ = aszBase64[puch[2] & 0x3F];
|
||||
|
||||
puch += 3;
|
||||
}
|
||||
|
||||
*pch++ = aszBase64[*puch >> 2];
|
||||
*pch++ = aszBase64[(*puch & 0x03) << 4];
|
||||
|
||||
*pch = 0;
|
||||
|
||||
return szID;
|
||||
}
|
||||
|
||||
extern char *
|
||||
PositionIDFromKey(const positionkey * pkey)
|
||||
{
|
||||
TanBoard anBoard;
|
||||
oldpositionkey okey;
|
||||
|
||||
PositionFromKey(anBoard, pkey);
|
||||
oldPositionKey((ConstTanBoard) anBoard, &okey);
|
||||
|
||||
return oldPositionIDFromKey(&okey);
|
||||
}
|
||||
|
||||
extern char *
|
||||
PositionID(const TanBoard anBoard)
|
||||
{
|
||||
oldpositionkey key;
|
||||
|
||||
oldPositionKey(anBoard, &key);
|
||||
|
||||
return oldPositionIDFromKey(&key);
|
||||
}
|
||||
|
||||
extern int
|
||||
PositionFromXG(TanBoard anBoard, const char *pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 26; i++) {
|
||||
int p0, p1;
|
||||
|
||||
if (i == 0) {
|
||||
p0 = 24;
|
||||
p1 = -1;
|
||||
} else if (i == 25) {
|
||||
p0 = -1;
|
||||
p1 = 24;
|
||||
} else {
|
||||
p0 = 24 - i;
|
||||
p1 = i - 1;
|
||||
}
|
||||
|
||||
if (pos[i] >= 'A' && pos[i] <= 'P') {
|
||||
if (p0 > -1)
|
||||
anBoard[0][p0] = 0;
|
||||
anBoard[1][p1] = (unsigned int) (pos[i] - 'A' + 1);
|
||||
} else if (pos[i] >= 'a' && pos[i] <= 'p') {
|
||||
anBoard[0][p0] = (unsigned int) (pos[i] - 'a' + 1);
|
||||
if (p1 > -1)
|
||||
anBoard[1][p1] = 0;
|
||||
} else if (pos[i] == '-') {
|
||||
if (p0 > -1)
|
||||
anBoard[0][p0] = 0;
|
||||
if (p1 > -1)
|
||||
anBoard[1][p1] = 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int
|
||||
CheckPosition(const TanBoard anBoard)
|
||||
{
|
||||
unsigned int ac[2], i;
|
||||
|
||||
/* Check for a player with over 15 chequers */
|
||||
for (i = ac[0] = ac[1] = 0; i < 25; i++)
|
||||
if ((ac[0] += anBoard[0][i]) > 15 || (ac[1] += anBoard[1][i]) > 15) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for both players having chequers on the same point */
|
||||
for (i = 0; i < 24; i++)
|
||||
if (anBoard[0][i] && anBoard[1][23 - i]) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for both players on the bar against closed boards */
|
||||
for (i = 0; i < 6; i++)
|
||||
if (anBoard[0][i] < 2 || anBoard[1][i] < 2)
|
||||
return 1;
|
||||
|
||||
if (!anBoard[0][24] || !anBoard[1][24])
|
||||
return 1;
|
||||
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void
|
||||
ClosestLegalPosition(TanBoard anBoard)
|
||||
{
|
||||
unsigned int i, j, ac[2];
|
||||
|
||||
/* Limit each player to 15 chequers */
|
||||
for (i = 0; i < 2; i++) {
|
||||
ac[i] = 15;
|
||||
for (j = 0; j < 25; j++) {
|
||||
if (anBoard[i][j] <= ac[i])
|
||||
ac[i] -= anBoard[i][j];
|
||||
else {
|
||||
anBoard[i][j] = ac[i];
|
||||
ac[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Forbid both players having a chequer on the same point */
|
||||
for (i = 0; i < 24; i++)
|
||||
if (anBoard[0][i])
|
||||
anBoard[1][23 - i] = 0;
|
||||
|
||||
/* If both players have closed boards, let at least one of them off
|
||||
* the bar */
|
||||
for (i = 0; i < 6; i++)
|
||||
if (anBoard[0][i] < 2 || anBoard[1][i] < 2)
|
||||
/* open board */
|
||||
return;
|
||||
|
||||
if (anBoard[0][24])
|
||||
anBoard[1][24] = 0;
|
||||
}
|
||||
|
||||
extern unsigned char
|
||||
Base64(const unsigned char ch)
|
||||
{
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
return (unsigned char)(ch - 'A');
|
||||
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
return (unsigned char)(ch - 'a' + 26);
|
||||
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return (unsigned char)(ch - '0' + 52);
|
||||
|
||||
if (ch == '+')
|
||||
return 62;
|
||||
|
||||
if (ch == '/')
|
||||
return 63;
|
||||
|
||||
return 255;
|
||||
}
|
||||
|
||||
extern int
|
||||
PositionFromID(TanBoard anBoard, const char *pchEnc)
|
||||
{
|
||||
oldpositionkey key;
|
||||
unsigned char ach[L_POSITIONID + 1], *pch = ach, *puch = key.auch;
|
||||
int i;
|
||||
|
||||
memset(ach, 0, L_POSITIONID + 1);
|
||||
|
||||
for (i = 0; i < L_POSITIONID && pchEnc[i]; i++)
|
||||
pch[i] = Base64((unsigned char) pchEnc[i]);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
*puch++ = (unsigned char) (pch[0] << 2) | (pch[1] >> 4);
|
||||
*puch++ = (unsigned char) (pch[1] << 4) | (pch[2] >> 2);
|
||||
*puch++ = (unsigned char) (pch[2] << 6) | pch[3];
|
||||
|
||||
pch += 4;
|
||||
}
|
||||
|
||||
*puch = (unsigned char) (pch[0] << 2) | (pch[1] >> 4);
|
||||
|
||||
oldPositionFromKey(anBoard, &key);
|
||||
|
||||
return CheckPosition((ConstTanBoard) anBoard);
|
||||
}
|
||||
|
||||
extern int
|
||||
EqualBoards(const TanBoard anBoard0, const TanBoard anBoard1)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 25; i++)
|
||||
if (anBoard0[0][i] != anBoard1[0][i] || anBoard0[1][i] != anBoard1[1][i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_N 40
|
||||
#define MAX_R 25
|
||||
|
||||
static unsigned int anCombination[MAX_N][MAX_R], fCalculated = 0;
|
||||
|
||||
static void
|
||||
InitCombination(void)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0; i < MAX_N; i++)
|
||||
anCombination[i][0] = i + 1;
|
||||
|
||||
for (j = 1; j < MAX_R; j++)
|
||||
anCombination[0][j] = 0;
|
||||
|
||||
for (i = 1; i < MAX_N; i++)
|
||||
for (j = 1; j < MAX_R; j++)
|
||||
anCombination[i][j] = anCombination[i - 1][j - 1] + anCombination[i - 1][j];
|
||||
|
||||
fCalculated = 1;
|
||||
}
|
||||
|
||||
extern unsigned int
|
||||
Combination(const unsigned int n, const unsigned int r)
|
||||
{
|
||||
g_assert(n <= MAX_N && r <= MAX_R);
|
||||
|
||||
if (!fCalculated)
|
||||
InitCombination();
|
||||
|
||||
return anCombination[n - 1][r - 1];
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
PositionF(unsigned int fBits, unsigned int n, unsigned int r)
|
||||
{
|
||||
if (n == r)
|
||||
return 0;
|
||||
|
||||
return (fBits & (1u << (n - 1))) ? Combination(n - 1, r) +
|
||||
PositionF(fBits, n - 1, r - 1) : PositionF(fBits, n - 1, r);
|
||||
}
|
||||
|
||||
extern unsigned int
|
||||
PositionBearoff(const unsigned int anBoard[], unsigned int nPoints, unsigned int nChequers)
|
||||
{
|
||||
unsigned int i, fBits, j;
|
||||
|
||||
if (nPoints == 0) {
|
||||
g_assert_not_reached();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = nPoints - 1, i = 0; i < nPoints; i++)
|
||||
j += anBoard[i];
|
||||
|
||||
fBits = 1u << j;
|
||||
|
||||
for (i = 0; i < nPoints - 1; i++) {
|
||||
j -= anBoard[i] + 1;
|
||||
fBits |= (1u << j);
|
||||
}
|
||||
|
||||
return PositionF(fBits, nChequers + nPoints, nPoints);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
PositionInv(unsigned int nID, unsigned int n, unsigned int r)
|
||||
{
|
||||
unsigned int nC;
|
||||
|
||||
if (!r)
|
||||
return 0;
|
||||
else if (n == r)
|
||||
return (1u << n) - 1;
|
||||
|
||||
nC = Combination(n - 1, r);
|
||||
|
||||
return (nID >= nC) ? (1u << (n - 1)) | PositionInv(nID - nC, n - 1, r - 1) : PositionInv(nID, n - 1, r);
|
||||
}
|
||||
|
||||
extern void
|
||||
PositionFromBearoff(unsigned int anBoard[], unsigned int usID, unsigned int nPoints, unsigned int nChequers)
|
||||
{
|
||||
unsigned int fBits = PositionInv(usID, nChequers + nPoints, nPoints);
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0; i < nPoints; i++)
|
||||
anBoard[i] = 0;
|
||||
|
||||
j = nPoints - 1;
|
||||
for (i = 0; i < (nChequers + nPoints); i++) {
|
||||
if (fBits & (1u << i)) {
|
||||
if (j == 0)
|
||||
break;
|
||||
j--;
|
||||
} else
|
||||
anBoard[j]++;
|
||||
}
|
||||
}
|
||||
|
||||
extern unsigned short
|
||||
PositionIndex(unsigned int g, const unsigned int anBoard[6])
|
||||
{
|
||||
unsigned int i, fBits;
|
||||
unsigned int j;
|
||||
|
||||
if (g == 0) {
|
||||
g_assert_not_reached();
|
||||
return 0;
|
||||
}
|
||||
|
||||
j = g - 1;
|
||||
|
||||
for (i = 0; i < g; i++)
|
||||
j += anBoard[i];
|
||||
|
||||
fBits = 1u << j;
|
||||
|
||||
for (i = 0; i < g - 1; i++) {
|
||||
j -= anBoard[i] + 1;
|
||||
fBits |= (1u << j);
|
||||
}
|
||||
|
||||
/* FIXME: 15 should be replaced by nChequers, but the function is
|
||||
* only called from bearoffgammon, so this should be fine. */
|
||||
return (unsigned short) PositionF(fBits, 15, g);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2002 Gary Wong <gtw@gnu.org>
|
||||
* Copyright (C) 2000-2014 the AUTHORS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef POSITIONID_H
|
||||
#define POSITIONID_H
|
||||
|
||||
#include "gnubg-types.h"
|
||||
|
||||
#define L_POSITIONID 14
|
||||
|
||||
extern void PositionKey(const TanBoard anBoard, positionkey * pkey);
|
||||
extern char *PositionID(const TanBoard anBoard);
|
||||
extern char *PositionIDFromKey(const positionkey * pkey);
|
||||
|
||||
extern int PositionFromXG(TanBoard anBoard, const char * pos);
|
||||
|
||||
extern
|
||||
unsigned int PositionBearoff(const unsigned int anBoard[], unsigned int nPoints, unsigned int nChequers);
|
||||
|
||||
extern void PositionFromKey(TanBoard anBoard, const positionkey * pkey);
|
||||
extern void PositionFromKeySwapped(TanBoard anBoard, const positionkey * pkey);
|
||||
|
||||
/* Return 1 for success, 0 for invalid id */
|
||||
extern int PositionFromID(TanBoard anBoard, const char *pchEnc);
|
||||
|
||||
extern void PositionFromBearoff(unsigned int anBoard[], unsigned int usID,
|
||||
unsigned int nPoints, unsigned int nChequers);
|
||||
|
||||
extern unsigned short PositionIndex(unsigned int g, const unsigned int anBoard[6]);
|
||||
|
||||
#define EqualKeys(k1, k2) ((k1).data[0]==(k2).data[0]&&(k1).data[1]==(k2).data[1]&&(k1).data[2]==(k2).data[2]&&(k1).data[3]==(k2).data[3]&&(k1).data[4]==(k2).data[4]&&(k1).data[5]==(k2).data[5]&&(k1).data[6]==(k2).data[6])
|
||||
|
||||
#define CopyKey(ks, kd) (kd).data[0]=(ks).data[0],(kd).data[1]=(ks).data[1],(kd).data[2]=(ks).data[2],(kd).data[3]=(ks).data[3],(kd).data[4]=(ks).data[4],(kd).data[5]=(ks).data[5],(kd).data[6]=(ks).data[6]
|
||||
|
||||
extern int EqualBoards(const TanBoard anBoard0, const TanBoard anBoard1);
|
||||
|
||||
/* Return 1 for valid position, 0 for not */
|
||||
extern int CheckPosition(const TanBoard anBoard);
|
||||
|
||||
extern void ClosestLegalPosition(TanBoard anBoard);
|
||||
|
||||
extern unsigned int Combination(unsigned int n, unsigned int r);
|
||||
|
||||
extern unsigned char Base64(unsigned char ch);
|
||||
|
||||
extern void oldPositionFromKey(TanBoard anBoard, const oldpositionkey * pkey);
|
||||
extern void oldPositionKey(const TanBoard anBoard, oldpositionkey * pkey);
|
||||
|
||||
#endif
|
||||
@@ -29,6 +29,11 @@ for f in "${fichiers[@]}"; do
|
||||
if grep -q $'\r' "$f"; then
|
||||
signaler "$f : fins de ligne Windows (CRLF)"
|
||||
fi
|
||||
# Copies fidèles de GNU Backgammon (sources et données) : on ne
|
||||
# reformate pas leurs espaces, pour rester identique à l'original.
|
||||
case "$f" in
|
||||
engine/gnubg/* | engine/data/*) continue ;;
|
||||
esac
|
||||
if grep -nE '[[:blank:]]+$' "$f" >/dev/null; then
|
||||
signaler "$f : espaces en fin de ligne (lignes $(grep -nE '[[:blank:]]+$' "$f" | cut -d: -f1 | paste -sd, -))"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user