<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:media="http://search.yahoo.com/mrss/"
	
	>

<channel>
	<title>Vincent Mai Design</title>
	<link>https://vincentmai.com</link>
	<description>Vincent Mai Design</description>
	<pubDate>Tue, 15 Jun 2021 22:28:12 +0000</pubDate>
	<generator>https://vincentmai.com</generator>
	<language>en</language>
	
		
	<item>
		<title>Home</title>
				
		<link>https://vincentmai.com/Home</link>

		<pubDate>Wed, 03 Mar 2021 07:13:56 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Home</guid>

		<description>if (themeLoaded) adaptTheme();


	



	



“What I cannot create I do not understand.”
—Richard Feynman


“To design is to devise courses of action aimed at changing existing situations into preferred ones.”
—Herbert Simon
	




 
	

	

	




	Hi




This is Vincent Mai. I design, code, prototype, and learn. Done in concert, I find that it is the best way to explore ideas, master knowledge and build anything.
	








	


	
	Here you will find past and on-going works related to design and computation. They

reflect

 either  my formal education, past professional training, or simply side hobbies.
All can be viewed as exercises in crafting architectures toward particular objectives under constraints, no matter the language, techniques, or the level of abstraction.


	




</description>
		
	</item>
		
		
	<item>
		<title>Handling Data Trees</title>
				
		<link>https://vincentmai.com/Handling-Data-Trees</link>

		<pubDate>Wed, 03 Mar 2021 17:30:58 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Handling-Data-Trees</guid>

		<description>if (themeLoaded) adaptTheme();


    
    
Handling Data Trees in Grasshopper Python Scripts









Decorate your functions swiftly and easily with TreeHandler


Mar 24 / 2020




____________________









    

    
    
    

Published on Medium
&#60;img width="1300" height="900" width_o="1300" height_o="900" data-src="https://freight.cargo.site/t/original/i/f76f38d71e5d29409331f974e7e7b86f17446a021b9edec38d8fddb205c31ebc/cones_demo.gif" data-mid="103164780" border="0"  src="https://freight.cargo.site/w/1000/i/f76f38d71e5d29409331f974e7e7b86f17446a021b9edec38d8fddb205c31ebc/cones_demo.gif" /&#62;

In Grasshopper, all data are stored in Data Trees — a custom data structure which encapsulates information passed between various components. Normally the handling of a Data Tree is done automatically by Grasshopper, but once you start scripting your very own custom components, you may find Data Tree handling a less than intuitive process, especially when dealing with input trees with different shapes.

In the following tutorial, we will introduce treehandler — a lightweight utility library designed to simplify Data Tree handling in a GhPython module. This tutorial targets those familiar with Python scripting in Grasshopper. If you are new to working with grasshopper Data Tree or the GhPython module, I have included a few pointers in Additional Resources to help you get started. All Grasshopper definitions used in this tutorial can be downloaded from food4Rhino.




Content Overview
1. Motivation2. Installation3. Usage4. Performance5. Notes6. Additional Resources









Motivation
Whether you are performing simple tasks or creating complex components using the GhPython module, it is always preferable to remain consistent with how Grasshopper handles Data Tree by default, ergo, any users new to your script can readily rely on prior intuition on Data Trees. The following are code snippets of two tasks at different levels of complexity.

# Snippet of a simple task
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg

def standardCone(base, radius):
    """Returns a standard conic surface on the XY plane
    where its radius equals its height"""
    apex = rs.PointAdd(base, rg.Vector3d(0, 0, radius))
    return rs.AddCone(base, apex, radius)
a = standardCone(base, radius)




In this simple task, we’ll create a conic surface by calling the rhinoscriptsyntax function AddCone()whose input base and radius have a one-to-one correspondence. Thus, we will set both inputs to have item access, meaning that data will be piped into the component one item at a time. On the other hand, should our function take a list of objects as input, for instance, AddPolyline(points), we will need to set the input to have list access.
&#60;img width="1778" height="967" width_o="1778" height_o="967" data-src="https://freight.cargo.site/t/original/i/c0cde303ec70ffbe82830047619d0e2e65631ef496416d91a81d34b003f00700/simple_task.png" data-mid="103164784" border="0"  src="https://freight.cargo.site/w/1000/i/c0cde303ec70ffbe82830047619d0e2e65631ef496416d91a81d34b003f00700/simple_task.png" /&#62;


So what happens when we change radius to a list of numbers? If we test our script in grasshopper, we see that grasshopper had performed a number of implicit cycles which is equal to the size of the list of radius. Since we set both inputs to have item access, Grasshopper will automatically iterate through the input one item at the time. Despite there being only one base point but three radii, Grasshopper will automatically “extend” the list of base by repeating its last element until it has the same length as radius. This is Grasshopper’s default handling of inputs with different sizes.

&#60;img width="836" height="645" width_o="836" height_o="645" data-src="https://freight.cargo.site/t/original/i/8e2395a4bffda2b69722f509a7dd367df6b9ad072d3649dc99bde79cedc4adf3/implicit_cycles.png" data-mid="103164782" border="0"  src="https://freight.cargo.site/w/836/i/8e2395a4bffda2b69722f509a7dd367df6b9ad072d3649dc99bde79cedc4adf3/implicit_cycles.png" /&#62;


It’s worth interjecting that data do not truly exist as a ‘list’ or as an ‘item’. Data only exist in the form of a Data Tree. A ‘list’ is but a Data Tree with one branch which contains a list of data. Likewise, an ‘item’ is a ‘list’ (actually a Data Tree) that holds a single data entry. If this seems unfamiliar to you, check out Andrew Heumann’s tutorial on Data Tree. In short, if you are not performing more complex tasks, we can typically rely on Grasshopper to autopilot data retrieval, as long as we set the component with the correct input access.





&#60;img width="1300" height="900" width_o="1300" height_o="900" data-src="https://freight.cargo.site/t/original/i/08257a9796dc402d2abb658a4ab6e65e2cb64a257ba49160f2d7ded46a351822/cones_grid.png" data-mid="103164781" border="0"  src="https://freight.cargo.site/w/1000/i/08257a9796dc402d2abb658a4ab6e65e2cb64a257ba49160f2d7ded46a351822/cones_grid.png" /&#62;


But what if it becomes necessary to directly access Data Trees? Let’s take a look at the following code snippet. In this example, we will split a grid of cones into four quadrants, and use four attractor points to influence the sizes of the cones in each quadrant. We will assume that each attractor only affects the cones within its designated quadrant.

&#60;img width="1394" height="663" width_o="1394" height_o="663" data-src="https://freight.cargo.site/t/original/i/6041be0d1f678bca1a5fab72f222a93b63c08dd10cb6d164a89dd159fad1ab00/complex_task.png" data-mid="103164777" border="0"  src="https://freight.cargo.site/w/1000/i/6041be0d1f678bca1a5fab72f222a93b63c08dd10cb6d164a89dd159fad1ab00/complex_task.png" /&#62;




# Snippet of a more complex task:
from Grasshopper import DataTree
from Grasshopper.Kernel.Data import GH_Path
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import math

def standardCone(base, radius):
    """Returns a standard conic surface on a XY plane
    where its radius equals its height"""
    apex = rs.PointAdd(base, rg.Vector3d(0, 0, radius))
    return rs.AddCone(base, apex, radius)
