#StackBounty: #javascript #array #html #random #form Displaying Media with HTML and JavaScript

Bounty: 50

I have a personal website that I use to share videos and images with friends. Below is a media generator using JavaScript and HTML. Its main purpose is to display one image at a time at the click of a button, but any type of media can be displayed. My goal was to create a fast-loading page to hold all of my media.

//VIDEO ARRAY
var oddvideo = [
  'video1',
  'video2',
  'video3',
  'video4',
  'video5',
];
//AUDIO ARRAY
var oddaudio = [
  'audio1',
  'audio2',
  'audio3',
  'audio4',
  'audio5',
];
//PHOTO ARRAY
var oddphoto = [
  'photo1',
  'photo2',
  'photo3',
  'photo4',
  'photo5',
];
//TEXT ARRAY
var oddtext = [
  'text1',
  'text2',
  'text3',
  'text4',
  'text5',
];

//RANDOM UNUSED ARRAY ITEMS
var Uvideo = [];
var Uaudio = [];
var Uphoto = [];
var Utext = [];
//OLD-NEW VARIABLES
var videoFor = 0;
var audioFor = 0;
var photoFor = 0;
var textFor = 0;
//NEW-OLD VARIABLES
var videoRev = oddvideo.length - 1;
var audioRev = oddaudio.length - 1;
var photoRev = oddphoto.length - 1;
var textRev = oddtext.length - 1;

