Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lamp/cs206
  • bwermeil/cs206-2020
  • zabifade/cs206-2020
  • cauderan/cs206-2020
  • malonga/cs206-2020
  • dumoncel/cs206
  • bounekhe/cs206
  • bergerault/cs206
  • flealsan/cs206
  • hsu/cs206
  • mouchel/cs206
  • vebraun/cs206
  • vcanard/cs206
  • ybelghmi/cs206
  • belghmi/cs206
  • bousbina/cs206
  • waked/cs206
  • gtagemou/cs206
  • arahmoun/cs206
  • elhachem/cs206
  • benrahha/cs206
  • benslima/cs206
22 results
Show changes
Showing
with 0 additions and 2087 deletions
labs/lab4-barnes-hut-simulation/quadtree.png

33.4 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="quadtree.svg"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\quadtree.png"
inkscape:export-xdpi="32.65155"
inkscape:export-ydpi="32.65155">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker15906"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path15908"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker15660"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Mend"
inkscape:collect="always">
<path
transform="scale(0.4) rotate(180) translate(10,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path15662" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker15306"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Mend">
<path
transform="scale(0.4) rotate(180) translate(10,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path15308" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker15086"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path15088"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="marker15028"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path15030"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker12608"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path12610"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11876"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11878"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker10168"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path10170"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7470"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Mend">
<path
transform="scale(0.4) rotate(180) translate(10,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7472" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4228"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4231"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.175"
inkscape:cx="1095.4717"
inkscape:cy="135.41975"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1"
inkscape:snap-text-baseline="false" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path4142"
cx="83.397331"
cy="151.83354"
r="13.141105" />
<circle
r="13.141105"
cy="721.93744"
cx="1136.2686"
id="circle4144"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-17.160173"
y="189.79347"
id="text4146"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4148"
x="-17.160173"
y="189.79347">m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan4150">A</tspan></tspan></text>
<text
sodipodi:linespacing="125%"
id="text4152"
y="748.34113"
x="1165.1003"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="748.34113"
x="1165.1003"
id="tspan4154"
sodipodi:role="line">m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan4158">E</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="1152.1206"
y="688.21014"
id="text7888"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7890"
x="1152.1206"
y="688.21014">(x<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan14976">E</tspan>,y<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan14974">E</tspan>)</tspan></text>
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle8064"
cx="1028.7399"
cy="1033.1528"
r="13.141105" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="1045.5515"
y="1070.8625"
id="text8066"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan8068"
x="1045.5515"
y="1070.8625">m<tspan
id="tspan8070"
style="font-size:64.99999762%;baseline-shift:sub">C</tspan></tspan></text>
<circle
r="13.141105"
cy="653.45074"
cx="741.34894"
id="circle10468"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text10470"
y="682.58905"
x="766.01764"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="682.58905"
x="766.01764"
id="tspan10472"
sodipodi:role="line">m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan10474">D</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="743.56964"
y="1123.7406"
id="text10476"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan10478"
x="743.56964"
y="1123.7406">m<tspan
id="tspan10480"
style="font-size:64.99999762%;baseline-shift:sub">B</tspan></tspan></text>
<circle
r="13.141105"
cy="1088.6008"
cx="727.80518"
id="circle10482"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="966.52319"
y="915.48102"
id="text13406"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan13408"
x="966.52319"
y="915.48102">mass</tspan></text>
<circle
r="24.149361"
cy="902.3703"
cx="916.56573"
id="circle13404"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:10, 5;stroke-dashoffset:0;stroke-opacity:1" />
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle14942"
cx="1019.0909"
cy="35.033726"
r="13.141105" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="1029.74"
y="8.9094801"
id="text14944"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan14946"
x="1029.74"
y="8.9094801">m<tspan
id="tspan14948"
style="font-size:64.99999762%;baseline-shift:sub">F</tspan></tspan></text>
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect14952"
width="1052.579"
height="1052.579"
x="82.832512"
y="36.148746" />
<rect
y="558.17084"
x="604.85461"
height="531.79376"
width="531.79376"
id="rect14954"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect14956"
width="521.14429"
height="521.14429"
x="84.185783"
y="37.502014" />
<rect
y="-822.98016"
x="-869.66394"
height="264.46457"
width="264.46457"
id="rect14958"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
transform="scale(-1,-1)" />
<rect
transform="scale(-1,-1)"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect14960"
width="265.25757"
height="265.25757"
x="-1134.2817"
y="-1087.5979" />
<text
sodipodi:linespacing="125%"
id="text14978"
y="619.51978"
x="717.755"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="619.51978"
x="717.755"
id="tspan14980"
sodipodi:role="line">(x<tspan
id="tspan14982"
style="font-size:64.99999762%;baseline-shift:sub">D</tspan>,y<tspan
id="tspan14984"
style="font-size:64.99999762%;baseline-shift:sub">D</tspan>)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="704.62305"
y="1058.9362"
id="text14986"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan14988"
x="704.62305"
y="1058.9362">(x<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan14990">B</tspan>,y<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan14992">B</tspan>)</tspan></text>
<text
sodipodi:linespacing="125%"
id="text14994"
y="1004.3879"
x="991.50635"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1004.3879"
x="991.50635"
id="tspan14996"
sodipodi:role="line">(x<tspan
id="tspan14998"
style="font-size:64.99999762%;baseline-shift:sub">C</tspan>,y<tspan
id="tspan15000"
style="font-size:64.99999762%;baseline-shift:sub">C</tspan>)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:100%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="888.2475"
y="861.99701"
id="text15002"
sodipodi:linespacing="100%"
inkscape:export-xdpi="34.630001"
inkscape:export-ydpi="34.630001"><tspan
sodipodi:role="line"
id="tspan15004"
x="888.2475"
y="861.99701"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">(mass<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan15020">X</tspan>,mass<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan15016">Y</tspan>)</tspan></text>
<circle
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path15022"
cx="-218.31874"
cy="1531.9603"
r="74.751289" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4.89491892;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker15028);marker-end:url(#marker15086)"
d="m 611.75315,1157.4181 516.98645,0"
id="path15026"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="825.29462"
y="1220.0476"
id="text15252"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan15254"
x="825.29462"
y="1220.0476">size<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan15256">SE</tspan></tspan></text>
<circle
r="74.751289"
cy="1300.5319"
cx="301.68127"
id="circle15266"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
r="74.751289"
cy="1531.9603"
cx="130.25279"
id="circle15268"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
r="74.751289"
cy="1531.9603"
cx="495.96689"
id="circle15270"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle15272"
cx="861.68121"
cy="1531.9603"
r="74.751289" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="253.18787"
y="1313.6995"
id="text15274"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan15276"
x="253.18787"
y="1313.6995">Fork</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12608)"
d="m 229.18777,1310.8423 -392.8572,165.7143"
id="path15278"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path15304"
d="m 256.33057,1357.9852 -85.7143,108.5714"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15306)"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path15658"
d="m 350.61637,1359.4137 104.2857,108.5715"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15660)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15906)"
d="m 376.33067,1312.2709 425.7143,164.2857"
id="path15904"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="20.037586"
y="1358.3875"
id="text16312"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16314"
x="20.037586"
y="1358.3875">nw</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="143.27599"
y="1409.9053"
id="text16316"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16318"
x="143.27599"
y="1409.9053">ne</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="412.98669"
y="1405.8646"
id="text16320"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16322"
x="412.98669"
y="1405.8646">sw</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="537.23566"
y="1364.4484"
id="text16324"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16326"
x="537.23566"
y="1364.4484">se</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16328"
y="1544.2709"
x="430.90222"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1544.2709"
x="430.90222"
id="tspan16330"
sodipodi:role="line">Empty</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:111.40943146px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="97.928688"
y="1576.5566"
id="text16332"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16334"
x="97.928688"
y="1576.5566">F</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16342"
y="1574.5566"
x="-253.49989"
style="font-style:normal;font-weight:normal;font-size:111.40943146px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1574.5566"
x="-253.49989"
id="tspan16344"
sodipodi:role="line">A</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16916"
y="1542.2709"
x="813.18781"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1542.2709"
x="813.18781"
id="tspan16918"
sodipodi:role="line">Fork</tspan></text>
<circle
r="74.751289"
cy="1766.2461"
cx="338.8241"
id="circle16920"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle16922"
cx="687.39557"
cy="1766.2461"
r="74.751289" />
<circle
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle16924"
cx="1053.1097"
cy="1766.2461"
r="74.751289" />
<circle
r="74.751289"
cy="1766.2461"
cx="1418.8241"
id="circle16926"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path16928"
d="m 786.33067,1545.128 -392.8572,165.7143"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12608)" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15306)"
d="m 813.47347,1592.2709 -85.7143,108.5714"
id="path16930"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15660)"
d="m 907.75927,1593.6994 104.28563,108.5715"
id="path16932"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path16934"
d="m 933.47357,1546.5566 425.71423,164.2857"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15906)" />
<text
sodipodi:linespacing="125%"
id="text16936"
y="1584.1017"
x="605.75201"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1584.1017"
x="605.75201"
id="tspan16938"
sodipodi:role="line">nw</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16940"
y="1644.1909"
x="700.41876"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1644.1909"
x="700.41876"
id="tspan16942"
sodipodi:role="line">ne</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16944"
y="1640.1503"
x="970.12946"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1640.1503"
x="970.12946"
id="tspan16946"
sodipodi:role="line">sw</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16948"
y="1598.7341"
x="1094.3785"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1598.7341"
x="1094.3785"
id="tspan16950"
sodipodi:role="line">se</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16956"
y="1810.8424"
x="655.07159"
style="font-style:normal;font-weight:normal;font-size:111.40943146px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1810.8424"
x="655.07159"
id="tspan16958"
sodipodi:role="line">E</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:111.40943146px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="303.64294"
y="1808.8424"
id="text16960"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16962"
x="303.64294"
y="1808.8424">D</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:111.40943146px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="1383.6429"
y="1807.9852"
id="text16968"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16970"
x="1383.6429"
y="1807.9852">C</tspan></text>
<text
sodipodi:linespacing="125%"
id="text16972"
y="1808.8424"
x="1017.9285"
style="font-style:normal;font-weight:normal;font-size:111.40943146px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="1808.8424"
x="1017.9285"
id="tspan16974"
sodipodi:role="line">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="918.23126"
y="1466.4738"
id="text16976"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan16978"
x="918.23126"
y="1466.4738">mass = m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan16980">D</tspan> + m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan16982">E</tspan> + m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan16984">B</tspan> + m<tspan
style="font-size:64.99999762%;baseline-shift:sub"
id="tspan16986">C</tspan></tspan></text>
</g>
</svg>
labs/lab4-barnes-hut-simulation/sectormatrix.png