def makeQuadrants(ptGrid):
    """Divide input point grid into four quadrants"""
    result = DataTree[object]()
    div = int(math.sqrt(ptGrid.DataCount / 4))
    for i, branch in enumerate(ptGrid.Branches):
        for j, item in enumerate(branch):
            result.Add(item, GH_Path(0, i//div, j//div))
    return result
 
def dist(pt1, pt2, cutoff=15):
    """Returns the distance between two points. 
    Returns cutoff if the distance exceeds it."""
    return min(rs.Distance(pt1, pt2), cutoff)
 
def scale(scalar, val, bounds):
    """Returns a new value scaled by the scalar,
    but capped within bounds"""
    result = scalar*val
    lower, upper = bounds
    return max(min(result, upper), lower)

# split base and attractors into quadrants
# in essence modifying Data Tree topology
base = makeQuadrants(base)
attractor = makeQuadrants(attractor)

scalar = dist(base, attractor) * factor
radius = scale(scalar, radius, bounds=(0.1, radius))
a = standardCone(base, radius)






&#60;img width="2168" height="1118" width_o="2168" height_o="1118" data-src="https://freight.cargo.site/t/original/i/94b1d6c6f2ba0a2b279f2543aabd9fc4c26e1a6245ebe35cccd6c4af1b81aee2/numbered_grid.png" data-mid="103164783" border="0"  src="https://freight.cargo.site/w/1000/i/94b1d6c6f2ba0a2b279f2543aabd9fc4c26e1a6245ebe35cccd6c4af1b81aee2/numbered_grid.png" /&#62;

To split a grid of base points into four quadrants, the easiest route is to directly manipulate the Data Tree’s topology (from 6 branches, 6 points per branch, to a Data Tree of 4 branches, 9 points per branch). We can do so by calling makeQuardrants(), which can also be reused to split the attractors into quadrants. To use Data Trees as function arguments, we must set the corresponding input access of base and attractor to have tree access.

All seems well. It’s not until we call dist() that we get the following error from GhPython interpreter:

Runtime error (ValueErrorException): Could not convert tree {9;9;9;9} 
to a Point3d





This is due to the fact that the functions of dist(), scale(), and standardCone() expect inputs to have item access, that is, data items will be piped in one at a time. Thus, Python interpreter have no clue what to do with the Data Trees in the argument.

There are generally two ways around such a hurdle. We can either move subsequent functions after makeQuadrants() into a new GhPython component, set all input access as item access, and let Grasshopper handle data retrieval. Otherwise, we can manually loop through the input Data Trees and retrieve the data ourselves. The first method is a quick fix that may turn out to be cumbersome. For as long as there’s a need to directly process Data Trees, it must be wrapped inside a stand-alone component. Thus a well-encapsulated component may now have to explode into a bunch of unclear and unjustified GhPython components which will be hard to maintain and reuse. The second method is a rather complex procedure, for we must manually match input Data Trees with different topologies (dimensional depth and breadth). This involves implicitly “grafting” branches with “inferior” dimensions to one with higher dimensions (i.e., {0; 1} to {0; 0; 1}, matching branches with different number of child branches, and finally, matching branches containing different numbers of items.

While most tutorials advise that we’d better avoid manual processing of Data Trees, fear not! We can now utilize treehandler to swiftly and easily handle Data Trees as input while yielding results consistent with those returned by Grasshopper.








Installation
Option 1:
Git clone ghpythonutil into Rhino’s IronPython Library. Choose one of several destination &#38;lt;PATH&#38;gt; by runing the following in a GhPython component




# in a GhPython component
# Choose a &#38;lt;PATH&#38;gt; from sys.patimport sys
for path in sys.path:
&#38;nbsp; &#38;nbsp; print(path)
# in a linux terminal run the following$ git clone https://github.com/v-machine/gh_python_util$ mv -nv gh_python_util/src/ghpythonutil &#38;lt;PATH&#38;gt;/ghpythonutil$ rm gh_python_util






Option 2:
If you are unfamiliar with git, you can download the library from food4Rhino. Similar to Option 1, print out and choose one of the directory paths and copy the folder ghpythonutil into it.

Verify the installation by running the following import statement in a GhPython component:

from ghpythonutil.treehandler import TreeHandler




Usage
treehandler.TreeHandler is a function decorator for handling Data Trees as inputs in user-defined functions. Calls to decorated functions will avoid implicit looping behavior triggered by component inputs with item access or list access. The decorator will handle DataTree input in a fashion identical to any other default grasshopper component.

To use TreeHandler, simply decorate the function definition with @TreeHandler. For instance, in the previous complex task, we will right-click on all inputs to the GhPython component and choose tree access . We can then rewrite the function dist() as the following:

from ghpythonutil.treehandler import TreeHandler
@TreeHandlerdef dist(pt1, pt2, cutoff=15, access=["item", "item"]):&#38;nbsp; &#38;nbsp; """Returns the distance between two points"""&#38;nbsp; &#38;nbsp; return min(rs.Distance(pt1, pt2), cutoff)
Notice that we have added a default argument access as a list of access keywords: ["item", "item"]. Arguments in the decorated function definition must include the access default argument. This is due to the fact that the GhPython component will now parse all input as Data Trees. Thus, we must manually pass the actual access types to TreeHandler so that they are parsed correctly when the decorated function is called.

Specify list access if you know that the function takes a list of data as argument. For instance:

@TreeHandlerdef polyLine(vertices, access=["list"]): """Returns a polyline by connecting a list of vertices"""
&#38;nbsp; &#38;nbsp; return rs.AddPolyline(vertices)
Note that there’s no need to decorate every function that handles DataTree. In fact, all the subtasks — dist(), scale(), and standardCone() — can be wrapped inside a main() function, which shall be the only function to be decorated. Thus, we can modify our previous code snippets by replacing the last three function calls with a decorated main() function:

from ghpythonutil.treehandler import TreeHandler
# ...functions definitions same as previous code snippetsbase
base = makeQuadrants(base)attractor = makeQuadrants(attractor)

@TreeHandlerdef main(base, radius, attractor, factor=0.1,
&#38;nbsp; &#38;nbsp;      access=["item", "item", "item"]):
&#38;nbsp; &#38;nbsp; scalar = dist(base, attractor) * factor
&#38;nbsp; &#38;nbsp; radius = scale(scalar, radius, bounds=(0.1, radius))
&#38;nbsp; &#38;nbsp; return standardCone(base, radius)a = main(base, radius, attractor)
Note that we don’t care if makeQuadrants() is decorated, since the task of transforming the input Data Tree topology requires us to explicitly manipulate path indices. For all other functions, we can simply delegate Data Tree handling to TreeHandler.

Normally we can verify that our code is running as expected by inspecting the input and output Data Trees. However, since we had modified Data Tree topology of our inputs within a component, we need to manually inspect both arguments and return values from main().

print("Input Data Trees Topology")for arg in (base, radius, attractor):
&#38;nbsp; &#38;nbsp; print(arg.TopologyDescription)print("Output Data Trees Topology")&#38;nbsp; &#38;nbsp; print(a.TopologyDescription)
With main() being a function with “one-to-one” mapping (i.e., all input have item access), we can verify that the returned Data Tree has the expected topology, which normally coincides with that of the largest input. Note that other types of functions with different mappings, such as “many-to-one” (e.g., AddPolyline()) and “one-to-many” (e.g., divideCurve()) may yield different output topologies.

Input Data Trees Topology

Tree (Branches = 4){0;0;0} (N = 9){0;0;1} (N = 9){0;1;0} (N = 9{0;1;1} (N = 9)

Tree (Branches = 1){0} (N = 1)

Tree (Branches = 4){0;0;0} (N = 1){0;0;1} (N = 1){0;1;0} (N = 1){0;1;1} (N = 1)

Output Data Trees TopologyTree (Branches = 4){0;0;0} (N = 9){0;0;1} (N = 9){0;1;0} (N = 9){0;1;1} (N = 9)
We can also verify the result by visual inspection. As intended, we see that an attractor only affects cones within the same quadrant. We can also inspect individual Data Tree branches using the default Grasshopper Tree Branch component. By isolating each branch, we observe that the resulting grid of cones is indeed divided into quadrants.





&#60;img width="1400" height="798" width_o="1400" height_o="798" data-src="https://freight.cargo.site/t/original/i/eeb806818739bf6a401d7a40d4d163f7523e0e3ee3126529e8fe6771fb0dd5e2/cone_demo_attractors.gif" data-mid="103164778" border="0"  src="https://freight.cargo.site/w/1000/i/eeb806818739bf6a401d7a40d4d163f7523e0e3ee3126529e8fe6771fb0dd5e2/cone_demo_attractors.gif" /&#62;
&#60;img width="1400" height="799" width_o="1400" height_o="799" data-src="https://freight.cargo.site/t/original/i/3e32461c5bb4035404cd58ff48107231d7ab0d634c0921a2e0695ee6802f24de/cone_demo_branch.gif" data-mid="103164779" border="0"  src="https://freight.cargo.site/w/1000/i/3e32461c5bb4035404cd58ff48107231d7ab0d634c0921a2e0695ee6802f24de/cone_demo_branch.gif" /&#62;




Performance
There have long been discussions regarding the performance of the GhPython module, which has seen drastic improvement with the release of Rhino 6. Below shows the runtime of Data Trees processed in a native Grasshopper component, and in a GhPython component with implicit and manual looping, with multithreading, and finally, with TreeHandler decorator. Runtimes are measured on input sizes: N={2601, 10201, 40401, 90601, 160801, 250001}.

These are by no means objective nor comprehensive, due to the limitations of hardware and unavoidable fluctuations in the results even when running the same test consecutively.

One-to-One Function (with flattened input)
The first test calls the Rhino.Geometry.Circle() function. For flattened input (single branch), the performance of TreeHandler is on par with the native Grasshopper component, and with manual or parallel iteration on Data Trees. The slowest performing (3x slower) is implicit looping, with type hint enabled on a GhPython component. It has been mentioned in prior discussions that type hints seem to have a visible impact on performance, without which, however, certain function calls will require typecasting. To control for this variable, we shall disable type hints for all subsequent tests.




&#60;img width="3146" height="1280" width_o="3146" height_o="1280" data-src="https://freight.cargo.site/t/original/i/cc94337ceb0bc85624feb73c4ed6f39e5b9f9d8f240bd621d6e28c2a9afc2ab2/ghpython_runtime_flattened_one_to_one.png" data-mid="103165092" border="0"  src="https://freight.cargo.site/w/1000/i/cc94337ceb0bc85624feb73c4ed6f39e5b9f9d8f240bd621d6e28c2a9afc2ab2/ghpython_runtime_flattened_one_to_one.png" /&#62;


One-to-One Function
Next, we will measure runtime on unflatten inputs with multiple branches, while the function call remains unchanged. We observe that even with type hints turned off, GhPython with implicit looping still takes twice as long to finish the same task. Overall, TreeHandler seems to run closely along with all other options, if not marginally faster.
&#60;img width="3146" height="1280" width_o="3146" height_o="1280" data-src="https://freight.cargo.site/t/original/i/d9da3798b3f17308d4f0685880530a7791183556eece752a62295f6791b3cfc7/ghpython_runtime_one_to_one.png" data-mid="103165095" border="0"  src="https://freight.cargo.site/w/1000/i/d9da3798b3f17308d4f0685880530a7791183556eece752a62295f6791b3cfc7/ghpython_runtime_one_to_one.png" /&#62;




Many-to-One Function
In this test, the task is to connect a list of input points into a polyline (hence many-to-one) using the Rhino.Geometry.Polyline() function. Triggered by vertices with list access, GhPython module’s implicit looping still performs the slowest. However, we also observe that almost all other methods had outperformed TreeHandler, with the native Grasshopper component running the fastest.
&#60;img width="3146" height="1281" width_o="3146" height_o="1281" data-src="https://freight.cargo.site/t/original/i/dac8922f55e7d6bebf00ca35ab767f8474665dca517897b08ee4edb7afce09a2/ghpython_runtime_many_to_one.png" data-mid="103165093" border="0"  src="https://freight.cargo.site/w/1000/i/dac8922f55e7d6bebf00ca35ab767f8474665dca517897b08ee4edb7afce09a2/ghpython_runtime_many_to_one.png" /&#62;




One-to-Many Function
In our last test, we will divide a curve and obtain a set of dividing points using rhinoscriptsyntax.DivideCurve(). I shall point out that this is not a fair comparison for the native Grasshopper Divide Curve component returns three values versus single values returned by the GhPython components. From this, we can infer that Divide Curve probably executes a much more complicated algorithm and thus the longer runtime. Set aside this outlier, we see that TreeHandler performs squarely in the middle, on par with manual looping and the multi-threaded implementation.



&#60;img width="3146" height="1280" width_o="3146" height_o="1280" data-src="https://freight.cargo.site/t/original/i/fd29942fd22eb8913291b4df4d4d82695d856b6c4e121ca510c3757db62bba66/ghpython_runtime_one_to_many.png" data-mid="103165094" border="0"  src="https://freight.cargo.site/w/1000/i/fd29942fd22eb8913291b4df4d4d82695d856b6c4e121ca510c3757db62bba66/ghpython_runtime_one_to_many.png" /&#62;




Notes


In our performance tests, we mostly called functions from rhinoscriptsyntax and Rhino.Geometry. You’re welcomed to use TreeHandler to decorate functions from ghpythonlib.components, though be mindful of the performance decrease for this is essentially wrapping a Grasshopper component within a GhPython component.Functions decorated with TreeHandler will handle Data Trees exactly like any other native Grasshopper component, regardless of whether the Data Tree had been grafted, flattened, or simplified, and irrespective of whether the input Data Trees have mismatched shapes (topologies). What has yet to be tested is the performance on processing unmatching Data Trees, which is likely to run foreseeably slower due to branch matching.Should you forgot to set the component inputs to have tree access, TreeHandler will implicitly cast any item and list into trees. However, this is without the added benefit of runtime speed-up, for item access and list access inadvertently trigger the component’s implicit looping behavior.Parallelization of a decorated function is not supported yet. Although it is definitely possible to further optimize the performance of TreeHandler with leaner data structures, faster algorithms, and multi-threading. These are all subjects of experiment before the next release.



Additional Resources
Intro to Data TreeAndrew Heumann’s Rules for Healthy and Happy Data TreesData Tree to Python list and vice versaScripting Geometries in Grasshopper Python




    
</description>
		
	</item>
		
		
	<item>
		<title>Die Hard Jug Puzzle I</title>
				
		<link>https://vincentmai.com/Die-Hard-Jug-Puzzle-I</link>

		<pubDate>Tue, 15 Jun 2021 22:28:12 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Die-Hard-Jug-Puzzle-I</guid>

		<description>if (themeLoaded) adaptTheme();






	
	
Die Hard Jug Puzzle I




From jug puzzles to Bézout's Identity



June 15 / 2021
____________________



	


	

	
	
	
    
       &#60;img width="2578" height="1575" width_o="2578" height_o="1575" data-src="https://freight.cargo.site/t/original/i/bd62e239005cc02e0de46c35a1cb07c518b4e539b285af3f8054222d021f9349/cover_.png" data-mid="111492300" border="0"  src="https://freight.cargo.site/w/1000/i/bd62e239005cc02e0de46c35a1cb07c518b4e539b285af3f8054222d021f9349/cover_.png" /&#62;
       Suppose you have two jugs that hold 7 gallons and 10 gallons of liquid respectively. Let’s further suppose that there are no visible markings on the jug, thus making it impossible to eyeball the volume of liquid inside. Now, how would you fill up these jugs so that they sum to exactly 12 gallons?
This is the exact problem Detective McClane and Electrician Carver faced in the movie Die Hard 3, except for a much dire consequence—the resulting volume must be within an ounce to target or a ticking bomb goes off. Nonetheless, the jug puzzle in the movie—to make 4 gallons out of 3 and 5-gallon-jugs—seems to be a simpler variant. Therefore, a sensible approach is to toy with the simpler version and hope that it can generalize to the more difficult one.

&#60;img width="800" height="337" width_o="800" height_o="337" data-src="https://freight.cargo.site/t/original/i/6a95aa739ff7a4a7bf5622339c38f80675f0bd3a6ffd74bb38d76a95d4c384a7/die_hard_jug_scene.gif" data-mid="111662585" border="0"  src="https://freight.cargo.site/w/800/i/6a95aa739ff7a4a7bf5622339c38f80675f0bd3a6ffd74bb38d76a95d4c384a7/die_hard_jug_scene.gif" /&#62;



Given a 5-gallon and a 3-gallon-jug, how can you fill them with exactly 4 gallons of liquid?

With a bit of trial and error, we can first fill up the 5-gallon-jug, then pour it into the 3-gallon-jug until filled, leaving 2 gallons of liquid behind. We can then empty the 3-gallon-jug and into it pour the remaining 2-gallon-leftover. Notice that the 3-gallon-jug is only a gallon short of full. Now, all that's left is to refill the 5-gallon-jug and continue to pour the liquid into the 3-gallon-jug until filled. In other words, we have poured away 1 gallon from 5 gallons, leaving behind exactly 4 gallons.
Phew! Another day saved! But we are not quite done yet. Can you come up with a different way of filling the jugs to get 4 gallons?
This time, we will start by filling up the 3-gallon-jug, then empty it into the 5-gallon-jug. Now, let's refill the 3-gallon-jug and, similar to the previous solution, carefully pour away another 2 gallons to fill up the 5-gallon-jug. In the 3-gallon-jug currently sits exactly one gallon of liquid. Let's empty the 5-gallon-jug to make room for the 1-gallon-leftover. With one gallon secured, we can finally refill the 3-gallon-jug to get a total sum of 4 gallons.


That was not too thorny. But how can these two solutions help solve our original puzzle? What are steps taken that lead to the target? Can an algebraic representation generalize our solution to all other jug puzzles? Let's find out.
Let xm,ymx_m, y_mxm,ym denote the capacity of the two jugs, where xm&#38;gt;ymx_m &#38;gt; y_mxm&#38;gt;ym. Let xxx, yyy be the current volume of liquid inside the two jugs, where x∈[0,xm],y∈[0,ym]x in [0, x_m], y in [0, y_m]x∈[0,xm],y∈[0,ym].
In Die Hard 3, the jugs are 3 and 5-gallon respectively, or xm=5,ym=3x_m = 5, y_m = 3xm=5,ym=3. Now, let these symbols represent the steps in the two solutions.

Solution 1:



step
physical steps
symbolic step
volume




1
fill 5GL jug
(x,y)=(xm,0)(x, y) = (x_m, 0)(x,y)=(xm,0)
(5, 0)


2
pour 5GL jug into 3GL jug
x=x−ymx = x - y_mx=x−ym, y=ymy = y_my=ym
(2, 3)


3
empty 3GL jug, into it pour 2GL leftover
(x,y)=(0,x)(x, y) = (0, x)(x,y)=(0,x)
(0, 2)


4
refill 5GL jug
(x,y)=(xm,y)(x, y) = (x_m, y)(x,y)=(xm,y)
(5, 2)


5
pour 5GL jug into 3GL jug uitil filled
x=xm−(ym−y)x = x_m - (y_m - y)x=xm−(ym−y), y=ymy = y_my=ym
(4, 3)


6
empty 3GL jug
(x,y)=(x,0)(x, y) = (x, 0)(x,y)=(x,0)
(4, 0)




Solution 2:



step
physical steps
symbolic step
volume




1
fill 3GL jug
(x,y)=(0,ym)(x, y) = (0, y_m)(x,y)=(0,ym)
(0, 3)


2
empty 3GL jug into 5GL jug
(x,y)=(y,0)(x, y) = (y, 0)(x,y)=(y,0)
(3, 0)


3
refill 3GL jug
(x,y)=(x,ym)(x, y) = (x, y_m)(x,y)=(x,ym)
(3, 3)


4
pour 3GL jug into 5GL jug until filled
x=xmx = x_mx=xm, y=ym−(xm−x)y = y_m - (x_m - x)y=ym−(xm−x)
(5, 1)


5
empty 5GL jug, into it pour 1GL leftover
(x,y)=(y,0)(x, y) = (y, 0)(x,y)=(y,0)
(1, 0)


6
refill 3GL jug
(x,y)=(x,ym)(x, y) = (x, y_m)(x,y)=(x,ym)
(1, 3)




With the power of algebra, we can discard the numbers and focus on the symbols only. To help us generalize better, we can extract common operations used across the solutions as the following:
Note: these operations are valid if x∈[0,xm]x in [0, x_m]x∈[0,xm], y∈[0,ym]y in [0, y_m]y∈[0,ym].



id
operation
symbolic operation




a
fill empty x
(x,y)=(xm,y)(x, y) = (x_m, y)(x,y)=(xm,y)


b
fill empty y
(x,y)=(x,ym)(x, y) = (x, y_m)(x,y)=(x,ym)


c
pour away x to fill non-empty y
x=xm−(ym−y)x = x_m - (y_m - y)x=xm−(ym−y), y=ymy = y_my=ym


d
pour away y to fill non-empty x
x=xmx = x_mx=xm, y=ym−(xm−x)y = y_m - (x_m - x)y=ym−(xm−x)


e
pour x into empty y
(x,y)={(0,x)x≤ym(x−ym,ym)x&#38;gt;ym(x, y) =begin{cases} (0, x) &#38;amp; x leq y_m  (x - y_m, y_m) &#38;amp; x gt y_m end{cases}(x,y)={(0,x)(x−ym,ym)x≤ymx&#38;gt;ym


f
pour y into empty x
(x,y)=(y,0)(x, y) = (y, 0)(x,y)=(y,0)


g
dump x
(x,y)=(0,y)(x, y) = (0, y)(x,y)=(0,y)


h
dump y
(x,y)=(x,0)(x, y) = (x, 0)(x,y)=(x,0)




If we think of the volume of both jugs (x,y)(x, y)(x,y) as a state of the jug problem, then these operations are means to get from one state to another. For instance, the 4th step in Solution 1 shows an operation: x=xm−(ym−y)x = x_m - (y_m - y)x=xm−(ym−y) via which one can get from (5,2)(5, 2)(5,2) to (4,3)(4, 3)(4,3). Using states and operations as building blocks, an intuitive representation into which we can transform the problem is a graph.
&#60;img width="2639" height="882" width_o="2639" height_o="882" data-src="https://freight.cargo.site/t/original/i/b6493daee7af51267953655d25d22c499a3a42032be6103888e22460f39410f1/die_hard_jug_graph_00.png" data-mid="111651435" border="0"  src="https://freight.cargo.site/w/1000/i/b6493daee7af51267953655d25d22c499a3a42032be6103888e22460f39410f1/die_hard_jug_graph_00.png" /&#62;

Graph 1.1


A graph is composed of a set of vertices and edges. In Graph 1.1, the vertices represent the states (x,y)(x, y)(x,y) while the edges the allowable operations. Notice that the edges are bidirectional, in other words, the same operation can be reversed such that any given state can reach both of its predecessor and successor. For instance, from state (1,0)(1, 0)(1,0), one can perform operation b to get to (1,3)(1, 3)(1,3), or operation e then a to reverse back to (5,1)(5, 1)(5,1).
Since our target concerns only with the sum sis_isi = xi+yix_i + y_ixi+yi, we can simplify the above graph by summing each vertex and prunning repeated sums. Graph 1.2 shows a prunned version of Graph 1.1, where edges with more than one operation denote a sequence of operations to be performed in order. Let's take one step further and remove vertices whose si&#38;gt;xms_i &#38;gt; x_msi&#38;gt;xm. We are able to do so for the following reasons:

∀sjforall s_j∀sj where sj∈(xm,xm+ym]s_j in (x_m, x_m + y_m]sj∈(xm,xm+ym],
∃skexist s_k∃sk where sk∈(0,ym]s_k in (0, y_m]sk∈(0,ym], such that sj=sk+xms_j = s_k + x_msj=sk+xm.
∵because∵ sk=sj−xms_k = s_j - x_msk=sj−xm.
sj−xm∈(xm−xm,xm−xm+ym]s_j - x_m in (x_m - x_m, x_m - x_m + y_m]sj−xm∈(xm−xm,xm−xm+ym] ⟹sk∈(0,ym]Longrightarrow s_k in (0, y_m]⟹sk∈(0,ym]

For instance, Let sj=6,sk=1s_j = 6, s_k = 1sj=6,sk=1. sj=sk+xm=1+5s_j = s_k + x_m = 1 + 5sj=sk+xm=1+5. Thus, for any sum si&#38;gt;xm=5s_i &#38;gt; x_m = 5si&#38;gt;xm=5, if we can reach all sk∈(0,ym=3]s_k in (0, y_m = 3]sk∈(0,ym=3], then we shall reach all sj∈(5,8]s_j in (5, 8]sj∈(5,8].

Assumption [1]: ∀si∈(0,ym],∃(xi,yi)forall s_i in (0, y_m], exist (x_i, y_i)∀si∈(0,ym],∃(xi,yi), such that si=xi+yis_i = x_i + y_isi=xi+yi.


&#60;img width="2642" height="817" width_o="2642" height_o="817" data-src="https://freight.cargo.site/t/original/i/46d495feef80a76ef570a968406274b8dd7ebf4ef7875a59d433645a6959d69e/die_hard_jug_graph_01.png" data-mid="111651737" border="0"  src="https://freight.cargo.site/w/1000/i/46d495feef80a76ef570a968406274b8dd7ebf4ef7875a59d433645a6959d69e/die_hard_jug_graph_01.png" /&#62;
Graph 1.2 (L)&#38;nbsp; &#38;amp;&#38;nbsp; Graph 1.3 (R)
For now, should we take this assumption for granted, Graph 1.2 can be reduced to Graph 1.3. Furthermore, we can truncate the edges threading sis_isi by combining their sequence of operations. For instance, operations f, b, d, f going through vertex si=6s_i = 6si=6 can be reduced to si+1=si+ym−xms_{i+1} = s_i + y_m - x_msi+1=si+ym−xm, while operations a, c, h going through vertex si=7s_i = 7si=7 can be simplified to si+1=si+xm−yms_{i+1} = s_i + x_m - y_msi+1=si+xm−ym.
Thus, the distilled graph representation only requires the following operations:
Note: these operations are valid only when si+1∈[0,xm+ym]s_{i+1} in [0, x_m + y_m]si+1∈[0,xm+ym].



symbolic operation




si+1=si+xms_{i+1} = s_i+x_msi+1=si+xm


si+1=si±yms_{i+1} = s_i pm y_msi+1=si±ym


si+1=si±(xm−ym)s_{i+1} = s_i pm(x_m - y_m)si+1=si±(xm−ym)



Using this new symbolic representation, can you solve the original problem?

Given a 10 and a 7-gallon-jug, how can you fill them with exactly 12 gallons of liquid?


Well, we can start by reformulating the problem statement with our new found representation:

Let xm=10x_m = 10xm=10, ym=7y_m = 7ym=7. Perform one operation at a time, show all states in sequence {s0,s1,s2,...st}{s_0, s_1, s_2, ... s_t}{s0,s1,s2,...st} between s0=0s_0 = 0s0=0 and st=12s_t = 12st=12?

In this representation, there are no better ways to reach the target than trial and error, so long as the next state si+1∈(0,xm+ym]s_{i+1} in (0, x_m + y_m]si+1∈(0,xm+ym]. Let's begin from s0=0s_0 = 0s0=0. The valid options are +xm+x_m+xm or +ym+y_m+ym. Therefore s1s_1s1 is either 0+ym=70 + y_m = 70+ym=7 or 0+xm=100 + x_m = 100+xm=10. For s1=7s_1 = 7s1=7, the valid options are s2=s1±(xm−ym)s_2 = s_1 pm(x_m - y_m)s2=s1±(xm−ym), or s2=s1−yms_2 = s_1 - y_ms2=s1−ym. In the spirit of not repeating seen numbers, we proceed with s2=s1−(xm−ym)=4s_2 = s_1 - (x_m - y_m) = 4s2=s1−(xm−ym)=4. In addition, given Assumption [1], we can further avoid yielding si&#38;gt;xms_i &#38;gt; x_msi&#38;gt;xm for we conject that all sis_isi are reachable by sk+xms_k + x_msk+xm, where sk∈(0,ym]s_k in (0, y_m]sk∈(0,ym].
&#60;img width="2637" height="869" width_o="2637" height_o="869" data-src="https://freight.cargo.site/t/original/i/02d41960c016cfb2faaa7e9bab5cc03a2631213298c04c873c334f969fdf8861/die_hard_jug_graph_02.png" data-mid="111651490" border="0"  src="https://freight.cargo.site/w/1000/i/02d41960c016cfb2faaa7e9bab5cc03a2631213298c04c873c334f969fdf8861/die_hard_jug_graph_02.png" /&#62;

Thus we turn our trial-and-error into the following algorithm:
&#60;img width="1677" height="1023" width_o="1677" height_o="1023" data-src="https://freight.cargo.site/t/original/i/87ce982fb66cc5c57e21aab09491ec6736097a933090083212d1352a99eeb958/algorithm_1_.png" data-mid="111651464" border="0"  src="https://freight.cargo.site/w/1000/i/87ce982fb66cc5c57e21aab09491ec6736097a933090083212d1352a99eeb958/algorithm_1_.png" /&#62;If we "run" the algorithm in our heads, we get the following result: {0,7,4,1,8,5,12}{0, 7, 4, 1, 8, 5, 12}{0,7,4,1,8,5,12}.
&#60;img width="2637" height="903" width_o="2637" height_o="903" data-src="https://freight.cargo.site/t/original/i/577d0efe1034f5c44fc051a1db270ce45d35429454da857a3804ec0ae02d7e12/die_hard_jug_graph_03.png" data-mid="111651488" border="0"  src="https://freight.cargo.site/w/1000/i/577d0efe1034f5c44fc051a1db270ce45d35429454da857a3804ec0ae02d7e12/die_hard_jug_graph_03.png" /&#62;

With the trial and error algorithm, it is possible that we will visit all si∈(0,xm],si≠sts_i in (0, x_m], s_i neq s_tsi∈(0,xm],si=st before we can get to our target sts_tst. Thus, we can estimate an upper bound 

n for the worst case that takes n steps to reach the target, where n=∣operations∣∗xmn = &#124;operations&#124; * x_mn=∣operations∣∗xm.
All seems well, except for two minor problems:

The assumption on which our algorithm rests upon has yet to be proven.
Can we do better than trial and error, in other words, can we find an algorithm that takes less steps to get to the target?

To see how we might go about these problems, stay tune for part II.
References:
Eugenia Cheng. "The Perfect Glass of Wine." The University of Sheffield Youtube Channel.
Mathologer. "How not to Die Hard with Math." Youtube Channel.

	
</description>
		
	</item>
		
		
	<item>
		<title>Content - Ideas</title>
				
		<link>https://vincentmai.com/Content-Ideas</link>

		<pubDate>Wed, 03 Mar 2021 16:27:46 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Content-Ideas</guid>

		<description>
	
	
	
	
	

	
	
	
	
	
 


	
	




Die HardJug Puzzle I
From jug puzzles to Bézout's Identity06/15/2021




	

Handling Data Trees in Grasshopper Python Scripts


Decorate your functions swiftly and easily with TreeHandler03/24/2021








	


	






	


	




	
	




	




	




	


 if (themeLoaded) adaptTheme(); </description>
		
	</item>
		
		
	<item>
		<title>content - All</title>
				
		<link>https://vincentmai.com/content-All</link>

		<pubDate>Sat, 27 Feb 2021 02:49:27 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/content-All</guid>

		<description>console.log("in content-all"); if (themeLoaded) adaptTheme();

	




	
	
    Architecture Lecture Series&#60;img width="2177" height="1411" width_o="2177" height_o="1411" data-src="https://freight.cargo.site/t/original/i/7fe0702490e181b5d6d39a58015bb2116eaea6a5f453bbb246bfaed44c38c95c/architecture-lecture-series-poster_thumbnail.png" data-mid="100325283" border="0"  src="https://freight.cargo.site/w/1000/i/7fe0702490e181b5d6d39a58015bb2116eaea6a5f453bbb246bfaed44c38c95c/architecture-lecture-series-poster_thumbnail.png" /&#62;
	Architecture League Price&#60;img width="4477" height="2932" width_o="4477" height_o="2932" data-src="https://freight.cargo.site/t/original/i/9dae097219ac7efc4aa4f78c168e309c46d00343e4e48e7480460b88d5edf42c/architecture-league-price-booklet_thumbnail.jpg" data-mid="100325284" border="0"  src="https://freight.cargo.site/w/1000/i/9dae097219ac7efc4aa4f78c168e309c46d00343e4e48e7480460b88d5edf42c/architecture-league-price-booklet_thumbnail.jpg" /&#62;
	Auto Entourage&#60;img width="1200" height="673" width_o="1200" height_o="673" data-src="https://freight.cargo.site/t/original/i/b83e4df2a484f0c168214161287a948590b1479be49065fbec67f6d3613d21ed/auto_entourage_thumbnail.gif" data-mid="100325291" border="0"  src="https://freight.cargo.site/w/1000/i/b83e4df2a484f0c168214161287a948590b1479be49065fbec67f6d3613d21ed/auto_entourage_thumbnail.gif" /&#62;
	Carcassonne&#60;img width="2062" height="1674" width_o="2062" height_o="1674" data-src="https://freight.cargo.site/t/original/i/9bf88cbfa3684638935e18f86cc3145b6f54d27c7cc89721945f4e2680e33262/carcassonne-thumbnail.gif" data-mid="100325298" border="0"  src="https://freight.cargo.site/w/1000/i/9bf88cbfa3684638935e18f86cc3145b6f54d27c7cc89721945f4e2680e33262/carcassonne-thumbnail.gif" /&#62;
	Culinary Institute&#60;img width="1275" height="972" width_o="1275" height_o="972" data-src="https://freight.cargo.site/t/original/i/81ef525167425d536e7e6f6ba9d28d7c0f388b143029f82447926e47b3b699a2/culinary_institute_thumbnail.gif" data-mid="100325304" border="0"  src="https://freight.cargo.site/w/1000/i/81ef525167425d536e7e6f6ba9d28d7c0f388b143029f82447926e47b3b699a2/culinary_institute_thumbnail.gif" /&#62;
	Intergenerational Interaction&#60;img width="2319" height="1256" width_o="2319" height_o="1256" data-src="https://freight.cargo.site/t/original/i/811c4746a1a6f2688c7ccb372a7011328f47f5b95d21e13456e6e543308822f2/parametric_identity_tumbnail.gif" data-mid="100325292" border="0"  src="https://freight.cargo.site/w/1000/i/811c4746a1a6f2688c7ccb372a7011328f47f5b95d21e13456e6e543308822f2/parametric_identity_tumbnail.gif" /&#62;
	Integrate Softly&#60;img width="1200" height="854" width_o="1200" height_o="854" data-src="https://freight.cargo.site/t/original/i/ebb37d312d332548afc7172a0923518b52fc1421525b73f471f5f011a713783e/integrate-softly_thumbnail.gif" data-mid="100325303" border="0"  src="https://freight.cargo.site/w/1000/i/ebb37d312d332548afc7172a0923518b52fc1421525b73f471f5f011a713783e/integrate-softly_thumbnail.gif" /&#62;
	Flatiron Pavilion Competition&#60;img width="2246" height="1795" width_o="2246" height_o="1795" data-src="https://freight.cargo.site/t/original/i/23c89a555d0deb6a48be89c86ddb9068e464d31f1573399562bc305a9121c607/flatiron-pavilion-competition-booklet_thumbnail.jpg" data-mid="100325285" border="0"  src="https://freight.cargo.site/w/1000/i/23c89a555d0deb6a48be89c86ddb9068e464d31f1573399562bc305a9121c607/flatiron-pavilion-competition-booklet_thumbnail.jpg" /&#62;
	Flatiron Reflection&#60;img width="1780" height="1903" width_o="1780" height_o="1903" data-src="https://freight.cargo.site/t/original/i/1558dd6de1b265bb710420406718da7b0642885d3de3bcfdb2cf9fcd275377ac/flatiron-reflection-thumbnail.jpg" data-mid="100325297" border="0"  src="https://freight.cargo.site/w/1000/i/1558dd6de1b265bb710420406718da7b0642885d3de3bcfdb2cf9fcd275377ac/flatiron-reflection-thumbnail.jpg" /&#62;
	FoG Farm Master Plan&#60;img width="3954" height="2580" width_o="3954" height_o="2580" data-src="https://freight.cargo.site/t/original/i/0d781ed9062ef4b4d6465d4cce20cbb9a2b8d17a9acfa116deb7b4bcad86d143/fogg-farm-planning_thumbnail.png" data-mid="100325290" border="0"  src="https://freight.cargo.site/w/1000/i/0d781ed9062ef4b4d6465d4cce20cbb9a2b8d17a9acfa116deb7b4bcad86d143/fogg-farm-planning_thumbnail.png" /&#62;
	FoG Farm North Pond&#60;img width="1238" height="817" width_o="1238" height_o="817" data-src="https://freight.cargo.site/t/original/i/fee36a4e6669d9a9639a86d96c1d760ceccce7622cd0da9a3cb3fec395589479/fog-farm_north-pond_thumbnail.gif" data-mid="100325294" border="0"  src="https://freight.cargo.site/w/1000/i/fee36a4e6669d9a9639a86d96c1d760ceccce7622cd0da9a3cb3fec395589479/fog-farm_north-pond_thumbnail.gif" /&#62;
	Grassroots Prototypes&#60;img width="1000" height="851" width_o="1000" height_o="851" data-src="https://freight.cargo.site/t/original/i/ab6859ca54c9c9222520323a71521fb72c3084772a292b221732fc8e729aa922/grassroots-prototypes_thumbnail.gif" data-mid="100325293" border="0"  src="https://freight.cargo.site/w/1000/i/ab6859ca54c9c9222520323a71521fb72c3084772a292b221732fc8e729aa922/grassroots-prototypes_thumbnail.gif" /&#62;
	Kanslighted&#60;img width="2243" height="1495" width_o="2243" height_o="1495" data-src="https://freight.cargo.site/t/original/i/ede9cd0f36e8bd98075d87e4f28ef4b2dfef2b83217e57930b4c46e17b069bd1/Kanslighted_thumbnail.jpg" data-mid="100336365" border="0"  src="https://freight.cargo.site/w/1000/i/ede9cd0f36e8bd98075d87e4f28ef4b2dfef2b83217e57930b4c46e17b069bd1/Kanslighted_thumbnail.jpg" /&#62;
     Last.fm Music Recommender{image -}
    Lexigraph&#60;img width="2099" height="1500" width_o="2099" height_o="1500" data-src="https://freight.cargo.site/t/original/i/fd52531cda048a97801bf2f2637c780e2090b28d5e5cbc728260364bf2caeecd/lexigraph-thumbnail.gif" data-mid="100325299" border="0"  src="https://freight.cargo.site/w/1000/i/fd52531cda048a97801bf2f2637c780e2090b28d5e5cbc728260364bf2caeecd/lexigraph-thumbnail.gif" /&#62;
	Maruyama's Pond Slime&#60;img width="1888" height="1320" width_o="1888" height_o="1320" data-src="https://freight.cargo.site/t/original/i/869d00a396d5ec2938ac926ade32ce2b758ec67055b605a95f9bb4000207c033/maruyama-pond-slime_thumbnail.gif" data-mid="100325301" border="0"  src="https://freight.cargo.site/w/1000/i/869d00a396d5ec2938ac926ade32ce2b758ec67055b605a95f9bb4000207c033/maruyama-pond-slime_thumbnail.gif" /&#62;
	Parametric Identity&#60;img width="923" height="1258" width_o="923" height_o="1258" data-src="https://freight.cargo.site/t/original/i/fd52bac911f26cb3e822c8cb95258c2d5506be3fd108582a9995aeaae8fc6fc4/parametric-identity_thumbnail.png" data-mid="100325288" border="0"  src="https://freight.cargo.site/w/923/i/fd52bac911f26cb3e822c8cb95258c2d5506be3fd108582a9995aeaae8fc6fc4/parametric-identity_thumbnail.png" /&#62;
	Performative Concrete&#60;img width="932" height="1308" width_o="932" height_o="1308" data-src="https://freight.cargo.site/t/original/i/f9da561a0d0a18a40d1afa9fa62415d40318f5e116ec5b4b04ee8474f6aa084c/performative-concrete_thumbnail.png" data-mid="100325287" border="0"  src="https://freight.cargo.site/w/932/i/f9da561a0d0a18a40d1afa9fa62415d40318f5e116ec5b4b04ee8474f6aa084c/performative-concrete_thumbnail.png" /&#62;
	R.&#38;nbsp;Rauschenberg Foundation&#60;img width="832" height="1088" width_o="832" height_o="1088" data-src="https://freight.cargo.site/t/original/i/d3c887e84eb5970a65db333f9950fa58f10b4702fb2e113b034279e9cdd0757e/rauschenberg-foundation-thumbnail.gif" data-mid="100325296" border="0"  src="https://freight.cargo.site/w/832/i/d3c887e84eb5970a65db333f9950fa58f10b4702fb2e113b034279e9cdd0757e/rauschenberg-foundation-thumbnail.gif" /&#62;
	Recent Working Directory&#60;img width="753" height="375" width_o="753" height_o="375" data-src="https://freight.cargo.site/t/original/i/b88f91761d7f402f5e1c8f14f2ec0baed3f014a4fadcfd72613a46c42676445f/recent-working-directory-thumbnail.gif" data-mid="100325295" border="0"  src="https://freight.cargo.site/w/753/i/b88f91761d7f402f5e1c8f14f2ec0baed3f014a4fadcfd72613a46c42676445f/recent-working-directory-thumbnail.gif" /&#62;
	Shape Grammar&#60;img width="1889" height="1320" width_o="1889" height_o="1320" data-src="https://freight.cargo.site/t/original/i/f40def96ea07b15edaaae56ad16878835689f22f99bd68d0a24b2e285f7b7bbb/shape-grammar_thumbnail.gif" data-mid="100325281" border="0"  src="https://freight.cargo.site/w/1000/i/f40def96ea07b15edaaae56ad16878835689f22f99bd68d0a24b2e285f7b7bbb/shape-grammar_thumbnail.gif" /&#62;
	Social Interaction &#38;amp; Cohesion&#60;img width="1869" height="1240" width_o="1869" height_o="1240" data-src="https://freight.cargo.site/t/original/i/73d5b4d8fe2adafe4987e03d6aa099f798b897dd89577650b6a08dac3ec629aa/social-interaction--cohesion_thumbnail.png" data-mid="100325289" border="0"  src="https://freight.cargo.site/w/1000/i/73d5b4d8fe2adafe4987e03d6aa099f798b897dd89577650b6a08dac3ec629aa/social-interaction--cohesion_thumbnail.png" /&#62;
	The Amplifier&#60;img width="1000" height="662" width_o="1000" height_o="662" data-src="https://freight.cargo.site/t/original/i/2e5f5e5847153359fa2422a156fa74b5f33e086cdf651bd155a862067c9c2831/the-amplifier-thumbnail.gif" data-mid="100325305" border="0"  src="https://freight.cargo.site/w/1000/i/2e5f5e5847153359fa2422a156fa74b5f33e086cdf651bd155a862067c9c2831/the-amplifier-thumbnail.gif" /&#62;
	The Hult Plaze&#60;img width="1000" height="661" width_o="1000" height_o="661" data-src="https://freight.cargo.site/t/original/i/949776790ba14a15a9cf4169c10fbfb4e4554a0d7a80215d92fbb4ed962281f6/the-hult-plaza_thumbnail.gif" data-mid="100325300" border="0"  src="https://freight.cargo.site/w/1000/i/949776790ba14a15a9cf4169c10fbfb4e4554a0d7a80215d92fbb4ed962281f6/the-hult-plaza_thumbnail.gif" /&#62;
	Timber Interface&#60;img width="1144" height="1063" width_o="1144" height_o="1063" data-src="https://freight.cargo.site/t/original/i/2300f3058aaae7bdf29cfbc057362ff24be102f9fe93e9c833f493aa1254eaf9/Timber-Interface_thumbnial.png" data-mid="100325282" border="0"  src="https://freight.cargo.site/w/1000/i/2300f3058aaae7bdf29cfbc057362ff24be102f9fe93e9c833f493aa1254eaf9/Timber-Interface_thumbnial.png" /&#62;
	Underline Canopy&#60;img width="1200" height="890" width_o="1200" height_o="890" data-src="https://freight.cargo.site/t/original/i/d2305371064864ef5e13aee24c9eebbce132910ee51b4c814a4991d78247721e/underline-canopy_thumbnail.gif" data-mid="100325306" border="0"  src="https://freight.cargo.site/w/1000/i/d2305371064864ef5e13aee24c9eebbce132910ee51b4c814a4991d78247721e/underline-canopy_thumbnail.gif" /&#62;
    365Places Dimensional Reduction{image -}
    
	

</description>
		
	</item>
		
		
	<item>
		<title>Content - Architecture</title>
				
		<link>https://vincentmai.com/Content-Architecture</link>

		<pubDate>Mon, 22 Feb 2021 11:26:57 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Content-Architecture</guid>

		<description>console.log("in content - architecture"); if (themeLoaded) adaptTheme();



	
	

Timber Interface&#60;img width="1144" height="1063" width_o="1144" height_o="1063" data-src="https://freight.cargo.site/t/original/i/2300f3058aaae7bdf29cfbc057362ff24be102f9fe93e9c833f493aa1254eaf9/Timber-Interface_thumbnial.png" data-mid="100322229" border="0"  src="https://freight.cargo.site/w/1000/i/2300f3058aaae7bdf29cfbc057362ff24be102f9fe93e9c833f493aa1254eaf9/Timber-Interface_thumbnial.png" /&#62;


Culinary Institute&#60;img width="1275" height="972" width_o="1275" height_o="972" data-src="https://freight.cargo.site/t/original/i/81ef525167425d536e7e6f6ba9d28d7c0f388b143029f82447926e47b3b699a2/culinary_institute_thumbnail.gif" data-mid="100300779" border="0"  src="https://freight.cargo.site/w/1000/i/81ef525167425d536e7e6f6ba9d28d7c0f388b143029f82447926e47b3b699a2/culinary_institute_thumbnail.gif" /&#62;


Grassroots Prototypes&#60;img width="1000" height="851" width_o="1000" height_o="851" data-src="https://freight.cargo.site/t/original/i/ab6859ca54c9c9222520323a71521fb72c3084772a292b221732fc8e729aa922/grassroots-prototypes_thumbnail.gif" data-mid="100311625" border="0"  src="https://freight.cargo.site/w/1000/i/ab6859ca54c9c9222520323a71521fb72c3084772a292b221732fc8e729aa922/grassroots-prototypes_thumbnail.gif" /&#62;


Flatiron Reflection&#60;img width="1780" height="1903" width_o="1780" height_o="1903" data-src="https://freight.cargo.site/t/original/i/1558dd6de1b265bb710420406718da7b0642885d3de3bcfdb2cf9fcd275377ac/flatiron-reflection-thumbnail.jpg" data-mid="100310177" border="0"  src="https://freight.cargo.site/w/1000/i/1558dd6de1b265bb710420406718da7b0642885d3de3bcfdb2cf9fcd275377ac/flatiron-reflection-thumbnail.jpg" /&#62;


Integrate Softly&#60;img width="1200" height="854" width_o="1200" height_o="854" data-src="https://freight.cargo.site/t/original/i/ebb37d312d332548afc7172a0923518b52fc1421525b73f471f5f011a713783e/integrate-softly_thumbnail.gif" data-mid="100306461" border="0"  src="https://freight.cargo.site/w/1000/i/ebb37d312d332548afc7172a0923518b52fc1421525b73f471f5f011a713783e/integrate-softly_thumbnail.gif" /&#62;


R.&#38;nbsp;Rauschenberg Foundation&#60;img width="832" height="1088" width_o="832" height_o="1088" data-src="https://freight.cargo.site/t/original/i/d3c887e84eb5970a65db333f9950fa58f10b4702fb2e113b034279e9cdd0757e/rauschenberg-foundation-thumbnail.gif" data-mid="100309639" border="0"  src="https://freight.cargo.site/w/832/i/d3c887e84eb5970a65db333f9950fa58f10b4702fb2e113b034279e9cdd0757e/rauschenberg-foundation-thumbnail.gif" /&#62;


Underline Canopy&#60;img width="1200" height="890" width_o="1200" height_o="890" data-src="https://freight.cargo.site/t/original/i/d2305371064864ef5e13aee24c9eebbce132910ee51b4c814a4991d78247721e/underline-canopy_thumbnail.gif" data-mid="100304555" border="0"  src="https://freight.cargo.site/w/1000/i/d2305371064864ef5e13aee24c9eebbce132910ee51b4c814a4991d78247721e/underline-canopy_thumbnail.gif" /&#62;

The Amplifier&#60;img width="1000" height="662" width_o="1000" height_o="662" data-src="https://freight.cargo.site/t/original/i/2e5f5e5847153359fa2422a156fa74b5f33e086cdf651bd155a862067c9c2831/the-amplifier-thumbnail.gif" data-mid="100303102" border="0"  src="https://freight.cargo.site/w/1000/i/2e5f5e5847153359fa2422a156fa74b5f33e086cdf651bd155a862067c9c2831/the-amplifier-thumbnail.gif" /&#62;


FoG Farm North Pond&#60;img width="1238" height="817" width_o="1238" height_o="817" data-src="https://freight.cargo.site/t/original/i/fee36a4e6669d9a9639a86d96c1d760ceccce7622cd0da9a3cb3fec395589479/fog-farm_north-pond_thumbnail.gif" data-mid="100311718" border="0"  src="https://freight.cargo.site/w/1000/i/fee36a4e6669d9a9639a86d96c1d760ceccce7622cd0da9a3cb3fec395589479/fog-farm_north-pond_thumbnail.gif" /&#62;


	

	


</description>
		
	</item>
		
		
	<item>
		<title>Content - Urbanism</title>
				
		<link>https://vincentmai.com/Content-Urbanism</link>

		<pubDate>Tue, 23 Feb 2021 01:34:14 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Content-Urbanism</guid>

		<description>console.log("in content - urbanism"); if (themeLoaded) adaptTheme();

	
	

The Hult Plaze&#60;img width="1000" height="661" width_o="1000" height_o="661" data-src="https://freight.cargo.site/t/original/i/949776790ba14a15a9cf4169c10fbfb4e4554a0d7a80215d92fbb4ed962281f6/the-hult-plaza_thumbnail.gif" data-mid="100310063" border="0"  src="https://freight.cargo.site/w/1000/i/949776790ba14a15a9cf4169c10fbfb4e4554a0d7a80215d92fbb4ed962281f6/the-hult-plaza_thumbnail.gif" /&#62;


Parametric Identity&#60;img width="923" height="1258" width_o="923" height_o="1258" data-src="https://freight.cargo.site/t/original/i/fd52bac911f26cb3e822c8cb95258c2d5506be3fd108582a9995aeaae8fc6fc4/parametric-identity_thumbnail.png" data-mid="100316995" border="0"  src="https://freight.cargo.site/w/923/i/fd52bac911f26cb3e822c8cb95258c2d5506be3fd108582a9995aeaae8fc6fc4/parametric-identity_thumbnail.png" /&#62;


Social Interaction &#38;amp; Cohesion&#60;img width="1869" height="1240" width_o="1869" height_o="1240" data-src="https://freight.cargo.site/t/original/i/73d5b4d8fe2adafe4987e03d6aa099f798b897dd89577650b6a08dac3ec629aa/social-interaction--cohesion_thumbnail.png" data-mid="100314370" border="0"  src="https://freight.cargo.site/w/1000/i/73d5b4d8fe2adafe4987e03d6aa099f798b897dd89577650b6a08dac3ec629aa/social-interaction--cohesion_thumbnail.png" /&#62;


Intergenerational Interaction&#60;img width="2319" height="1256" width_o="2319" height_o="1256" data-src="https://freight.cargo.site/t/original/i/811c4746a1a6f2688c7ccb372a7011328f47f5b95d21e13456e6e543308822f2/parametric_identity_tumbnail.gif" data-mid="100316964" border="0"  src="https://freight.cargo.site/w/1000/i/811c4746a1a6f2688c7ccb372a7011328f47f5b95d21e13456e6e543308822f2/parametric_identity_tumbnail.gif" /&#62;



	

	


</description>
		
	</item>
		
		
	<item>
		<title>Content - Visual Design</title>
				
		<link>https://vincentmai.com/Content-Visual-Design</link>

		<pubDate>Tue, 23 Feb 2021 01:55:47 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Content-Visual-Design</guid>

		<description>if (themeLoaded) adaptTheme();


	
	

Architecture Lecture Series&#60;img width="2177" height="1411" width_o="2177" height_o="1411" data-src="https://freight.cargo.site/t/original/i/7fe0702490e181b5d6d39a58015bb2116eaea6a5f453bbb246bfaed44c38c95c/architecture-lecture-series-poster_thumbnail.png" data-mid="100322305" border="0"  src="https://freight.cargo.site/w/1000/i/7fe0702490e181b5d6d39a58015bb2116eaea6a5f453bbb246bfaed44c38c95c/architecture-lecture-series-poster_thumbnail.png" /&#62;


Architecture League Price&#60;img width="4477" height="2932" width_o="4477" height_o="2932" data-src="https://freight.cargo.site/t/original/i/9dae097219ac7efc4aa4f78c168e309c46d00343e4e48e7480460b88d5edf42c/architecture-league-price-booklet_thumbnail.jpg" data-mid="100321435" border="0"  src="https://freight.cargo.site/w/1000/i/9dae097219ac7efc4aa4f78c168e309c46d00343e4e48e7480460b88d5edf42c/architecture-league-price-booklet_thumbnail.jpg" /&#62;


Flatiron Pavilion Competition&#60;img width="2246" height="1795" width_o="2246" height_o="1795" data-src="https://freight.cargo.site/t/original/i/23c89a555d0deb6a48be89c86ddb9068e464d31f1573399562bc305a9121c607/flatiron-pavilion-competition-booklet_thumbnail.jpg" data-mid="100321436" border="0"  src="https://freight.cargo.site/w/1000/i/23c89a555d0deb6a48be89c86ddb9068e464d31f1573399562bc305a9121c607/flatiron-pavilion-competition-booklet_thumbnail.jpg" /&#62;


Kanslighted&#60;img width="2243" height="1495" width_o="2243" height_o="1495" data-src="https://freight.cargo.site/t/original/i/ede9cd0f36e8bd98075d87e4f28ef4b2dfef2b83217e57930b4c46e17b069bd1/Kanslighted_thumbnail.jpg" data-mid="100336263" border="0"  src="https://freight.cargo.site/w/1000/i/ede9cd0f36e8bd98075d87e4f28ef4b2dfef2b83217e57930b4c46e17b069bd1/Kanslighted_thumbnail.jpg" /&#62;



	

	


</description>
		
	</item>
		
		
	<item>
		<title>Content - Software Development</title>
				
		<link>https://vincentmai.com/Content-Software-Development</link>

		<pubDate>Mon, 22 Feb 2021 04:29:03 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Content-Software-Development</guid>

		<description>if (themeLoaded) adaptTheme();

	
	

Lexigraph
&#60;img width="2099" height="1500" width_o="2099" height_o="1500" data-src="https://freight.cargo.site/t/original/i/fd52531cda048a97801bf2f2637c780e2090b28d5e5cbc728260364bf2caeecd/lexigraph-thumbnail.gif" data-mid="100312050" border="0"  src="https://freight.cargo.site/w/1000/i/fd52531cda048a97801bf2f2637c780e2090b28d5e5cbc728260364bf2caeecd/lexigraph-thumbnail.gif" /&#62;

Recent Working Directory
&#60;img width="753" height="375" width_o="753" height_o="375" data-src="https://freight.cargo.site/t/original/i/b88f91761d7f402f5e1c8f14f2ec0baed3f014a4fadcfd72613a46c42676445f/recent-working-directory-thumbnail.gif" data-mid="100313573" border="0"  src="https://freight.cargo.site/w/753/i/b88f91761d7f402f5e1c8f14f2ec0baed3f014a4fadcfd72613a46c42676445f/recent-working-directory-thumbnail.gif" /&#62;

Carcassonne
&#60;img width="2062" height="1674" width_o="2062" height_o="1674" data-src="https://freight.cargo.site/t/original/i/9bf88cbfa3684638935e18f86cc3145b6f54d27c7cc89721945f4e2680e33262/carcassonne-thumbnail.gif" data-mid="100312785" border="0"  src="https://freight.cargo.site/w/1000/i/9bf88cbfa3684638935e18f86cc3145b6f54d27c7cc89721945f4e2680e33262/carcassonne-thumbnail.gif" /&#62;

Auto Entourage
&#60;img width="1200" height="673" width_o="1200" height_o="673" data-src="https://freight.cargo.site/t/original/i/b83e4df2a484f0c168214161287a948590b1479be49065fbec67f6d3613d21ed/auto_entourage_thumbnail.gif" data-mid="100315524" border="0"  src="https://freight.cargo.site/w/1000/i/b83e4df2a484f0c168214161287a948590b1479be49065fbec67f6d3613d21ed/auto_entourage_thumbnail.gif" /&#62;



	

	


</description>
		
	</item>
		
		
	<item>
		<title>Content - Design Computation</title>
				
		<link>https://vincentmai.com/Content-Design-Computation</link>

		<pubDate>Mon, 22 Feb 2021 14:47:42 +0000</pubDate>

		<dc:creator>Vincent Mai Design</dc:creator>

		<guid isPermaLink="true">https://vincentmai.com/Content-Design-Computation</guid>

		<description>if (themeLoaded) adaptTheme();

	
	

Maruyama's Pond Slime&#60;img width="1888" height="1320" width_o="1888" height_o="1320" data-src="https://freight.cargo.site/t/original/i/869d00a396d5ec2938ac926ade32ce2b758ec67055b605a95f9bb4000207c033/maruyama-pond-slime_thumbnail.gif" data-mid="100319392" border="0"  src="https://freight.cargo.site/w/1000/i/869d00a396d5ec2938ac926ade32ce2b758ec67055b605a95f9bb4000207c033/maruyama-pond-slime_thumbnail.gif" /&#62;


Shape Grammar&#60;img width="1889" height="1320" width_o="1889" height_o="1320" data-src="https://freight.cargo.site/t/original/i/f40def96ea07b15edaaae56ad16878835689f22f99bd68d0a24b2e285f7b7bbb/shape-grammar_thumbnail.gif" data-mid="100319391" border="0"  src="https://freight.cargo.site/w/1000/i/f40def96ea07b15edaaae56ad16878835689f22f99bd68d0a24b2e285f7b7bbb/shape-grammar_thumbnail.gif" /&#62;


Flatiron Reflection&#60;img width="1780" height="1903" width_o="1780" height_o="1903" data-src="https://freight.cargo.site/t/original/i/1558dd6de1b265bb710420406718da7b0642885d3de3bcfdb2cf9fcd275377ac/flatiron-reflection-thumbnail.jpg" data-mid="100313942" border="0"  src="https://freight.cargo.site/w/1000/i/1558dd6de1b265bb710420406718da7b0642885d3de3bcfdb2cf9fcd275377ac/flatiron-reflection-thumbnail.jpg" /&#62;


Performative Concrete&#60;img width="932" height="1308" width_o="932" height_o="1308" data-src="https://freight.cargo.site/t/original/i/f9da561a0d0a18a40d1afa9fa62415d40318f5e116ec5b4b04ee8474f6aa084c/performative-concrete_thumbnail.png" data-mid="100317232" border="0"  src="https://freight.cargo.site/w/932/i/f9da561a0d0a18a40d1afa9fa62415d40318f5e116ec5b4b04ee8474f6aa084c/performative-concrete_thumbnail.png" /&#62;


Parametric Identity&#60;img width="923" height="1258" width_o="923" height_o="1258" data-src="https://freight.cargo.site/t/original/i/fd52bac911f26cb3e822c8cb95258c2d5506be3fd108582a9995aeaae8fc6fc4/parametric-identity_thumbnail.png" data-mid="100319450" border="0"  src="https://freight.cargo.site/w/923/i/fd52bac911f26cb3e822c8cb95258c2d5506be3fd108582a9995aeaae8fc6fc4/parametric-identity_thumbnail.png" /&#62;


Social Interaction &#38;amp; Cohesion&#60;img width="1869" height="1240" width_o="1869" height_o="1240" data-src="https://freight.cargo.site/t/original/i/73d5b4d8fe2adafe4987e03d6aa099f798b897dd89577650b6a08dac3ec629aa/social-interaction--cohesion_thumbnail.png" data-mid="100314218" border="0"  src="https://freight.cargo.site/w/1000/i/73d5b4d8fe2adafe4987e03d6aa099f798b897dd89577650b6a08dac3ec629aa/social-interaction--cohesion_thumbnail.png" /&#62;


Intergenerational Interaction&#60;img width="2319" height="1256" width_o="2319" height_o="1256" data-src="https://freight.cargo.site/t/original/i/811c4746a1a6f2688c7ccb372a7011328f47f5b95d21e13456e6e543308822f2/parametric_identity_tumbnail.gif" data-mid="100319451" border="0"  src="https://freight.cargo.site/w/1000/i/811c4746a1a6f2688c7ccb372a7011328f47f5b95d21e13456e6e543308822f2/parametric_identity_tumbnail.gif" /&#62;


FoG Farm Planning&#60;img width="3954" height="2580" width_o="3954" height_o="2580" data-src="https://freight.cargo.site/t/original/i/0d781ed9062ef4b4d6465d4cce20cbb9a2b8d17a9acfa116deb7b4bcad86d143/fogg-farm-planning_thumbnail.png" data-mid="100317671" border="0"  src="https://freight.cargo.site/w/1000/i/0d781ed9062ef4b4d6465d4cce20cbb9a2b8d17a9acfa116deb7b4bcad86d143/fogg-farm-planning_thumbnail.png" /&#62;


	

	


</description>
		
	</item>
		
	</channel>
</rss>