//GENERATOR FUNCTION
function newThing() {
    //RANDOM MODE
    if(mode1.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {
      if (videoCheck.checked) {
        if (!Uvideo.length) Uvideo = [...oddvideo];
        var randomY = Uvideo;
      }
      if (audioCheck.checked) {
        if (!Uaudio.length) Uaudio = [...oddaudio];
        var randomY = Uaudio;
      }
      if (photoCheck.checked) {
        if (!Uphoto.length) Uphoto = [...oddphoto];
        var randomY = Uphoto;
      }
      if (textCheck.checked) {
        if (!Utext.length) Utext = [...oddtext];
        var randomY = Utext;
      }
      var randomX = Math.floor(Math.random() * (randomY.length));
      var y = randomY;
      var x = randomX;
      document.getElementById("thingDisplay").innerHTML = y[x];
      // remove randomx from the unused array since it's been used now
      randomY.splice(randomX, 1);
}
//OLD-NEW MODE
if(mode2.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {
    if(videoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddvideo[videoFor];
        videoFor++;
        if (videoFor >= oddvideo.length) videoFor = 0;
    }
    if(audioCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddaudio[audioFor];
        audioFor++;
        if (audioFor >= oddaudio.length) audioFor = 0;
    }
    if(photoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddphoto[photoFor];
        photoFor++;
        if (photoFor >= oddphoto.length) photoFor = 0;
    }
    if(textCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddtext[textFor];
        textFor++;
        if (textFor >= oddtext.length) textFor = 0;
    }
}
//NEW-OLD MODE
if(mode3.checked && (videoCheck.checked || audioCheck.checked || photoCheck.checked || textCheck.checked)) {
    if(videoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddvideo[videoRev];
        videoRev--;
        if (videoRev < 0) videoRev = oddvideo.length - 1;
    }
    if(audioCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddaudio[audioRev];
        audioRev--;
        if (audioRev < 0) audioRev = oddaudio.length - 1;
    }
    if(photoCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddphoto[photoRev];
        photoRev--;
        if (photoRev < 0) photoRev = oddphoto.length - 1;
    }
    if(textCheck.checked) {
        document.getElementById('thingDisplay').innerHTML = oddtext[textRev];
        textRev--;
        if (textRev < 0) textRev = oddtext.length - 1;
    }
}
}
<body>
  <div align="center" id='thingDisplay'></div>
  
  <div align="center">
    <button onclick="newThing()">New Thing</button>
  </div>
  
  <form id="mode">
    <label><input type="radio" name="modes" id="mode1"/></label>&nbsp;Random
    <br/><label><input type="radio" name="modes" id="mode2"/></label>&nbsp;Old&nbsp;-&nbsp;New
    <br/><label><input type="radio" name="modes" id="mode3"/></label>&nbsp;New&nbsp;-&nbsp;Old
  </form>

  <div align="right">
    <form id="categories" align="right">
      Video<label>&nbsp;<input type="radio" name="thing" id="videoCheck"/></label><br/>
      Audio<label>&nbsp;<input type="radio" name="thing" id="audioCheck"/></label><br/>
      Photo<label>&nbsp;<input type="radio" name="thing" id="photoCheck"/></label><br/>
      Text<label>&nbsp;<input type="radio" name="thing" id="textCheck"/></label>
    </form>
  </div>
</body>

A Few Things to Note…

  • I organize the JavaScript arrays with the youngest at the top and oldest at the bottom (with dates, it would look like this: oddDate = [‘Oct. 1’, ‘Oct. 2’, ‘Oct. 3’, ‘Oct. 4’, ‘Oct. 5’]; )
  • The random mode is pseudo random, and is designed to display all array items once before repeating one.
  • The old-new and new-old modes move through the arrays from top to
    bottom and bottom to top, respectively.
  • Each mode and category saves its place when you change to a different one. For example, let’s say you have the old-new mode on and are on item 3 of the text category. You switch to the photo category, run through the array a bit, then return to the text category. It will display the next item from where you left off last; so item 4.
  • One concern is that the generator and page will get slower and slower as I continue to add more items to the arrays, but I’m unsure if this is legitimate. In the live version, there are 500+ items in each array and more will be added over time.


Get this bounty!!!

#StackBounty: #game-design #game-mechanics #random #probability Preferred way of calculating run chances in Game of Cricket

Bounty: 50

For modelling a simple game of cricket, Considering a batsman has a single attribute rating. I can go about deciding run chances by weighted probabilities. Something like

    if batsman.rating <= 30:
        # map of run: probability
        probabilites = {0: 0.7, 1: 0.1, 2: 0.1, 3:0.5, 4:0.5, 6:0 }
    elif 30 <batsman.rating < 60
        probabilites = {0: 0.7, 1: 0.1, 2: 0.1, 3:0.5, 4:0.5, 6:0 }
    else:
        probabilites = {0: 0.7, 1: 0.1, 2: 0.1, 3:0.5, 4:0.5, 6:0 }

Now there are two challenges:

  1. What if I want finer control over batsman.rating and probabilities? How do I manage to keep the sum of all probabilities equal to 1?
  2. How to manage a second attribute to a batsman, let’s say aggression. Which can lower chances of 0 and increase chances of 6?

Initially tried dealing to have finer control like below:

# map of batsman.rating: probability, 
rating_to_zero_chances = {0: 0.9, 10: 0.7, 30: 0.5, 60: 0.3, 90: 0.1}
rating_to_one_chances = {0: 0.9, 10: 0.7, 30: 0.5, 60: 0.3, 90: 0.1}
chances_of_zero =  <some library>.interpolate(rating_to_zero_chances).yvalue(batsman.rating)
chances_of_one =  <some library>.interpolate(rating_to_one_chances).yvalue(batsman.rating)
.
.
.
#do this for each run

The problem with this is that I cannot interpolate the probabilities such that they are equal to 1, Since the slope of runs for the interpolated data are different

For challenge 2, Initially tried handling it by making a probability density function and shifting the mean of the curve if the aggression is more. This creates a problem when there is a 3rd or 4th attribute added (such as timing etc are added).

Currently am planning to deal with a single run with its chance, rather than having to sum their probabilities to 1 like below:

zero_chance = interpolate(rating_to_zero_chances).yvalue(batsman.rating)
zero_chance += aggression / 100  # assuming aggression on 1-100
is_zero_scored = binom([0,1], p=zero_chance).random()
if is_zero_scored:
    return 0    
one_chance = interpolate(rating_to_one_chances).yvalue(batsman.rating)
one_chance += aggression / 90  # assuming aggression on 1-100
is_one_scored = binom([0,1], p=one_chance).random()
if is_one_scored:
   return 1
. # similarly for 2
.
.

Is there any neater way to do this? I am new to game development and had learned about probability distributions recently. Are there some theoretical/ practically established concepts I should be looking at?
How do game developers handle and balance different chances of an event?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!

#StackBounty: #python #python-3.x #random #graph Test the hypothesis that the expected number of edges of a random connected graph is …

Bounty: 50

Motivation

The most common model for a random graph is the Erdős–Rényi model. However, it does not guarantee the connectedness of the graph. Instead, let’s consider the following algorithm (in python-style pseudocode) for generating a random connected graph with $n$ nodes:

g = empty graph
g.add_nodes_from(range(n))

while not g.is_connected:
    i, j = random combination of two (distinct) nodes in range(n)
    if {i, j} not in g.edges:
        g.add_edge(i, j)

return g

The graph generated this way is guaranteed to be connected. Now, my intuition tells me that its expected number of edges is of the order $ O(n log n) $, and I want to test my hypothesis in Python. I don’t intend to do a rigorous mathematical proof or a comprehensive statistical inference, just some basic graph plotting.

The Codes

In order to know whether a graph is connected, we need a partition structure (i.e. union-find). I first wrote a Partition class in the module partition.py. It uses path compression and union by weights:

# partition.py

class Partition:
    """Implement a partition of a set of items to disjoint subsets (groups) as
    a forest of trees, in which each tree represents a separate group.
    Two trees represent the same group if and only if they have the same root.
    Support union operation of two groups.
    """

    def __init__(self, items):
        items = list(items)

        # parents of every node in the forest
        self._parents = {item: item for item in items}

        # the sizes of the subtrees
        self._weights = {item: 1 for item in items}

    def __len__(self):
        return len(self._parents)

    def __contains__(self, item):
        return item in self._parents

    def __iter__(self):
        yield from self._parents

    def find(self, item):
        """Return the root of the group containing the given item.
        Also reset the parents of all nodes along the path to the root.
        """
        if self._parents[item] == item:
            return item
        else:
            # find the root and recursively set all parents to it
            root = self.find(self._parents[item])
            self._parents[item] = root
            return root

    def union(self, item1, item2):
        """Merge the two groups (if they are disjoint) containing
        the two given items.
        """
        root1 = self.find(item1)
        root2 = self.find(item2)

        if root1 != root2:
            if self._weights[root1] < self._weights[root2]:
                # swap two roots so that root1 becomes heavier
                root1, root2 = root2, root1

            # root1 is heavier, reset parent of root2 to root1
            # also update the weight of the tree at root1
            self._parents[root2] = root1
            self._weights[root1] += self._weights[root2]

    @property
    def is_single_group(self):
        """Return true if all items are contained in a single group."""
        # we just need one item, any item is ok
        item = next(iter(self))

        # group size is the weight of the root
        group_size = self._weights[self.find(item)]
        return group_size == len(self)

Next, since we are only interested in the number of edges, we don’t actually need to explicitly construct any graph object. The following function implicitly generates a random connected graph and return its number of edges:

import random
from partition import Partition

def connected_edge_count(n):
    """Implicitly generate a random connected graph and return its number of edges."""
    edges = set()
    forest = Partition(range(n))

    # each time we join two nodes we merge the two groups containing them
    # the graph is connected iff the forest of nodes form a single group
    while not forest.is_single_group:
        start = random.randrange(n)
        end = random.randrange(n)

        # we don't bother to check whether the edge already exists
        if start != end:
            forest.union(start, end)
            edge = frozenset({start, end})
            edges.add(edge)

    return len(edges)

We then estimate the expected number of edges for a given $n$:

def mean_edge_count(n, sample_size):
    """Compute the sample mean of numbers of edges in a sample of
    random connected graphs with n nodes.
    """
    total = sum(connected_edge_count(n) for _ in range(sample_size))
    return total / sample_size

Now, we can plot the expected numbers of edges against $ n log n $ for different values of $n$:

from math import log
import matplotlib.pyplot as plt

def plt_mean_vs_nlogn(nlist, sample_size):
    """Plot the expected numbers of edges against n * log(n) for
    a given list of values of n, where n is the number of nodes.
    """
    x_values = [n * log(n) for n in nlist]
    y_values = [mean_edge_count(n, sample_size) for n in nlist]
    plt.plot(x_values, y_values, '.')

Finally, when we called plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100), we got:

enter image description here

The plot seems very close to a straight line, supporting my hypothesis.

Questions and ideas for future work

  1. My program is slow! It took me 90 seconds to run plt_mean_vs_nlogn(range(10, 1001, 10), sample_size=100). How can I improve the performance?
  2. What other improvement can I make on my codes?
  3. An idea for future work: do a linear regression on the data. A high coefficient of determination would support my hypothesis. Also find out the coefficient of $ n log n $.
  4. Any other idea for testing my hypothesis programmatically?


Get this bounty!!!