12.3 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="sectormatrix.svg"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\sectormatrix.png"
inkscape:export-xdpi="32.6516"
inkscape:export-ydpi="32.6516">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="marker4830"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4832"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4542"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Mstart"
inkscape:collect="always">
<path
transform="scale(0.4) translate(10,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4544" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4196"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Sstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Sstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4202"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.2) translate(6,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="692.30131"
inkscape:cy="448.67197"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4138"
width="157.25688"
height="157.25688"
x="160.41716"
y="293.24829" />
<rect
y="293.24829"
x="317.80426"
height="157.25688"
width="157.25688"
id="rect4140"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="293.24829"
x="474.40179"
height="157.25688"
width="157.25688"
id="rect4142"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4144"
width="157.25688"
height="157.25688"
x="631.78894"
y="293.24829" />
<rect
y="450.89859"
x="160.41716"
height="157.25688"
width="157.25688"
id="rect4146"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4148"
width="157.25688"
height="157.25688"
x="317.80426"
y="450.89859" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4150"
width="157.25688"
height="157.25688"
x="474.40179"
y="450.89859" />
<rect
y="450.89859"
x="631.78894"
height="157.25688"
width="157.25688"
id="rect4152"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="608.02252"
x="160.41716"
height="157.25688"
width="157.25688"
id="rect4154"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4156"
width="157.25688"
height="157.25688"
x="317.80426"
y="608.02252" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4158"
width="157.25688"
height="157.25688"
x="474.40179"
y="608.02252" />
<rect
y="608.02252"
x="631.78894"
height="157.25688"
width="157.25688"
id="rect4160"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4162"
width="157.25688"
height="157.25688"
x="160.41716"
y="765.67279" />
<rect
y="765.67279"
x="317.80426"
height="157.25688"
width="157.25688"
id="rect4164"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="765.67279"
x="474.40179"
height="157.25688"
width="157.25688"
id="rect4166"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4168"
width="157.25688"
height="157.25688"
x="631.78894"
y="765.67279" />
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path4170"
cx="435"
cy="491.64792"
r="13.571428" />
<circle
r="13.571428"
cy="854.50507"
cx="699.28577"
id="circle4172"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle4174"
cx="769.28577"
cy="824.50507"
r="13.571428" />
<circle
r="13.571428"
cy="894.50507"
cx="790.71436"
id="circle4176"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle4178"
cx="726.42865"
cy="295.93362"
r="13.571428" />
<circle
r="13.571428"
cy="805.93365"
cx="267.85727"
id="circle4180"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle4182"
cx="555.20319"
cy="717.37964"
r="13.571428" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:15, 5;stroke-dashoffset:0;marker-start:url(#Arrow1Mstart)"
d="m 721.42857,569.50506 c 250,-70 350.00003,-5.71428 350.00003,-5.71428"
id="path4184"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="1090"
y="582.36218"
id="text4530"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4532"
x="1090"
y="582.36218"
style="-inkscape-font-specification:'Andale Mono';font-family:'Andale Mono';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">ConcBuffer[Body]</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4540"
d="m 738.57143,392.3622 c 250,-70 395.71437,142.85715 395.71437,142.85715"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:15, 5;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4542)"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:15, 5;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4830)"
d="m 725.71429,699.50506 c 280.00001,38.57143 402.85731,-92.85714 402.85731,-92.85714"
id="path4828"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="171.72594"
y="345.25543"
id="text5218"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5220"
x="171.72594"
y="345.25543">0,0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5222"
y="345.25543"
x="341.43158"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="345.25543"
x="341.43158"
id="tspan5224"
sodipodi:role="line">1,0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="494.97476"
y="345.25543"
id="text5226"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5228"
x="494.97476"
y="345.25543">2,0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5230"
y="345.25543"
x="650.53827"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="345.25543"
x="650.53827"
id="tspan5232"
sodipodi:role="line">3,0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5234"
y="504.85953"
x="171.72594"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="504.85953"
x="171.72594"
id="tspan5236"
sodipodi:role="line">0,1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="341.43158"
y="504.85953"
id="text5238"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5240"
x="341.43158"
y="504.85953">1,1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5242"
y="504.85953"
x="494.97476"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="504.85953"
x="494.97476"
id="tspan5244"
sodipodi:role="line">2,1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="650.53827"
y="504.85953"
id="text5246"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5248"
x="650.53827"
y="504.85953">3,1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="171.72594"
y="656.38239"
id="text5250"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5252"
x="171.72594"
y="656.38239">0,2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5254"
y="656.38239"
x="341.43158"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="656.38239"
x="341.43158"
id="tspan5256"
sodipodi:role="line">1,2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="494.97476"
y="656.38239"
id="text5258"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5260"
x="494.97476"
y="656.38239">2,2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5262"
y="656.38239"
x="650.53827"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="656.38239"
x="650.53827"
id="tspan5264"
sodipodi:role="line">3,2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5266"
y="813.96619"
x="171.72594"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="813.96619"
x="171.72594"
id="tspan5268"
sodipodi:role="line">0,3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="341.43158"
y="813.96619"
id="text5270"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5272"
x="341.43158"
y="813.96619">1,3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5274"
y="813.96619"
x="494.97476"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="813.96619"
x="494.97476"
id="tspan5276"
sodipodi:role="line">2,3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="650.53827"
y="813.96619"
id="text5278"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5280"
x="650.53827"
y="813.96619">3,3</tspan></text>
</g>
</svg>
# Concurrent Bounded Buffer
Use the following commands to make a fresh clone of your repository:
```
git clone -b pubsub git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-pubsub
```
## Useful links
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Introduction
The goal of this assignment is to implement a fixed size buffer that can be accessed concurrently by multiple threads running in parallel.
This is a simple yet important data structure that is widely used in concurrent applications.
In particular, we provide you an implementation of a Publish/Subscribe (PubSub) application that uses the bounded buffer you would be developing.
We will provide a brief overview of the Publish/Subscribe application, and instructions on how to run it towards the end of this assignment.
However, the only data structure that you should implement for this assignment is the bounded buffer, which is explained below:
## Bounded Buffer - Definition and Operations
A concurrent bounded buffer is a data structure that supports the following two operations:
- a method `put(e)` that puts a value `e` in the buffer,
- a method `take` that takes a value from the buffer, and removes it.
Importantly, the `put` and `take` methods should follow the FIFO (First-In, First-Out) semantics.
Intuitively, this means that `take` should return the _oldest_ element that was `put` into the buffer.
<!-- [comment]: # (A pointer to linearizability ?) -->
The buffer is *bounded*, which means that it can only store a finite number of elements.
The maximum number of elements the buffer can hold is passed as an argument to the constructor of `BoundedBuffer`.
The following is the definition of the data structure, which can be found in the file:
`src/main/scala/pubsub/collection/BoundedBuffer`
```scala
class BoundedBuffer[T](size: Int) extends AbstractBoundedBuffer[T](size) {
override def put(e: T): Unit = ???
override def take(): T = ???
}
```
A `put` operation invoked on a buffer that is full will *wait* (or block) until an element is taken from
the buffer. Dually, a `take` operation invoked on an empty buffer will *wait* until an element is put
into the buffer.
Note that multiple `put` and `take` operations can be initiated concurrently from different threads. Hence,
care must be taken to ensure that the `buffer` is not accessed or left in an inconsistent state by the `put` or `take`
methods. To understand the challenges better let us start by considering a sequential setting.
## A Sequential Bounded Buffer
Let us try to implement the `BoundedBuffer` class without worrying at all about concurrency.
That is, imagine that there is only one thread that performs a sequence of `put` and `take` operations on an object of type `BoundedBuffer`.
Can you implement the `put` and `take` methods in this setting?
Note that your implementation should run in constant time in the worst-case.
(A remark: the data structure you implement in this case is also called a _circular queue_.)
To write your solution, use the `pubsub.collection.BoundedBuffer` class skeleton that is given to you in the handout.
You are given two _variables_: `count` and `head`, and an internal buffer that exposes a minimal array-like API.
It is important that you use the variables given to you, and the internal buffer API.
*You are strongly advised not to create any other fields or classes or objects*. Otherwise,
you may fail the testcases.
The following is an illustration of the input/output behavior of the buffer in the sequential case.
In the comments, we show the contents of the array used internally by the `BoundedBuffer` class, and the
return values (if any) of the operations.
```scala
def example1() = { // Internal Buffer:
val buf = new BoundedBuffer(2) // | | |
buf.put(1) // | 1 | |
buf.put(2) // | 1 | 2 |
val x = buf.take() // | | 2 | and x is 1
buf.put(3) // | 3 | 2 |
val y = buf.take() // | 3 | | and y is 2
}
```
Now, think about what should happen if we try to `put` an element into a buffer that is full?
Obviously, the element cannot be stored in the buffer. Furthermore, there is no use of waiting for
some space to be created in the buffer because no element in the buffer could be read simultaneously.
(Recall that there is only one thread accessing the buffer in the sequential setting).
Hence, you may throw an exception in this case. Similarly, handle the dual case of invoking a
`take` on an empty buffer.
Think about what happens when your sequential buffer is used in a concurrent system. What can happen?
Try running the test suite that was given to you with the handout. What can you see?
As you may have seen, the test suite was able to find many problematic schedules for the non-concurrent buffer. This is to be expected!
Now, using your sequential implementation as a stepping stone, let us develop a concurrent bounded buffer, which is your real goal.
## Concurrent Bounded Buffer
Now, let us imagine that there are two threads currently performing operations on a shared buffer of
max size 2 as shown below:
```scala
val buf = new BoundedBuffer(2)
Thread 1 Thread 2
buf.put(1) y = buf.take()
```
The first change you need to make to your sequential implementation is that `buf.take()` invoked
by `Thread 2` should *wait* until an element is put into the buffer by `Thread 1`.
Similarly, a `put` method should *wait* until an element is taken from the buffer.
Throwing an exception in these cases as in the sequential case is not acceptable
here because operations can be happening simultaneously. In other words, a `put` that cannot
succeed now can succeed in the future, because of a concurrently executing `take`.
For this purpose, you may use a `wait` method of the Java standard library.
You can find a brief description of the semantics of the method, and references for further reading in the section *Synchronization Primitives* below. An alternative is to loop continuously until the buffer has an element. This is called as *busy waiting*. But as you can imagine this wastes precious processor cycles, and hence is not preferred. (See the section on busy waiting as well for some examples.)
With this waiting strategy, in the above example, `Thread 2` will enter into *wait* state if it executes before `Thread 1`,
and `Thread 1` will proceed to execute. However, after completing the execution `Thead 1` should *wake up*
`Thread 2` (and also every other thread that would be waiting on the buffer to become non-empty).
For this purpose, you have to use the `notify()`, and/or `notifyAll()` primitives (see section *Synchronization Primitives*).
Note that there are subtle differences between `notify()` and `notifyAll()` which is also briefly explained below.
*Important Hint: You should invoke the synchronization primitives like `wait`, `notify`, `synchronized` etc. only
on the `this` reference when implementing the methods of the `BoundedBuffer` class. Otherwise, your
implementation may get stuck (and run into deadlocks) while testing*
Also remember that `notify` and `wait` should be invoked only inside a `synchronized` block.
Now that we know how to implement the waiting strategy to alleviate the above problem of `Thread 2`
running before `Thread 1`, let us look at other issues that may arise when `put` and `take` methods run concurrently.
In particular, say `Thread 1` starts before `Thread 2`.
Let us study how the operations they perform can interleave, assuming that you implemented
them using `count` and `head`.
Consider the following interleaving of operations of `put` and `get`
```scala
val buf = new BoundedBuffer(2)
Thread 1 Thread 2
//start buf.put(1)
//start buf.take
//reads count -> 0
//...
//updates count -> 1
//reads count -> 1
//read internal buffer(0) (crash !!)
//internal buffer(0) <- 1
```
Clearly, if your code permits the above interleaving then it would crash. Now, your goal is to come up
with adequate synchronization so that no interleaving of operations of `put` and `take` performed
by any number of threads result either in a crash or in an incorrect buffer state.
You may use all the synchronization primitives described below.
The test suite provided along with the project may help you find problematic schedules.
A schedule is a sequence of operations carried out by the different threads such as the one
shown above.
The test suite runs your code on several thousand schedules. You may use that to check whether your bounded
buffer reaches a consistent state on some schedule.
An incorrect run on a schedule could either be that:
- An operation returns an incorrect value.
- An operation throws an exception when it should not.
Remember that some operations, even though they look *atomic*, are decomposed into multiple smaller operations.
For instance, consider `buffer(head) = ...`. Is this atomic ?
In the remaining sections, we talk about the synchronization primitives and some of the commons cases of errors.
## Synchronization Primitives
- `synchronized[T](body: => T)`, which executes `body` in a critical section. This ensures that only a single thread at a time can execute the instructions passed as argument.
- [`wait()`][1], which stops the execution of the thread until it is notified. `wait()` can only be called within a `synchronized` block.
- [`notify()`][2], which unblocks one of the waiting thread. Note that it's not possible to specify which thread is unblocked.
- [`notifyAll()`][3], which unblocks all of the waiting threads.
## Using the Pub/Sub Server
The following section describes how you can run and use the Pub/Sub server implemented for you,
This small server allows any amount of people to connect and chat together around topics of their choice. Playing with it may help you discover errors in your ConcurrentBoundedBuffer.
### Running the server
You can start the Pub/Sub Server as any normal SBT project, simply type `sbt run` while in the root folder of the project. No additional setup is required.
### Connecting to the server
You can connect to the server via command-line interface and the [`telnet`][4] protocole.
When the server is started it will display a line such as:
Connect to <server_ip> (or `localhost`), port 7676 with `telnet` to join this server
Which gives you the IP address of the running server.
In your command-line you must do the following telnet command: `telnet <server_ip> 7676`
You should then be greeted by the server with a `connection_ack`.
*telnet is not enabled by default on Windows 8 and 10; [here are fast and simple instructions to enable telnet on recent Windows][5]*
*There are also issues with telnet connecting to the server when using Windows 10 due to firewall issues. However on Linux telnet works flawlessy [sorry for any inconvenience]*
### Commands available
Now that the server is running and you have a connected client, here is the comprehensive list of the commands any client can use on the server:
- `rename <nickname>`: change your display name to `<nickname>`. Your new name cannot contain any space or single quote.
- `subscribe <topic>`: add yourself to the `<topic>` subscriber list. You will receive all messages sent to that topic.
- `unsubscribe <topic>`: remove yourself from the `<topic>` subscriber list. You will no longer receive messages sent to that topic.
- `publish <topic> '<message>'`: publish the `<message>` of your choice to the `<topic>` of your choice. Your `<message>` can span on multiple lines but has to be enclosed with single-quote `'` to be deemed valid.
- `leave`: end the connection with the server in a polite manner
## Common Pitfalls
### Busy Waiting
Consider the following code snippet that uses a while loop (with an empty body) to guard the execution of the `put` and `take` operations.
```scala
class BoundedBuffer[T](size: Int) extends AbstractBoundedBuffer[T](size) {
override def put(e: T): Unit = {
while (isFull) {}
// Rest of your code
???
}
override def take(): T = {
while (isEmpty) {}
// Rest of your code
???
}
}
```
What is the problem with this way of waiting? Apart from those potential problems,
is this code behaving correctly in a concurrent setting i.e, is there a schedule that would
result in an incorrect behavior on the above code.
_Hint: what happens when one `put` and two `take` are running in parallel ?_
### `notify()` vs `notifyAll()`
As per the documentation [documentation][2]:_ of `notify()`, invoking the `notify` method on an object `o` wakes up a _single_ thread that is waiting on the object `o`'s monitor. If there are multiple threads waiting on `o`, one of them is chosen **arbitrarily** at the discretion of the implementation. Note that a thread waits on an object's monitor by calling one of the wait methods.
Using the `notify` method often leads to tricky problems which can sometimes result in deadlocks. This can lead to bugs that can be hard to see and reproduce. For this reason, it is often strongly advised to use `notifyAll` instead.
Can you figure out why this is the case?
_Hint: Could it ever happen that the thread unblocked by notify somehow cannot execute even though there are other threads that could execute if they were unblocked instead ?_
### Waiting using `if` vs `while`
Due to the semantics of `notify` and `notifyAll`, there are no guarantees that the condition on which a thread is waiting will be fulfilled when the thread is unblocked. Therefore, the following code is problematic:
```scala
synchronized {
if (!condition) {
wait()
}
// We have no garantees that the condition holds here.
}
```
Instead, the waiting thread should always recheck the condition when it is unblocked. This can easily be done using a `while` instead of `if`.
Can you come up with a schedule in which using a simple `if` would be problematic?
_Hint: Try using a system with 3 threads, two of which try to execute `take` and one of which executes `put` in an initially empty buffer?_
_Hint: Note that, as specified in the [documentation of `notify`][2]:_
> The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, **the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object**.
[1]: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#wait()
[2]: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#notify()
[3]: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#notifyAll()
[4]: https://en.wikipedia.org/wiki/Telnet
[5]: http://www.sysprobs.com/install-and-enable-telnet-in-windows-8-use-as-telnet-client
# Lock-free Sorted List
Use the following commands to make a fresh clone of your repository:
```
git clone -b lockfree git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-lockfree
```
## Useful links
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Introduction
The goal of this assignment is to implement a concurrent list that stores values of type `Int` in ascending order.
Last week, we have seen how to use a monitor to make data structures operations behave correctly in a concurrent setting.
This week, the data structure we will implement will not use a monitor or a lock of any kind.
Instead, we will use an atomic operation, called `compareAndSet`, in your implementation of the data structure operations.
The goal will still be to have a data structure that can safely be used in a concurrent setting.
In addition, the sorted list operations you will implement will be *lock-free*.
In a system where all concurrent operations have this property, the progress of at least one thread is ***guaranteed***.
There can not be a global deadlock in which none of the thread can make progress!
Note that this does *not* guarantee that all threads can make progress.
Operation with this property is said to be *wait-free*.
## Atomic Variables
The list methods you will implement will make use of atomic variables. An atomic variable is an object which holds a value of a given type `T`. The object offers two methods to manipulate this value:
- `get`, which returns the current value held in the variable,
- `compareAndSet`, which modifies the content of the variable provided that the previous value is given. This method returns `true` if it was successful, `false` otherwise.
The operation `compareAndSet` applies the following logic ***atomically***, which means there cannot be any context switches between the instructions of the operation:
```scala
def compareAndSet(expected: T, value: T) {
if (current == expected) {
current = value
true
}
else {
false
}
}
```
The `AtomicVariable` class is given to you. You do not have to worry about implementing it!
Note that a similar class exists in the Java standard library, called [`AtomicReference`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html).
The main difference between `AtomicReference` and the `AtomicVariable` class we defined for this exercise is that `AtomicReference` uses referential equality to check whether `expected` and `current` are the same, while `AtomicVariable` uses the `==` method.
## The Sorted List Data Structure
The data structure you will implement is a mutable linked list of integers, sorted in ascending order. Each integer is stored in a `Node`. In addition to the integer value, each node contains a mutable reference to the next node in the list. This mutable reference is held in an `AtomicVariable`.
```scala
abstract class Node(val value: Int, initTail: Option[Node]) {
type State = Option[Node]
def initialState: State = initTail
val atomicState: AbstractAtomicVariable[State] = new AtomicVariable[State](initialState)
def next: Option[Node] = atomicState.get
// ...
}
```
Then, `SortedList` is simply a class that holds a reference to the first node of the list. This class is defined in `SortedList.scala`.
```scala
class SortedList extends AbstractSortedList {
// The sentinel node at the head.
private val _head = createNode(0, None, isHead=true)
// The first logical node is referenced by the head.
def firstNode: Option[Node] = _head.next
def findNodeWithPrev(pred: Int => Boolean): (Node, Option[Node]) = ???
def insert(e: Int): Unit = ???
def contains(e: Int): Boolean = ???
def delete(e: Int): Boolean = ???
}
```
The value `_head` of the list is called a [*sentinel* node](https://en.wikipedia.org/wiki/Sentinel_node). This value is simply `Node` that will serve only as a reference to the first actual node of the list. The value (viz. zero) held by this special node should be completely ignored. This technique is useful because it limits the duplication of code. An alternative is to have a reference to the first node using an `AtomicVariable`. But this would force us to handle the first node differently from the rest. So will use a sentinel node for this assignment.
### `findNodeWithPrev`
The first method you will implement is an internal helper method which will be used all other methods.
This method should do a traversal of the list to find the first node whose value satisfies the parameter predicate.
The method should return the following two values as a pair:
- the predecessor of the node,
- the node.
If `node` is the first node whose value satisfies the predicate and `predecessor` its predecessor, then the method should return `(predecessor, Some(node))`. Due to the use of the sentinel node at the head of the list, the method is bound to find a predecessor, even for the first logical node.
When the predicate doesn't hold on any of the values, then the function should return `(last, None)`, where
`last` is the last node of the list.
### `insert`
Your first goal will be to code the insert method of the lock-free list. The idea is very simple:
1. Locate the position you need to insert by using the `findNodeWithPrev` method you have just implemented.
2. Create a new node that holds the value and points to the correct next node. For this, you should use `createNode(value, nextNode)`.
3. Use the `compareAndSet` operation to make the previous node point to your newly created node.
4. If the operation failed, retry from the start! Otherwise, the operation is done!
### `contains`
Next, you should implement the `contains` method, which checks if the list contains a given element. You may of course use the `findNodeWithPrev` method you have implemented.
### `delete`
With the addition of `delete`, things get rapidly trickier. The intuitive solution would be to:
1. Find the node to delete and its predecessor using `findNodeWithPrev`.
2. Use an atomic `compareAndSet` operation to make the predecessor node point to the successor.
Unfortunately, this solution is not entirely satisfactory!
Indeed, there exist schedules in which some successful operations are lost. Can you think of any?
As an example, assume that the list currently contains the values `10` and `30`.
![Step 0](step0.png "Initial configuration")
- Imagine one thread starts executing the insertion of `20` in the list and correctly locates where to insert the new node (between `10` and `30`). The thread then creates a node with value `20` and makes it point to the node with value `30`. ![Step 1](step1.png "Right in the middle of inserting 20")
- Now, some other thread is scheduled and starts executing the deletion of the node with value `10`. The thread finds the two nodes that surround it, that is the sentinel node at the head of the list and the node with value `30` (note that the insertion of `20` by the other thread isn't visible yet!). The thread, using compare and set, changes the next pointer of the sentinel node to the node with value `30`. The `delete` operation then terminates successfully. ![Step 2](step2.png "After the deletion of 10")
- Now, the first thread resumes its execution. Its next instruction is to use compare and set to change the next pointer of the node with value `10`, which it can do without any problem! Indeed, this atomic variable wasn't touched by the delete operation. The `insert` operation looks successful, even though the node that was inserted is not reachable from the head of the list! The operation was lost... ![Step 3](step3.png "Final configuration")
One solution to this problem, as proposed by Timothy L. Harris in his paper [A Pragmatic Implementation of Non-Blocking Linked Lists](https://www.cl.cam.ac.uk/research/srg/netos/papers/2001-caslists.pdf), is to somehow record in the node that it was deleted.
We will proceed similarly in this assignment.
#### Marking Nodes
The first step is to modify the mutable state held by nodes. Open the `Node.scala` file. Until now the state was just `Option[Node]`, which is an optional reference to the next node.
You will need to add, in addition to this information, a boolean flag that indicates whether the node was deleted or not.
```scala
abstract class Node(val value: Int, initTail: Option[Node]) {
type State = ???
def initialState: State = ???
val atomicState: AbstractAtomicVariable[State] = new AtomicVariable[State](initialState)
def next: Option[Node] = ???
def deleted: Boolean = ???
def mark: Boolean = ???
}
```
Begin by modifying the `State` type to any type that you deem appropriate. Remember that the value of this type should contain an `Option[Node]` (the next node) and a flag (whether the node has been marked).
Complete the other functions, described below, as well:
- `initialState` should return the state of the node when it is first created. Note that the node should not be marked and the optional reference to the next node should be set to `initTail`.
- `next` should return the optional reference to the next node held currently in the state.
- `deleted` should return `true` if the node was marked, `false` otherwise.
- `mark` should mark the node as `deleted`. The method should return `true` only if it is the first time this node is marked. If the node was previously marked, this method should return `false`. (Think carefully about this!)
#### Implementing `delete` of `SortedList`
Now, we can implement a version of delete that is not vulnerable to the problem exposed earlier. The idea is to:
1. Find the node to delete and its predecessor using `findNodeWithPrev`.
2. Mark the node as `deleted` using its `mark` method. If it returns false, retry from the start!
Once this is done, we still have to modify the other list methods to handle the fact that nodes can be marked.
Marked nodes will be deleted within the `findNodeWithPrev` method.
#### Adapting `findNodeWithPrev` to handle marked nodes
The first method you need to adapt is `findNodeWithPrev`. The method should do exactly as before except when it encounters a marked node during its traversal. When it does so, the method should use compare and set to modify the next node pointed by the predecessor node. Regardless of the outcome of the compare and set operation, the `findNodeWithPrev` should then restart from scratch.
#### Adapting `insert` to handle marked nodes
The last method you need to change is `insert`. The logic remains exactly the same, except that when you perform the `compareAndSet` operation, you should make sure that the parameters are of type `State` and are not flagged as deleted.
You are now done with this assignment. Congratulations!
labs/lab6-lock-free-sorted-list/step0.png

1.99 KiB

labs/lab6-lock-free-sorted-list/step1.png

4.18 KiB

labs/lab6-lock-free-sorted-list/step2.png

6.33 KiB

labs/lab6-lock-free-sorted-list/step3.png

6.95 KiB

## Binary Trees
Use the following commands to make a fresh clone of your repository:
```
git clone -b actorbintree git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-actorbintree
```
## Useful links
* [The API documentation of Akka](https://doc.akka.io/api/akka/current/akka/index.html)
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Introduction
Binary trees are tree based data structures where every node has at most two children (left and right).
In this exercise, every node stores an integer element.
From this we can build a binary search tree by requiring for every node that
* values of elements in the left subtree are strictly smaller than the node's element
* values of elements in the right subtree are strictly bigger than the node's element
In addition, there should be no duplicates, hence we obtain a binary tree set.
Your task in this assignment is to implement an actor-based binary tree set where each node is
represented by one actor. The advantage of such an actor-based solution is that it can execute
fully asynchronously and in parallel.
#### The API
You can find the message-based API for the actor-based binary tree to be implemented in the supplied `BinaryTreeSet` object
in the file `BinaryTreeSet.scala`.
The operations, represented by actor messages, that the implementation should support are the following:
* `Insert`
* `Remove`
* `Contains`
All three of the operations expect an `ActorRef` representing the requester of the operation, a numerical identifier of
the operation and the element itself. `Insert` and `Remove` operations should result in an `OperationFinished` message sent
to the provided requester `ActorRef` reference including the id of the operation. `Insert` and `Remove` should return an
`OperationFinished` message even if the element was already present in the tree or was not found, respectively.
`Contains` should result in a `ContainsResult` message containing the result of the lookup (a Boolean which is
true if and only if the element is in the tree when the query arrives) and the identifier of the `Contains` query.
#### Handling of Removal
You should observe that both the `Insert` and `Contains` operations share an important property, namely, they only
traverse a linear path from the root of the tree to the appropriate inner node or leaf. Since the tree nodes are actors
which process messages one-by-one, no additional synchronization is needed between these operations. Removal in a
binary tree unfortunately results in tree restructuring, which means that nodes would need to communicate and coordinate
between each other (while additional operations arrive from the external world!).
Therefore, instead of implementing the usual binary tree removal, in your solution you should use a flag that is stored
in every tree node (`removed`) indicating whether the element in the node has been removed or not. This will result in a very
simple implementation that is concurrent and correct with minimal effort. Unfortunately this decision results in the
side effect that the tree set accumulates "garbage" (elements that have been removed) over time.
#### Garbage Collection
As we have seen, removal of entries can be implemented simply by using a removal flag with the
added cost of growing garbage over time. To overcome this limitation you will need to implement a "garbage collection"
feature. Whenever your binary tree set receives a `GC` message, it should clean up all the removed elements, while
additional operations might arrive from the external world.
The garbage collection task can be implemented in two steps. The first subtask is to implement an internal
`CopyTo` operation on the binary tree that copies all its non-removed contents from the binary tree to a provided new one. This
implementation can assume that no operations arrive while the copying happens (i.e. the tree is protected from modifications
while copying takes places).
The second part of the implementation is to implement garbage collection in the manager (`BinaryTreeSet`) by using the copy operation.
The newly constructed tree should replace the old one and all actors from the old one should be stopped.
Since copying assumes no other concurrent operations, the manager should handle the case when operations arrive while still
performing the copy in the background. It is your responsibility to implement the manager in such a way that the fact
that garbage collection happens is invisible from the outside (of course additional delay is allowed).
For the sake of simplicity, your implementation should ignore GC requests that arrive while garbage collection is taking place.
#### Ordering Guarantees
Replies to operations may be sent in any order but the contents of `ContainsResult` replies must obey the order of the
operations. To illustrate what this means observe the following example:
Client sends:
Insert(testActor, id=100, elem=1)
Contains(testActor, id=50, elem=2)
Remove(testActor, id=10, elem=1)
Insert(testActor, id=20, elem=2)
Contains(testActor, id=80, elem=1)
Contains(testActor, id=70, elem=2)
Client receives:
ContainsResult(id=70, true)
OperationFinished(id=20)
OperationFinished(id=100)
ContainsResult(id=80, false)
OperationFinished(id=10)
ContainsResult(id=50, false)
While the results seem "garbled", they actually strictly correspond to the order of the original operations. On
closer examination you can observe that the order of original operations was [100, 50, 10, 20, 80, 70]. Now if you
order the responses according to this sequence the result would be:
Insert(testActor, id=100, elem=1) -> OperationFinished(id=100)
Contains(testActor, id=50, elem=2) -> ContainsResult(id=50, false)
Remove(testActor, id=10, elem=1) -> OperationFinished(id=10)
Insert(testActor, id=20, elem=2) -> OperationFinished(id=20)
Contains(testActor, id=80, elem=1) -> ContainsResult(id=80, false)
Contains(testActor, id=70, elem=2) -> ContainsResult(id=70, true)
As you can see, the responses the client received are the same, hence they must have been executed sequentially,
and only the responses have arrived out of order. Thus, the responses obey the semantics of sequential operations
-- it is simply their arrival order is not
defined. You might find it easier for testing to use sequential identifiers for the operations, since that makes it
easier to follow the sequence of responses.
You might also note that out-of-order responses can only happen if the client does not wait for each individual answer
before continuing with sending operations.
While this loose ordering guarantee on responses might look strange at first, it will significantly simplify the
implementation of the binary tree and you are encouraged to make full use of it.
#### Your task
You can find code stubs in the file `BinaryTreeSet.scala` which provides you with the API as described above,
the `BinaryTreeSet` and `BinaryTreeNode` classes. The `BinaryTreeSet` represents the whole binary tree.
This is also the only actor that is explicitly created by the user and the only actor the user sends messages to.
You can implement as many or as few message handlers as you like and you can add additional variables or helper
functions. We provide suggestions in your code stub, marked with the comment `optional`, but you are free to use
it fully or partially; the optional elements are not part of the tested API.
To see a binary tree in operation check our provided tests in `BinaryTreeSuite.scala`. Note in particular
that it is the user who triggers garbage collection by sending a `GC` message (for the sake of simplicity of this exercise).
Don't forget to make sure that no `Operation` messages interfere during garbage collection and that the user does
not receive any messages that may result from the copying process. To achieve this, put any incoming operation message
into a queue during the garbage collection process. When the copying process is finished, re-send the queued messages
to the tree root and clear the queue.
The following may be useful for your implementation:
* Another way to stop an actor, besides the `stop` method you have seen, is to send it a `PoisonPill` message.
* `context.parent` returns the ActorRef of the actor which created the current actor (i.e. its parent).
* If you see a log message like the following
[INFO] [11/21/2013 14:04:13.237] [PostponeSpec-akka.actor.default-dispatcher-2] [akka://PostponeSpec/deadLetters] Message [actorbintree.BinaryTreeSet$OperationFinished] from Actor[akka://PostponeSpec/user/$e/my-actor#-1012560631] to Actor[akka://PostponeSpec/deadLetters] was not delivered. [1] dead letters encountered.
it means that one of your messages (here the OperationFinished) message was not delivered from actor `my-actor` to actor `deadLetters`—the latter is where actors forward their messages after they terminate.
You should check that you do not stop actors prematurely.
*A word on Actor counts:*
* The grader verifies that enough Actors are created when inserting elements.
* The grader also verifies that enough Actors are stopped in response to a `GC` command (i.e. for those elements that were previously marked removed from the set).
# Tools Setup
## Note
We recommend using Linux or macOS for this course, we also support Windows but
typically people have more trouble getting everything working correctly on
Windows and it's harder for us to help them since we don't use Windows
ourselves.
**On Windows, if your username has spaces or special characters in it, the IDE might not
work properly. Please create a new user with a username containing only letters.**
# Step 1: Create an account on gitlab.epfl.ch
If you haven't already [log into gitlab](https://gitlab.epfl.ch/users/sign_in)
and fill in [this table](https://docs.google.com/spreadsheets/d/1rcq_UMgR6bAH-iK1L2I6WoClZtCqUoIOLqQO3NJKdgg) with your GASPAR and SCIPER number to initialize your GitLab repository for the course. Do this as soon as possible because it will take some time between the account creation and the lab submission system working for your account.
## Step 2: Installing the Java Development Kit (JDK) and sbt via coursier
We will use coursier to install the correct version of
Java as well as the sbt build tool:
### On Linux
```shell
curl -fLo cs https://git.io/coursier-cli-linux
```
```shell
chmod +x cs
```
```shell
./cs setup -y --jvm 8 --apps cs,sbt
```
Please reboot after this point.
### On macOS
First, install the Homebrew package manager:
```shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
Use Homebrew to install coursier:
```scala
brew install coursier/formulas/coursier
```
```shell
[ -f ~/.bash_profile ] && sudo chmod 0666 ~/.bash_profile
```
```shell
cs setup -y --jvm 8 --apps sbt
```
Please close this terminal and open a new one after this point.
### On Windows
Download and install the [Visual C++ 2010 SP1 Redistributable Package](https://www.microsoft.com/en-us/download/details.aspx?id=13523).
Open `cmd.exe` (and not powershell)
First, make sure that you are not in the `System32` directory, instead you
should be in `C:\Users\yourusername`. If you are in `System32` you will need to
change directory to your user directory every time you start a terminal by
running:
```shell
cd %USERPROFILE%
```
Now assuming that you're in the correct directory you can run:
```shell
bitsadmin /transfer cs-cli https://git.io/coursier-cli-windows-exe "%cd%\cs.exe"
```
```shell
.\cs setup -y --jvm 8 --apps cs,sbt
```
(This command might cause your anti-virus to misidentify cs.exe as a virus,
please override that, that might require temporarily turning off your anti-virus
during this setup).
If this command fails with `Error running powershell script`, use the following
alternative instructions (if the command didn't fail, continue to the next
step):
1. Run `.\cs setup --jvm 8 --apps cs,sbt`, at every question answer "n" and
press Enter.
2. The last question should look like "Should we add `C:\...\bin` to your PATH?",
please copy the `C:\...\bin` part here.
3. Edit the Path environment variable and paste the path you just copied to it, see
https://www.architectryan.com/2018/08/31/how-to-change-environment-variables-on-windows-10/
and make sure the path you're adding is the first entry in the Path environment
variable.
4. Start a **new** cmd.exe and continue with the rest of the instructions
**In case of errors please ask on Discord or Gitlab issues for help, but don't
try to run commands as Administrator as this will likely cause further issues!**
Please close this terminal and open a new one after this point.
## Step 5: Installing git
git is a version control system.
### On Ubuntu and Debian
```shell
sudo apt update && sudo apt install git
```
### On macOS
```shell
brew install git
```
### On Windows
Download and install git from [https://git-scm.com/downloads](https://git-scm.com/downloads).
Once git is installed, open a **new** terminal and run:
```shell
git config --global core.autocrlf false
```
If this command worked it will not print anything.
## Step 6: Installing Code
Visual Studio Code is the IDE we strongly recommend using for this class (you are free to use any editor you want, but we won't don't have the resources to help you configure it for Scala).
### On Linux
See [https://code.visualstudio.com/docs/setup/linux](https://code.visualstudio.com/docs/setup/linux)
### On macOS
```shell
brew install --cask visual-studio-code
```
### On Windows
See [https://code.visualstudio.com/docs/setup/windows](https://code.visualstudio.com/docs/setup/windows).
Make sure that the checkbox "Add to PATH (available after restart)" in the
installer is checked.
## Step 7: Installing the Scala support for Code
Open a **new** terminal and run:
```scala
code --install-extension lampepfl.dotty-syntax
```
If you're on Windows and the command is not found, try closing and restarting
the terminal, if that doesn't work
## Step 8: Generate a public/private SSH key pair
To submit labs, you will need an SSH key. If you don't already have one, here's how to generate it:
### Step 8.1: Installing OpenSSH
#### On Ubuntu and Debian
```shell
sudo apt update && sudo apt install openssh-client
```
#### On macOS
Nothing to do, OpenSSH is pre-installed
#### On Windows
Follow the instructions under "Enable OpenSSH Client in Windows 10" on
[https://winaero.com/blog/enable-openssh-client-windows-10/](https://winaero.com/blog/enable-openssh-client-windows-10/)
### Step 8.2: Generating the key pair
Open a **new** terminal and run:
```shell
ssh-keygen -t rsa -b 4096 -C "youremail@example.com"
```
The command will then ask for a location, which you can leave as the default. It will then also ask for a passphrase to encrypt your private key, which you may leave empty. If you don't, make sure to remember your passphrase!
### Adding your public key on Gitlab
To be able to push your code, you'll need to add the public part of your key on Gitlab:
- Go to [gitlab.epfl.ch](https://gitlab.epfl.ch), log in with your EPFL account
- Go to [gitlab.epfl.ch/profile/keys](https://gitlab.epfl.ch/profile/keys) and copy-paste the content of the `id_rsa.pub` file created by the `ssh-keygen` command you just ran (when the command was ran it printed the location where this file was saved).
- Press `Add key`
## Step 9: Follow the example lab
Time to do the [example lab](example-lab.md)!
File deleted
File deleted
File deleted
File deleted
File deleted
File deleted
File deleted
File deleted